[haiku-commits] BRANCH HaikuPM-github.package-management - src/servers/package src/add-ons/kernel/file_systems/packagefs headers/private/package

  • From: HaikuPM-github.package-management <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 9 Apr 2013 23:45:34 +0200 (CEST)

added 3 changesets to branch 'refs/remotes/HaikuPM-github/package-management'
old head: 19a268a459bb8a117f42937901532ef3b117a8d7
new head: 40cbf171efee048cd28a69e791b2ebac38cad3c2
overview: https://github.com/haiku/HaikuPM/compare/19a268a...40cbf17

----------------------------------------------------------------------------

a96531f: package daemon: On changes write a file with the active packages

19dc1d0: 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.

40cbf17: packagefs: don't dup() the packages directory FD
  
  Volume::_AddInitialPackagesFromDirectory(): Use openat() instead of
  dup() to get a FD for the packages directory. Currently our fdopendir()
  implementation doesn't use it directly anyway, but in theory it could
  and would then change the state of the original FD.

                                    [ Ingo Weinhold <ingo_weinhold@xxxxxx> ]

----------------------------------------------------------------------------

5 files changed, 309 insertions(+), 31 deletions(-)
headers/private/package/PackagesDirectoryDefs.h  |  18 ++
.../kernel/file_systems/packagefs/Volume.cpp     | 184 ++++++++++++++++---
.../kernel/file_systems/packagefs/Volume.h       |   4 +
src/servers/package/Volume.cpp                   | 128 ++++++++++++-
src/servers/package/Volume.h                     |   6 +

############################################################################

Commit:      a96531fc511e210c34cb054310b61b560a82a06c
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Tue Apr  9 20:12:22 2013 UTC

package daemon: On changes write a file with the active packages

----------------------------------------------------------------------------

diff --git a/headers/private/package/PackagesDirectoryDefs.h 
b/headers/private/package/PackagesDirectoryDefs.h
new file mode 100644
index 0000000..dacd05b
--- /dev/null
+++ b/headers/private/package/PackagesDirectoryDefs.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Ingo Weinhold <ingo_weinhold@xxxxxx>
+ */
+#ifndef _PACKAGE__PRIVATE__PACKAGES_DIRECTORY_DEFS_H_
+#define _PACKAGE__PRIVATE__PACKAGES_DIRECTORY_DEFS_H_
+
+
+#define PACKAGES_DIRECTORY_CONFIG_DIRECTORY    "config"
+#define PACKAGES_DIRECTORY_ACTIVATION_FILE     "activated-packages"
+
+
+
+#endif // _PACKAGE__PRIVATE__PACKAGES_DIRECTORY_DEFS_H_
+
diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index f5082ba..bd8ba7b 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -16,6 +16,7 @@
 
 #include <Directory.h>
 #include <Entry.h>
+#include <File.h>
 #include <Looper.h>
 #include <NodeMonitor.h>
 #include <Path.h>
@@ -29,11 +30,18 @@
 
 #include <AutoDeleter.h>
 #include <AutoLocker.h>
+#include <PackagesDirectoryDefs.h>
 
 #include "DebugSupport.h"
 
 
-static const char* kPackageFileNameExtension = ".hpkg";
+static const char* const kPackageFileNameExtension = ".hpkg";
+static const char* const kConfigDirectoryName
+       = PACKAGES_DIRECTORY_CONFIG_DIRECTORY;
+static const char* const kActivationFileName
+       = PACKAGES_DIRECTORY_ACTIVATION_FILE;
+static const char* const kTemporaryActivationFileName
+       = PACKAGES_DIRECTORY_ACTIVATION_FILE ".tmp";
 
 
 // #pragma mark - Listener
@@ -493,6 +501,47 @@ fPackagesToBeActivated.size(), 
fPackagesToBeDeactivated.size());
 
        fPackagesToBeActivated.clear();
        fPackagesToBeDeactivated.clear();
