* Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "kernel_interface.h"
#include <dirent.h>
#include <new>
#include <fs_info.h>
#include <fs_interface.h>
#include <KernelExport.h>
#include <io_requests.h>
#include <slab/Slab.h>
#include <AutoDeleter.h>
#include <package/hpkg/PackageFileHeapAccessorBase.h>
#include "util/TwoKeyAVLTree.h"
#include "AttributeCookie.h"
#include "AttributeDirectoryCookie.h"
#include "DebugSupport.h"
#include "Directory.h"
#include "Query.h"
#include "PackageFSRoot.h"
#include "StringConstants.h"
#include "StringPool.h"
#include "Utils.h"
#include "Volume.h"
template<> object_cache* TwoKeyAVLTreeNode<void*>::sNodeCache = NULL;
static const uint32 kOptimalIOSize = 64 * 1024;
static bool
lock_directory_for_node(Volume* volume, Node* node, DirectoryReadLocker& locker)
{
if (Directory* directory = dynamic_cast<Directory*>(node)) {
locker.SetTo(directory, false, true);
return locker.IsLocked();
} else {
BReference<Directory> parentRef = node->GetParent();
if (!parentRef.IsSet())
return false;
locker.SetTo(parentRef.Get(), false, true);
return locker.IsLocked() && node->GetParentUnchecked() == locker.Get();
}
}
static status_t
check_access(Node* node, int mode)
{
if (mode & W_OK)
return B_READ_ONLY_DEVICE;
return check_access_permissions(mode, node->Mode(), node->GroupID(),
node->UserID());
}
static status_t
packagefs_mount(fs_volume* fsVolume, const char* device, uint32 flags,
const char* parameters, ino_t* _rootID)
{
FUNCTION("fsVolume: %p, device: \"%s\", flags: %#" B_PRIx32 ", parameters: "
"\"%s\"\n", fsVolume, device, flags, parameters);
Volume* volume = new(std::nothrow) Volume(fsVolume);
if (volume == NULL)
RETURN_ERROR(B_NO_MEMORY);
VolumeWriteLocker volumeWriteLocker(volume);
fsVolume->private_volume = volume;
fsVolume->ops = &gPackageFSVolumeOps;
status_t error = volume->Mount(parameters);
if (error != B_OK) {
volumeWriteLocker.Unlock();
delete volume;
return error;
}
*_rootID = volume->RootDirectory()->ID();
return B_OK;
}
static status_t
packagefs_unmount(fs_volume* fsVolume)
{
Volume* volume = (Volume*)fsVolume->private_volume;
FUNCTION("volume: %p\n", volume);
volume->WriteLock();
volume->Unmount();
delete volume;
return B_OK;
}
static status_t
packagefs_read_fs_info(fs_volume* fsVolume, struct fs_info* info)
{
Volume* volume = (Volume*)fsVolume->private_volume;
FUNCTION("volume: %p, info: %p\n", volume, info);
info->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY | B_FS_HAS_MIME
| B_FS_HAS_ATTR | B_FS_HAS_QUERY | B_FS_SUPPORTS_NODE_MONITORING;
info->block_size = 4096;
info->io_size = kOptimalIOSize;
info->total_blocks = info->free_blocks = 0;
strlcpy(info->volume_name, volume->RootDirectory()->Name(),
sizeof(info->volume_name));
return B_OK;
}
static status_t
packagefs_lookup(fs_volume* fsVolume, fs_vnode* fsDir, const char* entryName,
ino_t* _vnid)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsDir->private_node;
FUNCTION("volume: %p, dir: %p (%" B_PRId64 "), entry: \"%s\"\n", volume,
node, node->ID(), entryName);
if (!S_ISDIR(node->Mode()))
return B_NOT_A_DIRECTORY;
Directory* dir = dynamic_cast<Directory*>(node);
if (strcmp(entryName, ".") == 0) {
Node* self;
*_vnid = dir->ID();
return volume->GetVNode(*_vnid, self);
}
if (strcmp(entryName, "..") == 0) {
BReference<Directory> parent = dir->GetParent();
if (parent == NULL)
return B_ENTRY_NOT_FOUND;
Node* dummy;
*_vnid = parent->ID();
return volume->GetVNode(*_vnid, dummy);
}
DirectoryReadLocker dirLocker(dir);
String entryNameString;
Node* child = dir->FindChild(StringKey(entryName));
if (child == NULL)
return B_ENTRY_NOT_FOUND;
BReference<Node> childReference(child);
dirLocker.Unlock();
*_vnid = child->ID();
RETURN_ERROR(volume->GetVNode(*_vnid, child));
}
static status_t
packagefs_get_vnode_name(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer,
size_t bufferSize)
{
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), %p, %zu\n",
fsVolume->private_volume, node, node->ID(), buffer, bufferSize);
if (strlcpy(buffer, node->Name(), bufferSize) >= bufferSize)
return B_BUFFER_OVERFLOW;
return B_OK;
}
static status_t
packagefs_get_vnode(fs_volume* fsVolume, ino_t vnid, fs_vnode* fsNode,
int* _type, uint32* _flags, bool reenter)
{
Volume* volume = (Volume*)fsVolume->private_volume;
FUNCTION("volume: %p, vnid: %" B_PRId64 "\n", volume, vnid);
VolumeReadLocker volumeLocker(volume);
Node* node = volume->FindNode(vnid);
if (node == NULL)
return B_ENTRY_NOT_FOUND;
BReference<Node> nodeReference(node);
DirectoryWriteLocker dirLocker;
if (Directory* directory = dynamic_cast<Directory*>(node)) {
dirLocker.SetTo(directory, false, true);
if (!dirLocker.IsLocked())
return B_NO_INIT;
} else {
dirLocker.SetTo(node->GetParentUnchecked(), false, true);
if (!dirLocker.IsLocked())
return B_NO_INIT;
}
volumeLocker.Unlock();
status_t error = node->VFSInit(volume->ID());
if (error != B_OK)
RETURN_ERROR(error);
dirLocker.Unlock();
fsNode->private_node = nodeReference.Detach();
fsNode->ops = &gPackageFSVnodeOps;
*_type = node->Mode() & S_IFMT;
*_flags = 0;
return B_OK;
}
static status_t
packagefs_put_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p\n", volume, node);
TOUCH(volume);
VolumeReadLocker volumeLocker(volume);
DirectoryWriteLocker dirLocker;
if (Directory* directory = dynamic_cast<Directory*>(node)) {
dirLocker.SetTo(directory, false, true);
ASSERT(dirLocker.IsLocked());
} else {
dirLocker.SetTo(node->GetParentUnchecked(), false, true);
if (dirLocker.Get() == NULL) {
ASSERT(volume->IsWriteLocked() || node->CountReferences() == 1);
}
}
volumeLocker.Unlock();
node->VFSUninit();
dirLocker.Unlock();
node->ReleaseReference();
return B_OK;
}
static status_t
packagefs_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
io_request* request)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p, request: %p\n",
volume, node, node->ID(), cookie, request);
TOUCH(volume);
if (io_request_is_write(request))
RETURN_ERROR(B_READ_ONLY_DEVICE);
status_t error = node->Read(request);
notify_io_request(request, error);
return error;
}
status_t
packagefs_ioctl(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
uint32 operation, void* buffer, size_t size)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p, operation: %"
B_PRIu32 ", buffer: %p, size: %zu\n", volume, node, node->ID(), cookie,
operation, buffer, size);
TOUCH(cookie);
return volume->IOCtl(node, operation, buffer, size);
}
static status_t
packagefs_read_symlink(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer,
size_t* _bufferSize)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
node->ID());
TOUCH(volume);
DirectoryReadLocker dirLocker;
if (!lock_directory_for_node(volume, node, dirLocker))
return B_NO_INIT;
if (!S_ISLNK(node->Mode()))
return B_BAD_VALUE;
return node->ReadSymlink(buffer, _bufferSize);
}
static status_t
packagefs_access(fs_volume* fsVolume, fs_vnode* fsNode, int mode)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
node->ID());
TOUCH(volume);
DirectoryReadLocker dirLocker;
if (!lock_directory_for_node(volume, node, dirLocker))
return B_NO_INIT;
return check_access(node, mode);
}
static status_t
packagefs_read_stat(fs_volume* fsVolume, fs_vnode* fsNode, struct stat* st)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
node->ID());
TOUCH(volume);
DirectoryReadLocker dirLocker;
if (!lock_directory_for_node(volume, node, dirLocker))
return B_NO_INIT;
st->st_mode = node->Mode();
st->st_nlink = 1;
st->st_uid = node->UserID();
st->st_gid = node->GroupID();
st->st_size = node->FileSize();
st->st_blksize = kOptimalIOSize;
st->st_mtim = node->ModifiedTime();
st->st_atim = st->st_mtim;
st->st_ctim = st->st_mtim;
st->st_crtim = st->st_mtim;
st->st_blocks = (st->st_size + 511) / 512;
return B_OK;
}
struct FileCookie {
int openMode;
FileCookie(int openMode)
:
openMode(openMode)
{
}
};
static status_t
packagefs_open(fs_volume* fsVolume, fs_vnode* fsNode, int openMode,
void** _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), openMode %#x\n",
volume, node, node->ID(), openMode);
TOUCH(volume);
DirectoryReadLocker dirLocker;
if (!lock_directory_for_node(volume, node, dirLocker))
return B_NO_INIT;
if (S_ISDIR(node->Mode()) && (openMode & O_RWMASK) != O_RDONLY)
return B_IS_A_DIRECTORY;
if ((openMode & O_DIRECTORY) != 0 && !S_ISDIR(node->Mode()))
return B_NOT_A_DIRECTORY;
if ((openMode & O_RWMASK) != O_RDONLY)
return B_NOT_ALLOWED;
status_t error = check_access(node, R_OK);
if (error != B_OK)
return error;
FileCookie* cookie = new(std::nothrow) FileCookie(openMode);
if (cookie == NULL)
RETURN_ERROR(B_NO_MEMORY);
*_cookie = cookie;
return B_OK;
}
static status_t
packagefs_close(fs_volume* fs, fs_vnode* _node, void* cookie)
{
return B_OK;
}
static status_t
packagefs_free_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FileCookie* cookie = (FileCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
delete cookie;
return B_OK;
}
static status_t
packagefs_read(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
off_t offset, void* buffer, size_t* bufferSize)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FileCookie* cookie = (FileCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p, offset: %"
B_PRId64 ", buffer: %p, size: %" B_PRIuSIZE "\n", volume, node,
node->ID(), cookie, offset, buffer, *bufferSize);
TOUCH(volume);
if ((cookie->openMode & O_RWMASK) != O_RDONLY)
return EBADF;
return node->Read(offset, buffer, bufferSize);
}
struct DirectoryCookie : DirectoryIterator {
Directory* directory;
int32 state;
bool registered;
DirectoryCookie(Directory* directory)
:
directory(directory),
state(0),
registered(false)
{
Rewind();
}
~DirectoryCookie()
{
if (registered)
directory->RemoveDirectoryIterator(this);
}
void Rewind()
{
if (registered)
directory->RemoveDirectoryIterator(this);
registered = false;
state = 0;
node = directory;
}
Node* Current(const char*& _name) const
{
if (node == NULL)
return NULL;
if (state == 0)
_name = ".";
else if (state == 1)
_name = "..";
else
_name = node->Name();
return node;
}
Node* Next()
{
if (state == 0) {
state = 1;
node = directory->GetParentUnchecked();
if (node == NULL)
node = directory;
return node;
}
if (state == 1) {
node = directory->FirstChild();
state = 2;
} else {
if (node != NULL)
node = directory->NextChild(node);
}
if (node == NULL) {
if (registered) {
directory->RemoveDirectoryIterator(this);
registered = false;
}
return NULL;
}
if (!registered) {
directory->AddDirectoryIterator(this);
registered = true;
}
return node;
}
};
static status_t
packagefs_open_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
node->ID());
TOUCH(volume);
if (!S_ISDIR(node->Mode()))
return B_NOT_A_DIRECTORY;
Directory* dir = dynamic_cast<Directory*>(node);
status_t error = check_access(dir, R_OK);
if (error != B_OK)
return error;
DirectoryWriteLocker dirLocker(dir);
DirectoryCookie* cookie = new(std::nothrow) DirectoryCookie(dir);
if (cookie == NULL)
RETURN_ERROR(B_NO_MEMORY);
*_cookie = cookie;
return B_OK;
}
static status_t
packagefs_close_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie)
{
return B_OK;
}
static status_t
packagefs_free_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
DirectoryWriteLocker dirLocker(dynamic_cast<Directory*>(node));
delete cookie;
return B_OK;
}
static status_t
packagefs_read_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
struct dirent* buffer, size_t bufferSize, uint32* _count)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
DirectoryWriteLocker dirLocker(cookie->directory);
uint32 maxCount = *_count;
uint32 count = 0;
dirent* previousEntry = NULL;
const char* name;
while (Node* child = cookie->Current(name)) {
if (count >= maxCount)
break;
if (count > 0) {
addr_t offset = (addr_t)buffer % 8;
if (offset > 0) {
offset = 8 - offset;
if (bufferSize <= offset)
break;
previousEntry->d_reclen += offset;
buffer = (dirent*)((addr_t)buffer + offset);
bufferSize -= offset;
}
}
if (!set_dirent_name(buffer, bufferSize, name)) {
if (count == 0)
RETURN_ERROR(B_BUFFER_OVERFLOW);
break;
}
buffer->d_dev = volume->ID();
buffer->d_ino = child->ID();
count++;
previousEntry = buffer;
bufferSize -= buffer->d_reclen;
buffer = (dirent*)((addr_t)buffer + buffer->d_reclen);
cookie->Next();
}
*_count = count;
return B_OK;
}
static status_t
packagefs_rewind_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
DirectoryCookie* cookie = (DirectoryCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
DirectoryWriteLocker dirLocker(dynamic_cast<Directory*>(node));
cookie->Rewind();
return B_OK;
}
status_t
packagefs_open_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%" B_PRId64 ")\n", volume, node,
node->ID());
TOUCH(volume);
status_t error = check_access(node, R_OK);
if (error != B_OK)
return error;
DirectoryReadLocker dirLocker;
if (!lock_directory_for_node(volume, node, dirLocker))
return B_NO_INIT;
AttributeDirectoryCookie* cookie;
error = node->OpenAttributeDirectory(cookie);
if (error != B_OK)
RETURN_ERROR(error);
*_cookie = cookie;
return B_OK;
}
status_t
packagefs_close_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
{
AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
return cookie->Close();
}
status_t
packagefs_free_attr_dir_cookie(fs_volume* fsVolume, fs_vnode* fsNode,
void* _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
delete cookie;
return B_OK;
}
status_t
packagefs_read_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
struct dirent* buffer, size_t bufferSize, uint32* _count)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
return cookie->Read(volume->ID(), node->ID(), buffer, bufferSize, _count);
}
status_t
packagefs_rewind_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
return cookie->Rewind();
}
status_t
packagefs_open_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name,
int openMode, void** _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), name: \"%s\", openMode "
"%#x\n", volume, node, node->ID(), name, openMode);
TOUCH(volume);
DirectoryReadLocker dirLocker;
if (!lock_directory_for_node(volume, node, dirLocker))
return B_NO_INIT;
if ((openMode & O_RWMASK) != O_RDONLY)
return B_NOT_ALLOWED;
status_t error = check_access(node, R_OK);
if (error != B_OK)
return error;
AttributeCookie* cookie;
error = node->OpenAttribute(StringKey(name), openMode, cookie);
if (error != B_OK)
return error;
*_cookie = cookie;
return B_OK;
}
status_t
packagefs_close_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
{
AttributeCookie* cookie = (AttributeCookie*)_cookie;
RETURN_ERROR(cookie->Close());
}
status_t
packagefs_free_attr_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
AttributeCookie* cookie = (AttributeCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
delete cookie;
return B_OK;
}
status_t
packagefs_read_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
off_t offset, void* buffer, size_t* bufferSize)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
AttributeCookie* cookie = (AttributeCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
return cookie->ReadAttribute(offset, buffer, bufferSize);
}
status_t
packagefs_read_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode,
void* _cookie, struct stat* st)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Node* node = (Node*)fsNode->private_node;
AttributeCookie* cookie = (AttributeCookie*)_cookie;
FUNCTION("volume: %p, node: %p (%" B_PRId64 "), cookie: %p\n", volume, node,
node->ID(), cookie);
TOUCH(volume);
TOUCH(node);
return cookie->ReadAttributeStat(st);
}
status_t
packagefs_open_index_dir(fs_volume* fsVolume, void** _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
FUNCTION("volume: %p\n", volume);
IndexDirIterator* iterator = new(std::nothrow) IndexDirIterator(
volume->GetIndexDirIterator());
if (iterator == NULL)
return B_NO_MEMORY;
*_cookie = iterator;
return B_OK;
}
status_t
packagefs_close_index_dir(fs_volume* fsVolume, void* cookie)
{
return B_OK;
}
status_t
packagefs_free_index_dir_cookie(fs_volume* fsVolume, void* cookie)
{
FUNCTION("volume: %p, cookie: %p\n", fsVolume->private_volume, cookie);
delete (IndexDirIterator*)cookie;
return B_OK;
}
status_t
packagefs_read_index_dir(fs_volume* fsVolume, void* cookie,
struct dirent* buffer, size_t bufferSize, uint32* _num)
{
Volume* volume = (Volume*)fsVolume->private_volume;
FUNCTION("volume: %p, cookie: %p, buffer: %p, bufferSize: %zu, num: %"
B_PRIu32 "\n", volume, cookie, buffer, bufferSize, *_num);
IndexDirIterator* iterator = (IndexDirIterator*)cookie;
if (*_num == 0)
return B_BAD_VALUE;
IndexDirIterator previousIterator = *iterator;
Index* index = iterator->Next();
if (index == NULL) {
*_num = 0;
return B_OK;
}
if (!set_dirent_name(buffer, bufferSize, index->Name())) {
*iterator = previousIterator;
return B_BUFFER_OVERFLOW;
}
buffer->d_dev = volume->ID();
buffer->d_ino = 0;
*_num = 1;
return B_OK;
}
status_t
packagefs_rewind_index_dir(fs_volume* fsVolume, void* cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
FUNCTION("volume: %p, cookie: %p\n", volume, cookie);
IndexDirIterator* iterator = (IndexDirIterator*)cookie;
*iterator = volume->GetIndexDirIterator();
return B_OK;
}
status_t
packagefs_create_index(fs_volume* fsVolume, const char* name, uint32 type,
uint32 flags)
{
return B_NOT_SUPPORTED;
}
status_t
packagefs_remove_index(fs_volume* fsVolume, const char* name)
{
return B_NOT_SUPPORTED;
}
status_t
packagefs_read_index_stat(fs_volume* fsVolume, const char* name,
struct stat* stat)
{
Volume* volume = (Volume*)fsVolume->private_volume;
FUNCTION("volume: %p, name: \"%s\", stat: %p\n", volume, name, stat);
Index* index = volume->FindIndex(StringKey(name));
if (index == NULL)
return B_ENTRY_NOT_FOUND;
VolumeReadLocker volumeReadLocker(volume);
memset(stat, 0, sizeof(*stat));
stat->st_type = index->Type();
stat->st_size = index->CountEntries();
return B_OK;
}
status_t
packagefs_open_query(fs_volume* fsVolume, const char* queryString, uint32 flags,
port_id port, uint32 token, void** _cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
FUNCTION("volume: %p, query: \"%s\", flags: %#" B_PRIx32 ", port: %"
B_PRId32 ", token: %" B_PRIu32 "\n", volume, queryString, flags, port,
token);
VolumeWriteLocker volumeWriteLocker(volume);
Query* query;
status_t error = Query::Create(volume, queryString, flags, port, token,
query);
if (error != B_OK)
return error;
*_cookie = query;
return B_OK;
}
status_t
packagefs_close_query(fs_volume* fsVolume, void* cookie)
{
FUNCTION_START();
return B_OK;
}
status_t
packagefs_free_query_cookie(fs_volume* fsVolume, void* cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Query* query = (Query*)cookie;
FUNCTION("volume: %p, query: %p\n", volume, query);
VolumeWriteLocker volumeWriteLocker(volume);
delete query;
return B_OK;
}
status_t
packagefs_read_query(fs_volume* fsVolume, void* cookie, struct dirent* buffer,
size_t bufferSize, uint32* _num)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Query* query = (Query*)cookie;
FUNCTION("volume: %p, query: %p\n", volume, query);
VolumeWriteLocker volumeWriteLocker(volume);
status_t error = query->GetNextEntry(buffer, bufferSize);
if (error == B_OK)
*_num = 1;
else if (error == B_ENTRY_NOT_FOUND)
*_num = 0;
else
return error;
return B_OK;
}
status_t
packagefs_rewind_query(fs_volume* fsVolume, void* cookie)
{
Volume* volume = (Volume*)fsVolume->private_volume;
Query* query = (Query*)cookie;
FUNCTION("volume: %p, query: %p\n", volume, query);
VolumeWriteLocker volumeWriteLocker(volume);
return query->Rewind();
}
static status_t
packagefs_std_ops(int32 op, ...)
{
using BPackageKit::BHPKG::BPrivate::PackageFileHeapAccessorBase;
switch (op) {
case B_MODULE_INIT:
{
init_debugging();
PRINT("package_std_ops(): B_MODULE_INIT\n");
status_t error = StringPool::Init();
if (error != B_OK) {
ERROR("Failed to init StringPool\n");
exit_debugging();
return error;
}
if (!StringConstants::Init()) {
ERROR("Failed to init string constants\n");
StringPool::Cleanup();
exit_debugging();
return error;
}
object_cache* quadChunkCache;
PackageFileHeapAccessorBase::sQuadChunkCache = quadChunkCache =
create_object_cache("pkgfs heap buffers",
PackageFileHeapAccessorBase::kChunkSize * 4,
0);
object_cache_set_minimum_reserve(quadChunkCache, 1);
TwoKeyAVLTreeNode<void*>::sNodeCache =
create_object_cache("pkgfs TKAVLTreeNodes",
sizeof(TwoKeyAVLTreeNode<void*>), CACHE_NO_DEPOT);
error = PackageFSRoot::GlobalInit();
if (error != B_OK) {
ERROR("Failed to init PackageFSRoot\n");
StringConstants::Cleanup();
StringPool::Cleanup();
exit_debugging();
return error;
}
return B_OK;
}
case B_MODULE_UNINIT:
{
PRINT("package_std_ops(): B_MODULE_UNINIT\n");
PackageFSRoot::GlobalUninit();
delete_object_cache(TwoKeyAVLTreeNode<void*>::sNodeCache);
delete_object_cache((object_cache*)
PackageFileHeapAccessorBase::sQuadChunkCache);
StringConstants::Cleanup();
StringPool::Cleanup();
exit_debugging();
return B_OK;
}
default:
return B_ERROR;
}
}
static file_system_module_info sPackageFSModuleInfo = {
{
"file_systems/packagefs" B_CURRENT_FS_API_VERSION,
0,
packagefs_std_ops,
},
"packagefs",
"Package File System",
0,
NULL,
NULL,
NULL,
NULL,
&packagefs_mount
};
fs_volume_ops gPackageFSVolumeOps = {
&packagefs_unmount,
&packagefs_read_fs_info,
NULL,
NULL,
&packagefs_get_vnode,
&packagefs_open_index_dir,
&packagefs_close_index_dir,
&packagefs_free_index_dir_cookie,
&packagefs_read_index_dir,
&packagefs_rewind_index_dir,
&packagefs_create_index,
&packagefs_remove_index,
&packagefs_read_index_stat,
&packagefs_open_query,
&packagefs_close_query,
&packagefs_free_query_cookie,
&packagefs_read_query,
&packagefs_rewind_query,
};
fs_vnode_ops gPackageFSVnodeOps = {
&packagefs_lookup,
&packagefs_get_vnode_name,
&packagefs_put_vnode,
&packagefs_put_vnode,
NULL,
NULL,
NULL,
&packagefs_io,
NULL,
NULL,
&packagefs_ioctl,
NULL,
NULL,
NULL,
NULL,
&packagefs_read_symlink,
NULL,
NULL,
NULL,
NULL,
&packagefs_access,
&packagefs_read_stat,
NULL,
NULL,
NULL,
&packagefs_open,
&packagefs_close,
&packagefs_free_cookie,
&packagefs_read,
NULL,
NULL,
NULL,
&packagefs_open_dir,
&packagefs_close_dir,
&packagefs_free_dir_cookie,
&packagefs_read_dir,
&packagefs_rewind_dir,
&packagefs_open_attr_dir,
&packagefs_close_attr_dir,
&packagefs_free_attr_dir_cookie,
&packagefs_read_attr_dir,
&packagefs_rewind_attr_dir,
NULL,
&packagefs_open_attr,
&packagefs_close_attr,
&packagefs_free_attr_cookie,
&packagefs_read_attr,
NULL,
&packagefs_read_attr_stat,
NULL,
NULL,
NULL
};
module_info *modules[] = {
(module_info *)&sPackageFSModuleInfo,
NULL,
};