/*! This method recursively iterates through the descendents of the given package root node and adds all package nodes to the node tree in pre-order. Due to limited kernel stack space we avoid deep recursive function calls and rather use the package node stack implied by the tree. */ status_t Volume::_AddPackageContentRootNode(Package* package, PackageNode* rootPackageNode, bool notify) { PackageNode* packageNode = rootPackageNode; Directory* directory = fRootDirectory; directory->WriteLock(); do { Node* node; status_t error = _AddPackageNode(directory, packageNode, notify, node); // returns B_OK with a NULL node, when skipping the node if (error != B_OK) { // unlock all directories while (directory != NULL) { directory->WriteUnlock(); directory = directory->Parent(); } // remove the added package nodes _RemovePackageContentRootNode(package, rootPackageNode, packageNode, notify); RETURN_ERROR(error); } // recurse into directory, unless we're supposed to skip the node if (node != NULL) { if (PackageDirectory* packageDirectory = dynamic_cast<PackageDirectory*>(packageNode)) { if (packageDirectory->FirstChild() != NULL) { directory = dynamic_cast<Directory*>(node); packageNode = packageDirectory->FirstChild(); directory->WriteLock(); continue; } } } // continue with the next available (ancestors's) sibling do { PackageDirectory* packageDirectory = packageNode->Parent(); PackageNode* sibling = packageDirectory != NULL ? packageDirectory->NextChild(packageNode) : NULL; if (sibling != NULL) { packageNode = sibling; break; } // no more siblings -- go back up the tree packageNode = packageDirectory; directory->WriteUnlock(); directory = directory->Parent(); // the parent is still locked, so this is safe } while (packageNode != NULL); } while (packageNode != NULL); return B_OK; }
virtual status_t GetNextEntry(void* _cookie, char* nameBuffer, size_t bufferSize) { Cookie* cookie = (Cookie*)_cookie; PackageNode* child = cookie->nextChild; if (child == NULL) return B_ENTRY_NOT_FOUND; cookie->nextChild = fDirectory->NextChild(child); strlcpy(nameBuffer, child->Name(), bufferSize); return B_OK; }
/*! Recursively iterates through the descendents of the given package root node and removes all package nodes from the node tree in post-order, until encountering \a endPackageNode (if non-null). Due to limited kernel stack space we avoid deep recursive function calls and rather use the package node stack implied by the tree. */ void Volume::_RemovePackageContentRootNode(Package* package, PackageNode* rootPackageNode, PackageNode* endPackageNode, bool notify) { PackageNode* packageNode = rootPackageNode; Directory* directory = fRootDirectory; directory->WriteLock(); do { if (packageNode == endPackageNode) break; // recurse into directory if (PackageDirectory* packageDirectory = dynamic_cast<PackageDirectory*>(packageNode)) { if (packageDirectory->FirstChild() != NULL) { if (Directory* childDirectory = dynamic_cast<Directory*>( directory->FindChild(packageNode->Name()))) { directory = childDirectory; packageNode = packageDirectory->FirstChild(); directory->WriteLock(); continue; } } } // continue with the next available (ancestors's) sibling do { PackageDirectory* packageDirectory = packageNode->Parent(); PackageNode* sibling = packageDirectory != NULL ? packageDirectory->NextChild(packageNode) : NULL; // we're done with the node -- remove it _RemovePackageNode(directory, packageNode, directory->FindChild(packageNode->Name()), notify); if (sibling != NULL) { packageNode = sibling; break; } // no more siblings -- go back up the tree packageNode = packageDirectory; directory->WriteUnlock(); directory = directory->Parent(); // the parent is still locked, so this is safe } while (packageNode != NULL/* && packageNode != rootPackageNode*/); } while (packageNode != NULL/* && packageNode != rootPackageNode*/); }
virtual void RemoveEntry(const char* path) { const char* componentEnd = strchr(path, '/'); if (componentEnd == NULL) componentEnd = path + strlen(path); PackageNode* child = _LookupChild(path, componentEnd - path); if (child == NULL) return; if (*componentEnd == '\0') { // last path component -- delete the child fEntries.Remove(child); delete child; } else { // must be a directory component -- continue resolving the path child->RemoveEntry(componentEnd + 1); } }
void Volume::_RemovePackageContent(Package* package, PackageNode* endNode, bool notify) { PackageNode* node = package->Nodes().Head(); while (node != NULL) { if (node == endNode) break; PackageNode* nextNode = package->Nodes().GetNext(node); // 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; } fPackageFSRoot->RemovePackage(package);; }
virtual status_t HandleEntryAttribute(BPackageEntry* entry, BPackageEntryAttribute* attribute) { if (fErrorOccurred) return B_OK; PackageNode* node = (PackageNode*)entry->UserToken(); PackageNodeAttribute* nodeAttribute = new(std::nothrow) PackageNodeAttribute(attribute->Type(), attribute->Data()); if (nodeAttribute == NULL) RETURN_ERROR(B_NO_MEMORY) status_t error = nodeAttribute->Init(attribute->Name()); if (error != B_OK) { delete nodeAttribute; RETURN_ERROR(error); } node->AddAttribute(nodeAttribute); return B_OK; }
virtual status_t HandleEntry(BPackageEntry* entry) { if (fErrorOccurred) return B_OK; PackageDirectory* parentDir = NULL; if (entry->Parent() != NULL) { parentDir = dynamic_cast<PackageDirectory*>( (PackageNode*)entry->Parent()->UserToken()); if (parentDir == NULL) RETURN_ERROR(B_BAD_DATA); } status_t error; // get the file mode -- filter out write permissions mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // create the package node PackageNode* node; if (S_ISREG(mode)) { // file node = new(std::nothrow) PackageFile(fPackage, mode, entry->Data()); } else if (S_ISLNK(mode)) { // symlink PackageSymlink* symlink = new(std::nothrow) PackageSymlink( fPackage, mode); if (symlink == NULL) RETURN_ERROR(B_NO_MEMORY); error = symlink->SetSymlinkPath(entry->SymlinkPath()); if (error != B_OK) { delete symlink; return error; } node = symlink; } else if (S_ISDIR(mode)) { // directory node = new(std::nothrow) PackageDirectory(fPackage, mode); } else RETURN_ERROR(B_BAD_DATA); if (node == NULL) RETURN_ERROR(B_NO_MEMORY); BReference<PackageNode> nodeReference(node, true); error = node->Init(parentDir, entry->Name()); if (error != B_OK) RETURN_ERROR(error); node->SetModifiedTime(entry->ModifiedTime()); // add it to the parent directory if (parentDir != NULL) parentDir->AddChild(node); else fPackage->AddNode(node); entry->SetUserToken(node); return B_OK; }
virtual status_t HandleEntry(BPackageEntry* entry) { if (fErrorOccurred || (fLastSettingsEntry != NULL && fLastSettingsEntry->IsBlackListed())) { return B_OK; } PackageDirectory* parentDir = NULL; if (const BPackageEntry* parentEntry = entry->Parent()) { if (!S_ISDIR(parentEntry->Mode())) RETURN_ERROR(B_BAD_DATA); parentDir = static_cast<PackageDirectory*>( (PackageNode*)parentEntry->UserToken()); } if (fSettingsItem != NULL && (parentDir == NULL || entry->Parent() == fLastSettingsEntryEntry)) { PackageSettingsItem::Entry* settingsEntry = fSettingsItem->FindEntry(fLastSettingsEntry, entry->Name()); if (settingsEntry != NULL) { fLastSettingsEntry = settingsEntry; fLastSettingsEntryEntry = entry; if (fLastSettingsEntry->IsBlackListed()) return B_OK; } } if (parentDir == NULL) parentDir = fVolume->RootDirectory(); status_t error; // get the file mode -- filter out write permissions mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // create the package node PackageNode* node; if (S_ISREG(mode)) { // file node = new(std::nothrow) PackageFile(fVolume, mode, entry->Data()); } else if (S_ISLNK(mode)) { // symlink PackageSymlink* symlink = new(std::nothrow) PackageSymlink( fVolume, mode); if (symlink == NULL) RETURN_ERROR(B_NO_MEMORY); error = symlink->SetSymlinkPath(entry->SymlinkPath()); if (error != B_OK) { delete symlink; return error; } node = symlink; } else if (S_ISDIR(mode)) { // directory node = new(std::nothrow) PackageDirectory(fVolume, mode); } else RETURN_ERROR(B_BAD_DATA); if (node == NULL) RETURN_ERROR(B_NO_MEMORY); error = node->Init(parentDir, entry->Name(), fVolume->NextNodeID()); if (error != B_OK) { delete node; RETURN_ERROR(error); } node->SetModifiedTime(entry->ModifiedTime()); // add it to the parent directory parentDir->AddChild(node); entry->SetUserToken(node); return B_OK; }