From 617ed3e4a9ea91cf5be9b9e55d465840c36b1639 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 1 Mar 2007 01:16:13 +0000 Subject: [PATCH] Implemented the new attribute open/close/... FS hooks. The mapping to the old interface is completely done in userland ATM. It becomes more and more obvious that we probably need to provide the kernel add-on with a bit more information about what the client FS interface supports in the first place, so we can save unnecessary trips to the userland. Opening/closing attributes for a FS using the old style interface could be handled completely in the kernel add-on, for instance (even if we lose a bit of accuracy wrt to open modes etc.). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20258 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/userlandfs/private/Requests.h | 93 ++++++++ .../userlandfs/private/userlandfs_ioctl.h | 1 + .../userlandfs/kernel_add_on/Volume.cpp | 198 +++++++++++++++++ .../userlandfs/kernel_add_on/Volume.h | 11 + .../kernel_add_on/kernel_interface.cpp | 59 ++++- .../userlandfs/private/Requests.cpp | 33 +++ .../userlandfs/server/BeOSKernelVolume.cpp | 201 ++++++++++++++++-- .../userlandfs/server/BeOSKernelVolume.h | 15 ++ .../server/UserlandRequestHandler.cpp | 128 +++++++++++ .../server/UserlandRequestHandler.h | 8 + .../file_systems/userlandfs/server/Volume.cpp | 30 +++ .../file_systems/userlandfs/server/Volume.h | 7 + 12 files changed, 754 insertions(+), 30 deletions(-) diff --git a/headers/private/userlandfs/private/Requests.h b/headers/private/userlandfs/private/Requests.h index cf6e072ffe..358a165dc0 100644 --- a/headers/private/userlandfs/private/Requests.h +++ b/headers/private/userlandfs/private/Requests.h @@ -122,6 +122,14 @@ enum { REWIND_ATTR_DIR_REPLY, // attributes + CREATE_ATTR_REQUEST, + CREATE_ATTR_REPLY, + OPEN_ATTR_REQUEST, + OPEN_ATTR_REPLY, + CLOSE_ATTR_REQUEST, + CLOSE_ATTR_REPLY, + FREE_ATTR_COOKIE_REQUEST, + FREE_ATTR_COOKIE_REPLY, READ_ATTR_REQUEST, READ_ATTR_REPLY, WRITE_ATTR_REQUEST, @@ -960,6 +968,67 @@ public: // #pragma mark - attributes +// CreateAttrRequest +class CreateAttrRequest : public NodeRequest { +public: + CreateAttrRequest() : NodeRequest(CREATE_ATTR_REQUEST) {} + status_t GetAddressInfos(AddressInfo* infos, int32* count); + + Address name; + uint32 type; + int openMode; +}; + +// CreateAttrReply +class CreateAttrReply : public ReplyRequest { +public: + CreateAttrReply() : ReplyRequest(CREATE_ATTR_REPLY) {} + + fs_cookie attrCookie; +}; + +// OpenAttrRequest +class OpenAttrRequest : public NodeRequest { +public: + OpenAttrRequest() : NodeRequest(OPEN_ATTR_REQUEST) {} + status_t GetAddressInfos(AddressInfo* infos, int32* count); + + Address name; + int openMode; +}; + +// OpenAttrReply +class OpenAttrReply : public ReplyRequest { +public: + OpenAttrReply() : ReplyRequest(OPEN_ATTR_REPLY) {} + + fs_cookie attrCookie; +}; + +// CloseAttrRequest +class CloseAttrRequest : public AttributeRequest { +public: + CloseAttrRequest() : AttributeRequest(CLOSE_ATTR_REQUEST) {} +}; + +// CloseAttrReply +class CloseAttrReply : public ReplyRequest { +public: + CloseAttrReply() : ReplyRequest(CLOSE_ATTR_REPLY) {} +}; + +// FreeAttrCookieRequest +class FreeAttrCookieRequest : public AttributeRequest { +public: + FreeAttrCookieRequest() : AttributeRequest(FREE_ATTR_COOKIE_REQUEST) {} +}; + +// FreeAttrCookieReply +class FreeAttrCookieReply : public ReplyRequest { +public: + FreeAttrCookieReply() : ReplyRequest(FREE_ATTR_COOKIE_REPLY) {} +}; + // ReadAttrRequest class ReadAttrRequest : public AttributeRequest { public: @@ -1605,6 +1674,22 @@ do_for_request(Request* request, Task& task) case REWIND_ATTR_DIR_REPLY: return task((RewindAttrDirReply*)request); // attributes + case CREATE_ATTR_REQUEST: + return task((CreateAttrRequest*)request); + case CREATE_ATTR_REPLY: + return task((CreateAttrReply*)request); + case OPEN_ATTR_REQUEST: + return task((OpenAttrRequest*)request); + case OPEN_ATTR_REPLY: + return task((OpenAttrReply*)request); + case CLOSE_ATTR_REQUEST: + return task((CloseAttrRequest*)request); + case CLOSE_ATTR_REPLY: + return task((CloseAttrReply*)request); + case FREE_ATTR_COOKIE_REQUEST: + return task((FreeAttrCookieRequest*)request); + case FREE_ATTR_COOKIE_REPLY: + return task((FreeAttrCookieReply*)request); case READ_ATTR_REQUEST: return task((ReadAttrRequest*)request); case READ_ATTR_REPLY: @@ -1834,6 +1919,14 @@ using UserlandFSUtil::ReadAttrDirReply; using UserlandFSUtil::RewindAttrDirRequest; using UserlandFSUtil::RewindAttrDirReply; // attributes +using UserlandFSUtil::CreateAttrRequest; +using UserlandFSUtil::CreateAttrReply; +using UserlandFSUtil::OpenAttrRequest; +using UserlandFSUtil::OpenAttrReply; +using UserlandFSUtil::CloseAttrRequest; +using UserlandFSUtil::CloseAttrReply; +using UserlandFSUtil::FreeAttrCookieRequest; +using UserlandFSUtil::FreeAttrCookieReply; using UserlandFSUtil::ReadAttrRequest; using UserlandFSUtil::ReadAttrReply; using UserlandFSUtil::WriteAttrRequest; diff --git a/headers/private/userlandfs/private/userlandfs_ioctl.h b/headers/private/userlandfs/private/userlandfs_ioctl.h index e7867850ad..468e43279a 100644 --- a/headers/private/userlandfs/private/userlandfs_ioctl.h +++ b/headers/private/userlandfs/private/userlandfs_ioctl.h @@ -32,6 +32,7 @@ enum { USERLAND_IOCTL_OPEN_FILES, USERLAND_IOCTL_OPEN_DIRECTORIES, USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES, + USERLAND_IOCTL_OPEN_ATTRIBUTES, USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES, USERLAND_IOCTL_OPEN_QUERIES, }; diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.cpp b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.cpp index 8bc420c6b2..05ead6c77a 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.cpp @@ -74,6 +74,7 @@ Volume::Volume(FileSystem* fileSystem, mount_id id) fOpenFiles(0), fOpenDirectories(0), fOpenAttributeDirectories(0), + fOpenAttributes(0), fOpenIndexDirectories(0), fOpenQueries(0), fVNodeCountMap(NULL), @@ -1097,6 +1098,7 @@ Volume::Create(fs_vnode dir, const char* name, int openMode, int mode, if (!port) return B_ERROR; PortReleaser _(fFileSystem->GetPortPool(), port); + AutoIncrementer incrementer(&fOpenFiles); // prepare the request RequestAllocator allocator(port->GetPort()); @@ -1124,6 +1126,7 @@ Volume::Create(fs_vnode dir, const char* name, int openMode, int mode, // process the reply if (reply->error != B_OK) return reply->error; + incrementer.Keep(); *vnid = reply->vnid; *cookie = reply->fileCookie; // The VFS will balance the new_vnode() call for the FS. @@ -1197,6 +1200,7 @@ Volume::FreeCookie(fs_vnode node, fs_cookie cookie) error = B_OK; disconnected = true; } + int32 openFiles = atomic_add(&fOpenFiles, -1); if (openFiles <= 1 && disconnected) _PutAllPendingVNodes(); @@ -1710,6 +1714,126 @@ Volume::RewindAttrDir(fs_vnode node, fs_cookie cookie) // #pragma mark - attributes +// CreateAttr +status_t +Volume::CreateAttr(fs_vnode node, const char* name, uint32 type, int openMode, + fs_cookie* cookie) +{ + // get a free port + RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); + if (!port) + return B_ERROR; + PortReleaser _(fFileSystem->GetPortPool(), port); + AutoIncrementer incrementer(&fOpenAttributes); + + // prepare the request + RequestAllocator allocator(port->GetPort()); + CreateAttrRequest* request; + status_t error = AllocateRequest(allocator, &request); + if (error != B_OK) + return error; + + request->volume = fUserlandVolume; + request->node = node; + error = allocator.AllocateString(request->name, name); + request->type = type; + request->openMode = openMode; + if (error != B_OK) + return error; + + // send the request + KernelRequestHandler handler(this, CREATE_ATTR_REPLY); + CreateAttrReply* reply; + error = _SendRequest(port, &allocator, &handler, (Request**)&reply); + if (error != B_OK) + return error; + RequestReleaser requestReleaser(port, reply); + + // process the reply + if (reply->error != B_OK) + return reply->error; + incrementer.Keep(); + *cookie = reply->attrCookie; + return error; +} + +// OpenAttr +status_t +Volume::OpenAttr(fs_vnode node, const char* name, int openMode, + fs_cookie* cookie) +{ + // get a free port + RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); + if (!port) + return B_ERROR; + PortReleaser _(fFileSystem->GetPortPool(), port); + AutoIncrementer incrementer(&fOpenAttributes); + + // prepare the request + RequestAllocator allocator(port->GetPort()); + OpenAttrRequest* request; + status_t error = AllocateRequest(allocator, &request); + if (error != B_OK) + return error; + + request->volume = fUserlandVolume; + request->node = node; + error = allocator.AllocateString(request->name, name); + request->openMode = openMode; + if (error != B_OK) + return error; + + // send the request + KernelRequestHandler handler(this, OPEN_ATTR_REPLY); + OpenAttrReply* reply; + error = _SendRequest(port, &allocator, &handler, (Request**)&reply); + if (error != B_OK) + return error; + RequestReleaser requestReleaser(port, reply); + + // process the reply + if (reply->error != B_OK) + return reply->error; + incrementer.Keep(); + *cookie = reply->attrCookie; + return error; +} + +// CloseAttr +status_t +Volume::CloseAttr(fs_vnode node, fs_cookie cookie) +{ + status_t error = _CloseAttr(node, cookie); + if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { + // This isn't really necessary, as the return value is irrelevant to + // the VFS. OBOS ignores it completely. The fsshell returns it to the + // userland, but considers the node closed anyway. + WARN(("Volume::CloseAttr(): connection lost, forcing close attr\n")); + return B_OK; + } + return error; +} + +// FreeAttrCookie +status_t +Volume::FreeAttrCookie(fs_vnode node, fs_cookie cookie) +{ + status_t error = _FreeAttrCookie(node, cookie); + bool disconnected = false; + if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) { + // This isn't really necessary, as the return value is irrelevant to + // the VFS. It's completely ignored by OBOS as well as by the fsshell. + WARN(("Volume::FreeAttrCookie(): connection lost, forcing free attr " + "cookie\n")); + error = B_OK; + disconnected = true; + } + + int32 openAttributes = atomic_add(&fOpenAttributes, -1); + if (openAttributes <= 1 && disconnected) + _PutAllPendingVNodes(); + return error; +} // ReadAttr status_t @@ -2708,6 +2832,76 @@ Volume::_FreeAttrDirCookie(fs_vnode node, fs_cookie cookie) return error; } +// _CloseAttr +status_t +Volume::_CloseAttr(fs_vnode node, fs_cookie cookie) +{ + // get a free port + RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); + if (!port) + return B_ERROR; + PortReleaser _(fFileSystem->GetPortPool(), port); + + // prepare the request + RequestAllocator allocator(port->GetPort()); + CloseAttrRequest* request; + status_t error = AllocateRequest(allocator, &request); + if (error != B_OK) + return error; + + request->volume = fUserlandVolume; + request->node = node; + request->attrCookie = cookie; + + // send the request + KernelRequestHandler handler(this, CLOSE_ATTR_REPLY); + CloseAttrReply* reply; + error = _SendRequest(port, &allocator, &handler, (Request**)&reply); + if (error != B_OK) + return error; + RequestReleaser requestReleaser(port, reply); + + // process the reply + if (reply->error != B_OK) + return reply->error; + return error; +} + +// _FreeAttrCookie +status_t +Volume::_FreeAttrCookie(fs_vnode node, fs_cookie cookie) +{ + // get a free port + RequestPort* port = fFileSystem->GetPortPool()->AcquirePort(); + if (!port) + return B_ERROR; + PortReleaser _(fFileSystem->GetPortPool(), port); + + // prepare the request + RequestAllocator allocator(port->GetPort()); + FreeAttrCookieRequest* request; + status_t error = AllocateRequest(allocator, &request); + if (error != B_OK) + return error; + + request->volume = fUserlandVolume; + request->node = node; + request->attrCookie = cookie; + + // send the request + KernelRequestHandler handler(this, FREE_ATTR_COOKIE_REPLY); + FreeAttrCookieReply* reply; + error = _SendRequest(port, &allocator, &handler, (Request**)&reply); + if (error != B_OK) + return error; + RequestReleaser requestReleaser(port, reply); + + // process the reply + if (reply->error != B_OK) + return reply->error; + return error; +} + // _CloseIndexDir status_t Volume::_CloseIndexDir(fs_cookie cookie) @@ -2982,6 +3176,10 @@ PRINT(("Volume::_PutAllPendingVNodes()\n")); PRINT(("Volume::_PutAllPendingVNodes() failed: open attr dirs\n")); return USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES; } + if (fOpenAttributes > 0) { + PRINT(("Volume::_PutAllPendingVNodes() failed: open attributes\n")); + return USERLAND_IOCTL_OPEN_ATTRIBUTES; + } if (fOpenIndexDirectories > 0) { PRINT(("Volume::_PutAllPendingVNodes() failed: open index dirs\n")); return USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES; diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.h b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.h index 123536c31a..5de7dbc886 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.h +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Volume.h @@ -125,6 +125,13 @@ public: status_t RewindAttrDir(fs_vnode node, fs_cookie cookie); // attributes + status_t CreateAttr(fs_vnode node, const char* name, + uint32 type, int openMode, + fs_cookie* cookie); + status_t OpenAttr(fs_vnode node, const char* name, + int openMode, fs_cookie* cookie); + status_t CloseAttr(fs_vnode node, fs_cookie cookie); + status_t FreeAttrCookie(fs_vnode node, fs_cookie cookie); status_t ReadAttr(fs_vnode node, fs_cookie cookie, off_t pos, void* buffer, size_t bufferSize, size_t* bytesRead); @@ -176,6 +183,9 @@ private: status_t _CloseAttrDir(fs_vnode node, fs_cookie cookie); status_t _FreeAttrDirCookie(fs_vnode node, fs_cookie cookie); + status_t _CloseAttr(fs_vnode node, fs_cookie cookie); + status_t _FreeAttrCookie(fs_vnode node, + fs_cookie cookie); status_t _CloseIndexDir(fs_cookie cookie); status_t _FreeIndexDirCookie(fs_cookie cookie); status_t _CloseQuery(fs_cookie cookie); @@ -208,6 +218,7 @@ private: vint32 fOpenFiles; vint32 fOpenDirectories; vint32 fOpenAttributeDirectories; + vint32 fOpenAttributes; vint32 fOpenIndexDirectories; vint32 fOpenQueries; VNodeCountMap* fVNodeCountMap; diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/kernel_interface.cpp b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/kernel_interface.cpp index 73415993df..f190a04198 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/kernel_interface.cpp @@ -629,10 +629,53 @@ userlandfs_rewind_attr_dir(fs_volume fs, fs_vnode node, fs_cookie cookie) // #pragma mark - attributes -// TODO: create_attr() -// TODO: open_attr() -// TODO: close_attr() -// TODO: free_attr_cookie() +// userlandfs_create_attr +status_t +userlandfs_create_attr(fs_volume fs, fs_vnode node, const char *name, + uint32 type, int openMode, fs_cookie *cookie) +{ + Volume* volume = (Volume*)fs; + PRINT(("userlandfs_create_attr(%p, %p, \"%s\", 0x%lx, %d, %p)\n", fs, node, + name, type, openMode, cookie)); + status_t error = volume->CreateAttr(node, name, type, openMode, cookie); + PRINT(("userlandfs_create_attr() done: (%lx, %p)\n", error, *cookie)); + return error; +} + +// userlandfs_open_attr +status_t +userlandfs_open_attr(fs_volume fs, fs_vnode node, const char *name, + int openMode, fs_cookie *cookie) +{ + Volume* volume = (Volume*)fs; + PRINT(("userlandfs_open_attr(%p, %p, \"%s\", %d, %p)\n", fs, node, name, + openMode, cookie)); + status_t error = volume->OpenAttr(node, name, openMode, cookie); + PRINT(("userlandfs_open_attr() done: (%lx, %p)\n", error, *cookie)); + return error; +} + +// userlandfs_close_attr +status_t +userlandfs_close_attr(fs_volume fs, fs_vnode node, fs_cookie cookie) +{ + Volume* volume = (Volume*)fs; + PRINT(("userlandfs_close_attr(%p, %p, %p)\n", fs, node, cookie)); + status_t error = volume->CloseAttr(node, cookie); + PRINT(("userlandfs_close_attr() done: %lx\n", error)); + return error; +} + +// userlandfs_free_attr_cookie +status_t +userlandfs_free_attr_cookie(fs_volume fs, fs_vnode node, fs_cookie cookie) +{ + Volume* volume = (Volume*)fs; + PRINT(("userlandfs_close_attr(%p, %p, %p)\n", fs, node, cookie)); + status_t error = volume->FreeAttrCookie(node, cookie); + PRINT(("userlandfs_close_attr() done: %lx\n", error)); + return error; +} // userlandfs_read_attr static status_t @@ -1016,10 +1059,10 @@ static file_system_module_info sUserlandFSModuleInfo = { &userlandfs_rewind_attr_dir, /* attribute operations */ - NULL, // &userlandfs_create_attr, - NULL, // &userlandfs_open_attr, - NULL, // &userlandfs_close_attr, - NULL, // &userlandfs_free_attr_cookie, + &userlandfs_create_attr, + &userlandfs_open_attr, + &userlandfs_close_attr, + &userlandfs_free_attr_cookie, &userlandfs_read_attr, &userlandfs_write_attr, diff --git a/src/add-ons/kernel/file_systems/userlandfs/private/Requests.cpp b/src/add-ons/kernel/file_systems/userlandfs/private/Requests.cpp index a1f1d10ba8..eff963c1e6 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/private/Requests.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/private/Requests.cpp @@ -175,6 +175,22 @@ ReadAttrDirReply::GetAddressInfos(AddressInfo* infos, int32* count) return B_OK; } +// CreateAttrRequest +status_t +CreateAttrRequest::GetAddressInfos(AddressInfo* infos, int32* count) +{ + ADD_NON_NULL_STRING(name); + return B_OK; +} + +// OpenAttrRequest +status_t +OpenAttrRequest::GetAddressInfos(AddressInfo* infos, int32* count) +{ + ADD_NON_NULL_STRING(name); + return B_OK; +} + // ReadAttrReply status_t ReadAttrReply::GetAddressInfos(AddressInfo* infos, int32* count) @@ -563,12 +579,21 @@ UserlandFSUtil::is_kernel_request(uint32 type) case REWIND_ATTR_DIR_REPLY: return false; // attributes + case CREATE_ATTR_REQUEST: + case OPEN_ATTR_REQUEST: + case CLOSE_ATTR_REQUEST: + case FREE_ATTR_COOKIE_REQUEST: case READ_ATTR_REQUEST: case WRITE_ATTR_REQUEST: case READ_ATTR_STAT_REQUEST: case RENAME_ATTR_REQUEST: case REMOVE_ATTR_REQUEST: return true; + case CREATE_ATTR_REPLY: + case OPEN_ATTR_REPLY: + case CLOSE_ATTR_REPLY: + case FREE_ATTR_COOKIE_REPLY: + case READ_ATTR_REPLY: case WRITE_ATTR_REPLY: case READ_ATTR_STAT_REPLY: @@ -753,12 +778,20 @@ UserlandFSUtil::is_userland_request(uint32 type) case REWIND_ATTR_DIR_REPLY: return true; // attributes + case CREATE_ATTR_REQUEST: + case OPEN_ATTR_REQUEST: + case CLOSE_ATTR_REQUEST: + case FREE_ATTR_COOKIE_REQUEST: case READ_ATTR_REQUEST: case WRITE_ATTR_REQUEST: case RENAME_ATTR_REQUEST: case READ_ATTR_STAT_REQUEST: case REMOVE_ATTR_REQUEST: return false; + case CREATE_ATTR_REPLY: + case OPEN_ATTR_REPLY: + case CLOSE_ATTR_REPLY: + case FREE_ATTR_COOKIE_REPLY: case READ_ATTR_REPLY: case WRITE_ATTR_REPLY: case READ_ATTR_STAT_REPLY: diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/BeOSKernelVolume.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/BeOSKernelVolume.cpp index e9eb59b975..bdb9e8d32e 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/BeOSKernelVolume.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/BeOSKernelVolume.cpp @@ -2,9 +2,41 @@ #include "BeOSKernelVolume.h" +#include + +#include +#include + #include "beos_fs_interface.h" #include "kernel_emu.h" + +using std::nothrow; + +static int open_mode_to_access(int openMode); + + +// AttributeCookie +class BeOSKernelVolume::AttributeCookie { +public: + AttributeCookie(const char* name, uint32 type, int openMode, bool exists, + bool create) + : fType(type), + fOpenMode(openMode), + fExists(exists), + fCreate(create) + { + strcpy(fName, name); + } + + char fName[B_ATTR_NAME_LENGTH]; + uint32 fType; + int fOpenMode; + bool fExists; + bool fCreate; +}; + + // constructor BeOSKernelVolume::BeOSKernelVolume(FileSystem* fileSystem, mount_id id, beos_vnode_ops* fsOps) @@ -503,43 +535,106 @@ BeOSKernelVolume::RewindAttrDir(fs_vnode node, fs_cookie cookie) // #pragma mark - attributes +// CreateAttr +status_t +BeOSKernelVolume::CreateAttr(fs_vnode node, const char* name, uint32 type, + int openMode, fs_cookie* cookie) +{ + return _OpenAttr(node, name, type, openMode, true, cookie); +} + +// OpenAttr +status_t +BeOSKernelVolume::OpenAttr(fs_vnode node, const char* name, int openMode, + fs_cookie* cookie) +{ + return _OpenAttr(node, name, 0, openMode, false, cookie); +} + +// CloseAttr +status_t +BeOSKernelVolume::CloseAttr(fs_vnode node, fs_cookie cookie) +{ + return B_OK; +} + +// FreeAttrCookie +status_t +BeOSKernelVolume::FreeAttrCookie(fs_vnode node, fs_cookie _cookie) +{ + AttributeCookie* cookie = (AttributeCookie*)_cookie; + + // If the attribute doesn't exist yet and it was opened with + // CreateAttr(), we could create it now. We have a race condition here + // though, since someone else could have created it in the meantime. + + delete cookie; + + return B_OK; +} + // ReadAttr status_t -BeOSKernelVolume::ReadAttr(fs_vnode node, fs_cookie cookie, off_t pos, +BeOSKernelVolume::ReadAttr(fs_vnode node, fs_cookie _cookie, off_t pos, void* buffer, size_t bufferSize, size_t* bytesRead) { -// TODO: Implement! -return B_BAD_VALUE; -// if (!fFSOps->read_attr) -// return B_BAD_VALUE; -// *bytesRead = bufferSize; -// return fFSOps->read_attr(fVolumeCookie, node, name, type, buffer, bytesRead, -// pos); + AttributeCookie* cookie = (AttributeCookie*)_cookie; + + // check, if open mode allows reading + if ((open_mode_to_access(cookie->fOpenMode) | R_OK) == 0) + return B_FILE_ERROR; + + // read + if (!fFSOps->read_attr) + return B_BAD_VALUE; + + *bytesRead = bufferSize; + return fFSOps->read_attr(fVolumeCookie, node, cookie->fName, cookie->fType, + buffer, bytesRead, pos); } // WriteAttr status_t -BeOSKernelVolume::WriteAttr(fs_vnode node, fs_cookie cookie, off_t pos, +BeOSKernelVolume::WriteAttr(fs_vnode node, fs_cookie _cookie, off_t pos, const void* buffer, size_t bufferSize, size_t* bytesWritten) { -// TODO: Implement! -return B_BAD_VALUE; -// if (!fFSOps->write_attr) -// return B_BAD_VALUE; -// *bytesWritten = bufferSize; -// return fFSOps->write_attr(fVolumeCookie, node, name, type, buffer, -// bytesWritten, pos); + AttributeCookie* cookie = (AttributeCookie*)_cookie; + + // check, if open mode allows writing + if ((open_mode_to_access(cookie->fOpenMode) | W_OK) == 0) + return B_FILE_ERROR; + + // write + if (!fFSOps->write_attr) + return B_BAD_VALUE; + + *bytesWritten = bufferSize; + return fFSOps->write_attr(fVolumeCookie, node, cookie->fName, cookie->fType, + buffer, bytesWritten, pos); } // ReadAttrStat status_t -BeOSKernelVolume::ReadAttrStat(fs_vnode node, fs_cookie cookie, struct stat *st) +BeOSKernelVolume::ReadAttrStat(fs_vnode node, fs_cookie _cookie, + struct stat *st) { -// TODO: Implement! -return B_BAD_VALUE; -// if (!fFSOps->stat_attr) -// return B_BAD_VALUE; -// return fFSOps->stat_attr(fVolumeCookie, node, name, attrInfo); + AttributeCookie* cookie = (AttributeCookie*)_cookie; + + // get the stats + beos_attr_info attrInfo; + if (!fFSOps->stat_attr) + return B_BAD_VALUE; + + status_t error = fFSOps->stat_attr(fVolumeCookie, node, cookie->fName, + &attrInfo); + if (error != B_OK) + return error; + + // translate to struct stat + st->st_size = attrInfo.size; + st->st_type = attrInfo.type; + + return B_OK; } // RenameAttr @@ -708,3 +803,65 @@ BeOSKernelVolume::ReadQuery(fs_cookie cookie, void* buffer, size_t bufferSize, (struct beos_dirent*)buffer, bufferSize); } + +// #pragma mark - Private + + +// _OpenAttr +status_t +BeOSKernelVolume::_OpenAttr(fs_vnode node, const char* name, uint32 type, + int openMode, bool create, fs_cookie* _cookie) +{ + // check permissions first + int accessMode = open_mode_to_access(openMode) | (create ? W_OK : 0); + status_t error = Access(node, accessMode); + if (error != B_OK) + return error; + + // check whether the attribute already exists + beos_attr_info attrInfo; + if (!fFSOps->stat_attr) + return B_BAD_VALUE; + bool exists + = (fFSOps->stat_attr(fVolumeCookie, node, name, &attrInfo) == B_OK); + + if (create) { + // create: fail, if attribute exists and non-existence was required + if (exists && (openMode & O_EXCL)) + return B_FILE_EXISTS; + } else { + // open: fail, if attribute doesn't exist + if (!exists) + return B_ENTRY_NOT_FOUND; + + // keep the attribute type + type = attrInfo.type; + } + + // create an attribute cookie + AttributeCookie* cookie = new(nothrow) AttributeCookie(name, type, + openMode, exists, create); + if (!cookie) + return B_NO_MEMORY; + + // TODO: If we want to support O_TRUNC, we should do that here. + + *_cookie = cookie; + return B_OK; +} + +// open_mode_to_access +static int +open_mode_to_access(int openMode) +{ + switch (openMode & O_RWMASK) { + case O_RDONLY: + return R_OK; + case O_WRONLY: + return W_OK; + case O_RDWR: + default: + return W_OK | R_OK; + } +} + diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/BeOSKernelVolume.h b/src/add-ons/kernel/file_systems/userlandfs/server/BeOSKernelVolume.h index e882ab46f1..e09bd4fc95 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/BeOSKernelVolume.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/BeOSKernelVolume.h @@ -98,6 +98,13 @@ public: virtual status_t RewindAttrDir(fs_vnode node, fs_cookie cookie); // attributes + virtual status_t CreateAttr(fs_vnode node, const char *name, + uint32 type, int openMode, + fs_cookie *cookie); + virtual status_t OpenAttr(fs_vnode node, const char *name, + int openMode, fs_cookie *cookie); + virtual status_t CloseAttr(fs_vnode node, fs_cookie cookie); + virtual status_t FreeAttrCookie(fs_vnode node, fs_cookie cookie); virtual status_t ReadAttr(fs_vnode node, fs_cookie cookie, off_t pos, void* buffer, size_t bufferSize, size_t* bytesRead); @@ -135,6 +142,14 @@ public: size_t bufferSize, uint32 count, uint32* countRead); +private: + class AttributeCookie; + +private: + status_t _OpenAttr(fs_vnode node, const char* name, + uint32 type, int openMode, bool create, + fs_cookie* cookie); + private: beos_vnode_ops* fFSOps; void* fVolumeCookie; diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.cpp index e9eb675dde..e7460971c8 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.cpp @@ -138,6 +138,14 @@ UserlandRequestHandler::HandleRequest(Request* request) return _HandleRequest((RewindAttrDirRequest*)request); // attributes + case CREATE_ATTR_REQUEST: + return _HandleRequest((CreateAttrRequest*)request); + case OPEN_ATTR_REQUEST: + return _HandleRequest((OpenAttrRequest*)request); + case CLOSE_ATTR_REQUEST: + return _HandleRequest((CloseAttrRequest*)request); + case FREE_ATTR_COOKIE_REQUEST: + return _HandleRequest((FreeAttrCookieRequest*)request); case READ_ATTR_REQUEST: return _HandleRequest((ReadAttrRequest*)request); case WRITE_ATTR_REQUEST: @@ -1493,6 +1501,126 @@ UserlandRequestHandler::_HandleRequest(RewindAttrDirRequest* request) // #pragma mark - attributes +// _HandleRequest +status_t +UserlandRequestHandler::_HandleRequest(CreateAttrRequest* request) +{ + // check and execute the request + status_t result = B_OK; + Volume* volume = (Volume*)request->volume; + if (!volume) + result = B_BAD_VALUE; + + fs_cookie attrCookie; + if (result == B_OK) { + RequestThreadContext context(volume); + result = volume->CreateAttr(request->node, + (const char*)request->name.GetData(), request->type, + request->openMode, &attrCookie); + } + + // prepare the reply + RequestAllocator allocator(fPort->GetPort()); + CreateAttrReply* reply; + status_t error = AllocateRequest(allocator, &reply); + if (error != B_OK) + RETURN_ERROR(error); + + reply->error = result; + reply->attrCookie = attrCookie; + + // send the reply + return _SendReply(allocator, false); +} + +// _HandleRequest +status_t +UserlandRequestHandler::_HandleRequest(OpenAttrRequest* request) +{ + // check and execute the request + status_t result = B_OK; + Volume* volume = (Volume*)request->volume; + if (!volume) + result = B_BAD_VALUE; + + fs_cookie attrCookie; + if (result == B_OK) { + RequestThreadContext context(volume); + result = volume->OpenAttr(request->node, + (const char*)request->name.GetData(), request->openMode, + &attrCookie); + } + + // prepare the reply + RequestAllocator allocator(fPort->GetPort()); + OpenAttrReply* reply; + status_t error = AllocateRequest(allocator, &reply); + if (error != B_OK) + RETURN_ERROR(error); + + reply->error = result; + reply->attrCookie = attrCookie; + + // send the reply + return _SendReply(allocator, false); +} + +// _HandleRequest +status_t +UserlandRequestHandler::_HandleRequest(CloseAttrRequest* request) +{ + // check and execute the request + status_t result = B_OK; + Volume* volume = (Volume*)request->volume; + if (!volume) + result = B_BAD_VALUE; + + if (result == B_OK) { + RequestThreadContext context(volume); + result = volume->CloseAttr(request->node, request->attrCookie); + } + + // prepare the reply + RequestAllocator allocator(fPort->GetPort()); + CloseAttrReply* reply; + status_t error = AllocateRequest(allocator, &reply); + if (error != B_OK) + RETURN_ERROR(error); + + reply->error = result; + + // send the reply + return _SendReply(allocator, false); +} + +// _HandleRequest +status_t +UserlandRequestHandler::_HandleRequest(FreeAttrCookieRequest* request) +{ + // check and execute the request + status_t result = B_OK; + Volume* volume = (Volume*)request->volume; + if (!volume) + result = B_BAD_VALUE; + + if (result == B_OK) { + RequestThreadContext context(volume); + result = volume->FreeAttrCookie(request->node, request->attrCookie); + } + + // prepare the reply + RequestAllocator allocator(fPort->GetPort()); + FreeAttrCookieReply* reply; + status_t error = AllocateRequest(allocator, &reply); + if (error != B_OK) + RETURN_ERROR(error); + + reply->error = result; + + // send the reply + return _SendReply(allocator, false); +} + // _HandleRequest status_t UserlandRequestHandler::_HandleRequest(ReadAttrRequest* request) diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.h b/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.h index 717bf9e0d8..94342df573 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.h @@ -54,6 +54,10 @@ class FreeAttrDirCookieRequest; class ReadAttrDirRequest; class RewindAttrDirRequest; // attributes +class CreateAttrRequest; +class OpenAttrRequest; +class CloseAttrRequest; +class FreeAttrCookieRequest; class ReadAttrRequest; class WriteAttrRequest; class ReadAttrStatRequest; @@ -148,6 +152,10 @@ private: status_t _HandleRequest(RewindAttrDirRequest* request); // attributes + status_t _HandleRequest(CreateAttrRequest* request); + status_t _HandleRequest(OpenAttrRequest* request); + status_t _HandleRequest(CloseAttrRequest* request); + status_t _HandleRequest(FreeAttrCookieRequest* request); status_t _HandleRequest(ReadAttrRequest* request); status_t _HandleRequest(WriteAttrRequest* request); status_t _HandleRequest(ReadAttrStatRequest* request); diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/Volume.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/Volume.cpp index 75b867dce7..f56683fbf7 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/Volume.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/Volume.cpp @@ -347,6 +347,36 @@ Volume::RewindAttrDir(fs_vnode node, fs_cookie cookie) // #pragma mark - attributes +// CreateAttr +status_t +Volume::CreateAttr(fs_vnode node, const char* name, uint32 type, int openMode, + fs_cookie* cookie) +{ + return B_BAD_VALUE; +} + +// OpenAttr +status_t +Volume::OpenAttr(fs_vnode node, const char* name, int openMode, + fs_cookie* cookie) +{ + return B_BAD_VALUE; +} + +// CloseAttr +status_t +Volume::CloseAttr(fs_vnode node, fs_cookie cookie) +{ + return B_BAD_VALUE; +} + +// FreeAttrCookie +status_t +Volume::FreeAttrCookie(fs_vnode node, fs_cookie cookie) +{ + return B_BAD_VALUE; +} + // ReadAttr status_t Volume::ReadAttr(fs_vnode node, fs_cookie cookie, off_t pos, void* buffer, diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/Volume.h b/src/add-ons/kernel/file_systems/userlandfs/server/Volume.h index ea625e26bd..76bd6055c2 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/Volume.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/Volume.h @@ -101,6 +101,13 @@ public: virtual status_t RewindAttrDir(fs_vnode node, fs_cookie cookie); // attributes + virtual status_t CreateAttr(fs_vnode node, const char* name, + uint32 type, int openMode, + fs_cookie* cookie); + virtual status_t OpenAttr(fs_vnode node, const char* name, + int openMode, fs_cookie* cookie); + virtual status_t CloseAttr(fs_vnode node, fs_cookie cookie); + virtual status_t FreeAttrCookie(fs_vnode node, fs_cookie cookie); virtual status_t ReadAttr(fs_vnode node, fs_cookie cookie, off_t pos, void* buffer, size_t bufferSize, size_t* bytesRead);