/*! 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; }
/*! 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*/); }