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:
Ingo Weinhold 2013-04-05 18:52:09 +02:00
parent 5b6fb78c40
commit 91586bd3b6
3 changed files with 94 additions and 49 deletions

View File

@ -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)

View File

@ -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

View File

@ -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));