From 4caf282707b832ce5a9f86bce398ce466066f9f3 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 15 Jul 2011 13:21:26 +0200 Subject: [PATCH] Fix handling of shine-through directories * Add a new class ShineThroughDirectory for shine-through directories instead of using UnpackingDirectory. * Split up setting up the shine-through directories in two steps. First the directories are only created. That happens before adding the initial package domains. After publishing the root node we bind the shine-through directories to the underlying directories. * This makes adding a package directory with the same name as a shine-through directory fail in _AddPackageNode() as originally intended. Since we no longer want it to fail -- the package daemon will copy the files in the respective directories as part of the activation process -- we simply skip the directory now. Adjust _AddPackageNode() and _AddPackageContentRootNode() accordingly. --- .../kernel/file_systems/packagefs/Volume.cpp | 145 ++++++++++++++---- .../kernel/file_systems/packagefs/Volume.h | 4 + 2 files changed, 117 insertions(+), 32 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 38fb0de063..2581ed90fb 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -46,6 +46,7 @@ #include "SizeIndex.h" #include "UnpackingLeafNode.h" #include "UnpackingDirectory.h" +#include "Utils.h" #include "Version.h" @@ -443,6 +444,27 @@ private: }; +// #pragma mark - ShineThroughDirectory + + +struct Volume::ShineThroughDirectory : public Directory { + ShineThroughDirectory(ino_t id) + : + Directory(id) + { + get_real_time(fModifiedTime); + } + + virtual timespec ModifiedTime() const + { + return fModifiedTime; + } + +private: + timespec fModifiedTime; +}; + + // #pragma mark - Volume @@ -656,6 +678,11 @@ Volume::Mount(const char* parameterString) RETURN_ERROR(error); } + // create shine-through directories + error = _CreateShineThroughDirectories(shineThrough); + if (error != B_OK) + RETURN_ERROR(error); + // create default package domain error = _AddInitialPackageDomain(packages); if (error != B_OK) @@ -667,11 +694,6 @@ Volume::Mount(const char* parameterString) if (fPackageLoader < 0) RETURN_ERROR(fPackageLoader); - // establish shine-through directories - error = _CreateShineThroughDirectories(shineThrough); - if (error != B_OK) - RETURN_ERROR(error); - // publish the root node fRootDirectory->AcquireReference(); error = PublishVNode(fRootDirectory); @@ -680,6 +702,11 @@ Volume::Mount(const char* parameterString) RETURN_ERROR(error); } + // bind and publish the shine-through directories + error = _PublishShineThroughDirectories(); + if (error != B_OK) + RETURN_ERROR(error); + // run the package loader resume_thread(fPackageLoader); @@ -1083,6 +1110,7 @@ Volume::_AddPackageContentRootNode(Package* package, do { Node* node; status_t error = _AddPackageNode(directory, packageNode, notify, node); + // returns B_OK with a NULL node, when skipping the node if (error != B_OK) { // unlock all directories while (directory != NULL) { @@ -1096,14 +1124,16 @@ Volume::_AddPackageContentRootNode(Package* package, RETURN_ERROR(error); } - // recursive into directory - if (PackageDirectory* packageDirectory - = dynamic_cast(packageNode)) { - if (packageDirectory->FirstChild() != NULL) { - directory = dynamic_cast(node); - packageNode = packageDirectory->FirstChild(); - directory->WriteLock(); - continue; + // recursive into directory, unless we're supposed to skip the node + if (node != NULL) { + if (PackageDirectory* packageDirectory + = dynamic_cast(packageNode)) { + if (packageDirectory->FirstChild() != NULL) { + directory = dynamic_cast(node); + packageNode = packageDirectory->FirstChild(); + directory->WriteLock(); + continue; + } } } @@ -1196,8 +1226,11 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode, if (node != NULL) { unpackingNode = dynamic_cast(node); - if (unpackingNode == NULL) - RETURN_ERROR(B_BAD_VALUE); + if (unpackingNode == NULL) { + _node = NULL; + return B_OK; + } + oldPackageNode = unpackingNode->GetPackageNode(); } else { status_t error = _CreateUnpackingNode(packageNode->Mode(), directory, packageNode->Name(), unpackingNode); @@ -1205,7 +1238,6 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode, RETURN_ERROR(error); node = unpackingNode->GetNode(); - oldPackageNode = unpackingNode->GetPackageNode(); newNode = true; } @@ -1356,7 +1388,7 @@ Volume::_CreateUnpackingNode(mode_t mode, Directory* parent, const char* name, fNodes.Insert(node); nodeReference.Detach(); - // we keep the initial node reference for this table + // we keep the initial node reference for the table _node = unpackingNode; return B_OK; @@ -1547,6 +1579,31 @@ Volume::_InitMountType(const char* mountType) } +status_t +Volume::_CreateShineThroughDirectory(Directory* parent, const char* name, + Directory*& _directory) +{ + ShineThroughDirectory* directory = new(std::nothrow) ShineThroughDirectory( + fNextNodeID++); + if (directory == NULL) + RETURN_ERROR(B_NO_MEMORY); + BReference directoryReference(directory, true); + + status_t error = directory->Init(parent, name, 0); + if (error != B_OK) + RETURN_ERROR(error); + + parent->AddChild(directory); + + fNodes.Insert(directory); + directoryReference.Detach(); + // we keep the initial node reference for the table + + _directory = directory; + return B_OK; +} + + status_t Volume::_CreateShineThroughDirectories(const char* shineThroughSetting) { @@ -1582,9 +1639,38 @@ Volume::_CreateShineThroughDirectories(const char* shineThroughSetting) if (directories == NULL) return B_OK; - // iterate through the directory list, create the directories, and bind them - // to the mount point subdirectories + // iterate through the directory list and create the directories while (const char* directoryName = *(directories++)) { + // create the directory + Directory* directory; + status_t error = _CreateShineThroughDirectory(fRootDirectory, + directoryName, directory); + if (error != B_OK) + RETURN_ERROR(error); + } + + return B_OK; +} + + +status_t +Volume::_PublishShineThroughDirectories() +{ + // Iterate through the root directory children and bind the shine-through + // directories to the respective mount point subdirectories. + Node* nextNode; + for (Node* node = fRootDirectory->FirstChild(); node != NULL; + node = nextNode) { + nextNode = fRootDirectory->NextChild(node); + + // skip anything but shine-through directories + ShineThroughDirectory* directory + = dynamic_cast(node); + if (directory == NULL) + continue; + + const char* directoryName = directory->Name(); + // look up the mount point subdirectory struct vnode* vnode; status_t error = vfs_entry_ref_to_vnode(fMountPoint.deviceID, @@ -1592,6 +1678,7 @@ Volume::_CreateShineThroughDirectories(const char* shineThroughSetting) if (error != B_OK) { dprintf("packagefs: Failed to get shine-through directory \"%s\": " "%s\n", directoryName, strerror(error)); + _RemoveNode(directory); continue; } CObjectDeleter vnodePutter(vnode, &vfs_put_vnode); @@ -1602,35 +1689,29 @@ Volume::_CreateShineThroughDirectories(const char* shineThroughSetting) if (error != B_OK) { dprintf("packagefs: Failed to stat shine-through directory \"%s\": " "%s\n", directoryName, strerror(error)); + _RemoveNode(directory); continue; } if (!S_ISDIR(st.st_mode)) { dprintf("packagefs: Shine-through entry \"%s\" is not a " "directory\n", directoryName); + _RemoveNode(directory); continue; } - // create the directory - UnpackingNode* directory; - error = _CreateUnpackingNode(S_IFDIR, fRootDirectory, directoryName, - directory); - if (error != B_OK) - RETURN_ERROR(error); - - // publish its vnode, so the VFS will find it without asking us - Node* directoryNode = directory->GetNode(); - error = PublishVNode(directoryNode); + // publish the vnode, so the VFS will find it without asking us + error = PublishVNode(directory); if (error != B_OK) { - _RemoveNode(directoryNode); + _RemoveNode(directory); RETURN_ERROR(error); } // bind the directory error = vfs_bind_mount_directory(st.st_dev, st.st_ino, fFSVolume->id, - directoryNode->ID()); + directory->ID()); - PutVNode(directoryNode->ID()); + PutVNode(directory->ID()); // release our reference again -- on success // vfs_bind_mount_directory() got one diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h index 6f68c5c6ad..d939b66a8f 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.h +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h @@ -111,6 +111,7 @@ private: struct PackageLoaderErrorOutput; struct PackageLoaderContentHandler; struct DomainDirectoryListener; + struct ShineThroughDirectory; friend struct AddPackageDomainJob; friend struct DomainDirectoryEventJob; @@ -175,8 +176,11 @@ private: const char* name, bool notify); status_t _InitMountType(const char* mountType); + status_t _CreateShineThroughDirectory(Directory* parent, + const char* name, Directory*& _directory); status_t _CreateShineThroughDirectories( const char* shineThroughSetting); + status_t _PublishShineThroughDirectories(); status_t _AddPackageLinksDirectory(); void _RemovePackageLinksDirectory();