From 19dc1d084f13bed77863dd1be56e846c314dd546 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 9 Apr 2013 23:26:56 +0200 Subject: [PATCH] packagefs: Use the package activation file If the file exists load only the packages specified in it. If it doesn't exist or any kind of error occurs, fall back to loading all packages in the packages directory. --- .../kernel/file_systems/packagefs/Volume.cpp | 184 +++++++++++++++--- .../kernel/file_systems/packagefs/Volume.h | 4 + 2 files changed, 160 insertions(+), 28 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 16126af844..21bc96fb5b 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -64,6 +65,13 @@ const char* const* kHomeShineThroughDirectories // sanity limit for activation change request const size_t kMaxActivationRequestSize = 10 * 1024 * 1024; +// sanity limit for activation file size +const size_t kMaxActivationFileSize = 10 * 1024 * 1024; + +static const char* const kActivationFilePath + = PACKAGES_DIRECTORY_CONFIG_DIRECTORY "/" + PACKAGES_DIRECTORY_ACTIVATION_FILE; + // #pragma mark - ShineThroughDirectory @@ -291,12 +299,7 @@ Volume::~Volume() } // delete the packages - Package* package = fPackages.Clear(true); - while (package != NULL) { - Package* next = package->FileNameHashTableNext(); - package->ReleaseReference(); - package = next; - } + _RemoveAllPackages(); // delete all indices Index* index = fIndices.Clear(true); @@ -731,6 +734,124 @@ Volume::_AddInitialPackages() dprintf("packagefs: Adding packages from \"%s\"\n", fPackagesDirectory->Path()); + // try reading the activation file + status_t error = _AddInitialPackagesFromActivationFile(); + if (error != B_OK) { + INFORM("Loading packages from activation file failed. Loading all " + "packages in packages directory.\n"); + + // remove all packages already added + { + VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf()); + VolumeWriteLocker volumeLocker(this); + _RemoveAllPackages(); + } + + // read the whole directory + error = _AddInitialPackagesFromDirectory(); + if (error != B_OK) + RETURN_ERROR(error); + } + + // add the packages to the node tree + VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf()); + VolumeWriteLocker volumeLocker(this); + for (PackageFileNameHashTable::Iterator it = fPackages.GetIterator(); + Package* package = it.Next();) { + error = _AddPackageContent(package, false); + if (error != B_OK) { + for (it.Rewind(); Package* activePackage = it.Next();) { + if (activePackage == package) + break; + _RemovePackageContent(activePackage, NULL, false); + } + RETURN_ERROR(error); + } + } + + return B_OK; +} + + +status_t +Volume::_AddInitialPackagesFromActivationFile() +{ + // try reading the activation file + int fd = openat(fPackagesDirectory->DirectoryFD(), + kActivationFilePath, O_RDONLY); + if (fd < 0) { + INFORM("Failed to open packages activation file: %s\n", + strerror(errno)); + RETURN_ERROR(errno); + } + FileDescriptorCloser fdCloser(fd); + + // read the whole file into memory to simplify things + struct stat st; + if (fstat(fd, &st) != 0) { + ERROR("Failed to stat packages activation file: %s\n", + strerror(errno)); + RETURN_ERROR(errno); + } + + if (st.st_size > kMaxActivationFileSize) { + ERROR("The packages activation file is too big.\n"); + RETURN_ERROR(B_BAD_DATA); + } + + char* fileContent = (char*)malloc(st.st_size + 1); + if (fileContent == NULL) + RETURN_ERROR(B_NO_MEMORY); + MemoryDeleter fileContentDeleter(fileContent); + + ssize_t bytesRead = read(fd, fileContent, st.st_size); + if (bytesRead < 0) { + ERROR("Failed to read packages activation file: %s\n", strerror(errno)); + RETURN_ERROR(errno); + } + + if (bytesRead != st.st_size) { + ERROR("Failed to read whole packages activation file\n"); + RETURN_ERROR(B_ERROR); + } + + // null-terminate to simplify parsing + fileContent[st.st_size] = '\0'; + + // parse the file and add the respective packages + const char* packageName = fileContent; + char* const fileContentEnd = fileContent + st.st_size; + while (packageName < fileContentEnd) { + char* packageNameEnd = strchr(packageName, '\n'); + if (packageNameEnd == NULL) + packageNameEnd = fileContentEnd; + + // skip empty lines + if (packageName == packageNameEnd) { + packageName++; + continue; + } + *packageNameEnd = '\0'; + + if (packageNameEnd - packageName >= B_FILE_NAME_LENGTH) { + ERROR("Invalid packages activation file content.\n"); + RETURN_ERROR(B_BAD_DATA); + } + + status_t error = _LoadAndAddInitialPackage(packageName); + if (error != B_OK) + RETURN_ERROR(error); + + packageName = packageNameEnd + 1; + } + + return B_OK; +} + + +status_t +Volume::_AddInitialPackagesFromDirectory() +{ // iterate through the dir and create packages int fd = dup(fPackagesDirectory->DirectoryFD()); if (fd < 0) { @@ -758,32 +879,27 @@ Volume::_AddInitialPackages() continue; } - Package* package; - if (_LoadPackage(entry->d_name, package) != B_OK) - continue; - BReference packageReference(package, true); - - VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf()); - VolumeWriteLocker volumeLocker(this); - _AddPackage(package); - + _LoadAndAddInitialPackage(entry->d_name); } - // add the packages to the node tree + return B_OK; +} + + +status_t +Volume::_LoadAndAddInitialPackage(const char* name) +{ + Package* package; + status_t error = _LoadPackage(name, package); + if (error != B_OK) { + ERROR("Failed to load package \"%s\": %s\n", name, strerror(error)); + RETURN_ERROR(error); + } + BReference packageReference(package, true); + VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf()); VolumeWriteLocker volumeLocker(this); - for (PackageFileNameHashTable::Iterator it = fPackages.GetIterator(); - Package* package = it.Next();) { - status_t error = _AddPackageContent(package, false); - if (error != B_OK) { - for (it.Rewind(); Package* activePackage = it.Next();) { - if (activePackage == package) - break; - _RemovePackageContent(activePackage, NULL, false); - } - RETURN_ERROR(error); - } - } + _AddPackage(package); return B_OK; } @@ -805,6 +921,18 @@ Volume::_RemovePackage(Package* package) } +void +Volume::_RemoveAllPackages() +{ + Package* package = fPackages.Clear(true); + while (package != NULL) { + Package* next = package->FileNameHashTableNext(); + package->ReleaseReference(); + package = next; + } +} + + inline Package* Volume::_FindPackage(const char* fileName) const { diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h index 23caf19fb8..525a979ff3 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.h +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h @@ -111,9 +111,13 @@ private: private: status_t _AddInitialPackages(); + status_t _AddInitialPackagesFromActivationFile(); + status_t _AddInitialPackagesFromDirectory(); + status_t _LoadAndAddInitialPackage(const char* name); inline void _AddPackage(Package* package); inline void _RemovePackage(Package* package); + void _RemoveAllPackages(); inline Package* _FindPackage(const char* fileName) const; status_t _AddPackageContent(Package* package,