Enabled full attribute support under the Haiku kernel.

It's not as clean as it could, but it works for now.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10377 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2004-12-08 04:18:44 +00:00
parent 1bcd71834b
commit d48f7182eb
4 changed files with 488 additions and 212 deletions
@@ -0,0 +1,209 @@
/* Attribute - connection between pure inode and kernel_interface attributes
*
* Copyright 2004, Axel Dörfler, [email protected].
* This file may be used under the terms of the MIT License.
*/
#include "Attribute.h"
#include <stdlib.h>
// ToDo: clean this up, find a better separation between Inode and this class
// ToDo: even after Create(), the attribute cannot be stat() for until the first write
extern void fill_stat_buffer(Inode *inode, struct stat &stat);
Attribute::Attribute(Inode *inode)
:
fNodeGetter(inode->GetVolume()),
fInode(inode),
fSmall(NULL),
fAttribute(NULL),
fName(NULL)
{
}
Attribute::Attribute(Inode *inode, attr_cookie *cookie)
:
fNodeGetter(inode->GetVolume()),
fInode(inode),
fSmall(NULL),
fAttribute(NULL),
fName(NULL)
{
Get(cookie->name);
}
Attribute::~Attribute()
{
Put();
}
status_t
Attribute::InitCheck()
{
return (fSmall != NULL || fAttribute != NULL) ? B_OK : B_NO_INIT;
}
status_t
Attribute::CheckAccess(const char *name, int openMode)
{
// Opening the name attribute using this function is not allowed,
// also using the reserved indices name, last_modified, and size
// shouldn't be allowed.
// ToDo: we might think about allowing to update those values, but
// really change their corresponding values in the bfs_inode structure
if (name[0] == FILE_NAME_NAME && name[1] == '\0'
|| !strcmp(name, "name")
|| !strcmp(name, "last_modified")
|| !strcmp(name, "size"))
RETURN_ERROR(B_NOT_ALLOWED);
return fInode->CheckPermissions(openModeToAccess(openMode)
| (openMode & O_TRUNC ? W_OK : 0));
}
status_t
Attribute::Get(const char *name)
{
Put();
fName = name;
// try to find it in the small data region
if (fInode->SmallDataLock().Lock() == B_OK) {
fNodeGetter.SetToNode(fInode);
fSmall = fInode->FindSmallData(fNodeGetter.Node(), (const char *)name);
if (fSmall != NULL)
return B_OK;
fInode->SmallDataLock().Unlock();
fNodeGetter.Unset();
}
// then, search in the attribute directory
return fInode->GetAttribute(name, &fAttribute);
}
void
Attribute::Put()
{
if (fSmall != NULL) {
fInode->SmallDataLock().Unlock();
fNodeGetter.Unset();
fSmall = NULL;
}
if (fAttribute != NULL) {
fInode->ReleaseAttribute(fAttribute);
fAttribute = NULL;
}
}
status_t
Attribute::Create(const char *name, type_code type, int openMode, attr_cookie **_cookie)
{
status_t status = CheckAccess(name, openMode);
if (status < B_OK)
return status;
attr_cookie *cookie = (attr_cookie *)malloc(sizeof(attr_cookie));
if (cookie == NULL)
RETURN_ERROR(B_NO_MEMORY);
fName = name;
// initialize the cookie
strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
cookie->type = type;
cookie->open_mode = openMode;
cookie->create = true;
*_cookie = cookie;
return B_OK;
}
status_t
Attribute::Open(const char *name, int openMode, attr_cookie **_cookie)
{
status_t status = CheckAccess(name, openMode);
if (status < B_OK)
return status;
status = Get(name);
if (status < B_OK)
return status;
attr_cookie *cookie = (attr_cookie *)malloc(sizeof(attr_cookie));
if (cookie == NULL)
RETURN_ERROR(B_NO_MEMORY);
// initialize the cookie
strlcpy(cookie->name, fName, B_ATTR_NAME_LENGTH);
cookie->open_mode = openMode;
cookie->create = false;
// Should we truncate the attribute?
if (openMode & O_TRUNC) {
// ToDo!
}
*_cookie = cookie;
return B_OK;
}
status_t
Attribute::Stat(struct stat &stat)
{
if (fSmall == NULL && fAttribute == NULL)
return B_NO_INIT;
if (fSmall != NULL) {
fill_stat_buffer(fInode, stat);
// overwrite some data to suit our needs
stat.st_type = fSmall->Type();
stat.st_size = fSmall->DataSize();
}
if (fAttribute != NULL)
fill_stat_buffer(fAttribute, stat);
return B_OK;
}
status_t
Attribute::Read(attr_cookie *cookie, off_t pos, uint8 *buffer, size_t *_length)
{
if (fSmall == NULL && fAttribute == NULL)
return B_NO_INIT;
// ToDo: move small_data logic from Inode::ReadAttribute() over to here!
return fInode->ReadAttribute(cookie->name, 0, pos, buffer, _length);
}
status_t
Attribute::Write(Transaction &transaction, attr_cookie *cookie,
off_t pos, const uint8 *buffer, size_t *_length)
{
if (!cookie->create && fSmall == NULL && fAttribute == NULL)
return B_NO_INIT;
return fInode->WriteAttribute(transaction, cookie->name, cookie->type,
pos, buffer, _length);
}
@@ -0,0 +1,50 @@
/* Attribute - connection between pure inode and kernel_interface attributes
*
* Copyright 2004, Axel Dörfler, [email protected].
* This file may be used under the terms of the MIT License.
*/
#ifndef ATTRIBUTE_H
#define ATTRIBUTE_H
#include <Inode.h>
struct attr_cookie {
char name[B_ATTR_NAME_LENGTH];
uint32 type;
int open_mode;
bool create;
};
class Attribute {
public:
Attribute(Inode *inode);
Attribute(Inode *inode, attr_cookie *cookie);
~Attribute();
status_t InitCheck();
status_t CheckAccess(const char *name, int openMode);
status_t Get(const char *name);
void Put();
status_t Create(const char *name, type_code type, int openMode, attr_cookie **_cookie);
status_t Open(const char *name, int openMode, attr_cookie **_cookie);
status_t Stat(struct stat &stat);
status_t Read(attr_cookie *cookie, off_t pos, uint8 *buffer, size_t *_length);
status_t Write(Transaction &transaction, attr_cookie *cookie,
off_t pos, const uint8 *buffer, size_t *_length);
private:
NodeGetter fNodeGetter;
Inode *fInode;
small_data *fSmall;
Inode *fAttribute;
const char *fName;
};
#endif /* ATTRIBUTE_H */
@@ -35,6 +35,7 @@ KernelAddon bfs : kernel file_systems :
BlockAllocator.cpp
BPlusTree.cpp
kernel_cpp.cpp
Attribute.cpp
Debug.cpp
Index.cpp
Inode.cpp
@@ -11,6 +11,7 @@
#include "Index.h"
#include "BPlusTree.h"
#include "Query.h"
#include "Attribute.h"
#include "bfs_control.h"
#include <util/kernel_cpp.h>
@@ -32,6 +33,36 @@
#define BFS_IO_SIZE 65536
extern void fill_stat_buffer(Inode *inode, struct stat &stat);
void
fill_stat_buffer(Inode *inode, struct stat &stat)
{
const bfs_inode &node = inode->Node();
stat.st_dev = inode->GetVolume()->ID();
stat.st_ino = inode->ID();
stat.st_nlink = 1;
stat.st_blksize = BFS_IO_SIZE;
stat.st_uid = node.UserID();
stat.st_gid = node.GroupID();
stat.st_mode = node.Mode();
stat.st_type = node.Type();
stat.st_atime = time(NULL);
stat.st_mtime = stat.st_ctime = (time_t)(node.LastModifiedTime() >> INODE_TIME_SHIFT);
stat.st_crtime = (time_t)(node.CreateTime() >> INODE_TIME_SHIFT);
if (inode->IsSymLink() && (node.Flags() & INODE_LONG_SYMLINK) == 0) {
// symlinks report the size of the link here
stat.st_size = strlen(node.short_symlink) + 1;
} else
stat.st_size = inode->Size();
}
// ToDo: Temporary hack to get it working
@@ -606,35 +637,14 @@ bfs_fsync(void *_ns, void *_node)
*/
static status_t
bfs_read_stat(void *_ns, void *_node, struct stat *st)
bfs_read_stat(void *_ns, void *_node, struct stat *stat)
{
FUNCTION();
Volume *volume = (Volume *)_ns;
Inode *inode = (Inode *)_node;
const bfs_inode &node = inode->Node();
st->st_dev = volume->ID();
st->st_ino = inode->ID();
st->st_nlink = 1;
st->st_blksize = BFS_IO_SIZE;
st->st_uid = node.UserID();
st->st_gid = node.GroupID();
st->st_mode = node.Mode();
if (inode->IsSymLink() && (node.Flags() & INODE_LONG_SYMLINK) == 0) {
// symlinks report the size of the link here
st->st_size = strlen(node.short_symlink) + 1;
} else
st->st_size = inode->Size();
st->st_atime = time(NULL);
st->st_mtime = st->st_ctime = (time_t)(node.LastModifiedTime() >> INODE_TIME_SHIFT);
st->st_crtime = (time_t)(node.CreateTime() >> INODE_TIME_SHIFT);
return B_NO_ERROR;
fill_stat_buffer(inode, *stat);
return B_OK;
}
@@ -722,10 +732,10 @@ bfs_write_stat(void *_ns, void *_node, const struct stat *stat, uint32 mask)
status_t
bfs_create(void *_ns, void *_directory, const char *name, int omode, int mode,
bfs_create(void *_ns, void *_directory, const char *name, int openMode, int mode,
void **_cookie, vnode_id *vnodeID)
{
FUNCTION_START(("name = \"%s\", perms = %d, omode = %d\n", name, mode, omode));
FUNCTION_START(("name = \"%s\", perms = %d, openMode = %d\n", name, mode, openMode));
if (_ns == NULL || _directory == NULL || _cookie == NULL
|| name == NULL || *name == '\0')
@@ -744,7 +754,7 @@ bfs_create(void *_ns, void *_directory, const char *name, int omode, int mode,
RETURN_ERROR(B_NO_MEMORY);
// initialize the cookie
cookie->open_mode = omode;
cookie->open_mode = openMode;
cookie->last_size = 0;
cookie->last_notification = system_time();
@@ -754,7 +764,7 @@ bfs_create(void *_ns, void *_directory, const char *name, int omode, int mode,
Transaction transaction(volume, directory->BlockNumber());
status_t status = Inode::Create(transaction, directory, name, S_FILE | (mode & S_IUMSK),
omode, 0, vnodeID);
openMode, 0, vnodeID);
if (status >= B_OK) {
transaction.Done();
@@ -1051,25 +1061,24 @@ bfs_rename(void *_ns, void *_oldDir, const char *oldName, void *_newDir, const c
*/
static status_t
bfs_open(void *_ns, void *_node, int omode, void **_cookie)
bfs_open(void *_fs, void *_node, int openMode, void **_cookie)
{
FUNCTION();
if (_ns == NULL || _node == NULL || _cookie == NULL)
RETURN_ERROR(B_BAD_VALUE);
Volume *volume = (Volume *)_ns;
Volume *volume = (Volume *)_fs;
Inode *inode = (Inode *)_node;
// opening a directory read-only is allowed, although you can't read
// any data from it.
if (inode->IsDirectory() && omode & O_RWMASK) {
omode = omode & ~O_RWMASK;
if (inode->IsDirectory() && openMode & O_RWMASK) {
openMode = openMode & ~O_RWMASK;
// ToDo: for compatibility reasons, we don't return an error here...
// e.g. "copyattr" tries to do that
//return B_IS_A_DIRECTORY;
}
status_t status = inode->CheckPermissions(openModeToAccess(omode));
status_t status = inode->CheckPermissions(openModeToAccess(openMode)
| (openMode & O_TRUNC ? W_OK : 0));
if (status < B_OK)
RETURN_ERROR(status);
@@ -1086,13 +1095,13 @@ bfs_open(void *_ns, void *_node, int omode, void **_cookie)
RETURN_ERROR(B_NO_MEMORY);
// initialize the cookie
cookie->open_mode = omode;
cookie->open_mode = openMode;
// needed by e.g. bfs_write() for O_APPEND
cookie->last_size = inode->Size();
cookie->last_notification = system_time();
// Should we truncate the file?
if (omode & O_TRUNC) {
if (openMode & O_TRUNC) {
WriteLocked locked(inode->Lock());
Transaction transaction(volume, inode->BlockNumber());
@@ -1490,27 +1499,25 @@ bfs_free_dir_cookie(void *ns, void *node, void *_cookie)
// #pragma mark -
// Attribute functions
#if 0
static status_t
bfs_open_attrdir(void *_ns, void *_node, void **cookie)
bfs_open_attr_dir(void *_ns, void *_node, void **_cookie)
{
FUNCTION();
Inode *inode = (Inode *)_node;
if (inode == NULL || inode->Node() == NULL)
RETURN_ERROR(B_ERROR);
FUNCTION();
AttributeIterator *iterator = new AttributeIterator(inode);
if (iterator == NULL)
RETURN_ERROR(B_NO_MEMORY);
*cookie = iterator;
*_cookie = iterator;
return B_OK;
}
static status_t
bfs_close_attrdir(void *ns, void *node, void *cookie)
bfs_close_attr_dir(void *ns, void *node, void *cookie)
{
FUNCTION();
return B_OK;
@@ -1518,7 +1525,7 @@ bfs_close_attrdir(void *ns, void *node, void *cookie)
static status_t
bfs_free_attrdir_cookie(void *ns, void *node, void *_cookie)
bfs_free_attr_dir_cookie(void *ns, void *node, void *_cookie)
{
FUNCTION();
AttributeIterator *iterator = (AttributeIterator *)_cookie;
@@ -1532,7 +1539,7 @@ bfs_free_attrdir_cookie(void *ns, void *node, void *_cookie)
static status_t
bfs_rewind_attrdir(void *_ns, void *_node, void *_cookie)
bfs_rewind_attr_dir(void *_ns, void *_node, void *_cookie)
{
FUNCTION();
@@ -1545,7 +1552,8 @@ bfs_rewind_attrdir(void *_ns, void *_node, void *_cookie)
static status_t
bfs_read_attrdir(void *_ns, void *node, void *_cookie, long *num, struct dirent *dirent, size_t bufsize)
bfs_read_attr_dir(void *_ns, void *node, void *_cookie, struct dirent *dirent,
size_t bufferSize, uint32 *_num)
{
FUNCTION();
AttributeIterator *iterator = (AttributeIterator *)_cookie;
@@ -1557,54 +1565,127 @@ bfs_read_attrdir(void *_ns, void *node, void *_cookie, long *num, struct dirent
size_t length;
status_t status = iterator->GetNext(dirent->d_name, &length, &type, &dirent->d_ino);
if (status == B_ENTRY_NOT_FOUND) {
*num = 0;
*_num = 0;
return B_OK;
} else if (status != B_OK)
} else if (status != B_OK) {
RETURN_ERROR(status);
}
Volume *volume = (Volume *)_ns;
dirent->d_dev = volume->ID();
dirent->d_reclen = sizeof(struct dirent) + length;
*num = 1;
*_num = 1;
return B_OK;
}
static status_t
bfs_remove_attr(void *_ns, void *_node, const char *name)
bfs_create_attr(fs_volume _fs, fs_vnode _node, const char *name, uint32 type,
int openMode, fs_cookie *_cookie)
{
FUNCTION_START(("name = \"%s\"\n", name));
FUNCTION();
if (_ns == NULL || _node == NULL || name == NULL)
return B_BAD_VALUE;
Volume *volume = (Volume *)_ns;
Inode *inode = (Inode *)_node;
Attribute attribute(inode);
status_t status = inode->CheckPermissions(W_OK);
if (status < B_OK)
return status;
#ifdef UNSAFE_GET_VNODE
RecursiveLocker locker(volume->Lock());
#endif
Transaction transaction(volume, inode->BlockNumber());
status = inode->RemoveAttribute(transaction, name);
if (status == B_OK) {
transaction.Done();
notify_listener(B_ATTR_CHANGED, volume->ID(), 0, 0, inode->ID(), name);
}
RETURN_ERROR(status);
return attribute.Create(name, type, openMode, (attr_cookie **)_cookie);
}
static status_t
bfs_rename_attr(void *ns, void *node, const char *oldname, const char *newname)
bfs_open_attr(fs_volume _fs, fs_vnode _node, const char *name, int openMode,
fs_cookie *_cookie)
{
FUNCTION();
Inode *inode = (Inode *)_node;
Attribute attribute(inode);
return attribute.Open(name, openMode, (attr_cookie **)_cookie);
}
static status_t
bfs_close_attr(fs_volume _fs, fs_vnode _file, fs_cookie cookie)
{
return B_OK;
}
static status_t
bfs_free_attr_cookie(fs_volume _fs, fs_vnode _file, fs_cookie cookie)
{
free(cookie);
return B_OK;
}
static status_t
bfs_read_attr(fs_volume _fs, fs_vnode _file, fs_cookie _cookie, off_t pos,
void *buffer, size_t *_length)
{
FUNCTION();
attr_cookie *cookie = (attr_cookie *)_cookie;
Inode *inode = (Inode *)_file;
Attribute attribute(inode, cookie);
return attribute.Read(cookie, pos, (uint8 *)buffer, _length);
}
static status_t
bfs_write_attr(fs_volume _fs, fs_vnode _file, fs_cookie _cookie, off_t pos,
const void *buffer, size_t *_length)
{
FUNCTION();
attr_cookie *cookie = (attr_cookie *)_cookie;
Volume *volume = (Volume *)_fs;
Inode *inode = (Inode *)_file;
Transaction transaction(volume, inode->BlockNumber());
Attribute attribute(inode, cookie);
status_t status = attribute.Write(transaction, cookie, pos, (const uint8 *)buffer, _length);
if (status == B_OK) {
transaction.Done();
notify_listener(B_ATTR_CHANGED, volume->ID(), 0, 0, inode->ID(), cookie->name);
}
return status;
}
static status_t
bfs_read_attr_stat(fs_volume _fs, fs_vnode _file, fs_cookie _cookie, struct stat *stat)
{
FUNCTION();
attr_cookie *cookie = (attr_cookie *)_cookie;
Inode *inode = (Inode *)_file;
Attribute attribute(inode, cookie);
return attribute.Stat(*stat);
}
static status_t
bfs_write_attr_stat(fs_volume fs, fs_vnode file, fs_cookie cookie,
const struct stat *stat, int statMask)
{
return EOPNOTSUPP;
}
static status_t
bfs_rename_attr(fs_volume _fs, fs_vnode fromFile, const char *fromName,
fs_vnode toFile, const char *toName)
{
FUNCTION_START(("name = \"%s\", to = \"%s\"\n", oldname, newname));
@@ -1618,107 +1699,39 @@ bfs_rename_attr(void *ns, void *node, const char *oldname, const char *newname)
static status_t
bfs_stat_attr(void *ns, void *_node, const char *name, struct attr_info *attrInfo)
bfs_remove_attr(fs_volume _fs, fs_vnode _node, const char *name)
{
FUNCTION_START(("name = \"%s\"\n", name));
Inode *inode = (Inode *)_node;
if (inode == NULL || inode->Node() == NULL)
RETURN_ERROR(B_ERROR);
if (name == NULL)
return B_BAD_VALUE;
// first, try to find it in the small data region
small_data *smallData = NULL;
if (inode->SmallDataLock().Lock() == B_OK) {
if ((smallData = inode->FindSmallData((const char *)name)) != NULL) {
attrInfo->type = smallData->Type();
attrInfo->size = smallData->DataSize();
}
inode->SmallDataLock().Unlock();
}
if (smallData != NULL)
return B_OK;
// then, search in the attribute directory
Inode *attribute;
status_t status = inode->GetAttribute(name, &attribute);
if (status == B_OK) {
attrInfo->type = attribute->Type();
attrInfo->size = attribute->Size();
inode->ReleaseAttribute(attribute);
return B_OK;
}
RETURN_ERROR(status);
}
static status_t
bfs_write_attr(void *_ns, void *_node, const char *name, int type, const void *buffer,
size_t *_length, off_t pos)
{
FUNCTION_START(("name = \"%s\"\n", name));
if (_ns == NULL || _node == NULL || name == NULL || *name == '\0')
RETURN_ERROR(B_BAD_VALUE);
// Writing the name attribute using this function is not allowed,
// also using the reserved indices name, last_modified, and size
// shouldn't be allowed.
// ToDo: we might think about allowing to update those values, but
// really change their corresponding values in the bfs_inode structure
if (name[0] == FILE_NAME_NAME && name[1] == '\0'
|| !strcmp(name, "name")
|| !strcmp(name, "last_modified")
|| !strcmp(name, "size"))
RETURN_ERROR(B_NOT_ALLOWED);
Volume *volume = (Volume *)_ns;
Volume *volume = (Volume *)_fs;
Inode *inode = (Inode *)_node;
status_t status = inode->CheckPermissions(W_OK);
if (status < B_OK)
return status;
#ifdef UNSAFE_GET_VNODE
RecursiveLocker locker(volume->Lock());
#endif
Transaction transaction(volume, inode->BlockNumber());
status = inode->WriteAttribute(transaction, name, type, pos, (const uint8 *)buffer, _length);
status = inode->RemoveAttribute(transaction, name);
if (status == B_OK) {
transaction.Done();
notify_listener(B_ATTR_CHANGED, volume->ID(), 0, 0, inode->ID(), name);
}
return status;
RETURN_ERROR(status);
}
static status_t
bfs_read_attr(void *_ns, void *_node, const char *name, int type, void *buffer,
size_t *_length, off_t pos)
{
FUNCTION();
Inode *inode = (Inode *)_node;
if (inode == NULL || name == NULL || *name == '\0' || buffer == NULL)
RETURN_ERROR(B_BAD_VALUE);
status_t status = inode->CheckPermissions(R_OK);
if (status < B_OK)
return status;
return inode->ReadAttribute(name, type, pos, (uint8 *)buffer, _length);
}
#endif
// #pragma mark -
// Index functions
static status_t
bfs_open_indexdir(void *_ns, void **_cookie)
bfs_open_index_dir(void *_ns, void **_cookie)
{
FUNCTION();
if (_ns == NULL || _cookie == NULL)
@@ -1739,7 +1752,7 @@ bfs_open_indexdir(void *_ns, void **_cookie)
static status_t
bfs_close_indexdir(fs_volume _fs, fs_cookie _cookie)
bfs_close_index_dir(fs_volume _fs, fs_cookie _cookie)
{
FUNCTION();
if (_fs == NULL || _cookie == NULL)
@@ -1751,7 +1764,7 @@ bfs_close_indexdir(fs_volume _fs, fs_cookie _cookie)
static status_t
bfs_free_indexdir_cookie(fs_volume _fs, fs_cookie _cookie)
bfs_free_index_dir_cookie(fs_volume _fs, fs_cookie _cookie)
{
FUNCTION();
if (_fs == NULL || _cookie == NULL)
@@ -1763,7 +1776,7 @@ bfs_free_indexdir_cookie(fs_volume _fs, fs_cookie _cookie)
static status_t
bfs_rewind_indexdir(fs_volume _fs, fs_cookie _cookie)
bfs_rewind_index_dir(fs_volume _fs, fs_cookie _cookie)
{
FUNCTION();
if (_fs == NULL || _cookie == NULL)
@@ -1775,7 +1788,8 @@ bfs_rewind_indexdir(fs_volume _fs, fs_cookie _cookie)
static status_t
bfs_read_indexdir(fs_volume _fs, fs_cookie _cookie, struct dirent *dirent, size_t bufferSize, uint32 *_num)
bfs_read_index_dir(fs_volume _fs, fs_cookie _cookie, struct dirent *dirent,
size_t bufferSize, uint32 *_num)
{
FUNCTION();
if (_fs == NULL || _cookie == NULL)
@@ -1999,87 +2013,89 @@ static file_system_info sBeFileSystem = {
bfs_std_ops,
},
&bfs_mount, // mount
&bfs_unmount, // unmount
&bfs_read_fs_stat, // read fs stat
&bfs_write_fs_stat, // write fs stat
&bfs_sync, // sync
&bfs_mount,
&bfs_unmount,
&bfs_read_fs_stat,
&bfs_write_fs_stat,
&bfs_sync,
/* vnode operations */
&bfs_lookup, // lookup
&bfs_lookup,
NULL, // get_vnode_name
&bfs_read_vnode, // read_vnode
&bfs_release_vnode, // write_vnode
&bfs_remove_vnode, // remove_vnode
&bfs_read_vnode,
&bfs_release_vnode,
&bfs_remove_vnode,
/* VM file access */
&bfs_can_page,
&bfs_read_pages,
&bfs_write_pages,
&bfs_get_file_map, // get file map
&bfs_get_file_map,
&bfs_ioctl, // ioctl
&bfs_set_flags, // set flags
&bfs_fsync, // sync
&bfs_ioctl,
&bfs_set_flags,
&bfs_fsync,
&bfs_read_link, // read link
&bfs_read_link,
NULL, // write link
&bfs_create_symlink, // create symlink
&bfs_create_symlink,
&bfs_link, // link
&bfs_unlink, // unlink
&bfs_rename, // rename
&bfs_link,
&bfs_unlink,
&bfs_rename,
&bfs_access, // access
&bfs_read_stat, // read stat
&bfs_write_stat, // write stat
&bfs_access,
&bfs_read_stat,
&bfs_write_stat,
/* file operations */
&bfs_create, // create
&bfs_open, // open file
&bfs_close, // close file
&bfs_free_cookie, // free cookie
&bfs_read, // read file
&bfs_write, // write file
&bfs_create,
&bfs_open,
&bfs_close,
&bfs_free_cookie,
&bfs_read,
&bfs_write,
/* directory operations */
&bfs_create_dir, // create dir
&bfs_remove_dir, // remove dir
&bfs_open_dir, // opendir
&bfs_close_dir, // closedir
&bfs_free_dir_cookie, // free_dircookie
&bfs_read_dir, // readdir
&bfs_rewind_dir, // rewinddir
&bfs_create_dir,
&bfs_remove_dir,
&bfs_open_dir,
&bfs_close_dir,
&bfs_free_dir_cookie,
&bfs_read_dir,
&bfs_rewind_dir,
NULL, NULL, NULL, NULL, NULL, // attr dir
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, // attr
#if 0
/* attribute directory operations */
&bfs_open_attrdir, // open attr dir
&bfs_close_attrdir, // close attr dir
&bfs_free_attrdir_cookie, // free attr dir cookie
&bfs_read_attrdir, // read attr dir
&bfs_rewind_attrdir, // rewind attr dir
&bfs_open_attr_dir,
&bfs_close_attr_dir,
&bfs_free_attr_dir_cookie,
&bfs_read_attr_dir,
&bfs_rewind_attr_dir,
/* attribute operations */
&bfs_write_attr, // write attr
&bfs_read_attr, // read attr
&bfs_remove_attr, // remove attr
&bfs_rename_attr, // rename attr
&bfs_stat_attr, // stat attr
#endif
/* index directory & index operations */
&bfs_open_indexdir, // open index dir
&bfs_close_indexdir, // close index dir
&bfs_free_indexdir_cookie, // free index dir cookie
&bfs_read_indexdir, // read index dir
&bfs_rewind_indexdir, // rewind index dir
&bfs_create_attr,
&bfs_open_attr,
&bfs_close_attr,
&bfs_free_attr_cookie,
&bfs_read_attr,
&bfs_write_attr,
&bfs_create_index, // create index
&bfs_remove_index, // remove index
&bfs_stat_index, // stat index
&bfs_read_attr_stat,
&bfs_write_attr_stat,
&bfs_rename_attr,
&bfs_remove_attr,
/* index directory & index operations */
&bfs_open_index_dir,
&bfs_close_index_dir,
&bfs_free_index_dir_cookie,
&bfs_read_index_dir,
&bfs_rewind_index_dir,
&bfs_create_index,
&bfs_remove_index,
&bfs_stat_index,
#if 0
/* query operations */
&bfs_open_query, // open query