packagefs: Fix handling of package domain paths
* The package directory path specified when mounting must be interpreted in the caller's I/O context. We did always interpret it in the kernel's I/O context, so that a relative path or a path in a chroot environment wouldn't work correctly. Now opening the directory is done in PackageDomain::Init() where we can at least guess the path's origin. * We also normalize the path, though merely to get more conclusive debug output, since after opening the directory the path isn't used for anything else anymore. * Make the "packages" mount parameter optional. If not specified, use the "packages" folder at our mount point.
This commit is contained in:
parent
5b6fb78c40
commit
91586bd3b6
@ -15,10 +15,14 @@
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
#include <fs/KPath.h>
|
||||
#include <fs/node_monitor.h>
|
||||
#include <Notifications.h>
|
||||
#include <team.h>
|
||||
#include <vfs.h>
|
||||
|
||||
#include "DebugSupport.h"
|
||||
#include "Volume.h"
|
||||
|
||||
|
||||
PackageDomain::PackageDomain(::Volume* volume)
|
||||
@ -55,16 +59,71 @@ PackageDomain::~PackageDomain()
|
||||
|
||||
|
||||
status_t
|
||||
PackageDomain::Init(const char* path)
|
||||
PackageDomain::Init(const char* path, struct stat* _st)
|
||||
{
|
||||
fPath = strdup(path);
|
||||
// Open the directory. We want the path be interpreted depending on from
|
||||
// where it came (kernel or userland), but we always want a FD in the kernel
|
||||
// I/O context. There's no VFS service method to do that for us, so we need
|
||||
// to do that ourselves.
|
||||
bool calledFromKernel
|
||||
= team_get_current_team_id() == team_get_kernel_team_id();
|
||||
// Not entirely correct, but good enough for now. The only alternative
|
||||
// is to have that information passed in as well.
|
||||
|
||||
struct vnode* vnode;
|
||||
status_t error;
|
||||
if (path != NULL) {
|
||||
error = vfs_get_vnode_from_path(path, calledFromKernel, &vnode);
|
||||
} else {
|
||||
// No path given -- use the "packages" directory at our mount point.
|
||||
error = vfs_entry_ref_to_vnode(fVolume->MountPointDeviceID(),
|
||||
fVolume->MountPointNodeID(), "packages", &vnode);
|
||||
}
|
||||
if (error != B_OK) {
|
||||
ERROR("Failed to open package domain \"%s\"\n", strerror(error));
|
||||
RETURN_ERROR(error);
|
||||
}
|
||||
|
||||
fDirFD = vfs_open_vnode(vnode, O_RDONLY, true);
|
||||
|
||||
if (fDirFD < 0) {
|
||||
ERROR("Failed to open package domain \"%s\"\n", strerror(fDirFD));
|
||||
vfs_put_vnode(vnode);
|
||||
RETURN_ERROR(fDirFD);
|
||||
}
|
||||
// Our vnode reference has been transferred to the FD.
|
||||
|
||||
// Is it a directory at all?
|
||||
struct stat st;
|
||||
if (fstat(fDirFD, &st) < 0)
|
||||
RETURN_ERROR(errno);
|
||||
|
||||
fDeviceID = st.st_dev;
|
||||
fNodeID = st.st_ino;
|
||||
|
||||
// get a normalized path
|
||||
KPath normalizedPath;
|
||||
if (normalizedPath.InitCheck() != B_OK)
|
||||
RETURN_ERROR(normalizedPath.InitCheck());
|
||||
|
||||
char* normalizedPathBuffer = normalizedPath.LockBuffer();
|
||||
error = vfs_entry_ref_to_path(fDeviceID, fNodeID, NULL,
|
||||
normalizedPathBuffer, normalizedPath.BufferSize());
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
fPath = strdup(normalizedPathBuffer);
|
||||
if (fPath == NULL)
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
|
||||
status_t error = fPackages.Init();
|
||||
// init packages hash table
|
||||
error = fPackages.Init();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
if (_st != NULL)
|
||||
*_st = st;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -74,19 +133,6 @@ PackageDomain::Prepare(NotificationListener* listener)
|
||||
{
|
||||
ObjectDeleter<NotificationListener> listenerDeleter(listener);
|
||||
|
||||
fDirFD = open(fPath, O_RDONLY);
|
||||
if (fDirFD < 0) {
|
||||
ERROR("Failed to open package domain \"%s\"\n", strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
if (fstat(fDirFD, &st) < 0)
|
||||
RETURN_ERROR(errno);
|
||||
|
||||
fDeviceID = st.st_dev;
|
||||
fNodeID = st.st_ino;
|
||||
|
||||
status_t error = add_node_listener(fDeviceID, fNodeID, B_WATCH_DIRECTORY,
|
||||
*listener);
|
||||
if (error != B_OK)
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "Package.h"
|
||||
|
||||
|
||||
struct stat;
|
||||
|
||||
class NotificationListener;
|
||||
class Volume;
|
||||
|
||||
@ -29,7 +31,7 @@ public:
|
||||
dev_t DeviceID() { return fDeviceID; }
|
||||
ino_t NodeID() { return fNodeID; }
|
||||
|
||||
status_t Init(const char* path);
|
||||
status_t Init(const char* path, struct stat* _st);
|
||||
status_t Prepare(NotificationListener* listener);
|
||||
// takes over ownership of the listener
|
||||
|
||||
|
@ -617,8 +617,8 @@ Volume::Mount(const char* parameterString)
|
||||
CObjectDeleter<void, status_t> parameterHandleDeleter(parameterHandle,
|
||||
&delete_driver_settings);
|
||||
|
||||
if (packages == NULL || packages[0] == '\0') {
|
||||
FATAL("need package folder ('packages' parameter)!\n");
|
||||
if (packages != NULL && packages[0] == '\0') {
|
||||
FATAL("invalid package folder ('packages' parameter)!\n");
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
|
||||
@ -628,11 +628,22 @@ Volume::Mount(const char* parameterString)
|
||||
RETURN_ERROR(error);
|
||||
}
|
||||
|
||||
// get our mount point
|
||||
error = vfs_get_mount_point(fFSVolume->id, &fMountPoint.deviceID,
|
||||
&fMountPoint.nodeID);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// create initial package domain
|
||||
PackageDomain* packageDomain = new(std::nothrow) PackageDomain(this);
|
||||
if (packageDomain == NULL)
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
BReference<PackageDomain> packageDomainReference(packageDomain, true);
|
||||
|
||||
struct stat st;
|
||||
if (stat(packages, &st) < 0) {
|
||||
FATAL("failed to stat: \"%s\": %s\n", packages, strerror(errno));
|
||||
RETURN_ERROR(B_ERROR);
|
||||
}
|
||||
error = packageDomain->Init(packages, &st);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// If no volume name is given, infer it from the mount type.
|
||||
if (volumeName == NULL) {
|
||||
@ -663,12 +674,6 @@ Volume::Mount(const char* parameterString)
|
||||
fRootDirectory->AcquireReference();
|
||||
// one reference for the table
|
||||
|
||||
// get our mount point
|
||||
error = vfs_get_mount_point(fFSVolume->id, &fMountPoint.deviceID,
|
||||
&fMountPoint.nodeID);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// register with packagefs root
|
||||
error = ::PackageFSRoot::RegisterVolume(this);
|
||||
if (error != B_OK)
|
||||
@ -685,8 +690,8 @@ Volume::Mount(const char* parameterString)
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// create default package domain
|
||||
error = _AddInitialPackageDomain(packages);
|
||||
// add initial package domain
|
||||
error = _AddPackageDomain(packageDomain, false);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
@ -823,7 +828,7 @@ Volume::AddPackageDomain(const char* path)
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
BReference<PackageDomain> packageDomainReference(packageDomain, true);
|
||||
|
||||
status_t error = packageDomain->Init(path);
|
||||
status_t error = packageDomain->Init(path, NULL);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
@ -928,25 +933,11 @@ Volume::_PushJob(Job* job)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::_AddInitialPackageDomain(const char* path)
|
||||
{
|
||||
PackageDomain* domain = new(std::nothrow) PackageDomain(this);
|
||||
if (domain == NULL)
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
BReference<PackageDomain> domainReference(domain, true);
|
||||
|
||||
status_t error = domain->Init(path);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
return _AddPackageDomain(domain, false);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
|
||||
{
|
||||
dprintf("packagefs: Adding package domain \"%s\"\n", domain->Path());
|
||||
|
||||
// create a directory listener
|
||||
DomainDirectoryListener* listener = new(std::nothrow)
|
||||
DomainDirectoryListener(this, domain);
|
||||
@ -962,7 +953,13 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
|
||||
}
|
||||
|
||||
// iterate through the dir and create packages
|
||||
DIR* dir = opendir(domain->Path());
|
||||
int fd = dup(domain->DirectoryFD());
|
||||
if (fd < 0) {
|
||||
ERROR("Failed to dup() package domain FD: %s\n", strerror(errno));
|
||||
RETURN_ERROR(errno);
|
||||
}
|
||||
|
||||
DIR* dir = fdopendir(fd);
|
||||
if (dir == NULL) {
|
||||
ERROR("Failed to open package domain directory \"%s\": %s\n",
|
||||
domain->Path(), strerror(errno));
|
||||
|
Loading…
Reference in New Issue
Block a user