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:
@@ -15,10 +15,14 @@
|
|||||||
|
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
|
#include <fs/KPath.h>
|
||||||
#include <fs/node_monitor.h>
|
#include <fs/node_monitor.h>
|
||||||
#include <Notifications.h>
|
#include <Notifications.h>
|
||||||
|
#include <team.h>
|
||||||
|
#include <vfs.h>
|
||||||
|
|
||||||
#include "DebugSupport.h"
|
#include "DebugSupport.h"
|
||||||
|
#include "Volume.h"
|
||||||
|
|
||||||
|
|
||||||
PackageDomain::PackageDomain(::Volume* volume)
|
PackageDomain::PackageDomain(::Volume* volume)
|
||||||
@@ -55,16 +59,71 @@ PackageDomain::~PackageDomain()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
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)
|
if (fPath == NULL)
|
||||||
RETURN_ERROR(B_NO_MEMORY);
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
|
|
||||||
status_t error = fPackages.Init();
|
// init packages hash table
|
||||||
|
error = fPackages.Init();
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
if (_st != NULL)
|
||||||
|
*_st = st;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,19 +133,6 @@ PackageDomain::Prepare(NotificationListener* listener)
|
|||||||
{
|
{
|
||||||
ObjectDeleter<NotificationListener> listenerDeleter(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,
|
status_t error = add_node_listener(fDeviceID, fNodeID, B_WATCH_DIRECTORY,
|
||||||
*listener);
|
*listener);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
#include "Package.h"
|
#include "Package.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct stat;
|
||||||
|
|
||||||
class NotificationListener;
|
class NotificationListener;
|
||||||
class Volume;
|
class Volume;
|
||||||
|
|
||||||
@@ -29,7 +31,7 @@ public:
|
|||||||
dev_t DeviceID() { return fDeviceID; }
|
dev_t DeviceID() { return fDeviceID; }
|
||||||
ino_t NodeID() { return fNodeID; }
|
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);
|
status_t Prepare(NotificationListener* listener);
|
||||||
// takes over ownership of the listener
|
// takes over ownership of the listener
|
||||||
|
|
||||||
|
|||||||
@@ -617,8 +617,8 @@ Volume::Mount(const char* parameterString)
|
|||||||
CObjectDeleter<void, status_t> parameterHandleDeleter(parameterHandle,
|
CObjectDeleter<void, status_t> parameterHandleDeleter(parameterHandle,
|
||||||
&delete_driver_settings);
|
&delete_driver_settings);
|
||||||
|
|
||||||
if (packages == NULL || packages[0] == '\0') {
|
if (packages != NULL && packages[0] == '\0') {
|
||||||
FATAL("need package folder ('packages' parameter)!\n");
|
FATAL("invalid package folder ('packages' parameter)!\n");
|
||||||
RETURN_ERROR(B_BAD_VALUE);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,11 +628,22 @@ Volume::Mount(const char* parameterString)
|
|||||||
RETURN_ERROR(error);
|
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;
|
struct stat st;
|
||||||
if (stat(packages, &st) < 0) {
|
error = packageDomain->Init(packages, &st);
|
||||||
FATAL("failed to stat: \"%s\": %s\n", packages, strerror(errno));
|
if (error != B_OK)
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(error);
|
||||||
}
|
|
||||||
|
|
||||||
// If no volume name is given, infer it from the mount type.
|
// If no volume name is given, infer it from the mount type.
|
||||||
if (volumeName == NULL) {
|
if (volumeName == NULL) {
|
||||||
@@ -663,12 +674,6 @@ Volume::Mount(const char* parameterString)
|
|||||||
fRootDirectory->AcquireReference();
|
fRootDirectory->AcquireReference();
|
||||||
// one reference for the table
|
// 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
|
// register with packagefs root
|
||||||
error = ::PackageFSRoot::RegisterVolume(this);
|
error = ::PackageFSRoot::RegisterVolume(this);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
@@ -685,8 +690,8 @@ Volume::Mount(const char* parameterString)
|
|||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
// create default package domain
|
// add initial package domain
|
||||||
error = _AddInitialPackageDomain(packages);
|
error = _AddPackageDomain(packageDomain, false);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
@@ -823,7 +828,7 @@ Volume::AddPackageDomain(const char* path)
|
|||||||
RETURN_ERROR(B_NO_MEMORY);
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
BReference<PackageDomain> packageDomainReference(packageDomain, true);
|
BReference<PackageDomain> packageDomainReference(packageDomain, true);
|
||||||
|
|
||||||
status_t error = packageDomain->Init(path);
|
status_t error = packageDomain->Init(path, NULL);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
RETURN_ERROR(error);
|
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
|
status_t
|
||||||
Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
|
Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
|
||||||
{
|
{
|
||||||
|
dprintf("packagefs: Adding package domain \"%s\"\n", domain->Path());
|
||||||
|
|
||||||
// create a directory listener
|
// create a directory listener
|
||||||
DomainDirectoryListener* listener = new(std::nothrow)
|
DomainDirectoryListener* listener = new(std::nothrow)
|
||||||
DomainDirectoryListener(this, domain);
|
DomainDirectoryListener(this, domain);
|
||||||
@@ -962,7 +953,13 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// iterate through the dir and create packages
|
// 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) {
|
if (dir == NULL) {
|
||||||
ERROR("Failed to open package domain directory \"%s\": %s\n",
|
ERROR("Failed to open package domain directory \"%s\": %s\n",
|
||||||
domain->Path(), strerror(errno));
|
domain->Path(), strerror(errno));
|
||||||
|
|||||||
Reference in New Issue
Block a user