From 744a460c12f6471054cbb2e8472ea64d02e7b43e Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 17 Nov 2009 22:04:46 +0000 Subject: [PATCH] * Package: Added Open() (and matching Close()) method, which opens the package file once, tracking an open count. * Added VFSInit()/VFSUninit() methods to the Node and PackageNode class hierarchies, called by the {get,put}_vnode() PackageFile implements them to set up/tear down access to the file data. Also added a Read() reading the data. * Implemented the open(), free_cookie(), and read() FS hooks for real. Reading files works now. Executing doesn't yet -- it requires working with IORequests in a way not supported by the userlandfs. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34102 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../file_systems/packagefs/Directory.cpp | 20 +++ .../kernel/file_systems/packagefs/Directory.h | 6 + .../file_systems/packagefs/LeafNode.cpp | 26 +++ .../kernel/file_systems/packagefs/LeafNode.h | 6 + .../kernel/file_systems/packagefs/Node.h | 6 + .../kernel/file_systems/packagefs/Package.cpp | 63 +++++++ .../kernel/file_systems/packagefs/Package.h | 31 ++++ .../packagefs/PackageDirectory.cpp | 4 +- .../file_systems/packagefs/PackageDirectory.h | 2 +- .../file_systems/packagefs/PackageFile.cpp | 140 ++++++++++++++- .../file_systems/packagefs/PackageFile.h | 12 +- .../packagefs/PackageLeafNode.cpp | 11 +- .../file_systems/packagefs/PackageLeafNode.h | 5 +- .../file_systems/packagefs/PackageNode.cpp | 16 +- .../file_systems/packagefs/PackageNode.h | 7 +- .../file_systems/packagefs/PackageSymlink.cpp | 4 +- .../file_systems/packagefs/PackageSymlink.h | 2 +- .../kernel/file_systems/packagefs/Volume.cpp | 21 +-- .../packagefs/kernel_interface.cpp | 163 +++++++++++++----- 19 files changed, 476 insertions(+), 69 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp index 9df1ab2430..0dbb8feaa7 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp @@ -38,6 +38,19 @@ Directory::Init(Directory* parent, const char* name) } +status_t +Directory::VFSInit(dev_t deviceID) +{ + return B_OK; +} + + +void +Directory::VFSUninit() +{ +} + + mode_t Directory::Mode() const { @@ -98,6 +111,13 @@ Directory::AddPackageNode(PackageNode* packageNode) } +status_t +Directory::Read(off_t offset, void* buffer, size_t* bufferSize) +{ + return B_IS_A_DIRECTORY; +} + + void Directory::AddChild(Node* node) { diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.h b/src/add-ons/kernel/file_systems/packagefs/Directory.h index ac45adf487..a48059f8ac 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.h +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.h @@ -31,6 +31,9 @@ public: virtual status_t Init(Directory* parent, const char* name); + virtual status_t VFSInit(dev_t deviceID); + virtual void VFSUninit(); + virtual mode_t Mode() const; virtual uid_t UserID() const; virtual gid_t GroupID() const; @@ -39,6 +42,9 @@ public: virtual status_t AddPackageNode(PackageNode* packageNode); + virtual status_t Read(off_t offset, void* buffer, + size_t* bufferSize); + void AddChild(Node* node); void RemoveChild(Node* node); Node* FindChild(const char* name); diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp index f491099b2d..e25fa003b0 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp @@ -26,6 +26,23 @@ LeafNode::Init(Directory* parent, const char* name) } +status_t +LeafNode::VFSInit(dev_t deviceID) +{ + if (PackageLeafNode* packageNode = fPackageNodes.Head()) + return packageNode->VFSInit(deviceID, fID); + return B_OK; +} + + +void +LeafNode::VFSUninit() +{ + if (PackageLeafNode* packageNode = fPackageNodes.Head()) + packageNode->VFSUninit(); +} + + mode_t LeafNode::Mode() const { @@ -85,6 +102,15 @@ LeafNode::AddPackageNode(PackageNode* packageNode) } +status_t +LeafNode::Read(off_t offset, void* buffer, size_t* bufferSize) +{ + if (PackageLeafNode* packageNode = fPackageNodes.Head()) + return packageNode->Read(offset, buffer, bufferSize); + return B_ERROR; +} + + const char* LeafNode::SymlinkPath() const { diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h b/src/add-ons/kernel/file_systems/packagefs/LeafNode.h index c9c13b5b70..1384d73405 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h +++ b/src/add-ons/kernel/file_systems/packagefs/LeafNode.h @@ -17,6 +17,9 @@ public: virtual status_t Init(Directory* parent, const char* name); + virtual status_t VFSInit(dev_t deviceID); + virtual void VFSUninit(); + virtual mode_t Mode() const; virtual uid_t UserID() const; virtual gid_t GroupID() const; @@ -25,6 +28,9 @@ public: virtual status_t AddPackageNode(PackageNode* packageNode); + virtual status_t Read(off_t offset, void* buffer, + size_t* bufferSize); + const char* SymlinkPath() const; private: diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.h b/src/add-ons/kernel/file_systems/packagefs/Node.h index e312422bca..37541eb7af 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.h +++ b/src/add-ons/kernel/file_systems/packagefs/Node.h @@ -42,6 +42,9 @@ public: virtual status_t Init(Directory* parent, const char* name); + virtual status_t VFSInit(dev_t deviceID) = 0; + virtual void VFSUninit() = 0; + virtual mode_t Mode() const = 0; virtual uid_t UserID() const = 0; virtual gid_t GroupID() const = 0; @@ -50,6 +53,9 @@ public: virtual status_t AddPackageNode(PackageNode* packageNode) = 0; + virtual status_t Read(off_t offset, void* buffer, + size_t* bufferSize) = 0; + protected: rw_lock fLock; ino_t fID; diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.cpp b/src/add-ons/kernel/file_systems/packagefs/Package.cpp index c567afec2d..0546566b1c 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Package.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Package.cpp @@ -6,19 +6,28 @@ #include "Package.h" +#include +#include #include #include +#include + +#include #include "DebugSupport.h" +#include "PackageDomain.h" Package::Package(PackageDomain* domain, dev_t deviceID, ino_t nodeID) : fDomain(domain), fName(NULL), + fFD(-1), + fOpenCount(0), fNodeID(nodeID), fDeviceID(deviceID) { + mutex_init(&fLock, "packagefs package"); } @@ -28,6 +37,8 @@ Package::~Package() delete node; free(fName); + + mutex_destroy(&fLock); } @@ -47,3 +58,55 @@ Package::AddNode(PackageNode* node) { fNodes.Add(node); } + + +int +Package::Open() +{ + MutexLocker locker(fLock); + if (fOpenCount > 0) { + fOpenCount++; + return fFD; + } + + // open the file + fFD = openat(fDomain->DirectoryFD(), fName, O_RDONLY); + if (fFD < 0) { + ERROR("Failed to open package file \"%s\"\n", fName); + return errno; + } + + // stat it to verify that it's still the same file + struct stat st; + if (fstat(fFD, &st) < 0) { + ERROR("Failed to stat package file \"%s\"\n", fName); + close(fFD); + fFD = -1; + return errno; + } + + if (st.st_dev != fDeviceID || st.st_ino != fNodeID) { + close(fFD); + fFD = -1; + RETURN_ERROR(B_ENTRY_NOT_FOUND); + } + + fOpenCount = 1; + return fFD; +} + + +void +Package::Close() +{ + MutexLocker locker(fLock); + if (fOpenCount == 0) { + ERROR("Package open count already 0!\n"); + return; + } + + if (--fOpenCount == 0) { + close(fFD); + fFD = -1; + } +} diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.h b/src/add-ons/kernel/file_systems/packagefs/Package.h index 87a9c12add..b026cedac2 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Package.h +++ b/src/add-ons/kernel/file_systems/packagefs/Package.h @@ -9,6 +9,8 @@ #include #include +#include + #include "PackageNode.h" @@ -30,12 +32,18 @@ public: void AddNode(PackageNode* node); + int Open(); + void Close(); + const PackageNodeList& Nodes() const { return fNodes; } private: + mutex fLock; PackageDomain* fDomain; char* fName; + int fFD; + uint32 fOpenCount; Package* fHashTableNext; ino_t fNodeID; dev_t fDeviceID; @@ -43,6 +51,29 @@ private: }; +struct PackageCloser { + PackageCloser(Package* package) + : + fPackage(package) + { + } + + ~PackageCloser() + { + if (fPackage != NULL) + fPackage->Close(); + } + + void Detach() + { + fPackage = NULL; + } + +private: + Package* fPackage; +}; + + struct PackageHashDefinition { typedef const char* KeyType; typedef Package ValueType; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageDirectory.cpp index 02876e1d41..62e4fb864f 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageDirectory.cpp @@ -7,9 +7,9 @@ #include "PackageDirectory.h" -PackageDirectory::PackageDirectory(mode_t mode) +PackageDirectory::PackageDirectory(Package* package, mode_t mode) : - PackageNode(mode) + PackageNode(package, mode) { } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageDirectory.h index e2d01fb043..624b8694c8 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageDirectory.h @@ -14,7 +14,7 @@ class PackageDirectory : public PackageNode, public DoublyLinkedListLinkImpl { public: - PackageDirectory(mode_t mode); + PackageDirectory(Package* package, mode_t mode); virtual ~PackageDirectory(); void AddChild(PackageNode* node); diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp index 6d762c8cc1..9465b89efe 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp @@ -6,11 +6,99 @@ #include "PackageFile.h" +#include +#include -PackageFile::PackageFile(mode_t mode, const PackageData& data) +#include + +#include "DataReader.h" +#include "PackageDataReader.h" + +#include "DebugSupport.h" +#include "Package.h" + + +// #pragma mark - DataAccessor + + +struct PackageFile::DataAccessor { + DataAccessor(PackageData* data) + : + fData(data), + fDataReader(NULL), + fReader(NULL), + fFileCache(NULL) + { + } + + ~DataAccessor() + { + file_cache_delete(fFileCache); + delete fReader; + delete fDataReader; + } + + status_t Init(dev_t deviceID, ino_t nodeID, int fd) + { + // create a DataReader for the compressed data + if (fData->IsEncodedInline()) { + fDataReader = new(std::nothrow) BufferDataReader( + fData->InlineData(), fData->CompressedSize()); + } else + fDataReader = new(std::nothrow) FDDataReader(fd); + + if (fDataReader == NULL) + RETURN_ERROR(B_NO_MEMORY); + + // create a PackageDataReader + status_t error = PackageDataReaderFactory::CreatePackageDataReader( + fDataReader, *fData, fReader); + if (error != B_OK) + RETURN_ERROR(error); + + // create a file cache + fFileCache = file_cache_create(deviceID, nodeID, + fData->UncompressedSize()); + if (fFileCache == NULL) + RETURN_ERROR(B_NO_MEMORY); + + return B_OK; + } + + status_t ReadData(off_t offset, void* buffer, size_t* bufferSize) + { + if (offset < 0 || (uint64)offset > fData->UncompressedSize()) + return B_BAD_VALUE; + + size_t toRead = std::min((uint64)*bufferSize, + fData->UncompressedSize() - offset); + + if (toRead > 0) { + status_t error = fReader->ReadData(offset, buffer, toRead); + if (error != B_OK) + RETURN_ERROR(error); + } + + *bufferSize = toRead; + return B_OK; + } + +private: + PackageData* fData; + DataReader* fDataReader; + PackageDataReader* fReader; + void* fFileCache; +}; + + +// #pragma mark - PackageFile + + +PackageFile::PackageFile(Package* package, mode_t mode, const PackageData& data) : - PackageLeafNode(mode), - fData(data) + PackageLeafNode(package, mode), + fData(data), + fDataAccessor(NULL) { } @@ -20,8 +108,54 @@ PackageFile::~PackageFile() } +status_t +PackageFile::VFSInit(dev_t deviceID, ino_t nodeID) +{ + // open the package + int fd = fPackage->Open(); + if (fd < 0) + RETURN_ERROR(fd); + PackageCloser packageCloser(fPackage); + + // create the data accessor + fDataAccessor = new(std::nothrow) DataAccessor(&fData); + if (fDataAccessor == NULL) + RETURN_ERROR(B_NO_MEMORY); + + status_t error = fDataAccessor->Init(deviceID, nodeID, fd); + if (error != B_OK) { + delete fDataAccessor; + fDataAccessor = NULL; + return error; + } + + packageCloser.Detach(); + return B_OK; +} + + +void +PackageFile::VFSUninit() +{ + if (fDataAccessor != NULL) { + fPackage->Close(); + delete fDataAccessor; + fDataAccessor = NULL; + } +} + + off_t PackageFile::FileSize() const { return fData.UncompressedSize(); } + + +status_t +PackageFile::Read(off_t offset, void* buffer, size_t* bufferSize) +{ + if (fDataAccessor == NULL) + return B_BAD_VALUE; + return fDataAccessor->ReadData(offset, buffer, bufferSize); +} diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFile.h b/src/add-ons/kernel/file_systems/packagefs/PackageFile.h index 10eae045bb..7fa0f67433 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFile.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFile.h @@ -13,14 +13,24 @@ class PackageFile : public PackageLeafNode { public: - PackageFile(mode_t mode, + PackageFile(Package* package, mode_t mode, const PackageData& data); virtual ~PackageFile(); + virtual status_t VFSInit(dev_t deviceID, ino_t nodeID); + virtual void VFSUninit(); + virtual off_t FileSize() const; + virtual status_t Read(off_t offset, void* buffer, + size_t* bufferSize); + +private: + struct DataAccessor; + private: PackageData fData; + DataAccessor* fDataAccessor; }; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.cpp index c8fcd51702..f915b18b09 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.cpp @@ -7,9 +7,9 @@ #include "PackageLeafNode.h" -PackageLeafNode::PackageLeafNode(mode_t mode) +PackageLeafNode::PackageLeafNode(Package* package, mode_t mode) : - PackageNode(mode) + PackageNode(package, mode) { } @@ -24,3 +24,10 @@ PackageLeafNode::SymlinkPath() const { return NULL; } + + +status_t +PackageLeafNode::Read(off_t offset, void* buffer, size_t* bufferSize) +{ + return EBADF; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.h b/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.h index 01bbce1028..38ee6cf935 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.h @@ -14,11 +14,14 @@ class PackageData; class PackageLeafNode : public PackageNode { public: - PackageLeafNode(mode_t mode); + PackageLeafNode(Package* package, mode_t mode); virtual ~PackageLeafNode(); virtual const char* SymlinkPath() const; + virtual status_t Read(off_t offset, void* buffer, + size_t* bufferSize); + public: SinglyLinkedListLink fListLink; }; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageNode.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageNode.cpp index cc23685c97..2283c34ead 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageNode.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageNode.cpp @@ -12,8 +12,9 @@ #include "DebugSupport.h" -PackageNode::PackageNode(mode_t mode) +PackageNode::PackageNode(Package* package, mode_t mode) : + fPackage(package), fParent(NULL), fName(NULL), fMode(mode), @@ -41,6 +42,19 @@ PackageNode::Init(PackageDirectory* parent, const char* name) } +status_t +PackageNode::VFSInit(dev_t deviceID, ino_t nodeID) +{ + return B_OK; +} + + +void +PackageNode::VFSUninit() +{ +} + + off_t PackageNode::FileSize() const { diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageNode.h b/src/add-ons/kernel/file_systems/packagefs/PackageNode.h index 273795a6e6..b68d0f5f16 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageNode.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageNode.h @@ -13,12 +13,13 @@ #include +class Package; class PackageDirectory; class PackageNode : public SinglyLinkedListLinkImpl { public: - PackageNode(mode_t mode); + PackageNode(Package* package, mode_t mode); virtual ~PackageNode(); PackageDirectory* Parent() const { return fParent; } @@ -27,6 +28,9 @@ public: virtual status_t Init(PackageDirectory* parent, const char* name); + virtual status_t VFSInit(dev_t deviceID, ino_t nodeID); + virtual void VFSUninit(); + mode_t Mode() const { return fMode; } uid_t UserID() const { return fUserID; } @@ -43,6 +47,7 @@ public: virtual off_t FileSize() const; protected: + Package* fPackage; PackageDirectory* fParent; char* fName; mode_t fMode; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageSymlink.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageSymlink.cpp index d23c8bea64..8f9961aa56 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageSymlink.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageSymlink.cpp @@ -10,9 +10,9 @@ #include -PackageSymlink::PackageSymlink(mode_t mode) +PackageSymlink::PackageSymlink(Package* package, mode_t mode) : - PackageLeafNode(mode), + PackageLeafNode(package, mode), fSymlinkPath(NULL) { } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageSymlink.h b/src/add-ons/kernel/file_systems/packagefs/PackageSymlink.h index 5979422a05..65940c7856 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageSymlink.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageSymlink.h @@ -11,7 +11,7 @@ class PackageSymlink : public PackageLeafNode { public: - PackageSymlink(mode_t mode); + PackageSymlink(Package* package, mode_t mode); virtual ~PackageSymlink(); status_t SetSymlinkPath(const char* path); diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 60a4cfc917..ca374eaa8d 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -141,10 +141,11 @@ struct Volume::PackageLoaderContentHandler : PackageContentHandler { PackageNode* node; if (S_ISREG(mode)) { // file - node = new(std::nothrow) PackageFile(mode, entry->Data()); + node = new(std::nothrow) PackageFile(fPackage, mode, entry->Data()); } else if (S_ISLNK(mode)) { // symlink - PackageSymlink* symlink = new(std::nothrow) PackageSymlink(mode); + PackageSymlink* symlink = new(std::nothrow) PackageSymlink( + fPackage, mode); if (symlink == NULL) RETURN_ERROR(B_NO_MEMORY); @@ -157,7 +158,7 @@ struct Volume::PackageLoaderContentHandler : PackageContentHandler { node = symlink; } else if (S_ISDIR(mode)) { // directory - node = new(std::nothrow) PackageDirectory(mode); + node = new(std::nothrow) PackageDirectory(fPackage, mode); } else RETURN_ERROR(B_BAD_DATA); @@ -476,16 +477,12 @@ status_t Volume::_LoadPackage(Package* package) { // open package file - int fd = openat(package->Domain()->DirectoryFD(), package->Name(), - O_RDONLY); - if (fd < 0) { - ERROR("Failed to open package file \"%s\"\n", package->Name()); - return errno; - } -// TODO: Verify that it's still the same file. - FDCloser fdCloser(fd); + int fd = package->Open(); + if (fd < 0) + RETURN_ERROR(fd); + PackageCloser packageCloser(package); - // open package + // initialize package reader PackageLoaderErrorOutput errorOutput(package); PackageReader packageReader(&errorOutput); status_t error = packageReader.Init(fd, false); diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp index 1b0dfce5c7..7a822ed8ea 100644 --- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp @@ -58,6 +58,43 @@ set_dirent_name(struct dirent* buffer, size_t bufferSize, const char* name, } +static status_t +check_access(Node* node, int mode) +{ + // write access requested? + if (mode & W_OK) + return B_READ_ONLY_DEVICE; + + // get node permissions + int userPermissions = (node->Mode() & S_IRWXU) >> 6; + int groupPermissions = (node->Mode() & S_IRWXG) >> 3; + int otherPermissions = node->Mode() & S_IRWXO; + + // get the permissions for this uid/gid + int permissions = 0; + uid_t uid = geteuid(); + + if (uid == 0) { + // user is root + // root has always read/write permission, but at least one of the + // X bits must be set for execute permission + permissions = userPermissions | groupPermissions | otherPermissions + | S_IROTH | S_IWOTH; + } else if (uid == node->UserID()) { + // user is node owner + permissions = userPermissions; + } else if (is_user_in_group(node->GroupID())) { + // user is in owning group + permissions = groupPermissions; + } else { + // user is one of the others + permissions = otherPermissions; + } + + return (mode & ~permissions) == 0 ? B_OK : B_NOT_ALLOWED; +} + + // #pragma mark - Volume @@ -171,9 +208,16 @@ packagefs_get_vnode(fs_volume* fsVolume, ino_t vnid, fs_vnode* fsNode, Node* node = volume->FindNode(vnid); if (node == NULL) return B_ENTRY_NOT_FOUND; - node->AcquireReference(); + BReference nodeReference(node); + volumeLocker.Unlock(); - fsNode->private_node = node; + NodeWriteLocker nodeLocker(node); + status_t error = node->VFSInit(volume->ID()); + if (error != B_OK) + RETURN_ERROR(error); + nodeLocker.Unlock(); + + fsNode->private_node = nodeReference.Detach(); fsNode->ops = &gPackageFSVnodeOps; *_type = node->Mode() & S_IFMT; *_flags = 0; @@ -191,12 +235,28 @@ packagefs_put_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter) FUNCTION("volume: %p, node: %p\n", volume, node); TOUCH(volume); + NodeWriteLocker nodeLocker(node); + node->VFSUninit(); + nodeLocker.Unlock(); + node->ReleaseReference(); return B_OK; } +// #pragma mark - Request I/O + + +#if 0 +static status_t +packagefs_io(fs_volume* volume, fs_vnode* vnode, void* cookie, + io_request* request) +{ +} +#endif + + // #pragma mark - Nodes @@ -238,39 +298,8 @@ packagefs_access(fs_volume* fsVolume, fs_vnode* fsNode, int mode) FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); TOUCH(volume); - // write access requested? - if (mode & W_OK) - return B_READ_ONLY_DEVICE; - NodeReadLocker nodeLocker(node); - - // get node permissions - int userPermissions = (node->Mode() & S_IRWXU) >> 6; - int groupPermissions = (node->Mode() & S_IRWXG) >> 3; - int otherPermissions = node->Mode() & S_IRWXO; - - // get the permissions for this uid/gid - int permissions = 0; - uid_t uid = geteuid(); - - if (uid == 0) { - // user is root - // root has always read/write permission, but at least one of the - // X bits must be set for execute permission - permissions = userPermissions | groupPermissions | otherPermissions - | S_IROTH | S_IWOTH; - } else if (uid == node->UserID()) { - // user is node owner - permissions = userPermissions; - } else if (is_user_in_group(node->GroupID())) { - // user is in owning group - permissions = groupPermissions; - } else { - // user is one of the others - permissions = otherPermissions; - } - - return (mode & ~permissions) ? B_NOT_ALLOWED : B_OK; + return check_access(node, mode); } @@ -304,6 +333,17 @@ packagefs_read_stat(fs_volume* fsVolume, fs_vnode* fsNode, struct stat* st) // #pragma mark - Files +struct FileCookie { + int openMode; + + FileCookie(int openMode) + : + openMode(openMode) + { + } +}; + + static status_t packagefs_open(fs_volume* fsVolume, fs_vnode* fsNode, int openMode, void** _cookie) @@ -314,10 +354,26 @@ packagefs_open(fs_volume* fsVolume, fs_vnode* fsNode, int openMode, FUNCTION("volume: %p, node: %p (%lld), openMode %#x\n", volume, node, node->ID(), openMode); TOUCH(volume); - TOUCH(node); -// TODO: Implement it for real! - *_cookie = NULL; + NodeReadLocker nodeLocker(node); + + // check the open mode and permissions + if (S_ISDIR(node->Mode()) && (openMode & O_RWMASK) != O_RDONLY) + return B_IS_A_DIRECTORY; + + if ((openMode & O_RWMASK) != O_RDONLY) + return B_NOT_ALLOWED; + + status_t error = check_access(node, R_OK); + if (error != B_OK) + return error; + + // allocate the cookie + FileCookie* cookie = new(std::nothrow) FileCookie(openMode); + if (cookie == NULL) + RETURN_ERROR(B_NO_MEMORY); + + *_cookie = cookie; return B_OK; } @@ -331,17 +387,40 @@ packagefs_close(fs_volume* fs, fs_vnode* _node, void* cookie) static status_t -packagefs_free_cookie(fs_volume* fs, fs_vnode* _node, void* cookie) +packagefs_free_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) { + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + FileCookie* cookie = (FileCookie*)_cookie; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p\n", volume, node, + node->ID(), cookie); + TOUCH(volume); + TOUCH(node); + + delete cookie; + return B_OK; } static status_t -packagefs_read(fs_volume* fs, fs_vnode* _node, void* cookie, off_t pos, - void* buffer, size_t* bufferSize) +packagefs_read(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie, + off_t offset, void* buffer, size_t* bufferSize) { - return B_UNSUPPORTED; + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + FileCookie* cookie = (FileCookie*)_cookie; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p, offset: %lld, " + "buffer: %p, size: %lu\n", volume, node, node->ID(), cookie, offset, + buffer, *bufferSize); + TOUCH(volume); + + if ((cookie->openMode & O_RWMASK) != O_RDONLY) + return EBADF; + + return node->Read(offset, buffer, bufferSize); } @@ -635,7 +714,7 @@ fs_vnode_ops gPackageFSVnodeOps = { NULL, // read_pages, NULL, // write_pages, - NULL, // io() + NULL, // &packagefs_io, NULL, // cancel_io() NULL, // get_file_map,