2 * Copyright 2009-2014, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
13 #include <sys/param.h>
19 #include <driver_settings.h>
20 #include <KernelExport.h>
21 #include <NodeMonitor.h>
22 #include <package/PackageInfoAttributes.h>
24 #include <AutoDeleter.h>
25 #include <PackagesDirectoryDefs.h>
29 #include "AttributeIndex.h"
30 #include "DebugSupport.h"
31 #include "kernel_interface.h"
32 #include "LastModifiedIndex.h"
33 #include "NameIndex.h"
34 #include "OldUnpackingNodeAttributes.h"
35 #include "PackageFSRoot.h"
36 #include "PackageLinkDirectory.h"
37 #include "PackageLinksDirectory.h"
38 #include "Resolvable.h"
39 #include "SizeIndex.h"
40 #include "UnpackingLeafNode.h"
41 #include "UnpackingDirectory.h"
46 // node ID of the root directory
47 static const ino_t kRootDirectoryID
= 1;
49 static const uint32 kAllStatFields
= B_STAT_MODE
| B_STAT_UID
| B_STAT_GID
50 | B_STAT_SIZE
| B_STAT_ACCESS_TIME
| B_STAT_MODIFICATION_TIME
51 | B_STAT_CREATION_TIME
| B_STAT_CHANGE_TIME
;
53 // shine-through directories
54 const char* const kShineThroughDirectories
[] = {
55 "cache", "non-packaged", "packages", "settings", "var", NULL
58 // sanity limit for activation change request
59 const size_t kMaxActivationRequestSize
= 10 * 1024 * 1024;
61 // sanity limit for activation file size
62 const size_t kMaxActivationFileSize
= 10 * 1024 * 1024;
64 static const char* const kAdministrativeDirectoryName
65 = PACKAGES_DIRECTORY_ADMIN_DIRECTORY
;
66 static const char* const kActivationFileName
67 = PACKAGES_DIRECTORY_ACTIVATION_FILE
;
68 static const char* const kActivationFilePath
69 = PACKAGES_DIRECTORY_ADMIN_DIRECTORY
"/"
70 PACKAGES_DIRECTORY_ACTIVATION_FILE
;
73 // #pragma mark - ShineThroughDirectory
76 struct Volume::ShineThroughDirectory
: public Directory
{
77 ShineThroughDirectory(ino_t id
)
81 get_real_time(fModifiedTime
);
84 virtual timespec
ModifiedTime() const
90 timespec fModifiedTime
;
94 // #pragma mark - ActivationChangeRequest
97 struct Volume::ActivationChangeRequest
{
99 ActivationChangeRequest()
106 ~ActivationChangeRequest()
111 status_t
Init(const void* userRequest
, size_t requestSize
)
113 // copy request to kernel
114 if (requestSize
> kMaxActivationRequestSize
)
115 RETURN_ERROR(B_BAD_VALUE
);
117 fRequest
= (PackageFSActivationChangeRequest
*)malloc(requestSize
);
118 if (fRequest
== NULL
)
119 RETURN_ERROR(B_NO_MEMORY
);
120 fRequestSize
= requestSize
;
122 status_t error
= user_memcpy(fRequest
, userRequest
, fRequestSize
);
126 uint32 itemCount
= fRequest
->itemCount
;
127 const char* requestEnd
= (const char*)fRequest
+ requestSize
;
128 if (&fRequest
->items
[itemCount
] > (void*)requestEnd
)
129 RETURN_ERROR(B_BAD_VALUE
);
131 // adjust the item name pointers and check their validity
132 addr_t nameDelta
= (addr_t
)fRequest
- (addr_t
)userRequest
;
133 for (uint32 i
= 0; i
< itemCount
; i
++) {
134 PackageFSActivationChangeItem
& item
= fRequest
->items
[i
];
135 item
.name
+= nameDelta
;
136 if (item
.name
< (char*)fRequest
|| item
.name
>= requestEnd
)
137 RETURN_ERROR(B_BAD_VALUE
);
138 size_t maxNameSize
= requestEnd
- item
.name
;
139 if (strnlen(item
.name
, maxNameSize
) == maxNameSize
)
140 RETURN_ERROR(B_BAD_VALUE
);
146 uint32
CountItems() const
148 return fRequest
->itemCount
;
151 PackageFSActivationChangeItem
* ItemAt(uint32 index
) const
153 return index
< CountItems() ? &fRequest
->items
[index
] : NULL
;
157 PackageFSActivationChangeRequest
* fRequest
;
162 // #pragma mark - Volume
165 Volume::Volume(fs_volume
* fsVolume
)
168 fRootDirectory(NULL
),
169 fPackageFSRoot(NULL
),
170 fPackagesDirectory(NULL
),
171 fPackagesDirectories(),
172 fPackagesDirectoriesByNodeRef(),
174 fNextNodeID(kRootDirectoryID
+ 1)
176 rw_lock_init(&fLock
, "packagefs volume");
182 // remove the packages from the node tree
184 VolumeWriteLocker
systemVolumeLocker(_SystemVolumeIfNotSelf());
185 VolumeWriteLocker
volumeLocker(this);
186 for (PackageFileNameHashTable::Iterator it
= fPackages
.GetIterator();
187 Package
* package
= it
.Next();) {
188 _RemovePackageContent(package
, NULL
, false);
192 // delete the packages
193 _RemoveAllPackages();
195 // delete all indices
196 Index
* index
= fIndices
.Clear(true);
197 while (index
!= NULL
) {
198 Index
* next
= index
->IndexHashLink();
203 // remove all nodes from the ID hash table
204 Node
* node
= fNodes
.Clear(true);
205 while (node
!= NULL
) {
206 Node
* next
= node
->IDHashTableNext();
207 node
->ReleaseReference();
211 if (fPackageFSRoot
!= NULL
) {
212 if (this == fPackageFSRoot
->SystemVolume())
213 _RemovePackageLinksDirectory();
215 fPackageFSRoot
->UnregisterVolume(this);
218 if (fRootDirectory
!= NULL
)
219 fRootDirectory
->ReleaseReference();
221 while (PackagesDirectory
* directory
= fPackagesDirectories
.RemoveHead())
222 directory
->ReleaseReference();
224 rw_lock_destroy(&fLock
);
229 Volume::Mount(const char* parameterString
)
231 // init the hash tables
232 status_t error
= fPackagesDirectoriesByNodeRef
.Init();
236 error
= fNodes
.Init();
240 error
= fNodeListeners
.Init();
244 error
= fPackages
.Init();
248 error
= fIndices
.Init();
252 // create the name index
254 NameIndex
* index
= new(std::nothrow
) NameIndex
;
256 RETURN_ERROR(B_NO_MEMORY
);
258 error
= index
->Init(this);
264 fIndices
.Insert(index
);
267 // create the size index
269 SizeIndex
* index
= new(std::nothrow
) SizeIndex
;
271 RETURN_ERROR(B_NO_MEMORY
);
273 error
= index
->Init(this);
279 fIndices
.Insert(index
);
282 // create the last modified index
284 LastModifiedIndex
* index
= new(std::nothrow
) LastModifiedIndex
;
286 RETURN_ERROR(B_NO_MEMORY
);
288 error
= index
->Init(this);
294 fIndices
.Insert(index
);
297 // create a BEOS:APP_SIG index
299 AttributeIndex
* index
= new(std::nothrow
) AttributeIndex
;
301 RETURN_ERROR(B_NO_MEMORY
);
303 error
= index
->Init(this, "BEOS:APP_SIG", B_MIME_STRING_TYPE
, 0);
309 fIndices
.Insert(index
);
312 // get the mount parameters
313 const char* packages
= NULL
;
314 const char* volumeName
= NULL
;
315 const char* mountType
= NULL
;
316 const char* shineThrough
= NULL
;
317 const char* packagesState
= NULL
;
319 void* parameterHandle
= parse_driver_settings_string(parameterString
);
320 if (parameterHandle
!= NULL
) {
321 packages
= get_driver_parameter(parameterHandle
, "packages", NULL
,
323 volumeName
= get_driver_parameter(parameterHandle
, "volume-name", NULL
,
325 mountType
= get_driver_parameter(parameterHandle
, "type", NULL
, NULL
);
326 shineThrough
= get_driver_parameter(parameterHandle
, "shine-through",
328 packagesState
= get_driver_parameter(parameterHandle
, "state", NULL
,
332 CObjectDeleter
<void, status_t
> parameterHandleDeleter(parameterHandle
,
333 &delete_driver_settings
);
335 if (packages
!= NULL
&& packages
[0] == '\0') {
336 FATAL("invalid package folder ('packages' parameter)!\n");
337 RETURN_ERROR(B_BAD_VALUE
);
340 error
= _InitMountType(mountType
);
342 FATAL("invalid mount type: \"%s\"\n", mountType
);
346 // get our mount point
347 error
= vfs_get_mount_point(fFSVolume
->id
, &fMountPoint
.deviceID
,
348 &fMountPoint
.nodeID
);
352 // load package settings
353 error
= fPackageSettings
.Load(fMountPoint
.deviceID
, fMountPoint
.nodeID
,
355 // abort only in case of serious issues (memory shortage)
356 if (error
== B_NO_MEMORY
)
359 // create package domain
360 fPackagesDirectory
= new(std::nothrow
) PackagesDirectory
;
361 if (fPackagesDirectory
== NULL
)
362 RETURN_ERROR(B_NO_MEMORY
);
363 fPackagesDirectories
.Add(fPackagesDirectory
);
364 fPackagesDirectoriesByNodeRef
.Insert(fPackagesDirectory
);
367 error
= fPackagesDirectory
->Init(packages
, fMountPoint
.deviceID
,
368 fMountPoint
.nodeID
, st
);
372 // If a packages state has been specified, load the needed states.
373 if (packagesState
!= NULL
) {
374 error
= _LoadOldPackagesStates(packagesState
);
379 // If no volume name is given, infer it from the mount type.
380 if (volumeName
== NULL
) {
381 switch (fMountType
) {
382 case PACKAGE_FS_MOUNT_TYPE_SYSTEM
:
383 volumeName
= "system";
385 case PACKAGE_FS_MOUNT_TYPE_HOME
:
386 volumeName
= "config";
388 case PACKAGE_FS_MOUNT_TYPE_CUSTOM
:
390 volumeName
= "Package FS";
395 String volumeNameString
;
396 if (!volumeNameString
.SetTo(volumeName
))
397 RETURN_ERROR(B_NO_MEMORY
);
399 // create the root node
401 = new(std::nothrow
) ::RootDirectory(kRootDirectoryID
, st
.st_mtim
);
402 if (fRootDirectory
== NULL
)
403 RETURN_ERROR(B_NO_MEMORY
);
404 fRootDirectory
->Init(NULL
, volumeNameString
);
405 fNodes
.Insert(fRootDirectory
);
406 fRootDirectory
->AcquireReference();
407 // one reference for the table
409 // register with packagefs root
410 error
= ::PackageFSRoot::RegisterVolume(this);
414 if (this == fPackageFSRoot
->SystemVolume()) {
415 error
= _AddPackageLinksDirectory();
420 // create shine-through directories
421 error
= _CreateShineThroughDirectories(shineThrough
);
425 // add initial packages
426 error
= _AddInitialPackages();
430 // publish the root node
431 fRootDirectory
->AcquireReference();
432 error
= PublishVNode(fRootDirectory
);
434 fRootDirectory
->ReleaseReference();
438 // bind and publish the shine-through directories
439 error
= _PublishShineThroughDirectories();
443 StringPool::DumpUsageStatistics();
456 Volume::IOCtl(Node
* node
, uint32 operation
, void* buffer
, size_t size
)
459 case PACKAGE_FS_OPERATION_GET_VOLUME_INFO
:
461 if (size
< sizeof(PackageFSVolumeInfo
))
462 RETURN_ERROR(B_BAD_VALUE
);
464 PackageFSVolumeInfo
* userVolumeInfo
465 = (PackageFSVolumeInfo
*)buffer
;
467 VolumeReadLocker
volumeReadLocker(this);
469 PackageFSVolumeInfo volumeInfo
;
470 volumeInfo
.mountType
= fMountType
;
471 volumeInfo
.rootDeviceID
= fPackageFSRoot
->DeviceID();
472 volumeInfo
.rootDirectoryID
= fPackageFSRoot
->NodeID();
473 volumeInfo
.packagesDirectoryCount
= fPackagesDirectories
.Count();
475 status_t error
= user_memcpy(userVolumeInfo
, &volumeInfo
,
480 uint32 directoryIndex
= 0;
481 for (PackagesDirectoryList::Iterator it
482 = fPackagesDirectories
.GetIterator();
483 PackagesDirectory
* directory
= it
.Next();
485 PackageFSDirectoryInfo info
;
486 info
.deviceID
= directory
->DeviceID();
487 info
.nodeID
= directory
->NodeID();
489 PackageFSDirectoryInfo
* userInfo
490 = userVolumeInfo
->packagesDirectoryInfos
+ directoryIndex
;
491 if (addr_t(userInfo
+ 1) > (addr_t
)buffer
+ size
)
494 if (user_memcpy(userInfo
, &info
, sizeof(info
)) != B_OK
)
495 return B_BAD_ADDRESS
;
501 case PACKAGE_FS_OPERATION_GET_PACKAGE_INFOS
:
503 if (size
< sizeof(PackageFSGetPackageInfosRequest
))
504 RETURN_ERROR(B_BAD_VALUE
);
506 PackageFSGetPackageInfosRequest
* request
507 = (PackageFSGetPackageInfosRequest
*)buffer
;
509 VolumeReadLocker
volumeReadLocker(this);
511 addr_t bufferEnd
= (addr_t
)buffer
+ size
;
512 uint32 packageCount
= fPackages
.CountElements();
513 char* nameBuffer
= (char*)(request
->infos
+ packageCount
);
515 uint32 packageIndex
= 0;
516 for (PackageFileNameHashTable::Iterator it
517 = fPackages
.GetIterator(); it
.HasNext();
519 Package
* package
= it
.Next();
520 PackageFSPackageInfo info
;
521 info
.packageDeviceID
= package
->DeviceID();
522 info
.packageNodeID
= package
->NodeID();
523 PackagesDirectory
* directory
= package
->Directory();
524 info
.directoryDeviceID
= directory
->DeviceID();
525 info
.directoryNodeID
= directory
->NodeID();
526 info
.name
= nameBuffer
;
528 PackageFSPackageInfo
* userInfo
= request
->infos
+ packageIndex
;
529 if (addr_t(userInfo
+ 1) <= bufferEnd
) {
530 if (user_memcpy(userInfo
, &info
, sizeof(info
)) != B_OK
)
531 return B_BAD_ADDRESS
;
534 const char* name
= package
->FileName();
535 size_t nameSize
= strlen(name
) + 1;
536 char* nameEnd
= nameBuffer
+ nameSize
;
537 if ((addr_t
)nameEnd
<= bufferEnd
) {
538 if (user_memcpy(nameBuffer
, name
, nameSize
) != B_OK
)
539 return B_BAD_ADDRESS
;
541 nameBuffer
= nameEnd
;
544 PackageFSGetPackageInfosRequest header
;
545 header
.bufferSize
= nameBuffer
- (char*)request
;
546 header
.packageCount
= packageCount
;
547 size_t headerSize
= (char*)&request
->infos
- (char*)request
;
548 RETURN_ERROR(user_memcpy(request
, &header
, headerSize
));
551 case PACKAGE_FS_OPERATION_CHANGE_ACTIVATION
:
553 ActivationChangeRequest request
;
554 status_t error
= request
.Init(buffer
, size
);
556 RETURN_ERROR(B_BAD_VALUE
);
558 return _ChangeActivation(request
);
568 Volume::AddNodeListener(NodeListener
* listener
, Node
* node
)
570 ASSERT(!listener
->IsListening());
572 listener
->StartedListening(node
);
574 if (NodeListener
* list
= fNodeListeners
.Lookup(node
))
575 list
->AddNodeListener(listener
);
577 fNodeListeners
.Insert(listener
);
582 Volume::RemoveNodeListener(NodeListener
* listener
)
584 ASSERT(listener
->IsListening());
586 Node
* node
= listener
->ListenedNode();
588 if (NodeListener
* next
= listener
->RemoveNodeListener()) {
589 // list not empty yet -- if we removed the head, add a new head to the
591 NodeListener
* list
= fNodeListeners
.Lookup(node
);
592 if (list
== listener
) {
593 fNodeListeners
.Remove(listener
);
594 fNodeListeners
.Insert(next
);
597 fNodeListeners
.Remove(listener
);
599 listener
->StoppedListening();
604 Volume::AddQuery(Query
* query
)
611 Volume::RemoveQuery(Query
* query
)
613 fQueries
.Remove(query
);
618 Volume::UpdateLiveQueries(Node
* node
, const char* attribute
, int32 type
,
619 const void* oldKey
, size_t oldLength
, const void* newKey
,
622 for (QueryList::Iterator it
= fQueries
.GetIterator();
623 Query
* query
= it
.Next();) {
624 query
->LiveUpdate(node
, attribute
, type
, oldKey
, oldLength
, newKey
,
631 Volume::GetVNode(ino_t nodeID
, Node
*& _node
)
633 return get_vnode(fFSVolume
, nodeID
, (void**)&_node
);
638 Volume::PutVNode(ino_t nodeID
)
640 return put_vnode(fFSVolume
, nodeID
);
645 Volume::RemoveVNode(ino_t nodeID
)
647 return remove_vnode(fFSVolume
, nodeID
);
652 Volume::PublishVNode(Node
* node
)
654 return publish_vnode(fFSVolume
, node
->ID(), node
, &gPackageFSVnodeOps
,
655 node
->Mode() & S_IFMT
, 0);
660 Volume::PackageLinkNodeAdded(Node
* node
)
662 _AddPackageLinksNode(node
);
664 notify_entry_created(ID(), node
->Parent()->ID(), node
->Name(), node
->ID());
665 _NotifyNodeAdded(node
);
670 Volume::PackageLinkNodeRemoved(Node
* node
)
672 _RemovePackageLinksNode(node
);
674 notify_entry_removed(ID(), node
->Parent()->ID(), node
->Name(), node
->ID());
675 _NotifyNodeRemoved(node
);
680 Volume::PackageLinkNodeChanged(Node
* node
, uint32 statFields
,
681 const OldNodeAttributes
& oldAttributes
)
683 Directory
* parent
= node
->Parent();
684 notify_stat_changed(ID(), parent
!= NULL
? parent
->ID() : -1, node
->ID(),
686 _NotifyNodeChanged(node
, statFields
, oldAttributes
);
691 Volume::_LoadOldPackagesStates(const char* packagesState
)
693 // open and stat the admininistrative dir
694 int fd
= openat(fPackagesDirectory
->DirectoryFD(),
695 kAdministrativeDirectoryName
, O_RDONLY
);
697 ERROR("Failed to open administrative directory: %s\n", strerror(errno
));
701 struct stat adminDirStat
;
702 if (fstat(fd
, &adminDirStat
) < 0) {
703 ERROR("Failed to fstat() administrative directory: %s\n",
708 // iterate through the "administrative" dir
709 DIR* dir
= fdopendir(fd
);
711 ERROR("Failed to open administrative directory: %s\n", strerror(errno
));
714 CObjectDeleter
<DIR, int> dirCloser(dir
, closedir
);
716 while (dirent
* entry
= readdir(dir
)) {
717 if (strncmp(entry
->d_name
, "state_", 6) != 0
718 || strcmp(entry
->d_name
, packagesState
) < 0) {
722 PackagesDirectory
* packagesDirectory
723 = new(std::nothrow
) PackagesDirectory
;
724 status_t error
= packagesDirectory
->InitOldState(adminDirStat
.st_dev
,
725 adminDirStat
.st_ino
, entry
->d_name
);
727 delete packagesDirectory
;
731 fPackagesDirectories
.Add(packagesDirectory
);
732 fPackagesDirectoriesByNodeRef
.Insert(packagesDirectory
);
734 INFORM("added old packages dir state \"%s\"\n",
735 packagesDirectory
->StateName().Data());
738 // sort the packages directories by state age
739 fPackagesDirectories
.Sort(&PackagesDirectory::IsNewer
);
746 Volume::_AddInitialPackages()
748 PackagesDirectory
* packagesDirectory
= fPackagesDirectories
.Last();
749 INFORM("Adding packages from \"%s\"\n", packagesDirectory
->Path());
751 // try reading the activation file of the oldest state
752 status_t error
= _AddInitialPackagesFromActivationFile(packagesDirectory
);
753 if (error
!= B_OK
&& packagesDirectory
!= fPackagesDirectory
) {
754 WARN("Loading packages from old state \"%s\" failed. Loading packages "
755 "from latest state.\n", packagesDirectory
->StateName().Data());
757 // remove all packages already added
759 VolumeWriteLocker
systemVolumeLocker(_SystemVolumeIfNotSelf());
760 VolumeWriteLocker
volumeLocker(this);
761 _RemoveAllPackages();
764 // remove the old states
765 while (fPackagesDirectories
.Last() != fPackagesDirectory
)
766 fPackagesDirectories
.RemoveTail()->ReleaseReference();
768 // try reading the activation file of the latest state
769 packagesDirectory
= fPackagesDirectory
;
770 error
= _AddInitialPackagesFromActivationFile(packagesDirectory
);
774 INFORM("Loading packages from activation file failed. Loading all "
775 "packages in packages directory.\n");
777 // remove all packages already added
779 VolumeWriteLocker
systemVolumeLocker(_SystemVolumeIfNotSelf());
780 VolumeWriteLocker
volumeLocker(this);
781 _RemoveAllPackages();
784 // read the whole directory
785 error
= _AddInitialPackagesFromDirectory();
790 // add the packages to the node tree
791 VolumeWriteLocker
systemVolumeLocker(_SystemVolumeIfNotSelf());
792 VolumeWriteLocker
volumeLocker(this);
793 for (PackageFileNameHashTable::Iterator it
= fPackages
.GetIterator();
794 Package
* package
= it
.Next();) {
795 error
= _AddPackageContent(package
, false);
797 for (it
.Rewind(); Package
* activePackage
= it
.Next();) {
798 if (activePackage
== package
)
800 _RemovePackageContent(activePackage
, NULL
, false);
811 Volume::_AddInitialPackagesFromActivationFile(
812 PackagesDirectory
* packagesDirectory
)
814 // try reading the activation file
815 int fd
= openat(packagesDirectory
->DirectoryFD(),
816 packagesDirectory
== fPackagesDirectory
817 ? kActivationFilePath
: kActivationFileName
,
820 INFORM("Failed to open packages activation file: %s\n",
824 FileDescriptorCloser
fdCloser(fd
);
826 // read the whole file into memory to simplify things
828 if (fstat(fd
, &st
) != 0) {
829 ERROR("Failed to stat packages activation file: %s\n",
834 if (st
.st_size
> (off_t
)kMaxActivationFileSize
) {
835 ERROR("The packages activation file is too big.\n");
836 RETURN_ERROR(B_BAD_DATA
);
839 char* fileContent
= (char*)malloc(st
.st_size
+ 1);
840 if (fileContent
== NULL
)
841 RETURN_ERROR(B_NO_MEMORY
);
842 MemoryDeleter
fileContentDeleter(fileContent
);
844 ssize_t bytesRead
= read(fd
, fileContent
, st
.st_size
);
846 ERROR("Failed to read packages activation file: %s\n", strerror(errno
));
850 if (bytesRead
!= st
.st_size
) {
851 ERROR("Failed to read whole packages activation file\n");
852 RETURN_ERROR(B_ERROR
);
855 // null-terminate to simplify parsing
856 fileContent
[st
.st_size
] = '\0';
858 // parse the file and add the respective packages
859 const char* packageName
= fileContent
;
860 char* const fileContentEnd
= fileContent
+ st
.st_size
;
861 while (packageName
< fileContentEnd
) {
862 char* packageNameEnd
= strchr(packageName
, '\n');
863 if (packageNameEnd
== NULL
)
864 packageNameEnd
= fileContentEnd
;
867 if (packageName
== packageNameEnd
) {
871 *packageNameEnd
= '\0';
873 if (packageNameEnd
- packageName
>= B_FILE_NAME_LENGTH
) {
874 ERROR("Invalid packages activation file content.\n");
875 RETURN_ERROR(B_BAD_DATA
);
878 status_t error
= _LoadAndAddInitialPackage(packagesDirectory
,
883 packageName
= packageNameEnd
+ 1;
891 Volume::_AddInitialPackagesFromDirectory()
893 // iterate through the dir and create packages
894 int fd
= openat(fPackagesDirectory
->DirectoryFD(), ".", O_RDONLY
);
896 ERROR("Failed to open packages directory: %s\n", strerror(errno
));
900 DIR* dir
= fdopendir(fd
);
902 ERROR("Failed to open packages directory \"%s\": %s\n",
903 fPackagesDirectory
->Path(), strerror(errno
));
906 CObjectDeleter
<DIR, int> dirCloser(dir
, closedir
);
908 while (dirent
* entry
= readdir(dir
)) {
910 if (strcmp(entry
->d_name
, ".") == 0 || strcmp(entry
->d_name
, "..") == 0)
913 // also skip any entry without a ".hpkg" extension
914 size_t nameLength
= strlen(entry
->d_name
);
916 || memcmp(entry
->d_name
+ nameLength
- 5, ".hpkg", 5) != 0) {
920 _LoadAndAddInitialPackage(fPackagesDirectory
, entry
->d_name
);
928 Volume::_LoadAndAddInitialPackage(PackagesDirectory
* packagesDirectory
,
932 status_t error
= _LoadPackage(packagesDirectory
, name
, package
);
934 ERROR("Failed to load package \"%s\": %s\n", name
, strerror(error
));
937 BReference
<Package
> packageReference(package
, true);
939 VolumeWriteLocker
systemVolumeLocker(_SystemVolumeIfNotSelf());
940 VolumeWriteLocker
volumeLocker(this);
941 _AddPackage(package
);
948 Volume::_AddPackage(Package
* package
)
950 fPackages
.Insert(package
);
951 package
->AcquireReference();
956 Volume::_RemovePackage(Package
* package
)
958 fPackages
.Remove(package
);
959 package
->ReleaseReference();
964 Volume::_RemoveAllPackages()
966 Package
* package
= fPackages
.Clear(true);
967 while (package
!= NULL
) {
968 Package
* next
= package
->FileNameHashTableNext();
969 package
->ReleaseReference();
976 Volume::_FindPackage(const char* fileName
) const
978 return fPackages
.Lookup(fileName
);
983 Volume::_AddPackageContent(Package
* package
, bool notify
)
985 // Open the package. We don't need the FD here, but this is an optimization.
986 // The attribute indices may want to read the package nodes' attributes and
987 // the package file would be opened and closed for each attribute instance.
988 // Since Package keeps and shares the FD as long as at least one party has
989 // the package open, we prevent that.
990 int fd
= package
->Open();
993 PackageCloser
packageCloser(package
);
995 status_t error
= fPackageFSRoot
->AddPackage(package
);
999 for (PackageNodeList::Iterator it
= package
->Nodes().GetIterator();
1000 PackageNode
* node
= it
.Next();) {
1001 // skip over ".PackageInfo" file, it isn't part of the package content
1002 if (strcmp(node
->Name(),
1003 BPackageKit::BHPKG::B_HPKG_PACKAGE_INFO_FILE_NAME
) == 0) {
1006 error
= _AddPackageContentRootNode(package
, node
, notify
);
1007 if (error
!= B_OK
) {
1008 _RemovePackageContent(package
, node
, notify
);
1009 RETURN_ERROR(error
);
1018 Volume::_RemovePackageContent(Package
* package
, PackageNode
* endNode
,
1021 PackageNode
* node
= package
->Nodes().Head();
1022 while (node
!= NULL
) {
1023 if (node
== endNode
)
1026 PackageNode
* nextNode
= package
->Nodes().GetNext(node
);
1028 // skip over ".PackageInfo" file, it isn't part of the package content
1029 if (strcmp(node
->Name(),
1030 BPackageKit::BHPKG::B_HPKG_PACKAGE_INFO_FILE_NAME
) != 0) {
1031 _RemovePackageContentRootNode(package
, node
, NULL
, notify
);
1037 fPackageFSRoot
->RemovePackage(package
);;
1041 /*! This method recursively iterates through the descendents of the given
1042 package root node and adds all package nodes to the node tree in
1044 Due to limited kernel stack space we avoid deep recursive function calls
1045 and rather use the package node stack implied by the tree.
1048 Volume::_AddPackageContentRootNode(Package
* package
,
1049 PackageNode
* rootPackageNode
, bool notify
)
1051 PackageNode
* packageNode
= rootPackageNode
;
1052 Directory
* directory
= fRootDirectory
;
1053 directory
->WriteLock();
1057 status_t error
= _AddPackageNode(directory
, packageNode
, notify
, node
);
1058 // returns B_OK with a NULL node, when skipping the node
1059 if (error
!= B_OK
) {
1060 // unlock all directories
1061 while (directory
!= NULL
) {
1062 directory
->WriteUnlock();
1063 directory
= directory
->Parent();
1066 // remove the added package nodes
1067 _RemovePackageContentRootNode(package
, rootPackageNode
, packageNode
,
1069 RETURN_ERROR(error
);
1072 // recurse into directory, unless we're supposed to skip the node
1074 if (PackageDirectory
* packageDirectory
1075 = dynamic_cast<PackageDirectory
*>(packageNode
)) {
1076 if (packageDirectory
->FirstChild() != NULL
) {
1077 directory
= dynamic_cast<Directory
*>(node
);
1078 packageNode
= packageDirectory
->FirstChild();
1079 directory
->WriteLock();
1085 // continue with the next available (ancestors's) sibling
1087 PackageDirectory
* packageDirectory
= packageNode
->Parent();
1088 PackageNode
* sibling
= packageDirectory
!= NULL
1089 ? packageDirectory
->NextChild(packageNode
) : NULL
;
1091 if (sibling
!= NULL
) {
1092 packageNode
= sibling
;
1096 // no more siblings -- go back up the tree
1097 packageNode
= packageDirectory
;
1098 directory
->WriteUnlock();
1099 directory
= directory
->Parent();
1100 // the parent is still locked, so this is safe
1101 } while (packageNode
!= NULL
);
1102 } while (packageNode
!= NULL
);
1108 /*! Recursively iterates through the descendents of the given package root node
1109 and removes all package nodes from the node tree in post-order, until
1110 encountering \a endPackageNode (if non-null).
1111 Due to limited kernel stack space we avoid deep recursive function calls
1112 and rather use the package node stack implied by the tree.
1115 Volume::_RemovePackageContentRootNode(Package
* package
,
1116 PackageNode
* rootPackageNode
, PackageNode
* endPackageNode
, bool notify
)
1118 PackageNode
* packageNode
= rootPackageNode
;
1119 Directory
* directory
= fRootDirectory
;
1120 directory
->WriteLock();
1123 if (packageNode
== endPackageNode
)
1126 // recurse into directory
1127 if (PackageDirectory
* packageDirectory
1128 = dynamic_cast<PackageDirectory
*>(packageNode
)) {
1129 if (packageDirectory
->FirstChild() != NULL
) {
1130 if (Directory
* childDirectory
= dynamic_cast<Directory
*>(
1131 directory
->FindChild(packageNode
->Name()))) {
1132 directory
= childDirectory
;
1133 packageNode
= packageDirectory
->FirstChild();
1134 directory
->WriteLock();
1140 // continue with the next available (ancestors's) sibling
1142 PackageDirectory
* packageDirectory
= packageNode
->Parent();
1143 PackageNode
* sibling
= packageDirectory
!= NULL
1144 ? packageDirectory
->NextChild(packageNode
) : NULL
;
1146 // we're done with the node -- remove it
1147 _RemovePackageNode(directory
, packageNode
,
1148 directory
->FindChild(packageNode
->Name()), notify
);
1150 if (sibling
!= NULL
) {
1151 packageNode
= sibling
;
1155 // no more siblings -- go back up the tree
1156 packageNode
= packageDirectory
;
1157 directory
->WriteUnlock();
1158 directory
= directory
->Parent();
1159 // the parent is still locked, so this is safe
1160 } while (packageNode
!= NULL
/* && packageNode != rootPackageNode*/);
1161 } while (packageNode
!= NULL
/* && packageNode != rootPackageNode*/);
1166 Volume::_AddPackageNode(Directory
* directory
, PackageNode
* packageNode
,
1167 bool notify
, Node
*& _node
)
1169 bool newNode
= false;
1170 UnpackingNode
* unpackingNode
;
1171 Node
* node
= directory
->FindChild(packageNode
->Name());
1172 PackageNode
* oldPackageNode
= NULL
;
1175 unpackingNode
= dynamic_cast<UnpackingNode
*>(node
);
1176 if (unpackingNode
== NULL
) {
1180 oldPackageNode
= unpackingNode
->GetPackageNode();
1182 status_t error
= _CreateUnpackingNode(packageNode
->Mode(), directory
,
1183 packageNode
->Name(), unpackingNode
);
1185 RETURN_ERROR(error
);
1187 node
= unpackingNode
->GetNode();
1191 BReference
<Node
> nodeReference(node
);
1192 NodeWriteLocker
nodeWriteLocker(node
);
1194 BReference
<Node
> newNodeReference
;
1195 NodeWriteLocker newNodeWriteLocker
;
1196 Node
* oldNode
= NULL
;
1198 if (!newNode
&& !S_ISDIR(node
->Mode()) && oldPackageNode
!= NULL
1199 && unpackingNode
->WillBeFirstPackageNode(packageNode
)) {
1200 // The package node we're going to add will represent the node,
1201 // replacing the current head package node. Since the node isn't a
1202 // directory, we must make sure that clients having opened or mapped the
1203 // node won't be surprised. So we create a new node and remove the
1205 // create a new node and transfer the package nodes to it
1206 UnpackingNode
* newUnpackingNode
;
1207 status_t error
= unpackingNode
->CloneTransferPackageNodes(
1208 fNextNodeID
++, newUnpackingNode
);
1210 RETURN_ERROR(error
);
1212 // remove the old node
1213 _NotifyNodeRemoved(node
);
1214 _RemoveNodeAndVNode(node
);
1218 unpackingNode
= newUnpackingNode
;
1219 node
= unpackingNode
->GetNode();
1220 newNodeReference
.SetTo(node
);
1221 newNodeWriteLocker
.SetTo(node
, false);
1223 directory
->AddChild(node
);
1224 fNodes
.Insert(node
);
1228 status_t error
= unpackingNode
->AddPackageNode(packageNode
, ID());
1229 if (error
!= B_OK
) {
1230 // Remove the node, if created before. If the node was created to
1231 // replace the previous node, send out notifications instead.
1233 if (oldNode
!= NULL
) {
1234 _NotifyNodeAdded(node
);
1236 notify_entry_removed(ID(), directory
->ID(), oldNode
->Name(),
1238 notify_entry_created(ID(), directory
->ID(), node
->Name(),
1244 RETURN_ERROR(error
);
1248 _NotifyNodeAdded(node
);
1249 } else if (packageNode
== unpackingNode
->GetPackageNode()) {
1250 _NotifyNodeChanged(node
, kAllStatFields
,
1251 OldUnpackingNodeAttributes(oldPackageNode
));
1256 if (oldNode
!= NULL
) {
1257 notify_entry_removed(ID(), directory
->ID(), oldNode
->Name(),
1260 notify_entry_created(ID(), directory
->ID(), node
->Name(),
1262 } else if (packageNode
== unpackingNode
->GetPackageNode()) {
1263 // The new package node has become the one representing the node.
1264 // Send stat changed notification for directories and entry
1265 // removed + created notifications for files and symlinks.
1266 notify_stat_changed(ID(), directory
->ID(), node
->ID(),
1268 // TODO: Actually the attributes might change, too!
1278 Volume::_RemovePackageNode(Directory
* directory
, PackageNode
* packageNode
,
1279 Node
* node
, bool notify
)
1281 UnpackingNode
* unpackingNode
= dynamic_cast<UnpackingNode
*>(node
);
1282 if (unpackingNode
== NULL
)
1285 BReference
<Node
> nodeReference(node
);
1286 NodeWriteLocker
nodeWriteLocker(node
);
1288 PackageNode
* headPackageNode
= unpackingNode
->GetPackageNode();
1289 bool nodeRemoved
= false;
1290 Node
* newNode
= NULL
;
1292 BReference
<Node
> newNodeReference
;
1293 NodeWriteLocker newNodeWriteLocker
;
1295 // If this is the last package node of the node, remove it completely.
1296 if (unpackingNode
->IsOnlyPackageNode(packageNode
)) {
1297 // Notify before removing the node. Otherwise the indices might not
1298 // find the node anymore.
1299 _NotifyNodeRemoved(node
);
1301 unpackingNode
->PrepareForRemoval();
1303 _RemoveNodeAndVNode(node
);
1305 } else if (packageNode
== headPackageNode
) {
1306 // The node does at least have one more package node, but the one to be
1307 // removed is the head. Unless it's a directory, we replace the node
1308 // with a completely new one and let the old one die. This is necessary
1309 // to avoid surprises for clients that have opened/mapped the node.
1310 if (S_ISDIR(packageNode
->Mode())) {
1311 unpackingNode
->RemovePackageNode(packageNode
, ID());
1312 _NotifyNodeChanged(node
, kAllStatFields
,
1313 OldUnpackingNodeAttributes(headPackageNode
));
1315 // create a new node and transfer the package nodes to it
1316 UnpackingNode
* newUnpackingNode
;
1317 status_t error
= unpackingNode
->CloneTransferPackageNodes(
1318 fNextNodeID
++, newUnpackingNode
);
1319 if (error
== B_OK
) {
1320 // remove the package node
1321 newUnpackingNode
->RemovePackageNode(packageNode
, ID());
1323 // remove the old node
1324 _NotifyNodeRemoved(node
);
1325 _RemoveNodeAndVNode(node
);
1328 newNode
= newUnpackingNode
->GetNode();
1329 newNodeReference
.SetTo(newNode
);
1330 newNodeWriteLocker
.SetTo(newNode
, false);
1332 directory
->AddChild(newNode
);
1333 fNodes
.Insert(newNode
);
1334 _NotifyNodeAdded(newNode
);
1336 // There's nothing we can do. Remove the node completely.
1337 _NotifyNodeRemoved(node
);
1339 unpackingNode
->PrepareForRemoval();
1341 _RemoveNodeAndVNode(node
);
1346 // The package node to remove is not the head of the node. This change
1347 // doesn't have any visible effect.
1348 unpackingNode
->RemovePackageNode(packageNode
, ID());
1354 // send notifications
1356 notify_entry_removed(ID(), directory
->ID(), node
->Name(), node
->ID());
1357 } else if (packageNode
== headPackageNode
) {
1358 // The removed package node was the one representing the node.
1359 // Send stat changed notification for directories and entry
1360 // removed + created notifications for files and symlinks.
1361 if (S_ISDIR(packageNode
->Mode())) {
1362 notify_stat_changed(ID(), directory
->ID(), node
->ID(),
1364 // TODO: Actually the attributes might change, too!
1366 notify_entry_removed(ID(), directory
->ID(), node
->Name(),
1368 notify_entry_created(ID(), directory
->ID(), newNode
->Name(),
1376 Volume::_CreateUnpackingNode(mode_t mode
, Directory
* parent
, const String
& name
,
1377 UnpackingNode
*& _node
)
1379 UnpackingNode
* unpackingNode
;
1380 if (S_ISREG(mode
) || S_ISLNK(mode
))
1381 unpackingNode
= new(std::nothrow
) UnpackingLeafNode(fNextNodeID
++);
1382 else if (S_ISDIR(mode
))
1383 unpackingNode
= new(std::nothrow
) UnpackingDirectory(fNextNodeID
++);
1385 RETURN_ERROR(B_UNSUPPORTED
);
1387 if (unpackingNode
== NULL
)
1388 RETURN_ERROR(B_NO_MEMORY
);
1390 Node
* node
= unpackingNode
->GetNode();
1391 BReference
<Node
> nodeReference(node
, true);
1393 status_t error
= node
->Init(parent
, name
);
1395 RETURN_ERROR(error
);
1397 parent
->AddChild(node
);
1399 fNodes
.Insert(node
);
1400 nodeReference
.Detach();
1401 // we keep the initial node reference for the table
1403 _node
= unpackingNode
;
1409 Volume::_RemoveNode(Node
* node
)
1411 // remove from parent
1412 Directory
* parent
= node
->Parent();
1413 parent
->RemoveChild(node
);
1415 // remove from node table
1416 fNodes
.Remove(node
);
1417 node
->ReleaseReference();
1422 Volume::_RemoveNodeAndVNode(Node
* node
)
1424 // If the node is known to the VFS, we get the vnode, remove it, and put it,
1425 // so that the VFS will discard it as soon as possible (i.e. now, if no one
1426 // else is using it).
1427 NodeWriteLocker
nodeWriteLocker(node
);
1429 // Remove the node from its parent and the volume. This makes the node
1430 // inaccessible via the get_vnode() and lookup() hooks.
1433 bool getVNode
= node
->IsKnownToVFS();
1435 nodeWriteLocker
.Unlock();
1437 // Get a vnode reference, if the node is already known to the VFS.
1439 if (getVNode
&& GetVNode(node
->ID(), dummyNode
) == B_OK
) {
1440 // TODO: There still is a race condition here which we can't avoid
1441 // without more help from the VFS. Right after we drop the write
1442 // lock a vnode for the node could be discarded by the VFS. At that
1443 // point another thread trying to get the vnode by ID would create
1444 // a vnode, mark it busy and call our get_vnode() hook. It would
1445 // block since we (i.e. the package loader thread executing this
1446 // method) still have the volume write lock. Our get_vnode() call
1447 // would block, since it finds the vnode marked busy. It times out
1448 // eventually, but until then a good deal of FS operations might
1449 // block as well due to us holding the volume lock and probably
1450 // several node locks as well. A get_vnode*() variant (e.g.
1451 // get_vnode_etc() with flags parameter) that wouldn't block and
1452 // only get the vnode, if already loaded and non-busy, would be
1454 RemoveVNode(node
->ID());
1455 PutVNode(node
->ID());
1461 Volume::_LoadPackage(PackagesDirectory
* packagesDirectory
, const char* name
,
1464 // Find the package -- check the specified packages directory and iterate
1465 // toward the newer states.
1468 if (packagesDirectory
== NULL
)
1469 return B_ENTRY_NOT_FOUND
;
1471 if (fstatat(packagesDirectory
->DirectoryFD(), name
, &st
, 0) == 0) {
1472 // check whether the entry is a file
1473 if (!S_ISREG(st
.st_mode
))
1478 packagesDirectory
= fPackagesDirectories
.GetPrevious(packagesDirectory
);
1482 Package
* package
= new(std::nothrow
) Package(this, packagesDirectory
,
1483 st
.st_dev
, st
.st_ino
);
1484 if (package
== NULL
)
1485 RETURN_ERROR(B_NO_MEMORY
);
1486 BReference
<Package
> packageReference(package
, true);
1488 status_t error
= package
->Init(name
);
1492 error
= package
->Load(fPackageSettings
);
1496 _package
= packageReference
.Detach();
1502 Volume::_ChangeActivation(ActivationChangeRequest
& request
)
1504 uint32 itemCount
= request
.CountItems();
1508 // first check the request
1509 int32 newPackageCount
= 0;
1510 int32 oldPackageCount
= 0;
1512 VolumeReadLocker
volumeLocker(this);
1514 for (uint32 i
= 0; i
< itemCount
; i
++) {
1515 PackageFSActivationChangeItem
* item
= request
.ItemAt(i
);
1516 if (item
->parentDeviceID
!= fPackagesDirectory
->DeviceID()
1517 || item
->parentDirectoryID
!= fPackagesDirectory
->NodeID()) {
1518 ERROR("Volume::_ChangeActivation(): mismatching packages "
1520 RETURN_ERROR(B_BAD_VALUE
);
1523 Package
* package
= _FindPackage(item
->name
);
1524 // TODO: We should better look up the package by node_ref!
1525 if (item
->type
== PACKAGE_FS_ACTIVATE_PACKAGE
) {
1526 if (package
!= NULL
) {
1527 ERROR("Volume::_ChangeActivation(): package to activate "
1528 "already activated: \"%s\"\n", item
->name
);
1529 RETURN_ERROR(B_BAD_VALUE
);
1532 } else if (item
->type
== PACKAGE_FS_DEACTIVATE_PACKAGE
) {
1533 if (package
== NULL
) {
1534 ERROR("Volume::_ChangeActivation(): package to deactivate "
1535 "not found: \"%s\"\n", item
->name
);
1536 RETURN_ERROR(B_BAD_VALUE
);
1539 } else if (item
->type
== PACKAGE_FS_REACTIVATE_PACKAGE
) {
1540 if (package
== NULL
) {
1541 ERROR("Volume::_ChangeActivation(): package to reactivate "
1542 "not found: \"%s\"\n", item
->name
);
1543 RETURN_ERROR(B_BAD_VALUE
);
1548 RETURN_ERROR(B_BAD_VALUE
);
1551 INFORM("Volume::_ChangeActivation(): %" B_PRId32
" new packages, %" B_PRId32
" old packages\n", newPackageCount
, oldPackageCount
);
1553 // Things look good so far -- allocate reference arrays for the packages to
1555 BReference
<Package
>* newPackageReferences
1556 = new(std::nothrow
) BReference
<Package
>[newPackageCount
];
1557 if (newPackageReferences
== NULL
)
1558 RETURN_ERROR(B_NO_MEMORY
);
1559 ArrayDeleter
<BReference
<Package
> > newPackageReferencesDeleter(
1560 newPackageReferences
);
1562 BReference
<Package
>* oldPackageReferences
1563 = new(std::nothrow
) BReference
<Package
>[oldPackageCount
];
1564 if (oldPackageReferences
== NULL
)
1565 RETURN_ERROR(B_NO_MEMORY
);
1566 ArrayDeleter
<BReference
<Package
> > oldPackageReferencesDeleter(
1567 oldPackageReferences
);
1569 // load all new packages
1570 int32 newPackageIndex
= 0;
1571 for (uint32 i
= 0; i
< itemCount
; i
++) {
1572 PackageFSActivationChangeItem
* item
= request
.ItemAt(i
);
1574 if (item
->type
!= PACKAGE_FS_ACTIVATE_PACKAGE
1575 && item
->type
!= PACKAGE_FS_REACTIVATE_PACKAGE
) {
1580 status_t error
= _LoadPackage(fPackagesDirectory
, item
->name
, package
);
1581 if (error
!= B_OK
) {
1582 ERROR("Volume::_ChangeActivation(): failed to load package "
1583 "\"%s\"\n", item
->name
);
1584 RETURN_ERROR(error
);
1587 newPackageReferences
[newPackageIndex
++].SetTo(package
, true);
1590 // apply the changes
1591 VolumeWriteLocker
systemVolumeLocker(_SystemVolumeIfNotSelf());
1592 VolumeWriteLocker
volumeLocker(this);
1593 // TODO: Add a change counter to Volume, so we can easily check whether
1594 // everything is still the same.
1596 // remove the old packages
1597 int32 oldPackageIndex
= 0;
1598 for (uint32 i
= 0; i
< itemCount
; i
++) {
1599 PackageFSActivationChangeItem
* item
= request
.ItemAt(i
);
1601 if (item
->type
!= PACKAGE_FS_DEACTIVATE_PACKAGE
1602 && item
->type
!= PACKAGE_FS_REACTIVATE_PACKAGE
) {
1606 Package
* package
= _FindPackage(item
->name
);
1607 // TODO: We should better look up the package by node_ref!
1608 oldPackageReferences
[oldPackageIndex
++].SetTo(package
);
1609 _RemovePackageContent(package
, NULL
, true);
1610 _RemovePackage(package
);
1611 INFORM("package \"%s\" deactivated\n", package
->FileName().Data());
1613 // TODO: Since package removal cannot fail, consider adding the new packages
1614 // first. The reactivation case may make that problematic, since two packages
1615 // with the same name would be active after activating the new one. Check!
1617 // add the new packages
1618 status_t error
= B_OK
;
1619 for (newPackageIndex
= 0; newPackageIndex
< newPackageCount
;
1620 newPackageIndex
++) {
1621 Package
* package
= newPackageReferences
[newPackageIndex
];
1622 _AddPackage(package
);
1624 // add the package to the node tree
1625 error
= _AddPackageContent(package
, true);
1626 if (error
!= B_OK
) {
1627 _RemovePackage(package
);
1630 INFORM("package \"%s\" activated\n", package
->FileName().Data());
1633 // Try to roll back the changes, if an error occurred.
1634 if (error
!= B_OK
) {
1635 for (int32 i
= newPackageIndex
- 1; i
>= 0; i
--) {
1636 Package
* package
= newPackageReferences
[i
];
1637 _RemovePackageContent(package
, NULL
, true);
1638 _RemovePackage(package
);
1641 for (int32 i
= oldPackageCount
- 1; i
>= 0; i
--) {
1642 Package
* package
= oldPackageReferences
[i
];
1643 _AddPackage(package
);
1645 if (_AddPackageContent(package
, true) != B_OK
) {
1646 // nothing we can do here
1647 ERROR("Volume::_ChangeActivation(): failed to roll back "
1648 "deactivation of package \"%s\" after error\n",
1649 package
->FileName().Data());
1650 _RemovePackage(package
);
1660 Volume::_InitMountType(const char* mountType
)
1662 if (mountType
== NULL
)
1663 fMountType
= PACKAGE_FS_MOUNT_TYPE_CUSTOM
;
1664 else if (strcmp(mountType
, "system") == 0)
1665 fMountType
= PACKAGE_FS_MOUNT_TYPE_SYSTEM
;
1666 else if (strcmp(mountType
, "home") == 0)
1667 fMountType
= PACKAGE_FS_MOUNT_TYPE_HOME
;
1668 else if (strcmp(mountType
, "custom") == 0)
1669 fMountType
= PACKAGE_FS_MOUNT_TYPE_CUSTOM
;
1671 RETURN_ERROR(B_BAD_VALUE
);
1678 Volume::_CreateShineThroughDirectory(Directory
* parent
, const char* name
,
1679 Directory
*& _directory
)
1681 ShineThroughDirectory
* directory
= new(std::nothrow
) ShineThroughDirectory(
1683 if (directory
== NULL
)
1684 RETURN_ERROR(B_NO_MEMORY
);
1685 BReference
<ShineThroughDirectory
> directoryReference(directory
, true);
1688 if (!nameString
.SetTo(name
))
1689 RETURN_ERROR(B_NO_MEMORY
);
1691 status_t error
= directory
->Init(parent
, nameString
);
1693 RETURN_ERROR(error
);
1695 parent
->AddChild(directory
);
1697 fNodes
.Insert(directory
);
1698 directoryReference
.Detach();
1699 // we keep the initial node reference for the table
1701 _directory
= directory
;
1707 Volume::_CreateShineThroughDirectories(const char* shineThroughSetting
)
1709 // get the directories to map
1710 const char* const* directories
= NULL
;
1712 if (shineThroughSetting
== NULL
) {
1713 // nothing specified -- derive from mount type
1714 switch (fMountType
) {
1715 case PACKAGE_FS_MOUNT_TYPE_SYSTEM
:
1716 case PACKAGE_FS_MOUNT_TYPE_HOME
:
1717 directories
= kShineThroughDirectories
;
1719 case PACKAGE_FS_MOUNT_TYPE_CUSTOM
:
1721 case PACKAGE_FS_MOUNT_TYPE_ENUM_COUNT
:
1724 } else if (strcmp(shineThroughSetting
, "system") == 0)
1725 directories
= kShineThroughDirectories
;
1726 else if (strcmp(shineThroughSetting
, "home") == 0)
1727 directories
= kShineThroughDirectories
;
1728 else if (strcmp(shineThroughSetting
, "none") == 0)
1731 RETURN_ERROR(B_BAD_VALUE
);
1733 if (directories
== NULL
)
1736 // iterate through the directory list and create the directories
1737 while (const char* directoryName
= *(directories
++)) {
1738 // create the directory
1739 Directory
* directory
;
1740 status_t error
= _CreateShineThroughDirectory(fRootDirectory
,
1741 directoryName
, directory
);
1743 RETURN_ERROR(error
);
1751 Volume::_PublishShineThroughDirectories()
1753 // Iterate through the root directory children and bind the shine-through
1754 // directories to the respective mount point subdirectories.
1756 for (Node
* node
= fRootDirectory
->FirstChild(); node
!= NULL
;
1758 nextNode
= fRootDirectory
->NextChild(node
);
1760 // skip anything but shine-through directories
1761 ShineThroughDirectory
* directory
1762 = dynamic_cast<ShineThroughDirectory
*>(node
);
1763 if (directory
== NULL
)
1766 const char* directoryName
= directory
->Name();
1768 // look up the mount point subdirectory
1769 struct vnode
* vnode
;
1770 status_t error
= vfs_entry_ref_to_vnode(fMountPoint
.deviceID
,
1771 fMountPoint
.nodeID
, directoryName
, &vnode
);
1772 if (error
!= B_OK
) {
1773 dprintf("packagefs: Failed to get shine-through directory \"%s\": "
1774 "%s\n", directoryName
, strerror(error
));
1775 _RemoveNode(directory
);
1778 CObjectDeleter
<struct vnode
> vnodePutter(vnode
, &vfs_put_vnode
);
1782 error
= vfs_stat_vnode(vnode
, &st
);
1783 if (error
!= B_OK
) {
1784 dprintf("packagefs: Failed to stat shine-through directory \"%s\": "
1785 "%s\n", directoryName
, strerror(error
));
1786 _RemoveNode(directory
);
1790 if (!S_ISDIR(st
.st_mode
)) {
1791 dprintf("packagefs: Shine-through entry \"%s\" is not a "
1792 "directory\n", directoryName
);
1793 _RemoveNode(directory
);
1797 // publish the vnode, so the VFS will find it without asking us
1798 directory
->AcquireReference();
1799 error
= PublishVNode(directory
);
1800 if (error
!= B_OK
) {
1801 directory
->ReleaseReference();
1802 _RemoveNode(directory
);
1803 RETURN_ERROR(error
);
1806 // bind the directory
1807 error
= vfs_bind_mount_directory(st
.st_dev
, st
.st_ino
, fFSVolume
->id
,
1810 PutVNode(directory
->ID());
1811 // release our reference again -- on success
1812 // vfs_bind_mount_directory() got one
1815 RETURN_ERROR(error
);
1823 Volume::_AddPackageLinksDirectory()
1825 // called when mounting, so we don't need to lock the volume
1827 PackageLinksDirectory
* packageLinksDirectory
1828 = fPackageFSRoot
->GetPackageLinksDirectory();
1830 NodeWriteLocker
rootDirectoryWriteLocker(fRootDirectory
);
1831 NodeWriteLocker
packageLinksDirectoryWriteLocker(packageLinksDirectory
);
1833 packageLinksDirectory
->SetParent(fRootDirectory
);
1834 fRootDirectory
->AddChild(packageLinksDirectory
);
1836 _AddPackageLinksNode(packageLinksDirectory
);
1838 packageLinksDirectory
->SetListener(this);
1845 Volume::_RemovePackageLinksDirectory()
1847 PackageLinksDirectory
* packageLinksDirectory
1848 = fPackageFSRoot
->GetPackageLinksDirectory();
1850 VolumeWriteLocker
volumeLocker(this);
1851 NodeWriteLocker
rootDirectoryWriteLocker(fRootDirectory
);
1852 NodeWriteLocker
packageLinksDirectoryWriteLocker(packageLinksDirectory
);
1854 if (packageLinksDirectory
->Parent() == fRootDirectory
) {
1855 packageLinksDirectory
->SetListener(NULL
);
1856 fRootDirectory
->RemoveChild(packageLinksDirectory
);
1857 packageLinksDirectory
->SetParent(NULL
);
1863 Volume::_AddPackageLinksNode(Node
* node
)
1865 node
->SetID(fNextNodeID
++);
1867 fNodes
.Insert(node
);
1868 node
->AcquireReference();
1870 // If this is a directory, recursively add descendants. The directory tree
1871 // for the package links isn't deep, so we can do recursion.
1872 if (Directory
* directory
= dynamic_cast<Directory
*>(node
)) {
1873 for (Node
* child
= directory
->FirstChild(); child
!= NULL
;
1874 child
= directory
->NextChild(child
)) {
1875 NodeWriteLocker
childWriteLocker(child
);
1876 _AddPackageLinksNode(child
);
1883 Volume::_RemovePackageLinksNode(Node
* node
)
1885 // If this is a directory, recursively remove descendants. The directory
1886 // tree for the package links isn't deep, so we can do recursion.
1887 if (Directory
* directory
= dynamic_cast<Directory
*>(node
)) {
1888 for (Node
* child
= directory
->FirstChild(); child
!= NULL
;
1889 child
= directory
->NextChild(child
)) {
1890 NodeWriteLocker
childWriteLocker(child
);
1891 _RemovePackageLinksNode(child
);
1895 fNodes
.Remove(node
);
1896 node
->ReleaseReference();
1901 Volume::_SystemVolumeIfNotSelf() const
1903 if (Volume
* systemVolume
= fPackageFSRoot
->SystemVolume())
1904 return systemVolume
== this ? NULL
: systemVolume
;
1910 Volume::_NotifyNodeAdded(Node
* node
)
1914 for (int i
= 0; i
< 2; i
++) {
1915 if (NodeListener
* listener
= fNodeListeners
.Lookup(key
)) {
1916 NodeListener
* last
= listener
->PreviousNodeListener();
1919 NodeListener
* next
= listener
->NextNodeListener();
1921 listener
->NodeAdded(node
);
1923 if (listener
== last
)
1936 Volume::_NotifyNodeRemoved(Node
* node
)
1940 for (int i
= 0; i
< 2; i
++) {
1941 if (NodeListener
* listener
= fNodeListeners
.Lookup(key
)) {
1942 NodeListener
* last
= listener
->PreviousNodeListener();
1945 NodeListener
* next
= listener
->NextNodeListener();
1947 listener
->NodeRemoved(node
);
1949 if (listener
== last
)
1962 Volume::_NotifyNodeChanged(Node
* node
, uint32 statFields
,
1963 const OldNodeAttributes
& oldAttributes
)
1967 for (int i
= 0; i
< 2; i
++) {
1968 if (NodeListener
* listener
= fNodeListeners
.Lookup(key
)) {
1969 NodeListener
* last
= listener
->PreviousNodeListener();
1972 NodeListener
* next
= listener
->NextNodeListener();
1974 listener
->NodeChanged(node
, statFields
, oldAttributes
);
1976 if (listener
== last
)