Implemented the new attribute open/close/... FS hooks. The mapping to the

old interface is completely done in userland ATM.

It becomes more and more obvious that we probably need to provide
the kernel add-on with a bit more information about what the client FS
interface supports in the first place, so we can save unnecessary trips to
the userland. Opening/closing attributes for a FS using the old style
interface could be handled completely in the kernel add-on, for instance
(even if we lose a bit of accuracy wrt to open modes etc.).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20258 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2007-03-01 01:16:13 +00:00
parent 9ce869f45f
commit 617ed3e4a9
12 changed files with 754 additions and 30 deletions
@@ -122,6 +122,14 @@ enum {
REWIND_ATTR_DIR_REPLY,
// attributes
CREATE_ATTR_REQUEST,
CREATE_ATTR_REPLY,
OPEN_ATTR_REQUEST,
OPEN_ATTR_REPLY,
CLOSE_ATTR_REQUEST,
CLOSE_ATTR_REPLY,
FREE_ATTR_COOKIE_REQUEST,
FREE_ATTR_COOKIE_REPLY,
READ_ATTR_REQUEST,
READ_ATTR_REPLY,
WRITE_ATTR_REQUEST,
@@ -960,6 +968,67 @@ public:
// #pragma mark - attributes
// CreateAttrRequest
class CreateAttrRequest : public NodeRequest {
public:
CreateAttrRequest() : NodeRequest(CREATE_ATTR_REQUEST) {}
status_t GetAddressInfos(AddressInfo* infos, int32* count);
Address name;
uint32 type;
int openMode;
};
// CreateAttrReply
class CreateAttrReply : public ReplyRequest {
public:
CreateAttrReply() : ReplyRequest(CREATE_ATTR_REPLY) {}
fs_cookie attrCookie;
};
// OpenAttrRequest
class OpenAttrRequest : public NodeRequest {
public:
OpenAttrRequest() : NodeRequest(OPEN_ATTR_REQUEST) {}
status_t GetAddressInfos(AddressInfo* infos, int32* count);
Address name;
int openMode;
};
// OpenAttrReply
class OpenAttrReply : public ReplyRequest {
public:
OpenAttrReply() : ReplyRequest(OPEN_ATTR_REPLY) {}
fs_cookie attrCookie;
};
// CloseAttrRequest
class CloseAttrRequest : public AttributeRequest {
public:
CloseAttrRequest() : AttributeRequest(CLOSE_ATTR_REQUEST) {}
};
// CloseAttrReply
class CloseAttrReply : public ReplyRequest {
public:
CloseAttrReply() : ReplyRequest(CLOSE_ATTR_REPLY) {}
};
// FreeAttrCookieRequest
class FreeAttrCookieRequest : public AttributeRequest {
public:
FreeAttrCookieRequest() : AttributeRequest(FREE_ATTR_COOKIE_REQUEST) {}
};
// FreeAttrCookieReply
class FreeAttrCookieReply : public ReplyRequest {
public:
FreeAttrCookieReply() : ReplyRequest(FREE_ATTR_COOKIE_REPLY) {}
};
// ReadAttrRequest
class ReadAttrRequest : public AttributeRequest {
public:
@@ -1605,6 +1674,22 @@ do_for_request(Request* request, Task& task)
case REWIND_ATTR_DIR_REPLY:
return task((RewindAttrDirReply*)request);
// attributes
case CREATE_ATTR_REQUEST:
return task((CreateAttrRequest*)request);
case CREATE_ATTR_REPLY:
return task((CreateAttrReply*)request);
case OPEN_ATTR_REQUEST:
return task((OpenAttrRequest*)request);
case OPEN_ATTR_REPLY:
return task((OpenAttrReply*)request);
case CLOSE_ATTR_REQUEST:
return task((CloseAttrRequest*)request);
case CLOSE_ATTR_REPLY:
return task((CloseAttrReply*)request);
case FREE_ATTR_COOKIE_REQUEST:
return task((FreeAttrCookieRequest*)request);
case FREE_ATTR_COOKIE_REPLY:
return task((FreeAttrCookieReply*)request);
case READ_ATTR_REQUEST:
return task((ReadAttrRequest*)request);
case READ_ATTR_REPLY:
@@ -1834,6 +1919,14 @@ using UserlandFSUtil::ReadAttrDirReply;
using UserlandFSUtil::RewindAttrDirRequest;
using UserlandFSUtil::RewindAttrDirReply;
// attributes
using UserlandFSUtil::CreateAttrRequest;
using UserlandFSUtil::CreateAttrReply;
using UserlandFSUtil::OpenAttrRequest;
using UserlandFSUtil::OpenAttrReply;
using UserlandFSUtil::CloseAttrRequest;
using UserlandFSUtil::CloseAttrReply;
using UserlandFSUtil::FreeAttrCookieRequest;
using UserlandFSUtil::FreeAttrCookieReply;
using UserlandFSUtil::ReadAttrRequest;
using UserlandFSUtil::ReadAttrReply;
using UserlandFSUtil::WriteAttrRequest;
@@ -32,6 +32,7 @@ enum {
USERLAND_IOCTL_OPEN_FILES,
USERLAND_IOCTL_OPEN_DIRECTORIES,
USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES,
USERLAND_IOCTL_OPEN_ATTRIBUTES,
USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES,
USERLAND_IOCTL_OPEN_QUERIES,
};
@@ -74,6 +74,7 @@ Volume::Volume(FileSystem* fileSystem, mount_id id)
fOpenFiles(0),
fOpenDirectories(0),
fOpenAttributeDirectories(0),
fOpenAttributes(0),
fOpenIndexDirectories(0),
fOpenQueries(0),
fVNodeCountMap(NULL),
@@ -1097,6 +1098,7 @@ Volume::Create(fs_vnode dir, const char* name, int openMode, int mode,
if (!port)
return B_ERROR;
PortReleaser _(fFileSystem->GetPortPool(), port);
AutoIncrementer incrementer(&fOpenFiles);
// prepare the request
RequestAllocator allocator(port->GetPort());
@@ -1124,6 +1126,7 @@ Volume::Create(fs_vnode dir, const char* name, int openMode, int mode,
// process the reply
if (reply->error != B_OK)
return reply->error;
incrementer.Keep();
*vnid = reply->vnid;
*cookie = reply->fileCookie;
// The VFS will balance the new_vnode() call for the FS.
@@ -1197,6 +1200,7 @@ Volume::FreeCookie(fs_vnode node, fs_cookie cookie)
error = B_OK;
disconnected = true;
}
int32 openFiles = atomic_add(&fOpenFiles, -1);
if (openFiles <= 1 && disconnected)
_PutAllPendingVNodes();
@@ -1710,6 +1714,126 @@ Volume::RewindAttrDir(fs_vnode node, fs_cookie cookie)
// #pragma mark - attributes
// CreateAttr
status_t
Volume::CreateAttr(fs_vnode node, const char* name, uint32 type, int openMode,
fs_cookie* cookie)
{
// get a free port
RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
if (!port)
return B_ERROR;
PortReleaser _(fFileSystem->GetPortPool(), port);
AutoIncrementer incrementer(&fOpenAttributes);
// prepare the request
RequestAllocator allocator(port->GetPort());
CreateAttrRequest* request;
status_t error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
request->volume = fUserlandVolume;
request->node = node;
error = allocator.AllocateString(request->name, name);
request->type = type;
request->openMode = openMode;
if (error != B_OK)
return error;
// send the request
KernelRequestHandler handler(this, CREATE_ATTR_REPLY);
CreateAttrReply* reply;
error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
if (error != B_OK)
return error;
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK)
return reply->error;
incrementer.Keep();
*cookie = reply->attrCookie;
return error;
}
// OpenAttr
status_t
Volume::OpenAttr(fs_vnode node, const char* name, int openMode,
fs_cookie* cookie)
{
// get a free port
RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
if (!port)
return B_ERROR;
PortReleaser _(fFileSystem->GetPortPool(), port);
AutoIncrementer incrementer(&fOpenAttributes);
// prepare the request
RequestAllocator allocator(port->GetPort());
OpenAttrRequest* request;
status_t error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
request->volume = fUserlandVolume;
request->node = node;
error = allocator.AllocateString(request->name, name);
request->openMode = openMode;
if (error != B_OK)
return error;
// send the request
KernelRequestHandler handler(this, OPEN_ATTR_REPLY);
OpenAttrReply* reply;
error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
if (error != B_OK)
return error;
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK)
return reply->error;
incrementer.Keep();
*cookie = reply->attrCookie;
return error;
}
// CloseAttr
status_t
Volume::CloseAttr(fs_vnode node, fs_cookie cookie)
{
status_t error = _CloseAttr(node, cookie);
if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
// This isn't really necessary, as the return value is irrelevant to
// the VFS. OBOS ignores it completely. The fsshell returns it to the
// userland, but considers the node closed anyway.
WARN(("Volume::CloseAttr(): connection lost, forcing close attr\n"));
return B_OK;
}
return error;
}
// FreeAttrCookie
status_t
Volume::FreeAttrCookie(fs_vnode node, fs_cookie cookie)
{
status_t error = _FreeAttrCookie(node, cookie);
bool disconnected = false;
if (error != B_OK && fFileSystem->GetPortPool()->IsDisconnected()) {
// This isn't really necessary, as the return value is irrelevant to
// the VFS. It's completely ignored by OBOS as well as by the fsshell.
WARN(("Volume::FreeAttrCookie(): connection lost, forcing free attr "
"cookie\n"));
error = B_OK;
disconnected = true;
}
int32 openAttributes = atomic_add(&fOpenAttributes, -1);
if (openAttributes <= 1 && disconnected)
_PutAllPendingVNodes();
return error;
}
// ReadAttr
status_t
@@ -2708,6 +2832,76 @@ Volume::_FreeAttrDirCookie(fs_vnode node, fs_cookie cookie)
return error;
}
// _CloseAttr
status_t
Volume::_CloseAttr(fs_vnode node, fs_cookie cookie)
{
// get a free port
RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
if (!port)
return B_ERROR;
PortReleaser _(fFileSystem->GetPortPool(), port);
// prepare the request
RequestAllocator allocator(port->GetPort());
CloseAttrRequest* request;
status_t error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
request->volume = fUserlandVolume;
request->node = node;
request->attrCookie = cookie;
// send the request
KernelRequestHandler handler(this, CLOSE_ATTR_REPLY);
CloseAttrReply* reply;
error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
if (error != B_OK)
return error;
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK)
return reply->error;
return error;
}
// _FreeAttrCookie
status_t
Volume::_FreeAttrCookie(fs_vnode node, fs_cookie cookie)
{
// get a free port
RequestPort* port = fFileSystem->GetPortPool()->AcquirePort();
if (!port)
return B_ERROR;
PortReleaser _(fFileSystem->GetPortPool(), port);
// prepare the request
RequestAllocator allocator(port->GetPort());
FreeAttrCookieRequest* request;
status_t error = AllocateRequest(allocator, &request);
if (error != B_OK)
return error;
request->volume = fUserlandVolume;
request->node = node;
request->attrCookie = cookie;
// send the request
KernelRequestHandler handler(this, FREE_ATTR_COOKIE_REPLY);
FreeAttrCookieReply* reply;
error = _SendRequest(port, &allocator, &handler, (Request**)&reply);
if (error != B_OK)
return error;
RequestReleaser requestReleaser(port, reply);
// process the reply
if (reply->error != B_OK)
return reply->error;
return error;
}
// _CloseIndexDir
status_t
Volume::_CloseIndexDir(fs_cookie cookie)
@@ -2982,6 +3176,10 @@ PRINT(("Volume::_PutAllPendingVNodes()\n"));
PRINT(("Volume::_PutAllPendingVNodes() failed: open attr dirs\n"));
return USERLAND_IOCTL_OPEN_ATTRIBUTE_DIRECTORIES;
}
if (fOpenAttributes > 0) {
PRINT(("Volume::_PutAllPendingVNodes() failed: open attributes\n"));
return USERLAND_IOCTL_OPEN_ATTRIBUTES;
}
if (fOpenIndexDirectories > 0) {
PRINT(("Volume::_PutAllPendingVNodes() failed: open index dirs\n"));
return USERLAND_IOCTL_OPEN_INDEX_DIRECTORIES;
@@ -125,6 +125,13 @@ public:
status_t RewindAttrDir(fs_vnode node, fs_cookie cookie);
// attributes
status_t CreateAttr(fs_vnode node, const char* name,
uint32 type, int openMode,
fs_cookie* cookie);
status_t OpenAttr(fs_vnode node, const char* name,
int openMode, fs_cookie* cookie);
status_t CloseAttr(fs_vnode node, fs_cookie cookie);
status_t FreeAttrCookie(fs_vnode node, fs_cookie cookie);
status_t ReadAttr(fs_vnode node, fs_cookie cookie,
off_t pos, void* buffer, size_t bufferSize,
size_t* bytesRead);
@@ -176,6 +183,9 @@ private:
status_t _CloseAttrDir(fs_vnode node, fs_cookie cookie);
status_t _FreeAttrDirCookie(fs_vnode node,
fs_cookie cookie);
status_t _CloseAttr(fs_vnode node, fs_cookie cookie);
status_t _FreeAttrCookie(fs_vnode node,
fs_cookie cookie);
status_t _CloseIndexDir(fs_cookie cookie);
status_t _FreeIndexDirCookie(fs_cookie cookie);
status_t _CloseQuery(fs_cookie cookie);
@@ -208,6 +218,7 @@ private:
vint32 fOpenFiles;
vint32 fOpenDirectories;
vint32 fOpenAttributeDirectories;
vint32 fOpenAttributes;
vint32 fOpenIndexDirectories;
vint32 fOpenQueries;
VNodeCountMap* fVNodeCountMap;
@@ -629,10 +629,53 @@ userlandfs_rewind_attr_dir(fs_volume fs, fs_vnode node, fs_cookie cookie)
// #pragma mark - attributes
// TODO: create_attr()
// TODO: open_attr()
// TODO: close_attr()
// TODO: free_attr_cookie()
// userlandfs_create_attr
status_t
userlandfs_create_attr(fs_volume fs, fs_vnode node, const char *name,
uint32 type, int openMode, fs_cookie *cookie)
{
Volume* volume = (Volume*)fs;
PRINT(("userlandfs_create_attr(%p, %p, \"%s\", 0x%lx, %d, %p)\n", fs, node,
name, type, openMode, cookie));
status_t error = volume->CreateAttr(node, name, type, openMode, cookie);
PRINT(("userlandfs_create_attr() done: (%lx, %p)\n", error, *cookie));
return error;
}
// userlandfs_open_attr
status_t
userlandfs_open_attr(fs_volume fs, fs_vnode node, const char *name,
int openMode, fs_cookie *cookie)
{
Volume* volume = (Volume*)fs;
PRINT(("userlandfs_open_attr(%p, %p, \"%s\", %d, %p)\n", fs, node, name,
openMode, cookie));
status_t error = volume->OpenAttr(node, name, openMode, cookie);
PRINT(("userlandfs_open_attr() done: (%lx, %p)\n", error, *cookie));
return error;
}
// userlandfs_close_attr
status_t
userlandfs_close_attr(fs_volume fs, fs_vnode node, fs_cookie cookie)
{
Volume* volume = (Volume*)fs;
PRINT(("userlandfs_close_attr(%p, %p, %p)\n", fs, node, cookie));
status_t error = volume->CloseAttr(node, cookie);
PRINT(("userlandfs_close_attr() done: %lx\n", error));
return error;
}
// userlandfs_free_attr_cookie
status_t
userlandfs_free_attr_cookie(fs_volume fs, fs_vnode node, fs_cookie cookie)
{
Volume* volume = (Volume*)fs;
PRINT(("userlandfs_close_attr(%p, %p, %p)\n", fs, node, cookie));
status_t error = volume->FreeAttrCookie(node, cookie);
PRINT(("userlandfs_close_attr() done: %lx\n", error));
return error;
}
// userlandfs_read_attr
static status_t
@@ -1016,10 +1059,10 @@ static file_system_module_info sUserlandFSModuleInfo = {
&userlandfs_rewind_attr_dir,
/* attribute operations */
NULL, // &userlandfs_create_attr,
NULL, // &userlandfs_open_attr,
NULL, // &userlandfs_close_attr,
NULL, // &userlandfs_free_attr_cookie,
&userlandfs_create_attr,
&userlandfs_open_attr,
&userlandfs_close_attr,
&userlandfs_free_attr_cookie,
&userlandfs_read_attr,
&userlandfs_write_attr,
@@ -175,6 +175,22 @@ ReadAttrDirReply::GetAddressInfos(AddressInfo* infos, int32* count)
return B_OK;
}
// CreateAttrRequest
status_t
CreateAttrRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
return B_OK;
}
// OpenAttrRequest
status_t
OpenAttrRequest::GetAddressInfos(AddressInfo* infos, int32* count)
{
ADD_NON_NULL_STRING(name);
return B_OK;
}
// ReadAttrReply
status_t
ReadAttrReply::GetAddressInfos(AddressInfo* infos, int32* count)
@@ -563,12 +579,21 @@ UserlandFSUtil::is_kernel_request(uint32 type)
case REWIND_ATTR_DIR_REPLY:
return false;
// attributes
case CREATE_ATTR_REQUEST:
case OPEN_ATTR_REQUEST:
case CLOSE_ATTR_REQUEST:
case FREE_ATTR_COOKIE_REQUEST:
case READ_ATTR_REQUEST:
case WRITE_ATTR_REQUEST:
case READ_ATTR_STAT_REQUEST:
case RENAME_ATTR_REQUEST:
case REMOVE_ATTR_REQUEST:
return true;
case CREATE_ATTR_REPLY:
case OPEN_ATTR_REPLY:
case CLOSE_ATTR_REPLY:
case FREE_ATTR_COOKIE_REPLY:
case READ_ATTR_REPLY:
case WRITE_ATTR_REPLY:
case READ_ATTR_STAT_REPLY:
@@ -753,12 +778,20 @@ UserlandFSUtil::is_userland_request(uint32 type)
case REWIND_ATTR_DIR_REPLY:
return true;
// attributes
case CREATE_ATTR_REQUEST:
case OPEN_ATTR_REQUEST:
case CLOSE_ATTR_REQUEST:
case FREE_ATTR_COOKIE_REQUEST:
case READ_ATTR_REQUEST:
case WRITE_ATTR_REQUEST:
case RENAME_ATTR_REQUEST:
case READ_ATTR_STAT_REQUEST:
case REMOVE_ATTR_REQUEST:
return false;
case CREATE_ATTR_REPLY:
case OPEN_ATTR_REPLY:
case CLOSE_ATTR_REPLY:
case FREE_ATTR_COOKIE_REPLY:
case READ_ATTR_REPLY:
case WRITE_ATTR_REPLY:
case READ_ATTR_STAT_REPLY:
@@ -2,9 +2,41 @@
#include "BeOSKernelVolume.h"
#include <new>
#include <fcntl.h>
#include <unistd.h>
#include "beos_fs_interface.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, mount_id id,
beos_vnode_ops* fsOps)
@@ -503,43 +535,106 @@ BeOSKernelVolume::RewindAttrDir(fs_vnode node, fs_cookie 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,
BeOSKernelVolume::ReadAttr(fs_vnode node, fs_cookie _cookie, off_t pos,
void* buffer, size_t bufferSize, size_t* bytesRead)
{
// TODO: Implement!
return B_BAD_VALUE;
// if (!fFSOps->read_attr)
// return B_BAD_VALUE;
// *bytesRead = bufferSize;
// return fFSOps->read_attr(fVolumeCookie, node, name, type, buffer, bytesRead,
// pos);
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,
BeOSKernelVolume::WriteAttr(fs_vnode node, fs_cookie _cookie, off_t pos,
const void* buffer, size_t bufferSize, size_t* bytesWritten)
{
// TODO: Implement!
return B_BAD_VALUE;
// if (!fFSOps->write_attr)
// return B_BAD_VALUE;
// *bytesWritten = bufferSize;
// return fFSOps->write_attr(fVolumeCookie, node, name, type, buffer,
// bytesWritten, pos);
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)
BeOSKernelVolume::ReadAttrStat(fs_vnode node, fs_cookie _cookie,
struct stat *st)
{
// TODO: Implement!
return B_BAD_VALUE;
// if (!fFSOps->stat_attr)
// return B_BAD_VALUE;
// return fFSOps->stat_attr(fVolumeCookie, node, name, attrInfo);
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
@@ -708,3 +803,65 @@ BeOSKernelVolume::ReadQuery(fs_cookie cookie, void* buffer, size_t bufferSize,
(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;
}
}
@@ -98,6 +98,13 @@ public:
virtual status_t RewindAttrDir(fs_vnode node, fs_cookie cookie);
// attributes
virtual status_t CreateAttr(fs_vnode node, const char *name,
uint32 type, int openMode,
fs_cookie *cookie);
virtual status_t OpenAttr(fs_vnode node, const char *name,
int openMode, fs_cookie *cookie);
virtual status_t CloseAttr(fs_vnode node, fs_cookie cookie);
virtual status_t FreeAttrCookie(fs_vnode node, fs_cookie cookie);
virtual status_t ReadAttr(fs_vnode node, fs_cookie cookie,
off_t pos, void* buffer, size_t bufferSize,
size_t* bytesRead);
@@ -135,6 +142,14 @@ public:
size_t bufferSize, uint32 count,
uint32* countRead);
private:
class AttributeCookie;
private:
status_t _OpenAttr(fs_vnode node, const char* name,
uint32 type, int openMode, bool create,
fs_cookie* cookie);
private:
beos_vnode_ops* fFSOps;
void* fVolumeCookie;
@@ -138,6 +138,14 @@ UserlandRequestHandler::HandleRequest(Request* request)
return _HandleRequest((RewindAttrDirRequest*)request);
// attributes
case CREATE_ATTR_REQUEST:
return _HandleRequest((CreateAttrRequest*)request);
case OPEN_ATTR_REQUEST:
return _HandleRequest((OpenAttrRequest*)request);
case CLOSE_ATTR_REQUEST:
return _HandleRequest((CloseAttrRequest*)request);
case FREE_ATTR_COOKIE_REQUEST:
return _HandleRequest((FreeAttrCookieRequest*)request);
case READ_ATTR_REQUEST:
return _HandleRequest((ReadAttrRequest*)request);
case WRITE_ATTR_REQUEST:
@@ -1493,6 +1501,126 @@ UserlandRequestHandler::_HandleRequest(RewindAttrDirRequest* request)
// #pragma mark - attributes
// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(CreateAttrRequest* request)
{
// check and execute the request
status_t result = B_OK;
Volume* volume = (Volume*)request->volume;
if (!volume)
result = B_BAD_VALUE;
fs_cookie attrCookie;
if (result == B_OK) {
RequestThreadContext context(volume);
result = volume->CreateAttr(request->node,
(const char*)request->name.GetData(), request->type,
request->openMode, &attrCookie);
}
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
CreateAttrReply* reply;
status_t error = AllocateRequest(allocator, &reply);
if (error != B_OK)
RETURN_ERROR(error);
reply->error = result;
reply->attrCookie = attrCookie;
// send the reply
return _SendReply(allocator, false);
}
// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(OpenAttrRequest* request)
{
// check and execute the request
status_t result = B_OK;
Volume* volume = (Volume*)request->volume;
if (!volume)
result = B_BAD_VALUE;
fs_cookie attrCookie;
if (result == B_OK) {
RequestThreadContext context(volume);
result = volume->OpenAttr(request->node,
(const char*)request->name.GetData(), request->openMode,
&attrCookie);
}
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
OpenAttrReply* reply;
status_t error = AllocateRequest(allocator, &reply);
if (error != B_OK)
RETURN_ERROR(error);
reply->error = result;
reply->attrCookie = attrCookie;
// send the reply
return _SendReply(allocator, false);
}
// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(CloseAttrRequest* request)
{
// check and execute the request
status_t result = B_OK;
Volume* volume = (Volume*)request->volume;
if (!volume)
result = B_BAD_VALUE;
if (result == B_OK) {
RequestThreadContext context(volume);
result = volume->CloseAttr(request->node, request->attrCookie);
}
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
CloseAttrReply* reply;
status_t error = AllocateRequest(allocator, &reply);
if (error != B_OK)
RETURN_ERROR(error);
reply->error = result;
// send the reply
return _SendReply(allocator, false);
}
// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(FreeAttrCookieRequest* request)
{
// check and execute the request
status_t result = B_OK;
Volume* volume = (Volume*)request->volume;
if (!volume)
result = B_BAD_VALUE;
if (result == B_OK) {
RequestThreadContext context(volume);
result = volume->FreeAttrCookie(request->node, request->attrCookie);
}
// prepare the reply
RequestAllocator allocator(fPort->GetPort());
FreeAttrCookieReply* reply;
status_t error = AllocateRequest(allocator, &reply);
if (error != B_OK)
RETURN_ERROR(error);
reply->error = result;
// send the reply
return _SendReply(allocator, false);
}
// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(ReadAttrRequest* request)
@@ -54,6 +54,10 @@ class FreeAttrDirCookieRequest;
class ReadAttrDirRequest;
class RewindAttrDirRequest;
// attributes
class CreateAttrRequest;
class OpenAttrRequest;
class CloseAttrRequest;
class FreeAttrCookieRequest;
class ReadAttrRequest;
class WriteAttrRequest;
class ReadAttrStatRequest;
@@ -148,6 +152,10 @@ private:
status_t _HandleRequest(RewindAttrDirRequest* request);
// attributes
status_t _HandleRequest(CreateAttrRequest* request);
status_t _HandleRequest(OpenAttrRequest* request);
status_t _HandleRequest(CloseAttrRequest* request);
status_t _HandleRequest(FreeAttrCookieRequest* request);
status_t _HandleRequest(ReadAttrRequest* request);
status_t _HandleRequest(WriteAttrRequest* request);
status_t _HandleRequest(ReadAttrStatRequest* request);
@@ -347,6 +347,36 @@ Volume::RewindAttrDir(fs_vnode node, fs_cookie cookie)
// #pragma mark - attributes
// CreateAttr
status_t
Volume::CreateAttr(fs_vnode node, const char* name, uint32 type, int openMode,
fs_cookie* cookie)
{
return B_BAD_VALUE;
}
// OpenAttr
status_t
Volume::OpenAttr(fs_vnode node, const char* name, int openMode,
fs_cookie* cookie)
{
return B_BAD_VALUE;
}
// CloseAttr
status_t
Volume::CloseAttr(fs_vnode node, fs_cookie cookie)
{
return B_BAD_VALUE;
}
// FreeAttrCookie
status_t
Volume::FreeAttrCookie(fs_vnode node, fs_cookie cookie)
{
return B_BAD_VALUE;
}
// ReadAttr
status_t
Volume::ReadAttr(fs_vnode node, fs_cookie cookie, off_t pos, void* buffer,
@@ -101,6 +101,13 @@ public:
virtual status_t RewindAttrDir(fs_vnode node, fs_cookie cookie);
// attributes
virtual status_t CreateAttr(fs_vnode node, const char* name,
uint32 type, int openMode,
fs_cookie* cookie);
virtual status_t OpenAttr(fs_vnode node, const char* name,
int openMode, fs_cookie* cookie);
virtual status_t CloseAttr(fs_vnode node, fs_cookie cookie);
virtual status_t FreeAttrCookie(fs_vnode node, fs_cookie cookie);
virtual status_t ReadAttr(fs_vnode node, fs_cookie cookie,
off_t pos, void* buffer, size_t bufferSize,
size_t* bytesRead);