+
+       // write the package activation file
+
+       // create the content
+       BString activationFileContent;
+       for (PackageFileNameHashTable::Iterator it
+                       = fPackagesByFileName.GetIterator(); it.HasNext();) {
+               Package* package = it.Next();
+               if (package->IsActive())
+                       activationFileContent << package->FileName() << '\n';
+       }
+
+       // open and write the temporary file
+       BFile activationFile;
+       BEntry activationFileEntry;
+       status_t error = _OpenPackagesFile(kConfigDirectoryName,
+               kTemporaryActivationFileName,
+               B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE, activationFile,
+               &activationFileEntry);
+       if (error != B_OK) {
+               ERROR("Volume::ProcessPendingPackageActivationChanges(): failed 
to "
+                       "create activation file: %s\n", strerror(error));
+               return;
+       }
+
+       ssize_t bytesWritten = 
activationFile.Write(activationFileContent.String(),
+               activationFileContent.Length());
+       if (bytesWritten < 0) {
+               ERROR("Volume::ProcessPendingPackageActivationChanges(): failed 
to "
+                       "write activation file: %s\n", strerror(bytesWritten));
+               return;
+       }
+
+       // rename the temporary file to the final file
+       error = activationFileEntry.Rename(kActivationFileName, true);
+       if (error != B_OK) {
+               ERROR("Volume::ProcessPendingPackageActivationChanges(): failed 
to "
+                       "rename temporary activation file to final file: %s\n",
+                       strerror(error));
+               return;
+       }
 }
 
 
@@ -672,8 +721,8 @@ Volume::_ReadPackagesDirectory()
        BDirectory directory;
        status_t error = directory.SetTo(&fPackagesDirectoryRef);
        if (error != B_OK) {
-               ERROR("Volume::_ReadPackagesDirectory(): open packages 
directory: %s\n",
-                       strerror(error));
+               ERROR("Volume::_ReadPackagesDirectory(): failed to open 
packages "
+                       "directory: %s\n", strerror(error));
                RETURN_ERROR(error);
        }
 
@@ -793,3 +842,76 @@ Volume::_AddRepository(BSolver* solver, BSolverRepository& 
repository,
 
        return B_OK;
 }
+
+
+status_t
+Volume::_OpenPackagesFile(const char* subDirectoryPath, const char* fileName,
+       uint32 openMode, BFile& _file, BEntry* _entry)
+{
+       BDirectory directory;
+       if (subDirectoryPath != NULL) {
+               status_t error = _OpenPackagesSubDirectory(subDirectoryPath,
+                       (openMode & B_CREATE_FILE) != 0, directory);
+               if (error != B_OK) {
+                       ERROR("Volume::_OpenPackagesFile(): failed to open 
packages "
+                               "subdirectory \"%s\": %s\n", subDirectoryPath, 
strerror(error));
+                       RETURN_ERROR(error);
+               }
+       } else {
+               status_t error = directory.SetTo(&fPackagesDirectoryRef);
+               if (error != B_OK) {
+                       ERROR("Volume::_OpenPackagesFile(): failed to open 
packages "
+                               "directory: %s\n", strerror(error));
+                       RETURN_ERROR(error);
+               }
+       }
+
+       BEntry stackEntry;
+       BEntry& entry = _entry != NULL ? *_entry : stackEntry;
+       status_t error = entry.SetTo(&directory, fileName);
+       if (error != B_OK) {
+               ERROR("Volume::_OpenPackagesFile(): failed to get entry for 
file: %s",
+                       strerror(error));
+               RETURN_ERROR(error);
+       }
+
+       return _file.SetTo(&entry, openMode);
+}
+
+
+status_t
+Volume::_OpenPackagesSubDirectory(const char* path, bool create,
+       BDirectory& _directory)
+{
+       // open the packages directory
+       BDirectory directory;
+       status_t error = directory.SetTo(&fPackagesDirectoryRef);
+       if (error != B_OK) {
+               ERROR("Volume::_OpenConfigSubDirectory(): failed to open 
packages "
+                       "directory: %s\n", strerror(error));
+               RETURN_ERROR(error);
+       }
+
+       // If creating is not allowed, just try to open it.
+       if (!create)
+               RETURN_ERROR(_directory.SetTo(&directory, path));
+
+       // get an absolute path and create the subdirectory
+       BPath absolutePath;
+       error = absolutePath.SetTo(&directory, path);
+       if (error != B_OK) {
+               ERROR("Volume::_OpenConfigSubDirectory(): failed to get 
absolute path "
+                       "for subdirectory \"%s\": %s\n", path, strerror(error));
+               RETURN_ERROR(error);
+       }
+
+       error = create_directory(absolutePath.Path(),
+               S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+       if (error != B_OK) {
+               ERROR("Volume::_OpenConfigSubDirectory(): failed to create 
packages "
+                       "subdirectory \"%s\": %s\n", path, strerror(error));
+               RETURN_ERROR(error);
+       }
+
+       RETURN_ERROR(_directory.SetTo(&directory, path));
+}
diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h
index ba95caa..1885b1d 100644
--- a/src/servers/package/Volume.h
+++ b/src/servers/package/Volume.h
@@ -113,6 +113,12 @@ private:
                                                                        
BSolverRepository& repository,
                                                                        bool 
activeOnly, bool installed);
 
