Only get/remove/put the vnode when the node is actually known to the
VFS. This does not only save unnecessary work, it also solves a
(temporary) deadlock -- at least partially. If another thread caused a
call to our get_vnode() hook just before, it would block on the volume
lock we're holding when adding/removing packages. The vnode would be
marked busy until the other thread's request was fulfilled and our call
to get_vnode() would block until timing out. Now we're calling
get_vnode() only, if we already know that the VFS already has a valid
vnode.
There still remains a race condition. If the VFS discards the vnode
right before we call get_vnode(), we essentially have the same situation
as before (i.e. us calling get_vnode() although the vnode is no longer
known to the VFS) with the same potential problem. For a real solution
we need a get_vnode() variant which can be told not to block.
* Node::VFSInit() and VFSUninit() set/clear the new node flag
NODE_FLAG_KNOWN_TO_VFS. They need to be called by overriding methods,
now.
* Add Node::IsKnownToVFS() which returns the VFS init status.
* UnpackingLeafNode: Add a fFinalPackageNode attribute. It is set when
the node is about to be removed and will point to the node's previous
head package node and be used in its stead. From the perspective of
the FS hooks this leaves the node in an unchanged state.
* Unpacking[Leaf,Directory]Node:
- Add WillBeFirstPackageNode(), returning whether the given package
node would become the head package node when added.
- Add PrepareForRemoval() which removes all package nodes. In case of
UnpackingLeafNode it also sets fFinalPackageNode.
- Add CloneTransferPackageNodes(). It is only implemented for
UnpackingLeafNode. It clones the node, transfers all package nodes
to the clone and sets fFinalPackageNode on this node.
* Volume::_{Add,Remove}PackageNode(): Solved the following TODO: When a
package is added or removed and a file present in both the
added/removed package and another package with the version in the
former having precedence, we have to remove the node (leaving it
unchanged) and replace it by a new node. This prevents clients having
the node opened or mapped from suddenly seeing different data. It also
fixes unbalanced calls to PackageNode::VFSInit()/VFSUninit() which
would result in file descriptors to package files being leaked.
Volume::_RemovePackageContentRootNode(): Check whether a directory
corresponding to the package directory does actually exist. This might
not be the case when the package directory has been skipped due to
clashing with a shine-through directory. Would crash in this case.
Apparently I should have done a complete rebuild after moving
directories.h from headers/private/libroot to .../system, since a lot of
stuff didn't build anymore.
The implementation is temporary. Currently it reads through the packages
in the respective packages directory and checks against the package
links. Once package activation is tracked explicitly we'll use the
activation file/directory.
A BPackageContentHandler subclass that initializes a BPackageInfo from
the read package attributes. Pulled out of RepositoryWriterImpl's
PackageContentHandler.
* Remove InitCheck() and the initializing constructor.
* Rename PackageCount() to CountPackages().
* Use BOpenHashTable instead of HashMap for the internal PackageMap.
* Allow multiple packages with the same name. Equally named packages are
in a singly linked list after the first package with that name.
* Add an Iterator inner class and a GetIterator() method, so one can now
iterate through the packages in the repository.
* Add a new class ShineThroughDirectory for shine-through directories
instead of using UnpackingDirectory.
* Split up setting up the shine-through directories in two steps. First
the directories are only created. That happens before adding the
initial package domains. After publishing the root node we bind the
shine-through directories to the underlying directories.
* This makes adding a package directory with the same name as a
shine-through directory fail in _AddPackageNode() as originally
intended. Since we no longer want it to fail -- the package daemon
will copy the files in the respective directories as part of the
activation process -- we simply skip the directory now. Adjust
_AddPackageNode() and _AddPackageContentRootNode() accordingly.
When adding a new package link directory, the volume would only be
notified about the addition of the directory itself, not of the addition
of its contents. Add a new PackageLinkDirectory::NotifyDirectoryAdded()
which does the whole job and use it in
PackageLinksDirectory::AddPackage().
* Node: Add default implementations for UserID(), GroupID(),
OpenAttributeDirectory(), and OpenAttribute().
* Directory: Add default implementations for Mode() and FileSize().
* Remove the respective hook implementations in the PackageLink*
classes.
Always create the common repository cache/config paths so the BEntry
that is returned is valid at least. Fixes BRefreshRepositoryRequest
failing when the common repository cache path didn't exist yet.
Volume::_RemovePackageNode(): Notify listeners before removing the last
package node from the node, . This prevents the size/last modified
indices from not finding the node anymore, since the node would return
a default value instead of the value it was added to the index with.
* With -b building a build package can be requested. It will be empty
save for the .PackageInfo. No license check is performed.
* -I allows to specify an install path.
The attribute is intended for simplifying package building. The
package's install path will be used for the package's .self package
symlink, allowing installation to a temporary directory when building
the package.
* Add AttributeIndex class.
* Each attribute does now have an attribute index cookie. The new
attribute index service methods Node::IndexAttribute() and
IndexCookieForAttribute() create+set/retrieve the cookie. The cookie
is actually the attribute index's tree node.
* Add OldNodeAttribute::IndexCookieForAttribute() so the cookie is
available when the node changes.
* Move tree node operations to a subpolicy TreePolicy.
* Add a GenericIndexIteratorTreePolicy templatized over the policy,
implementing the tree policy for the standard indices.