Add support for shine-through directories
* packagefs_mount(): Initialize the fs_volume earlier, so it is more usuable in Volume::Mount(). * The new mount parameter "shine-through" can be used to specify which shine-through mode shall be used. Can be "system", "common", "home", and "none". Depending on the setting it is decided which directories of the underlying file system are bind-mounted on top of ours. * Fix infinite loop in Volume::_RemovePackageContent(). * Use the RETURN_ERROR() macro in more places to help with debugging.
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
#include <Notifications.h>
|
#include <Notifications.h>
|
||||||
|
#include <vfs.h>
|
||||||
|
|
||||||
#include <package/hpkg/ErrorOutput.h>
|
#include <package/hpkg/ErrorOutput.h>
|
||||||
#include <package/hpkg/PackageEntry.h>
|
#include <package/hpkg/PackageEntry.h>
|
||||||
@@ -44,6 +45,16 @@ using BPackageKit::BHPKG::BPrivate::PackageReaderImpl;
|
|||||||
// node ID of the root directory
|
// node ID of the root directory
|
||||||
static const ino_t kRootDirectoryID = 1;
|
static const ino_t kRootDirectoryID = 1;
|
||||||
|
|
||||||
|
// shine-through directories
|
||||||
|
const char* const kSystemShineThroughDirectories[] = {
|
||||||
|
"packages", NULL
|
||||||
|
};
|
||||||
|
const char* const kCommonShineThroughDirectories[] = {
|
||||||
|
"non-packaged", "packages", "settings", "var", NULL
|
||||||
|
};
|
||||||
|
const char* const* kHomeShineThroughDirectories
|
||||||
|
= kCommonShineThroughDirectories;
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - Job
|
// #pragma mark - Job
|
||||||
|
|
||||||
@@ -355,14 +366,21 @@ Volume::Mount(const char* parameterString)
|
|||||||
|
|
||||||
const char* packages = NULL;
|
const char* packages = NULL;
|
||||||
const char* volumeName = NULL;
|
const char* volumeName = NULL;
|
||||||
|
const char* shineThrough = NULL;
|
||||||
|
|
||||||
void* parameterHandle = parse_driver_settings_string(parameterString);
|
void* parameterHandle = parse_driver_settings_string(parameterString);
|
||||||
if (parameterHandle != NULL) {
|
if (parameterHandle != NULL) {
|
||||||
packages
|
packages = get_driver_parameter(parameterHandle, "packages", NULL,
|
||||||
= get_driver_parameter(parameterHandle, "packages", NULL, NULL);
|
NULL);
|
||||||
volumeName
|
volumeName = get_driver_parameter(parameterHandle, "volume-name", NULL,
|
||||||
= get_driver_parameter(parameterHandle, "volume-name", NULL, NULL);
|
NULL);
|
||||||
delete_driver_settings(parameterHandle);
|
shineThrough = get_driver_parameter(parameterHandle, "shine-through",
|
||||||
|
NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CObjectDeleter<void, status_t> parameterHandleDeleter(parameterHandle,
|
||||||
|
&delete_driver_settings);
|
||||||
|
|
||||||
if (packages == NULL || packages[0] == '\0') {
|
if (packages == NULL || packages[0] == '\0') {
|
||||||
ERROR("need package folder ('packages' parameter)!\n");
|
ERROR("need package folder ('packages' parameter)!\n");
|
||||||
RETURN_ERROR(B_BAD_VALUE);
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
@@ -396,11 +414,23 @@ Volume::Mount(const char* parameterString)
|
|||||||
error = PublishVNode(fRootDirectory);
|
error = PublishVNode(fRootDirectory);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
fRootDirectory->ReleaseReference();
|
fRootDirectory->ReleaseReference();
|
||||||
return error;
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// establish shine-through directories
|
||||||
|
error = _CreateShineThroughDirectories(shineThrough);
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
// run the package loader
|
// run the package loader
|
||||||
resume_thread(fPackageLoader);
|
resume_thread(fPackageLoader);
|
||||||
|
dprintf("mounted packagefs successfully!\n");
|
||||||
|
{
|
||||||
|
for (Node* node = fRootDirectory->FirstChild(); node != NULL;
|
||||||
|
node = fRootDirectory->NextChild(node)) {
|
||||||
|
dprintf(" node %lld: \"%s\"\n", node->ID(), node->Name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -452,7 +482,7 @@ Volume::AddPackageDomain(const char* path)
|
|||||||
|
|
||||||
status_t error = packageDomain->Init(path);
|
status_t error = packageDomain->Init(path);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
Job* job = new(std::nothrow) AddPackageDomainJob(this, packageDomain);
|
Job* job = new(std::nothrow) AddPackageDomainJob(this, packageDomain);
|
||||||
if (job == NULL)
|
if (job == NULL)
|
||||||
@@ -536,7 +566,7 @@ Volume::_AddInitialPackageDomain(const char* path)
|
|||||||
|
|
||||||
status_t error = domain->Init(path);
|
status_t error = domain->Init(path);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
return _AddPackageDomain(domain, false);
|
return _AddPackageDomain(domain, false);
|
||||||
}
|
}
|
||||||
@@ -556,7 +586,7 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
|
|||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
ERROR("Failed to prepare package domain \"%s\": %s\n",
|
ERROR("Failed to prepare package domain \"%s\": %s\n",
|
||||||
domain->Path(), strerror(errno));
|
domain->Path(), strerror(errno));
|
||||||
return errno;
|
RETURN_ERROR(errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate through the dir and create packages
|
// iterate through the dir and create packages
|
||||||
@@ -564,7 +594,7 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
|
|||||||
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));
|
||||||
return errno;
|
RETURN_ERROR(errno);
|
||||||
}
|
}
|
||||||
CObjectDeleter<DIR, int> dirCloser(dir, closedir);
|
CObjectDeleter<DIR, int> dirCloser(dir, closedir);
|
||||||
|
|
||||||
@@ -589,7 +619,7 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
|
|||||||
break;
|
break;
|
||||||
_RemovePackageContent(activePackage, NULL, notify);
|
_RemovePackageContent(activePackage, NULL, notify);
|
||||||
}
|
}
|
||||||
return error;
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,17 +644,17 @@ Volume::_LoadPackage(Package* package)
|
|||||||
PackageReaderImpl packageReader(&errorOutput);
|
PackageReaderImpl packageReader(&errorOutput);
|
||||||
status_t error = packageReader.Init(fd, false);
|
status_t error = packageReader.Init(fd, false);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
// parse content
|
// parse content
|
||||||
PackageLoaderContentHandler handler(package);
|
PackageLoaderContentHandler handler(package);
|
||||||
error = handler.Init();
|
error = handler.Init();
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
error = packageReader.ParseContent(&handler);
|
error = packageReader.ParseContent(&handler);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -641,7 +671,7 @@ Volume::_AddPackageContent(Package* package, bool notify)
|
|||||||
status_t error = _AddPackageContentRootNode(package, node, notify);
|
status_t error = _AddPackageContentRootNode(package, node, notify);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
_RemovePackageContent(package, node, notify);
|
_RemovePackageContent(package, node, notify);
|
||||||
return error;
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,12 +688,12 @@ Volume::_RemovePackageContent(Package* package, PackageNode* endNode,
|
|||||||
if (node == endNode)
|
if (node == endNode)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// skip over ".PackageInfo" file, it isn't part of the package content
|
|
||||||
if (strcmp(node->Name(), B_HPKG_PACKAGE_INFO_FILE_NAME) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
PackageNode* nextNode = package->Nodes().GetNext(node);
|
PackageNode* nextNode = package->Nodes().GetNext(node);
|
||||||
_RemovePackageContentRootNode(package, node, NULL, notify);
|
|
||||||
|
// skip over ".PackageInfo" file, it isn't part of the package content
|
||||||
|
if (strcmp(node->Name(), B_HPKG_PACKAGE_INFO_FILE_NAME) != 0)
|
||||||
|
_RemovePackageContentRootNode(package, node, NULL, notify);
|
||||||
|
|
||||||
node = nextNode;
|
node = nextNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -696,7 +726,7 @@ Volume::_AddPackageContentRootNode(Package* package,
|
|||||||
// remove the added package nodes
|
// remove the added package nodes
|
||||||
_RemovePackageContentRootNode(package, rootPackageNode, packageNode,
|
_RemovePackageContentRootNode(package, rootPackageNode, packageNode,
|
||||||
notify);
|
notify);
|
||||||
return error;
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// recursive into directory
|
// recursive into directory
|
||||||
@@ -798,7 +828,7 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
|
|||||||
status_t error = _CreateNode(packageNode->Mode(), directory,
|
status_t error = _CreateNode(packageNode->Mode(), directory,
|
||||||
packageNode->Name(), node);
|
packageNode->Name(), node);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
RETURN_ERROR(error);
|
||||||
newNode = true;
|
newNode = true;
|
||||||
}
|
}
|
||||||
BReference<Node> nodeReference(node);
|
BReference<Node> nodeReference(node);
|
||||||
@@ -808,7 +838,7 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
|
|||||||
// remove the node, if created before
|
// remove the node, if created before
|
||||||
if (newNode)
|
if (newNode)
|
||||||
_RemoveNode(node);
|
_RemoveNode(node);
|
||||||
return error;
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notify) {
|
if (notify) {
|
||||||
@@ -911,7 +941,7 @@ Volume::_CreateNode(mode_t mode, Directory* parent, const char* name,
|
|||||||
|
|
||||||
status_t error = node->Init(parent, name);
|
status_t error = node->Init(parent, name);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
parent->AddChild(node);
|
parent->AddChild(node);
|
||||||
|
|
||||||
@@ -1084,3 +1114,92 @@ Volume::_DomainEntryMoved(PackageDomain* domain, dev_t deviceID,
|
|||||||
_DomainEntryCreated(domain, deviceID, toDirectoryID, nodeID, name, true,
|
_DomainEntryCreated(domain, deviceID, toDirectoryID, nodeID, name, true,
|
||||||
notify);
|
notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Volume::_CreateShineThroughDirectories(const char* shineThroughSetting)
|
||||||
|
{
|
||||||
|
if (shineThroughSetting == NULL)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
// get the directories to map
|
||||||
|
const char* const* directories = NULL;
|
||||||
|
|
||||||
|
if (strcmp(shineThroughSetting, "system") == 0)
|
||||||
|
directories = kSystemShineThroughDirectories;
|
||||||
|
else if (strcmp(shineThroughSetting, "common") == 0)
|
||||||
|
directories = kCommonShineThroughDirectories;
|
||||||
|
else if (strcmp(shineThroughSetting, "home") == 0)
|
||||||
|
directories = kHomeShineThroughDirectories;
|
||||||
|
else if (strcmp(shineThroughSetting, "none") == 0)
|
||||||
|
directories = NULL;
|
||||||
|
else
|
||||||
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
|
|
||||||
|
if (directories == NULL)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
// get our mount point
|
||||||
|
dev_t mountPointDevice;
|
||||||
|
ino_t mountPointNode;
|
||||||
|
status_t error = vfs_get_mount_point(fFSVolume->id, &mountPointDevice,
|
||||||
|
&mountPointNode);
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
// iterate through the directory list, create the directories, and bind them
|
||||||
|
// to the mount point subdirectories
|
||||||
|
while (const char* directoryName = *(directories++)) {
|
||||||
|
// look up the mount point subdirectory
|
||||||
|
struct vnode* vnode;
|
||||||
|
error = vfs_entry_ref_to_vnode(mountPointDevice, mountPointNode,
|
||||||
|
directoryName, &vnode);
|
||||||
|
if (error != B_OK) {
|
||||||
|
dprintf("packagefs: Failed to get shine-through directory \"%s\": "
|
||||||
|
"%s\n", directoryName, strerror(error));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CObjectDeleter<struct vnode> vnodePutter(vnode, &vfs_put_vnode);
|
||||||
|
|
||||||
|
// stat it
|
||||||
|
struct stat st;
|
||||||
|
error = vfs_stat_vnode(vnode, &st);
|
||||||
|
if (error != B_OK) {
|
||||||
|
dprintf("packagefs: Failed to stat shine-through directory \"%s\": "
|
||||||
|
"%s\n", directoryName, strerror(error));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!S_ISDIR(st.st_mode)) {
|
||||||
|
dprintf("packagefs: Shine-through entry \"%s\" is not a "
|
||||||
|
"directory\n", directoryName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the directory
|
||||||
|
Node* directory;
|
||||||
|
error = _CreateNode(S_IFDIR, fRootDirectory, directoryName, directory);
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
|
||||||
|
// publish its vnode, so the VFS will find it without asking us
|
||||||
|
error = PublishVNode(directory);
|
||||||
|
if (error != B_OK) {
|
||||||
|
_RemoveNode(directory);
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bind the directory
|
||||||
|
error = vfs_bind_mount_directory(st.st_dev, st.st_ino, fFSVolume->id,
|
||||||
|
directory->ID());
|
||||||
|
|
||||||
|
PutVNode(directory->ID());
|
||||||
|
// release our reference again -- on success
|
||||||
|
// vfs_bind_mount_directory() got one
|
||||||
|
|
||||||
|
if (error != B_OK)
|
||||||
|
RETURN_ERROR(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|||||||
@@ -118,6 +118,8 @@ private:
|
|||||||
ino_t nodeID, const char* fromName,
|
ino_t nodeID, const char* fromName,
|
||||||
const char* name, bool notify);
|
const char* name, bool notify);
|
||||||
|
|
||||||
|
status_t _CreateShineThroughDirectories(
|
||||||
|
const char* shineThroughSetting);
|
||||||
private:
|
private:
|
||||||
rw_lock fLock;
|
rw_lock fLock;
|
||||||
fs_volume* fFSVolume;
|
fs_volume* fFSVolume;
|
||||||
|
|||||||
@@ -117,14 +117,17 @@ packagefs_mount(fs_volume* fsVolume, const char* device, uint32 flags,
|
|||||||
RETURN_ERROR(B_NO_MEMORY);
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
ObjectDeleter<Volume> volumeDeleter(volume);
|
ObjectDeleter<Volume> volumeDeleter(volume);
|
||||||
|
|
||||||
|
// Initialize the fs_volume now already, so it is mostly usable in during
|
||||||
|
// mounting.
|
||||||
|
fsVolume->private_volume = volumeDeleter.Detach();
|
||||||
|
fsVolume->ops = &gPackageFSVolumeOps;
|
||||||
|
|
||||||
status_t error = volume->Mount(parameters);
|
status_t error = volume->Mount(parameters);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
// set return values
|
// set return values
|
||||||
*_rootID = volume->RootDirectory()->ID();
|
*_rootID = volume->RootDirectory()->ID();
|
||||||
fsVolume->private_volume = volumeDeleter.Detach();
|
|
||||||
fsVolume->ops = &gPackageFSVolumeOps;
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user