* Split the FSCapabilities bit mask into three bit masks for the FS, the
volume, and the vnodes, since we have three independent FS interface
structures, now. The latter is not supported in the kernel add-on, yet.
* Server:
- Temporarily removed some things from the build (the BeOS interface
and the cache implementations).
- Some WIP in HaikuKernelVolume and [haiku_]kernel_emu.{h,cpp}.
- Added HaikuKernelNode, which wraps fs_vnode for the client FS.
The server is still quite a bit away from being buildable again.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29323 a95241bf-73f2-0310-859d-f6bbb57e9c96
880 lines
19 KiB
C++
880 lines
19 KiB
C++
// BeOSKernelVolume.cpp
|
|
|
|
#include "BeOSKernelVolume.h"
|
|
|
|
#include <new>
|
|
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
#include "beos_fs_interface.h"
|
|
#include "Debug.h"
|
|
#include "kernel_emu.h"
|
|
|
|
|
|
using std::nothrow;
|
|
|
|
static int open_mode_to_access(int openMode);
|
|
|
|
|
|
// AttributeCookie
|
|
class BeOSKernelVolume::AttributeCookie {
|
|
public:
|
|
AttributeCookie(const char* name, uint32 type, int openMode, bool exists,
|
|
bool create)
|
|
: fType(type),
|
|
fOpenMode(openMode),
|
|
fExists(exists),
|
|
fCreate(create)
|
|
{
|
|
strcpy(fName, name);
|
|
}
|
|
|
|
char fName[B_ATTR_NAME_LENGTH];
|
|
uint32 fType;
|
|
int fOpenMode;
|
|
bool fExists;
|
|
bool fCreate;
|
|
};
|
|
|
|
|
|
// constructor
|
|
BeOSKernelVolume::BeOSKernelVolume(FileSystem* fileSystem, dev_t id,
|
|
beos_vnode_ops* fsOps)
|
|
: Volume(fileSystem, id),
|
|
fFSOps(fsOps),
|
|
fVolumeCookie(NULL)
|
|
{
|
|
}
|
|
|
|
// destructor
|
|
BeOSKernelVolume::~BeOSKernelVolume()
|
|
{
|
|
}
|
|
|
|
// #pragma mark -
|
|
// #pragma mark ----- FS -----
|
|
|
|
// Mount
|
|
status_t
|
|
BeOSKernelVolume::Mount(const char* device, uint32 flags,
|
|
const char* parameters, ino_t* rootID)
|
|
{
|
|
if (!fFSOps->mount)
|
|
return B_BAD_VALUE;
|
|
|
|
size_t len = (parameters ? strlen(parameters) : 0);
|
|
return fFSOps->mount(GetID(), device, flags, (void*)parameters, len,
|
|
&fVolumeCookie, rootID);
|
|
}
|
|
|
|
// Unmount
|
|
status_t
|
|
BeOSKernelVolume::Unmount()
|
|
{
|
|
if (!fFSOps->unmount)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->unmount(fVolumeCookie);
|
|
}
|
|
|
|
// Sync
|
|
status_t
|
|
BeOSKernelVolume::Sync()
|
|
{
|
|
if (!fFSOps->sync)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->sync(fVolumeCookie);
|
|
}
|
|
|
|
// ReadFSInfo
|
|
status_t
|
|
BeOSKernelVolume::ReadFSInfo(fs_info* info)
|
|
{
|
|
if (!fFSOps->rfsstat)
|
|
return B_BAD_VALUE;
|
|
|
|
// Haiku's fs_info equals BeOS's version
|
|
return fFSOps->rfsstat(fVolumeCookie, (beos_fs_info*)info);
|
|
}
|
|
|
|
// WriteFSInfo
|
|
status_t
|
|
BeOSKernelVolume::WriteFSInfo(const struct fs_info* info, uint32 mask)
|
|
{
|
|
if (!fFSOps->wfsstat)
|
|
return B_BAD_VALUE;
|
|
|
|
// Haiku's fs_info equals BeOS's version
|
|
return fFSOps->wfsstat(fVolumeCookie, (beos_fs_info*)info, (long)mask);
|
|
}
|
|
|
|
|
|
// #pragma mark - vnodes
|
|
|
|
|
|
// Lookup
|
|
status_t
|
|
BeOSKernelVolume::Lookup(fs_vnode dir, const char* entryName, ino_t* vnid)
|
|
{
|
|
if (!fFSOps->walk)
|
|
return B_BAD_VALUE;
|
|
|
|
status_t error = fFSOps->walk(fVolumeCookie, dir, entryName, NULL, vnid);
|
|
if (error != B_OK)
|
|
return error;
|
|
|
|
// We need to get the node stat to return the node's type.
|
|
// TODO: This is quite expensive. get_vnode() and put_vnode() cause trips to
|
|
// the kernel. If it is implemented properly walk() has already called
|
|
// get_vnode() for our node. Introducing a mechanism that would allow us to
|
|
// temporarily track the {get,put,new}_vnode() calls of our thread would save
|
|
// those two kernel trips.
|
|
|
|
// get the vnode
|
|
fs_vnode node;
|
|
error = UserlandFS::KernelEmu::get_vnode(GetID(), *vnid, &node);
|
|
if (error != B_OK) {
|
|
// walk() has called get_vnode() for the caller, so we need to put the
|
|
// node
|
|
UserlandFS::KernelEmu::put_vnode(GetID(), *vnid);
|
|
return error;
|
|
}
|
|
|
|
// get the node's stat
|
|
struct stat st;
|
|
error = ReadStat(node, &st);
|
|
if (error == B_OK)
|
|
*type = (st.st_mode & S_IFMT);
|
|
|
|
// put the node for our get_vnode()
|
|
UserlandFS::KernelEmu::put_vnode(GetID(), *vnid);
|
|
|
|
// on error put the node for walk()'s get_vnode()
|
|
if (error != B_OK)
|
|
UserlandFS::KernelEmu::put_vnode(GetID(), *vnid);
|
|
|
|
return error;
|
|
}
|
|
|
|
// LookupNoType
|
|
status_t
|
|
BeOSKernelVolume::LookupNoType(fs_vnode dir, const char* entryName,
|
|
ino_t* vnid)
|
|
{
|
|
if (!fFSOps->walk)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->walk(fVolumeCookie, dir, entryName, NULL, vnid);
|
|
}
|
|
|
|
// ReadVNode
|
|
status_t
|
|
BeOSKernelVolume::ReadVNode(ino_t vnid, bool reenter, fs_vnode* node, int* type,
|
|
uint32* flags)
|
|
{
|
|
#error Return type and flags!
|
|
if (!fFSOps->read_vnode)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->read_vnode(fVolumeCookie, vnid, (char)reenter, node);
|
|
}
|
|
|
|
// WriteVNode
|
|
status_t
|
|
BeOSKernelVolume::WriteVNode(fs_vnode node, bool reenter)
|
|
{
|
|
if (!fFSOps->write_vnode)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->write_vnode(fVolumeCookie, node, (char)reenter);
|
|
}
|
|
|
|
// RemoveVNode
|
|
status_t
|
|
BeOSKernelVolume::RemoveVNode(fs_vnode node, bool reenter)
|
|
{
|
|
if (!fFSOps->remove_vnode)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->remove_vnode(fVolumeCookie, node, (char)reenter);
|
|
}
|
|
|
|
|
|
// #pragma mark - nodes
|
|
|
|
|
|
// IOCtl
|
|
status_t
|
|
BeOSKernelVolume::IOCtl(fs_vnode node, fs_cookie cookie, uint32 command,
|
|
void* buffer, size_t size)
|
|
{
|
|
if (!fFSOps->ioctl)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->ioctl(fVolumeCookie, node, cookie, (int)command, buffer,
|
|
size);
|
|
}
|
|
|
|
// SetFlags
|
|
status_t
|
|
BeOSKernelVolume::SetFlags(fs_vnode node, fs_cookie cookie, int flags)
|
|
{
|
|
if (!fFSOps->setflags)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->setflags(fVolumeCookie, node, cookie, flags);
|
|
}
|
|
|
|
// Select
|
|
status_t
|
|
BeOSKernelVolume::Select(fs_vnode node, fs_cookie cookie, uint8 event,
|
|
selectsync* sync)
|
|
{
|
|
if (!fFSOps->select) {
|
|
UserlandFS::KernelEmu::notify_select_event(sync, event, false);
|
|
return B_OK;
|
|
}
|
|
return fFSOps->select(fVolumeCookie, node, cookie, event, 0, sync);
|
|
}
|
|
|
|
// Deselect
|
|
status_t
|
|
BeOSKernelVolume::Deselect(fs_vnode node, fs_cookie cookie, uint8 event,
|
|
selectsync* sync)
|
|
{
|
|
if (!fFSOps->select || !fFSOps->deselect)
|
|
return B_OK;
|
|
return fFSOps->deselect(fVolumeCookie, node, cookie, event, sync);
|
|
}
|
|
|
|
// FSync
|
|
status_t
|
|
BeOSKernelVolume::FSync(fs_vnode node)
|
|
{
|
|
if (!fFSOps->fsync)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->fsync(fVolumeCookie, node);
|
|
}
|
|
|
|
// ReadSymlink
|
|
status_t
|
|
BeOSKernelVolume::ReadSymlink(fs_vnode node, char* buffer, size_t bufferSize,
|
|
size_t* bytesRead)
|
|
{
|
|
if (!fFSOps->readlink)
|
|
return B_BAD_VALUE;
|
|
*bytesRead = bufferSize;
|
|
return fFSOps->readlink(fVolumeCookie, node, buffer, bytesRead);
|
|
}
|
|
|
|
// CreateSymlink
|
|
status_t
|
|
BeOSKernelVolume::CreateSymlink(fs_vnode dir, const char* name,
|
|
const char* target, int mode)
|
|
{
|
|
if (!fFSOps->symlink)
|
|
return B_BAD_VALUE;
|
|
// TODO: Don't ignore mode?
|
|
return fFSOps->symlink(fVolumeCookie, dir, name, target);
|
|
}
|
|
|
|
// Link
|
|
status_t
|
|
BeOSKernelVolume::Link(fs_vnode dir, const char* name, fs_vnode node)
|
|
{
|
|
if (!fFSOps->link)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->link(fVolumeCookie, dir, name, node);
|
|
}
|
|
|
|
// Unlink
|
|
status_t
|
|
BeOSKernelVolume::Unlink(fs_vnode dir, const char* name)
|
|
{
|
|
if (!fFSOps->unlink)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->unlink(fVolumeCookie, dir, name);
|
|
}
|
|
|
|
// Rename
|
|
status_t
|
|
BeOSKernelVolume::Rename(fs_vnode oldDir, const char* oldName, fs_vnode newDir,
|
|
const char* newName)
|
|
{
|
|
if (!fFSOps->rename)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->rename(fVolumeCookie, oldDir, oldName, newDir, newName);
|
|
}
|
|
|
|
// Access
|
|
status_t
|
|
BeOSKernelVolume::Access(fs_vnode node, int mode)
|
|
{
|
|
if (!fFSOps->access)
|
|
return B_OK;
|
|
return fFSOps->access(fVolumeCookie, node, mode);
|
|
}
|
|
|
|
// ReadStat
|
|
status_t
|
|
BeOSKernelVolume::ReadStat(fs_vnode node, struct stat* st)
|
|
{
|
|
if (!fFSOps->rstat)
|
|
return B_BAD_VALUE;
|
|
|
|
// Haiku's struct stat has an additional st_type field (for an attribute
|
|
// type), but that doesn't matter here
|
|
return fFSOps->rstat(fVolumeCookie, node, (struct beos_stat*)st);
|
|
}
|
|
|
|
// WriteStat
|
|
status_t
|
|
BeOSKernelVolume::WriteStat(fs_vnode node, const struct stat *st, uint32 mask)
|
|
{
|
|
if (!fFSOps->wstat)
|
|
return B_BAD_VALUE;
|
|
|
|
// Haiku's struct stat has an additional st_type field (for an attribute
|
|
// type), but that doesn't matter here
|
|
return fFSOps->wstat(fVolumeCookie, node, (struct beos_stat*)st,
|
|
(long)mask);
|
|
}
|
|
|
|
|
|
// #pragma mark - files
|
|
|
|
|
|
// Create
|
|
status_t
|
|
BeOSKernelVolume::Create(fs_vnode dir, const char* name, int openMode, int mode,
|
|
fs_cookie* cookie, ino_t* vnid)
|
|
{
|
|
if (!fFSOps->create)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->create(fVolumeCookie, dir, name, openMode, mode, vnid,
|
|
cookie);
|
|
}
|
|
|
|
// Open
|
|
status_t
|
|
BeOSKernelVolume::Open(fs_vnode node, int openMode, fs_cookie* cookie)
|
|
{
|
|
if (!fFSOps->open)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->open(fVolumeCookie, node, openMode, cookie);
|
|
}
|
|
|
|
// Close
|
|
status_t
|
|
BeOSKernelVolume::Close(fs_vnode node, fs_cookie cookie)
|
|
{
|
|
if (!fFSOps->close)
|
|
return B_OK;
|
|
return fFSOps->close(fVolumeCookie, node, cookie);
|
|
}
|
|
|
|
// FreeCookie
|
|
status_t
|
|
BeOSKernelVolume::FreeCookie(fs_vnode node, fs_cookie cookie)
|
|
{
|
|
if (!fFSOps->free_cookie)
|
|
return B_OK;
|
|
return fFSOps->free_cookie(fVolumeCookie, node, cookie);
|
|
}
|
|
|
|
// Read
|
|
status_t
|
|
BeOSKernelVolume::Read(fs_vnode node, fs_cookie cookie, off_t pos, void* buffer,
|
|
size_t bufferSize, size_t* bytesRead)
|
|
{
|
|
if (!fFSOps->read)
|
|
return B_BAD_VALUE;
|
|
*bytesRead = bufferSize;
|
|
return fFSOps->read(fVolumeCookie, node, cookie, pos, buffer, bytesRead);
|
|
}
|
|
|
|
// Write
|
|
status_t
|
|
BeOSKernelVolume::Write(fs_vnode node, fs_cookie cookie, off_t pos,
|
|
const void* buffer, size_t bufferSize, size_t* bytesWritten)
|
|
{
|
|
if (!fFSOps->write)
|
|
return B_BAD_VALUE;
|
|
*bytesWritten = bufferSize;
|
|
return fFSOps->write(fVolumeCookie, node, cookie, pos, buffer,
|
|
bytesWritten);
|
|
}
|
|
|
|
|
|
// #pragma mark - directories
|
|
|
|
|
|
// CreateDir
|
|
status_t
|
|
BeOSKernelVolume::CreateDir(fs_vnode dir, const char* name, int mode,
|
|
ino_t *newDir)
|
|
{
|
|
if (!fFSOps->mkdir || !fFSOps->walk) // we need walk() too
|
|
return B_BAD_VALUE;
|
|
|
|
status_t error = fFSOps->mkdir(fVolumeCookie, dir, name, mode);
|
|
if (error != B_OK)
|
|
return error;
|
|
|
|
// we need to get the node ID by invoking walk()
|
|
ino_t id;
|
|
error = fFSOps->walk(fVolumeCookie, dir, name, NULL, &id);
|
|
if (error != B_OK)
|
|
return error;
|
|
|
|
// put the node for walk()'s get_vnode()
|
|
UserlandFS::KernelEmu::put_vnode(GetID(), id);
|
|
|
|
*newDir = id;
|
|
return B_OK;
|
|
}
|
|
|
|
// RemoveDir
|
|
status_t
|
|
BeOSKernelVolume::RemoveDir(fs_vnode dir, const char* name)
|
|
{
|
|
if (!fFSOps->rmdir)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->rmdir(fVolumeCookie, dir, name);
|
|
}
|
|
|
|
// OpenDir
|
|
status_t
|
|
BeOSKernelVolume::OpenDir(fs_vnode node, fs_cookie* cookie)
|
|
{
|
|
if (!fFSOps->opendir)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->opendir(fVolumeCookie, node, cookie);
|
|
}
|
|
|
|
// CloseDir
|
|
status_t
|
|
BeOSKernelVolume::CloseDir(fs_vnode node, fs_vnode cookie)
|
|
{
|
|
if (!fFSOps->closedir)
|
|
return B_OK;
|
|
return fFSOps->closedir(fVolumeCookie, node, cookie);
|
|
}
|
|
|
|
// FreeDirCookie
|
|
status_t
|
|
BeOSKernelVolume::FreeDirCookie(fs_vnode node, fs_vnode cookie)
|
|
{
|
|
if (!fFSOps->free_dircookie)
|
|
return B_OK;
|
|
return fFSOps->free_dircookie(fVolumeCookie, node, cookie);
|
|
}
|
|
|
|
// ReadDir
|
|
status_t
|
|
BeOSKernelVolume::ReadDir(fs_vnode node, fs_vnode cookie, void* buffer,
|
|
size_t bufferSize, uint32 count, uint32* countRead)
|
|
{
|
|
if (!fFSOps->readdir)
|
|
return B_BAD_VALUE;
|
|
|
|
*countRead = count;
|
|
|
|
// Haiku's struct dirent equals BeOS's version
|
|
return fFSOps->readdir(fVolumeCookie, node, cookie, (long*)countRead,
|
|
(beos_dirent*)buffer, bufferSize);
|
|
}
|
|
|
|
// RewindDir
|
|
status_t
|
|
BeOSKernelVolume::RewindDir(fs_vnode node, fs_vnode cookie)
|
|
{
|
|
if (!fFSOps->rewinddir)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->rewinddir(fVolumeCookie, node, cookie);
|
|
}
|
|
|
|
|
|
// #pragma mark - attribute directories
|
|
|
|
|
|
// OpenAttrDir
|
|
status_t
|
|
BeOSKernelVolume::OpenAttrDir(fs_vnode node, fs_cookie *cookie)
|
|
{
|
|
if (!fFSOps->open_attrdir)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->open_attrdir(fVolumeCookie, node, cookie);
|
|
}
|
|
|
|
// CloseAttrDir
|
|
status_t
|
|
BeOSKernelVolume::CloseAttrDir(fs_vnode node, fs_cookie cookie)
|
|
{
|
|
if (!fFSOps->close_attrdir)
|
|
return B_OK;
|
|
return fFSOps->close_attrdir(fVolumeCookie, node, cookie);
|
|
}
|
|
|
|
// FreeAttrDirCookie
|
|
status_t
|
|
BeOSKernelVolume::FreeAttrDirCookie(fs_vnode node, fs_cookie cookie)
|
|
{
|
|
if (!fFSOps->free_attrdircookie)
|
|
return B_OK;
|
|
return fFSOps->free_attrdircookie(fVolumeCookie, node, cookie);
|
|
}
|
|
|
|
// ReadAttrDir
|
|
status_t
|
|
BeOSKernelVolume::ReadAttrDir(fs_vnode node, fs_cookie cookie, void* buffer,
|
|
size_t bufferSize, uint32 count, uint32* countRead)
|
|
{
|
|
if (!fFSOps->read_attrdir)
|
|
return B_BAD_VALUE;
|
|
|
|
*countRead = count;
|
|
|
|
// Haiku's struct dirent equals BeOS's version
|
|
return fFSOps->read_attrdir(fVolumeCookie, node, cookie, (long*)countRead,
|
|
(struct beos_dirent*)buffer, bufferSize);
|
|
}
|
|
|
|
// RewindAttrDir
|
|
status_t
|
|
BeOSKernelVolume::RewindAttrDir(fs_vnode node, fs_cookie cookie)
|
|
{
|
|
if (!fFSOps->rewind_attrdir)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->rewind_attrdir(fVolumeCookie, node, cookie);
|
|
}
|
|
|
|
|
|
// #pragma mark - attributes
|
|
|
|
|
|
// CreateAttr
|
|
status_t
|
|
BeOSKernelVolume::CreateAttr(fs_vnode node, const char* name, uint32 type,
|
|
int openMode, fs_cookie* cookie)
|
|
{
|
|
return _OpenAttr(node, name, type, openMode, true, cookie);
|
|
}
|
|
|
|
// OpenAttr
|
|
status_t
|
|
BeOSKernelVolume::OpenAttr(fs_vnode node, const char* name, int openMode,
|
|
fs_cookie* cookie)
|
|
{
|
|
return _OpenAttr(node, name, 0, openMode, false, cookie);
|
|
}
|
|
|
|
// CloseAttr
|
|
status_t
|
|
BeOSKernelVolume::CloseAttr(fs_vnode node, fs_cookie cookie)
|
|
{
|
|
return B_OK;
|
|
}
|
|
|
|
// FreeAttrCookie
|
|
status_t
|
|
BeOSKernelVolume::FreeAttrCookie(fs_vnode node, fs_cookie _cookie)
|
|
{
|
|
AttributeCookie* cookie = (AttributeCookie*)_cookie;
|
|
|
|
// If the attribute doesn't exist yet and it was opened with
|
|
// CreateAttr(), we could create it now. We have a race condition here
|
|
// though, since someone else could have created it in the meantime.
|
|
|
|
delete cookie;
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
// ReadAttr
|
|
status_t
|
|
BeOSKernelVolume::ReadAttr(fs_vnode node, fs_cookie _cookie, off_t pos,
|
|
void* buffer, size_t bufferSize, size_t* bytesRead)
|
|
{
|
|
AttributeCookie* cookie = (AttributeCookie*)_cookie;
|
|
|
|
// check, if open mode allows reading
|
|
if ((open_mode_to_access(cookie->fOpenMode) | R_OK) == 0)
|
|
return B_FILE_ERROR;
|
|
|
|
// read
|
|
if (!fFSOps->read_attr)
|
|
return B_BAD_VALUE;
|
|
|
|
*bytesRead = bufferSize;
|
|
return fFSOps->read_attr(fVolumeCookie, node, cookie->fName, cookie->fType,
|
|
buffer, bytesRead, pos);
|
|
}
|
|
|
|
// WriteAttr
|
|
status_t
|
|
BeOSKernelVolume::WriteAttr(fs_vnode node, fs_cookie _cookie, off_t pos,
|
|
const void* buffer, size_t bufferSize, size_t* bytesWritten)
|
|
{
|
|
AttributeCookie* cookie = (AttributeCookie*)_cookie;
|
|
|
|
// check, if open mode allows writing
|
|
if ((open_mode_to_access(cookie->fOpenMode) | W_OK) == 0)
|
|
return B_FILE_ERROR;
|
|
|
|
// write
|
|
if (!fFSOps->write_attr)
|
|
return B_BAD_VALUE;
|
|
|
|
*bytesWritten = bufferSize;
|
|
return fFSOps->write_attr(fVolumeCookie, node, cookie->fName, cookie->fType,
|
|
buffer, bytesWritten, pos);
|
|
}
|
|
|
|
// ReadAttrStat
|
|
status_t
|
|
BeOSKernelVolume::ReadAttrStat(fs_vnode node, fs_cookie _cookie,
|
|
struct stat *st)
|
|
{
|
|
AttributeCookie* cookie = (AttributeCookie*)_cookie;
|
|
|
|
// get the stats
|
|
beos_attr_info attrInfo;
|
|
if (!fFSOps->stat_attr)
|
|
return B_BAD_VALUE;
|
|
|
|
status_t error = fFSOps->stat_attr(fVolumeCookie, node, cookie->fName,
|
|
&attrInfo);
|
|
if (error != B_OK)
|
|
return error;
|
|
|
|
// translate to struct stat
|
|
st->st_size = attrInfo.size;
|
|
st->st_type = attrInfo.type;
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
// RenameAttr
|
|
status_t
|
|
BeOSKernelVolume::RenameAttr(fs_vnode oldNode, const char* oldName,
|
|
fs_vnode newNode, const char* newName)
|
|
{
|
|
if (!fFSOps->rename_attr)
|
|
return B_BAD_VALUE;
|
|
if (oldNode != newNode)
|
|
return B_BAD_VALUE;
|
|
|
|
return fFSOps->rename_attr(fVolumeCookie, oldNode, oldName, newName);
|
|
}
|
|
|
|
// RemoveAttr
|
|
status_t
|
|
BeOSKernelVolume::RemoveAttr(fs_vnode node, const char* name)
|
|
{
|
|
if (!fFSOps->remove_attr)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->remove_attr(fVolumeCookie, node, name);
|
|
}
|
|
|
|
|
|
// #pragma mark - indices
|
|
|
|
|
|
// OpenIndexDir
|
|
status_t
|
|
BeOSKernelVolume::OpenIndexDir(fs_cookie *cookie)
|
|
{
|
|
if (!fFSOps->open_indexdir)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->open_indexdir(fVolumeCookie, cookie);
|
|
}
|
|
|
|
// CloseIndexDir
|
|
status_t
|
|
BeOSKernelVolume::CloseIndexDir(fs_cookie cookie)
|
|
{
|
|
if (!fFSOps->close_indexdir)
|
|
return B_OK;
|
|
return fFSOps->close_indexdir(fVolumeCookie, cookie);
|
|
}
|
|
|
|
// FreeIndexDirCookie
|
|
status_t
|
|
BeOSKernelVolume::FreeIndexDirCookie(fs_cookie cookie)
|
|
{
|
|
if (!fFSOps->free_indexdircookie)
|
|
return B_OK;
|
|
return fFSOps->free_indexdircookie(fVolumeCookie, NULL, cookie);
|
|
}
|
|
|
|
// ReadIndexDir
|
|
status_t
|
|
BeOSKernelVolume::ReadIndexDir(fs_cookie cookie, void* buffer,
|
|
size_t bufferSize, uint32 count, uint32* countRead)
|
|
{
|
|
if (!fFSOps->read_indexdir)
|
|
return B_BAD_VALUE;
|
|
|
|
*countRead = count;
|
|
|
|
// Haiku's struct dirent equals BeOS's version
|
|
return fFSOps->read_indexdir(fVolumeCookie, cookie, (long*)countRead,
|
|
(struct beos_dirent*)buffer, bufferSize);
|
|
}
|
|
|
|
// RewindIndexDir
|
|
status_t
|
|
BeOSKernelVolume::RewindIndexDir(fs_cookie cookie)
|
|
{
|
|
if (!fFSOps->rewind_indexdir)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->rewind_indexdir(fVolumeCookie, cookie);
|
|
}
|
|
|
|
// CreateIndex
|
|
status_t
|
|
BeOSKernelVolume::CreateIndex(const char* name, uint32 type, uint32 flags)
|
|
{
|
|
if (!fFSOps->create_index)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->create_index(fVolumeCookie, name, (int)type, (int)flags);
|
|
}
|
|
|
|
// RemoveIndex
|
|
status_t
|
|
BeOSKernelVolume::RemoveIndex(const char* name)
|
|
{
|
|
if (!fFSOps->remove_index)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->remove_index(fVolumeCookie, name);
|
|
}
|
|
|
|
// StatIndex
|
|
status_t
|
|
BeOSKernelVolume::ReadIndexStat(const char *name, struct stat *st)
|
|
{
|
|
if (!fFSOps->stat_index)
|
|
return B_BAD_VALUE;
|
|
|
|
beos_index_info indexInfo;
|
|
status_t error = fFSOps->stat_index(fVolumeCookie, name, &indexInfo);
|
|
if (error != B_OK)
|
|
return error;
|
|
|
|
// translate index_info into struct stat
|
|
st->st_type = indexInfo.type;
|
|
st->st_size = indexInfo.size;
|
|
st->st_mtime = indexInfo.modification_time;
|
|
st->st_crtime = indexInfo.creation_time;
|
|
st->st_uid = indexInfo.uid;
|
|
st->st_gid = indexInfo.gid;
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
// #pragma mark - queries
|
|
|
|
|
|
// OpenQuery
|
|
status_t
|
|
BeOSKernelVolume::OpenQuery(const char* queryString, uint32 flags, port_id port,
|
|
uint32 token, fs_cookie *cookie)
|
|
{
|
|
if (!fFSOps->open_query)
|
|
return B_BAD_VALUE;
|
|
return fFSOps->open_query(fVolumeCookie, queryString, flags, port,
|
|
(long)token, cookie);
|
|
}
|
|
|
|
// CloseQuery
|
|
status_t
|
|
BeOSKernelVolume::CloseQuery(fs_cookie cookie)
|
|
{
|
|
if (!fFSOps->close_query)
|
|
return B_OK;
|
|
return fFSOps->close_query(fVolumeCookie, cookie);
|
|
}
|
|
|
|
// FreeQueryCookie
|
|
status_t
|
|
BeOSKernelVolume::FreeQueryCookie(fs_cookie cookie)
|
|
{
|
|
if (!fFSOps->free_querycookie)
|
|
return B_OK;
|
|
return fFSOps->free_querycookie(fVolumeCookie, NULL, cookie);
|
|
}
|
|
|
|
// ReadQuery
|
|
status_t
|
|
BeOSKernelVolume::ReadQuery(fs_cookie cookie, void* buffer, size_t bufferSize,
|
|
uint32 count, uint32* countRead)
|
|
{
|
|
if (!fFSOps->read_query)
|
|
return B_BAD_VALUE;
|
|
|
|
*countRead = count;
|
|
|
|
// Haiku's struct dirent equals BeOS's version
|
|
return fFSOps->read_query(fVolumeCookie, cookie, (long*)countRead,
|
|
(struct beos_dirent*)buffer, bufferSize);
|
|
}
|
|
|
|
|
|
// #pragma mark - Private
|
|
|
|
|
|
// _OpenAttr
|
|
status_t
|
|
BeOSKernelVolume::_OpenAttr(fs_vnode node, const char* name, uint32 type,
|
|
int openMode, bool create, fs_cookie* _cookie)
|
|
{
|
|
// check permissions first
|
|
int accessMode = open_mode_to_access(openMode) | (create ? W_OK : 0);
|
|
status_t error = Access(node, accessMode);
|
|
if (error != B_OK)
|
|
return error;
|
|
|
|
// check whether the attribute already exists
|
|
beos_attr_info attrInfo;
|
|
if (!fFSOps->stat_attr)
|
|
return B_BAD_VALUE;
|
|
bool exists
|
|
= (fFSOps->stat_attr(fVolumeCookie, node, name, &attrInfo) == B_OK);
|
|
|
|
if (create) {
|
|
// create: fail, if attribute exists and non-existence was required
|
|
if (exists && (openMode & O_EXCL))
|
|
return B_FILE_EXISTS;
|
|
} else {
|
|
// open: fail, if attribute doesn't exist
|
|
if (!exists)
|
|
return B_ENTRY_NOT_FOUND;
|
|
|
|
// keep the attribute type
|
|
type = attrInfo.type;
|
|
}
|
|
|
|
// create an attribute cookie
|
|
AttributeCookie* cookie = new(nothrow) AttributeCookie(name, type,
|
|
openMode, exists, create);
|
|
if (!cookie)
|
|
return B_NO_MEMORY;
|
|
|
|
// TODO: If we want to support O_TRUNC, we should do that here.
|
|
|
|
*_cookie = cookie;
|
|
return B_OK;
|
|
}
|
|
|
|
// open_mode_to_access
|
|
static int
|
|
open_mode_to_access(int openMode)
|
|
{
|
|
switch (openMode & O_RWMASK) {
|
|
case O_RDONLY:
|
|
return R_OK;
|
|
case O_WRONLY:
|
|
return W_OK;
|
|
case O_RDWR:
|
|
default:
|
|
return W_OK | R_OK;
|
|
}
|
|
}
|
|
|