* 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
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -6,19 +6,28 @@
|
||||
|
||||
#include "Package.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <util/AutoLock.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <util/khash.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
#include <lock.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
#include "PackageDirectory.h"
|
||||
|
||||
|
||||
PackageDirectory::PackageDirectory(mode_t mode)
|
||||
PackageDirectory::PackageDirectory(Package* package, mode_t mode)
|
||||
:
|
||||
PackageNode(mode)
|
||||
PackageNode(package, mode)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
class PackageDirectory : public PackageNode,
|
||||
public DoublyLinkedListLinkImpl<PackageDirectory> {
|
||||
public:
|
||||
PackageDirectory(mode_t mode);
|
||||
PackageDirectory(Package* package, mode_t mode);
|
||||
virtual ~PackageDirectory();
|
||||
|
||||
void AddChild(PackageNode* node);
|
||||
|
||||
@@ -6,11 +6,99 @@
|
||||
|
||||
#include "PackageFile.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <new>
|
||||
|
||||
PackageFile::PackageFile(mode_t mode, const PackageData& data)
|
||||
#include <fs_cache.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<PackageLeafNode> fListLink;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -13,12 +13,13 @@
|
||||
#include <util/SinglyLinkedList.h>
|
||||
|
||||
|
||||
class Package;
|
||||
class PackageDirectory;
|
||||
|
||||
|
||||
class PackageNode : public SinglyLinkedListLinkImpl<PackageNode> {
|
||||
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;
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
#include <string.h>
|
||||
|
||||
|
||||
PackageSymlink::PackageSymlink(mode_t mode)
|
||||
PackageSymlink::PackageSymlink(Package* package, mode_t mode)
|
||||
:
|
||||
PackageLeafNode(mode),
|
||||
PackageLeafNode(package, mode),
|
||||
fSymlinkPath(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<Node> 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,
|
||||
|
||||
Reference in New Issue
Block a user