diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp index d2f4ceaa57..d3e48d021d 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp @@ -15,10 +15,14 @@ #include +#include #include #include +#include +#include #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 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) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h index 67c0354fd0..0442547b6c 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h @@ -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 diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 37a08d49b4..1a4f1bc7b1 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -617,8 +617,8 @@ Volume::Mount(const char* parameterString) CObjectDeleter 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 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 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 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));