diff --git a/headers/private/kernel/vfs.h b/headers/private/kernel/vfs.h index 0ef087c164..fe4b2f103b 100644 --- a/headers/private/kernel/vfs.h +++ b/headers/private/kernel/vfs.h @@ -81,7 +81,7 @@ int vfs_getrlimit(int resource, struct rlimit *rlp); int vfs_setrlimit(int resource, const struct rlimit *rlp); /* calls needed by the VM for paging and by the file cache */ -int vfs_get_vnode_from_fd(int fd, bool kernel, struct vnode **_vnode); +status_t vfs_get_vnode_from_fd(int fd, bool kernel, struct vnode **_vnode); status_t vfs_get_vnode_from_path(const char *path, bool kernel, struct vnode **_vnode); status_t vfs_get_vnode(dev_t mountID, ino_t vnodeID, bool canWait, @@ -91,6 +91,7 @@ status_t vfs_entry_ref_to_vnode(dev_t mountID, ino_t directoryID, void vfs_vnode_to_node_ref(struct vnode *vnode, dev_t *_mountID, ino_t *_vnodeID); +int vfs_open_vnode(struct vnode* vnode, int openMode, bool kernel); status_t vfs_lookup_vnode(dev_t mountID, ino_t vnodeID, struct vnode **_vnode); void vfs_put_vnode(struct vnode *vnode); @@ -107,14 +108,14 @@ status_t vfs_vnode_io(struct vnode* vnode, void* cookie, io_request* request); status_t vfs_synchronous_io(io_request* request, status_t (*doIO)(void* cookie, off_t offset, void* buffer, - size_t* length), - void* cookie); + size_t* length), + void* cookie); status_t vfs_get_vnode_cache(struct vnode *vnode, struct VMCache **_cache, bool allocate); status_t vfs_get_file_map(struct vnode *vnode, off_t offset, size_t size, struct file_io_vec *vecs, size_t *_count); status_t vfs_get_fs_node_from_path(fs_volume *volume, const char *path, - bool kernel, void **_node); + bool traverseLeafLink, bool kernel, void **_node); status_t vfs_stat_vnode(struct vnode *vnode, struct stat *stat); status_t vfs_stat_node_ref(dev_t device, ino_t inode, struct stat *stat); status_t vfs_get_vnode_name(struct vnode *vnode, char *name, diff --git a/src/system/kernel/device_manager/AbstractModuleDevice.cpp b/src/system/kernel/device_manager/AbstractModuleDevice.cpp new file mode 100644 index 0000000000..e78673fd15 --- /dev/null +++ b/src/system/kernel/device_manager/AbstractModuleDevice.cpp @@ -0,0 +1,121 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2008-2009, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include "AbstractModuleDevice.h" + + +AbstractModuleDevice::AbstractModuleDevice() + : + fNode(NULL), + fInitialized(0), + fDeviceModule(NULL), + fDeviceData(NULL) +{ +} + + +AbstractModuleDevice::~AbstractModuleDevice() +{ +} + + +bool +AbstractModuleDevice::HasSelect() const +{ + return Module()->select != NULL; +} + + +bool +AbstractModuleDevice::HasDeselect() const +{ + return Module()->deselect != NULL; +} + + +bool +AbstractModuleDevice::HasRead() const +{ + return Module()->read != NULL; +} + + +bool +AbstractModuleDevice::HasWrite() const +{ + return Module()->write != NULL; +} + + +bool +AbstractModuleDevice::HasIO() const +{ + return Module()->io != NULL; +} + + +status_t +AbstractModuleDevice::Open(const char* path, int openMode, void** _cookie) +{ + return Module()->open(Data(), path, openMode, _cookie); +} + + +status_t +AbstractModuleDevice::Read(void* cookie, off_t pos, void* buffer, size_t* _length) +{ + return Module()->read(cookie, pos, buffer, _length); +} + + +status_t +AbstractModuleDevice::Write(void* cookie, off_t pos, const void* buffer, size_t* _length) +{ + return Module()->write(cookie, pos, buffer, _length); +} + + +status_t +AbstractModuleDevice::IO(void* cookie, io_request* request) +{ + return Module()->io(cookie, request); +} + + +status_t +AbstractModuleDevice::Control(void* cookie, int32 op, void* buffer, size_t length) +{ + return Module()->control(cookie, op, buffer, length); +} + + +status_t +AbstractModuleDevice::Select(void* cookie, uint8 event, selectsync* sync) +{ + return Module()->select(cookie, event, sync); +} + + +status_t +AbstractModuleDevice::Deselect(void* cookie, uint8 event, selectsync* sync) +{ + return Module()->deselect(cookie, event, sync); +} + + +status_t +AbstractModuleDevice::Close(void* cookie) +{ + return Module()->close(cookie); +} + + +status_t +AbstractModuleDevice::Free(void* cookie) +{ + return Module()->free(cookie); +} diff --git a/src/system/kernel/device_manager/AbstractModuleDevice.h b/src/system/kernel/device_manager/AbstractModuleDevice.h new file mode 100644 index 0000000000..7da1a1fb5a --- /dev/null +++ b/src/system/kernel/device_manager/AbstractModuleDevice.h @@ -0,0 +1,53 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2008-2009, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ +#ifndef ABSTRACT_MODULE_DEVICE_H +#define ABSTRACT_MODULE_DEVICE_H + + +#include "BaseDevice.h" + + +class AbstractModuleDevice : public BaseDevice { +public: + AbstractModuleDevice(); + virtual ~AbstractModuleDevice(); + + device_module_info* Module() const { return fDeviceModule; } + + void* Data() const { return fDeviceData; } + device_node* Node() const { return fNode; } + + virtual bool HasSelect() const; + virtual bool HasDeselect() const; + virtual bool HasRead() const; + virtual bool HasWrite() const; + virtual bool HasIO() const; + + virtual status_t Open(const char* path, int openMode, + void** _cookie); + virtual status_t Read(void* cookie, off_t pos, void* buffer, + size_t* _length); + virtual status_t Write(void* cookie, off_t pos, const void* buffer, + size_t* _length); + virtual status_t IO(void* cookie, io_request* request); + virtual status_t Control(void* cookie, int32 op, void* buffer, + size_t length); + virtual status_t Select(void* cookie, uint8 event, selectsync* sync); + virtual status_t Deselect(void* cookie, uint8 event, + selectsync* sync); + + virtual status_t Close(void* cookie); + virtual status_t Free(void* cookie); + +protected: + device_node* fNode; + int32 fInitialized; + device_module_info* fDeviceModule; + void* fDeviceData; +}; + + +#endif // ABSTRACT_MODULE_DEVICE_H diff --git a/src/system/kernel/device_manager/BaseDevice.cpp b/src/system/kernel/device_manager/BaseDevice.cpp index 780ce2f72f..d3d1c8b13b 100644 --- a/src/system/kernel/device_manager/BaseDevice.cpp +++ b/src/system/kernel/device_manager/BaseDevice.cpp @@ -8,11 +8,6 @@ BaseDevice::BaseDevice() - : - fNode(NULL), - fInitialized(0), - fDeviceModule(NULL), - fDeviceData(NULL) { } @@ -39,3 +34,80 @@ void BaseDevice::Removed() { } + + +bool +BaseDevice::HasSelect() const +{ + return false; +} + + +bool +BaseDevice::HasDeselect() const +{ + return false; +} + + +bool +BaseDevice::HasRead() const +{ + return false; +} + + +bool +BaseDevice::HasWrite() const +{ + return false; +} + + +bool +BaseDevice::HasIO() const +{ + return false; +} + + +status_t +BaseDevice::Read(void* cookie, off_t pos, void* buffer, size_t* _length) +{ + return B_UNSUPPORTED; +} + + +status_t +BaseDevice::Write(void* cookie, off_t pos, const void* buffer, size_t* _length) +{ + return B_UNSUPPORTED; +} + + +status_t +BaseDevice::IO(void* cookie, io_request* request) +{ + return B_UNSUPPORTED; +} + + +status_t +BaseDevice::Control(void* cookie, int32 op, void* buffer, size_t length) +{ + return B_UNSUPPORTED; +} + + +status_t +BaseDevice::Select(void* cookie, uint8 event, selectsync* sync) +{ + return B_UNSUPPORTED; +} + + +status_t +BaseDevice::Deselect(void* cookie, uint8 event, selectsync* sync) +{ + return B_UNSUPPORTED; +} diff --git a/src/system/kernel/device_manager/BaseDevice.h b/src/system/kernel/device_manager/BaseDevice.h index cf8b18ec76..e4c5f146a5 100644 --- a/src/system/kernel/device_manager/BaseDevice.h +++ b/src/system/kernel/device_manager/BaseDevice.h @@ -14,115 +14,39 @@ public: BaseDevice(); virtual ~BaseDevice(); - void SetID(ino_t id) { fID = id; } - ino_t ID() const { return fID; } - - device_node* Node() const { return fNode; } + void SetID(ino_t id) { fID = id; } + ino_t ID() const { return fID; } virtual status_t InitDevice(); virtual void UninitDevice(); virtual void Removed(); - device_module_info* Module() const { return fDeviceModule; } - void* Data() const { return fDeviceData; } - - bool HasSelect() const - { return Module()->select != NULL; } - bool HasDeselect() const - { return Module()->deselect != NULL; } - bool HasRead() const - { return Module()->read != NULL; } - bool HasWrite() const - { return Module()->write != NULL; } - bool HasIO() const - { return Module()->io != NULL; } + virtual bool HasSelect() const; + virtual bool HasDeselect() const; + virtual bool HasRead() const; + virtual bool HasWrite() const; + virtual bool HasIO() const; virtual status_t Open(const char* path, int openMode, - void** _cookie); - status_t Read(void* cookie, off_t pos, void* buffer, + void** _cookie) = 0; + virtual status_t Read(void* cookie, off_t pos, void* buffer, size_t* _length); - status_t Write(void* cookie, off_t pos, const void* buffer, + virtual status_t Write(void* cookie, off_t pos, const void* buffer, size_t* _length); - status_t IO(void* cookie, io_request* request); - status_t Control(void* cookie, int32 op, void* buffer, + virtual status_t IO(void* cookie, io_request* request); + virtual status_t Control(void* cookie, int32 op, void* buffer, size_t length); virtual status_t Select(void* cookie, uint8 event, selectsync* sync); - status_t Deselect(void* cookie, uint8 event, + virtual status_t Deselect(void* cookie, uint8 event, selectsync* sync); - status_t Close(void* cookie); - status_t Free(void* cookie); + virtual status_t Close(void* cookie) = 0; + virtual status_t Free(void* cookie) = 0; protected: ino_t fID; - device_node* fNode; - int32 fInitialized; - device_module_info* fDeviceModule; - void* fDeviceData; }; -inline status_t -BaseDevice::Open(const char* path, int openMode, void** _cookie) -{ - return Module()->open(Data(), path, openMode, _cookie); -} - - -inline status_t -BaseDevice::Read(void* cookie, off_t pos, void* buffer, size_t* _length) -{ - return Module()->read(cookie, pos, buffer, _length); -} - - -inline status_t -BaseDevice::Write(void* cookie, off_t pos, const void* buffer, size_t* _length) -{ - return Module()->write(cookie, pos, buffer, _length); -} - - -inline status_t -BaseDevice::IO(void* cookie, io_request* request) -{ - return Module()->io(cookie, request); -} - - -inline status_t -BaseDevice::Control(void* cookie, int32 op, void* buffer, size_t length) -{ - return Module()->control(cookie, op, buffer, length); -} - - -inline status_t -BaseDevice::Select(void* cookie, uint8 event, selectsync* sync) -{ - return Module()->select(cookie, event, sync); -} - - -inline status_t -BaseDevice::Deselect(void* cookie, uint8 event, selectsync* sync) -{ - return Module()->deselect(cookie, event, sync); -} - - -inline status_t -BaseDevice::Close(void* cookie) -{ - return Module()->close(cookie); -} - - -inline status_t -BaseDevice::Free(void* cookie) -{ - return Module()->free(cookie); -} - #endif // BASE_DEVICE_H diff --git a/src/system/kernel/device_manager/FileDevice.cpp b/src/system/kernel/device_manager/FileDevice.cpp new file mode 100644 index 0000000000..55e6fca21a --- /dev/null +++ b/src/system/kernel/device_manager/FileDevice.cpp @@ -0,0 +1,335 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "FileDevice.h" + +#include +#include + +#include + +#include + +#include + + +static const uint32 kBlockSize = 512; + + +struct FileDevice::Cookie { + int fd; + + Cookie(int fd) + : + fd(fd) + { + } + + ~Cookie() + { + if (fd >= 0) + close(fd); + } +}; + + +FileDevice::FileDevice() + : + fFD(-1), + fFileSize(0) +{ +} + + +FileDevice::~FileDevice() +{ + if (fFD >= 0) + close(fFD); +} + + +status_t +FileDevice::Init(const char* path) +{ + fFD = open(path, O_RDONLY | O_NOTRAVERSE); + if (fFD < 0) + return errno; + + struct stat st; + if (fstat(fFD, &st) != 0) + return errno; + + if (!S_ISREG(st.st_mode)) + return B_BAD_TYPE; + + fFileSize = st.st_size / kBlockSize * kBlockSize; + + return B_OK; +} + + +status_t +FileDevice::InitDevice() +{ + return B_OK; +} + + +void +FileDevice::UninitDevice() +{ +} + + +void +FileDevice::Removed() +{ + delete this; +} + + +bool +FileDevice::HasSelect() const +{ + return false; +} + + +bool +FileDevice::HasDeselect() const +{ + return false; +} + + +bool +FileDevice::HasRead() const +{ + return true; +} + + +bool +FileDevice::HasWrite() const +{ + return true; +} + + +bool +FileDevice::HasIO() const +{ + // TODO: Support! + return false; +} + + +status_t +FileDevice::Open(const char* path, int openMode, void** _cookie) +{ + // get the vnode + struct vnode* vnode; + status_t error = vfs_get_vnode_from_fd(fFD, true, &vnode); + if (error != B_OK) + return error; + + // open it + int fd = vfs_open_vnode(vnode, openMode, true); + if (fd < 0) { + vfs_put_vnode(vnode); + return fd; + } + // our vnode reference does now belong to the FD + + Cookie* cookie = new(std::nothrow) Cookie(fd); + if (cookie == NULL) { + close(fd); + return B_NO_MEMORY; + } + + *_cookie = cookie; + return B_OK; +} + + +status_t +FileDevice::Read(void* _cookie, off_t pos, void* buffer, size_t* _length) +{ + Cookie* cookie = (Cookie*)_cookie; + + ssize_t bytesRead = pread(cookie->fd, buffer, *_length, pos); + if (bytesRead < 0) { + *_length = 0; + return errno; + } + + *_length = bytesRead; + return B_OK; +} + + +status_t +FileDevice::Write(void* _cookie, off_t pos, const void* buffer, size_t* _length) +{ + Cookie* cookie = (Cookie*)_cookie; + + ssize_t bytesWritten = pwrite(cookie->fd, buffer, *_length, pos); + if (bytesWritten < 0) { + *_length = 0; + return errno; + } + + *_length = bytesWritten; + return B_OK; +} + + +status_t +FileDevice::IO(void* _cookie, io_request* request) +{ +// Cookie* cookie = (Cookie*)_cookie; +// return do_fd_io(cookie->fd, request); +// TODO: The implementation is fine in principle, but do_fd_io() requires either +// the io() hook or the {read,write}_pages() hooks of the underlying FS to be +// implemented, which we can't guarantee. do_fd_io() should work around by using +// read() and write(), but it's all quite of a mess, since we mix up the io() +// hook -- which ATM has the semantics of uncached_io() hook (i.e. ignoring the +// file cache) -- with the actual io() hook semantics (i.e. using the file +// cache). + return B_UNSUPPORTED; +} + + +template +static status_t +set_ioctl_result(const ResultType& result, void* buffer, size_t length) +{ + // NOTE: We omit the buffer size check for sake of callers (e.g. BFS) not + // specifying a length argument. +// if (sizeof(ResultType) < length) +// return B_BAD_VALUE; + + if (buffer == NULL) + return B_BAD_ADDRESS; + + if (!IS_USER_ADDRESS(buffer)) + return user_memcpy(buffer, &result, sizeof(ResultType)); + + memcpy(buffer, &result, sizeof(ResultType)); + return B_OK; +} + + +status_t +FileDevice::Control(void* _cookie, int32 op, void* buffer, size_t length) +{ + Cookie* cookie = (Cookie*)_cookie; + + switch (op) { + case B_GET_DEVICE_SIZE: + return set_ioctl_result( + fFileSize > ~(size_t)0 ? ~(size_t)0 : (size_t)fFileSize, + buffer, length); + + case B_SET_BLOCKING_IO: + case B_SET_NONBLOCKING_IO: + // TODO: Translate to O_NONBLOCK and pass on! + return B_OK; + + case B_GET_READ_STATUS: + case B_GET_WRITE_STATUS: + // TODO: poll() the FD! + return set_ioctl_result(true, buffer, length); + + case B_GET_ICON: + return B_UNSUPPORTED; + + case B_GET_GEOMETRY: + case B_GET_BIOS_GEOMETRY: + { + // fill in the geometry + // Optimally we have only 1 block per sector and only one head. + // Since we have only a uint32 for the cylinder count, this won't + // work for files > 2TB. So, we set the head count to the minimally + // possible value. + off_t blocks = fFileSize / kBlockSize; + uint32 heads = (blocks + 0xfffffffe) / 0xffffffff; + if (heads == 0) + heads = 1; + + device_geometry geometry; + geometry.bytes_per_sector = kBlockSize; + geometry.sectors_per_track = 1; + geometry.cylinder_count = blocks / heads; + geometry.head_count = heads; + geometry.device_type = B_DISK; + geometry.removable = false; + geometry.read_only = false; + geometry.write_once = false; + + return set_ioctl_result(geometry, buffer, length); + } + + case B_GET_MEDIA_STATUS: + return set_ioctl_result((status_t)B_OK, buffer, length); + + case B_SET_INTERRUPTABLE_IO: + case B_SET_UNINTERRUPTABLE_IO: + return B_OK; + + case B_FLUSH_DRIVE_CACHE: + return fsync(cookie->fd) == 0 ? B_OK : errno; + + case B_GET_BIOS_DRIVE_ID: + return set_ioctl_result((uint8)0xf8, buffer, length); + + case B_GET_DRIVER_FOR_DEVICE: + case B_SET_DEVICE_SIZE: + case B_SET_PARTITION: + case B_FORMAT_DEVICE: + case B_EJECT_DEVICE: + case B_LOAD_MEDIA: + case B_GET_NEXT_OPEN_DEVICE: + default: + return B_BAD_VALUE; + } + + return B_OK; +} + + +status_t +FileDevice::Select(void* _cookie, uint8 event, selectsync* sync) +{ + // TODO: Support (select_fd())! + return B_UNSUPPORTED; +} + + +status_t +FileDevice::Deselect(void* cookie, uint8 event, selectsync* sync) +{ + // TODO: Support (deselect_fd())! + return B_UNSUPPORTED; +} + + +status_t +FileDevice::Close(void* cookie) +{ + // TODO: This should probably really close the FD. Depending on the + // underlying FS operations could block and close() would be needed to + // unblock them. + return B_OK; +} + + +status_t +FileDevice::Free(void* _cookie) +{ + delete (Cookie*)_cookie; + return B_OK; +} diff --git a/src/system/kernel/device_manager/FileDevice.h b/src/system/kernel/device_manager/FileDevice.h new file mode 100644 index 0000000000..c49858fa8c --- /dev/null +++ b/src/system/kernel/device_manager/FileDevice.h @@ -0,0 +1,55 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef FILE_DEVICE_H +#define FILE_DEVICE_H + + +#include "BaseDevice.h" + + +class FileDevice : public BaseDevice { +public: + FileDevice(); + virtual ~FileDevice(); + + status_t Init(const char* path); + + virtual status_t InitDevice(); + virtual void UninitDevice(); + + virtual void Removed(); + + virtual bool HasSelect() const; + virtual bool HasDeselect() const; + virtual bool HasRead() const; + virtual bool HasWrite() const; + virtual bool HasIO() const; + + virtual status_t Open(const char* path, int openMode, + void** _cookie); + virtual status_t Read(void* cookie, off_t pos, void* buffer, + size_t* _length); + virtual status_t Write(void* cookie, off_t pos, const void* buffer, + size_t* _length); + virtual status_t IO(void* cookie, io_request* request); + virtual status_t Control(void* cookie, int32 op, void* buffer, + size_t length); + virtual status_t Select(void* cookie, uint8 event, selectsync* sync); + virtual status_t Deselect(void* cookie, uint8 event, + selectsync* sync); + + virtual status_t Close(void* cookie); + virtual status_t Free(void* cookie); + +private: + struct Cookie; + +private: + int fFD; + off_t fFileSize; +}; + + +#endif // FILE_DEVICE_H diff --git a/src/system/kernel/device_manager/Jamfile b/src/system/kernel/device_manager/Jamfile index 8be26e0d19..40013c0b28 100644 --- a/src/system/kernel/device_manager/Jamfile +++ b/src/system/kernel/device_manager/Jamfile @@ -4,9 +4,11 @@ UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ; UsePrivateHeaders [ FDirName kernel util ] shared ; KernelMergeObject kernel_device_manager.o : + AbstractModuleDevice.cpp BaseDevice.cpp device_manager.cpp devfs.cpp + FileDevice.cpp id_generator.cpp io_resources.cpp IOScheduler.cpp diff --git a/src/system/kernel/device_manager/devfs.cpp b/src/system/kernel/device_manager/devfs.cpp index e4ef7109eb..8f8feba264 100644 --- a/src/system/kernel/device_manager/devfs.cpp +++ b/src/system/kernel/device_manager/devfs.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -36,6 +37,7 @@ #include #include "BaseDevice.h" +#include "FileDevice.h" #include "IORequest.h" #include "legacy_drivers.h" @@ -484,7 +486,8 @@ static status_t get_node_for_path(struct devfs *fs, const char *path, struct devfs_vnode **_node) { - return vfs_get_fs_node_from_path(fs->volume, path, true, (void **)_node); + return vfs_get_fs_node_from_path(fs->volume, path, false, true, + (void **)_node); } @@ -508,21 +511,6 @@ out: } -static status_t -unpublish_node(struct devfs *fs, const char *path, mode_t type) -{ - devfs_vnode *node; - status_t status = get_node_for_path(fs, path, &node); - if (status != B_OK) - return status; - - status = unpublish_node(fs, node, type); - - put_vnode(fs->volume, node->id); - return status; -} - - static status_t publish_directory(struct devfs *fs, const char *path) { @@ -818,7 +806,6 @@ dump_node(int argc, char **argv) kprintf(" symlink to: %s\n", vnode->stream.u.symlink.path); } else { kprintf(" device: %p\n", vnode->stream.u.dev.device); - kprintf(" node: %p\n", vnode->stream.u.dev.device->Node()); kprintf(" partition: %p\n", vnode->stream.u.dev.partition); if (vnode->stream.u.dev.partition != NULL) { partition_info& info = vnode->stream.u.dev.partition->info; @@ -1622,6 +1609,7 @@ devfs_deselect(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, static bool devfs_can_page(fs_volume *_volume, fs_vnode *_vnode, void *cookie) { +#if 0 struct devfs_vnode *vnode = (devfs_vnode *)_vnode->private_node; //TRACE(("devfs_canpage: vnode %p\n", vnode)); @@ -1633,6 +1621,9 @@ devfs_can_page(fs_volume *_volume, fs_vnode *_vnode, void *cookie) return vnode->stream.u.dev.device->HasRead() || vnode->stream.u.dev.device->HasIO(); +#endif + // TODO: Obsolete hook! + return false; } @@ -1998,36 +1989,50 @@ file_system_module_info gDeviceFileSystem = { extern "C" status_t devfs_unpublish_file_device(const char *path) { - return unpublish_node(sDeviceFileSystem, path, S_IFLNK); + // get the device node + devfs_vnode* node; + status_t status = get_node_for_path(sDeviceFileSystem, path, &node); + if (status != B_OK) + return status; + + if (!S_ISCHR(node->stream.type)) { + put_vnode(sDeviceFileSystem->volume, node->id); + return B_BAD_VALUE; + } + + // if it is indeed a file device, unpublish it + FileDevice* device = dynamic_cast(node->stream.u.dev.device); + if (device == NULL) { + put_vnode(sDeviceFileSystem->volume, node->id); + return B_BAD_VALUE; + } + + status = unpublish_node(sDeviceFileSystem, node, S_IFCHR); + + put_vnode(sDeviceFileSystem->volume, node->id); + return status; } extern "C" status_t devfs_publish_file_device(const char *path, const char *filePath) { - struct devfs_vnode *node; - struct devfs_vnode *dirNode; - status_t status; - - filePath = strdup(filePath); - if (filePath == NULL) + // create a FileDevice for the file + FileDevice* device = new(std::nothrow) FileDevice; + if (device == NULL) return B_NO_MEMORY; + ObjectDeleter deviceDeleter(device); - RecursiveLocker locker(&sDeviceFileSystem->lock); + status_t error = device->Init(filePath); + if (error != B_OK) + return error; - status = new_node(sDeviceFileSystem, path, &node, &dirNode); - if (status != B_OK) { - free((char*)filePath); - return status; - } + // publish the device + error = publish_device(sDeviceFileSystem, path, device); + if (error != B_OK) + return error; - // all went fine, let's initialize the node - node->stream.type = S_IFLNK | 0644; - node->stream.u.symlink.path = filePath; - node->stream.u.symlink.length = strlen(filePath); - - // the node is now fully valid and we may insert it into the dir - publish_node(sDeviceFileSystem, dirNode, node); + deviceDeleter.Detach(); return B_OK; } diff --git a/src/system/kernel/device_manager/device_manager.cpp b/src/system/kernel/device_manager/device_manager.cpp index 1adf81ee35..b2eeb67ed0 100644 --- a/src/system/kernel/device_manager/device_manager.cpp +++ b/src/system/kernel/device_manager/device_manager.cpp @@ -27,7 +27,7 @@ #include #include -#include "BaseDevice.h" +#include "AbstractModuleDevice.h" #include "devfs_private.h" #include "id_generator.h" #include "IORequest.h" @@ -72,7 +72,8 @@ typedef struct io_resource_info { io_resource resource; // info about actual resource } io_resource_info; -class Device : public BaseDevice, public DoublyLinkedListLinkImpl { +class Device : public AbstractModuleDevice, + public DoublyLinkedListLinkImpl { public: Device(device_node* node, const char* moduleName); virtual ~Device(); @@ -1064,10 +1065,10 @@ device_attr_private::Compare(const device_attr* attrA, const device_attr *attrB) Device::Device(device_node* node, const char* moduleName) : + fModuleName(strdup(moduleName)), fRemovedFromParent(false) { fNode = node; - fModuleName = strdup(moduleName); } diff --git a/src/system/kernel/device_manager/legacy_drivers.cpp b/src/system/kernel/device_manager/legacy_drivers.cpp index f4c965fcf3..c871b1f00f 100644 --- a/src/system/kernel/device_manager/legacy_drivers.cpp +++ b/src/system/kernel/device_manager/legacy_drivers.cpp @@ -27,7 +27,7 @@ #include #include -#include "BaseDevice.h" +#include "AbstractModuleDevice.h" #include "devfs_private.h" @@ -42,7 +42,7 @@ struct legacy_driver; -class LegacyDevice : public BaseDevice, +class LegacyDevice : public AbstractModuleDevice, public DoublyLinkedListLinkImpl { public: LegacyDevice(legacy_driver* driver, diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index e78307996b..517782a3ac 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * @@ -518,6 +518,7 @@ static status_t dec_vnode_ref_count(struct vnode* vnode, bool alwaysFree, static inline void put_vnode(struct vnode* vnode); static status_t fs_unmount(char* path, dev_t mountID, uint32 flags, bool kernel); +static int open_vnode(struct vnode* vnode, int openMode, bool kernel); static struct fd_ops sFileOps = { @@ -3944,7 +3945,7 @@ vfs_get_cookie_from_fd(int fd, void** _cookie) } -extern "C" int +extern "C" status_t vfs_get_vnode_from_fd(int fd, bool kernel, struct vnode** vnode) { *vnode = get_vnode_from_fd(fd, kernel); @@ -4009,6 +4010,17 @@ vfs_vnode_to_node_ref(struct vnode* vnode, dev_t* _mountID, ino_t* _vnodeID) } +/*! + Calls fs_open() on the given vnode and returns a new + file descriptor for it +*/ +int +vfs_open_vnode(struct vnode* vnode, int openMode, bool kernel) +{ + return open_vnode(vnode, openMode, kernel); +} + + /*! Looks up a vnode with the given mount and vnode ID. Must only be used with "in-use" vnodes as it doesn't grab a reference to the node. @@ -4030,8 +4042,8 @@ vfs_lookup_vnode(dev_t mountID, ino_t vnodeID, struct vnode** _vnode) extern "C" status_t -vfs_get_fs_node_from_path(fs_volume* volume, const char* path, bool kernel, - void** _node) +vfs_get_fs_node_from_path(fs_volume* volume, const char* path, + bool traverseLeafLink, bool kernel, void** _node) { TRACE(("vfs_get_fs_node_from_path(volume = %p, path = \"%s\", kernel %d)\n", volume, path, kernel)); @@ -4051,12 +4063,12 @@ vfs_get_fs_node_from_path(fs_volume* volume, const char* path, bool kernel, struct vnode* vnode = mount->root_vnode; if (buffer[0] == '/') - status = path_to_vnode(buffer, true, &vnode, NULL, true); + status = path_to_vnode(buffer, traverseLeafLink, &vnode, NULL, kernel); else { inc_vnode_ref_count(vnode); // vnode_path_to_vnode() releases a reference to the starting vnode - status = vnode_path_to_vnode(vnode, buffer, true, 0, kernel, &vnode, - NULL); + status = vnode_path_to_vnode(vnode, buffer, traverseLeafLink, 0, + kernel, &vnode, NULL); } put_mount(mount);