+                       status_t                        _OpenPackagesFile(const 
char* subDirectoryPath,
+                                                                       const 
char* fileName, uint32 openMode,
+                                                                       BFile& 
_file, BEntry* _entry = NULL);
+                       status_t                        
_OpenPackagesSubDirectory(const char* path,
+                                                                       bool 
create, BDirectory& _directory);
+
 private:
                        BString                         fPath;
                        PackageFSMountType      fMountType;

############################################################################

Commit:      19dc1d084f13bed77863dd1be56e846c314dd546
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Tue Apr  9 21:26:56 2013 UTC

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.

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp 
b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 16126af..21bc96f 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 <package/PackageInfoAttributes.h>
 
 #include <AutoDeleter.h>
+#include <PackagesDirectoryDefs.h>
 
 #include <fs/KPath.h>
 #include <team.h>
@@ -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<Package> packageReference(package, true);
+               _LoadAndAddInitialPackage(entry->d_name);
+       }
+
+       return B_OK;
+}
 
-               VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
-               VolumeWriteLocker volumeLocker(this);
-               _AddPackage(package);
 
+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<Package> packageReference(package, true);
 
-       // add the packages to the node tree
        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 23caf19..525a979 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,

############################################################################

Commit:      40cbf171efee048cd28a69e791b2ebac38cad3c2
Author:      Ingo Weinhold <ingo_weinhold@xxxxxx>
Date:        Tue Apr  9 21:35:57 2013 UTC

packagefs: don't dup() the packages directory FD

Volume::_AddInitialPackagesFromDirectory(): Use openat() instead of
dup() to get a FD for the packages directory. Currently our fdopendir()
implementation doesn't use it directly anyway, but in theory it could
and would then change the state of the original FD.

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp 
b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 21bc96f..2e7af7d 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -853,9 +853,9 @@ status_t
 Volume::_AddInitialPackagesFromDirectory()
 {
        // iterate through the dir and create packages
-       int fd = dup(fPackagesDirectory->DirectoryFD());
+       int fd = openat(fPackagesDirectory->DirectoryFD(), ".", O_RDONLY);
        if (fd < 0) {
-               ERROR("Failed to dup() packages directory FD: %s\n", 
strerror(errno));
+               ERROR("Failed to open packages directory: %s\n", 
strerror(errno));
                RETURN_ERROR(errno);
        }
 


Other related posts: