Files
haiku-beta6/src/add-ons/kernel/file_systems/packagefs/volume/PackagesDirectory.cpp
T
Ingo Weinhold 5d55f327ed packagefs: Initial support for booting into old states
If an old state is specified via mount parameters we load the packages
as specified in its activated-packages file.

The interface for the package daemon, the package daemon itself, and
the package kit are still to be adjusted, so ATM some PM components
might be a bit confused when an old state was booted.
2014-04-18 23:31:40 +02:00

138 lines
3.1 KiB
C++

/*
* Copyright 2009-2014, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "PackagesDirectory.h"
#include <errno.h>
#include <fs/KPath.h>
#include <team.h>
#include <vfs.h>
#include "DebugSupport.h"
PackagesDirectory::PackagesDirectory()
:
fStateName(),
fPath(NULL),
fDirFD(-1),
fNodeRef(),
fHashNext(NULL)
{
}
PackagesDirectory::~PackagesDirectory()
{
if (fDirFD >= 0)
close(fDirFD);
free(fPath);
}
/*static*/ bool
PackagesDirectory::IsNewer(const PackagesDirectory* a,
const PackagesDirectory* b)
{
if (b->fStateName.IsEmpty())
return false;
if (a->fStateName.IsEmpty())
return true;
return strcmp(a->fStateName, b->fStateName) > 0;
}
status_t
PackagesDirectory::Init(const char* path, dev_t mountPointDeviceID,
ino_t mountPointNodeID, struct stat& _st)
{
// Open the directory. We want the path be interpreted depending on from
// where it came (kernel or userland), but we always want a FD in the
// kernel I/O context. There's no VFS service method to do that for us,
// so we need to do that ourselves.
bool calledFromKernel
= team_get_current_team_id() == team_get_kernel_team_id();
// Not entirely correct, but good enough for now. The only
// alternative is to have that information passed in as well.
struct vnode* vnode;
status_t error;
if (path != NULL) {
error = vfs_get_vnode_from_path(path, calledFromKernel, &vnode);
} else {
// No path given -- use the "packages" directory at our mount point.
error = vfs_entry_ref_to_vnode(mountPointDeviceID, mountPointNodeID,
"packages", &vnode);
}
if (error != B_OK) {
ERROR("Failed to open packages directory \"%s\"\n", strerror(error));
RETURN_ERROR(error);
}
return _Init(vnode, _st);
}
status_t
PackagesDirectory::InitOldState(dev_t adminDirDeviceID, ino_t adminDirNodeID,
const char* stateName)
{
if (!fStateName.SetTo(stateName))
RETURN_ERROR(B_NO_MEMORY);
struct vnode* vnode;
status_t error = vfs_entry_ref_to_vnode(adminDirDeviceID, adminDirNodeID,
stateName, &vnode);
if (error != B_OK) {
ERROR("Failed to open old state directory \"%s\"\n", strerror(error));
RETURN_ERROR(error);
}
struct stat st;
return _Init(vnode, st);
}
status_t
PackagesDirectory::_Init(struct vnode* vnode, struct stat& _st)
{
fDirFD = vfs_open_vnode(vnode, O_RDONLY, true);
if (fDirFD < 0) {
ERROR("Failed to open packages directory \"%s\"\n", strerror(fDirFD));
vfs_put_vnode(vnode);
RETURN_ERROR(fDirFD);
}
// Our vnode reference has been transferred to the FD.
// Is it a directory at all?
struct stat& st = _st;
if (fstat(fDirFD, &st) < 0)
RETURN_ERROR(errno);
fNodeRef.device = st.st_dev;
fNodeRef.node = st.st_ino;
// get a normalized path
KPath normalizedPath;
if (normalizedPath.InitCheck() != B_OK)
RETURN_ERROR(normalizedPath.InitCheck());
char* normalizedPathBuffer = normalizedPath.LockBuffer();
status_t error = vfs_entry_ref_to_path(fNodeRef.device, fNodeRef.node, NULL,
true, normalizedPathBuffer, normalizedPath.BufferSize());
if (error != B_OK)
RETURN_ERROR(error);
fPath = strdup(normalizedPathBuffer);
if (fPath == NULL)
RETURN_ERROR(B_NO_MEMORY);
return B_OK;
}