The last missing hooks -- get_vnode_name(), write_attr_stat() and
rewind_query() -- are passed to the userland. get_vnode_name() has an emulation in userland, in case the client FS doesn't implement it. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20522 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -43,6 +43,8 @@ enum {
|
||||
// vnodes
|
||||
LOOKUP_REQUEST,
|
||||
LOOKUP_REPLY,
|
||||
GET_VNODE_NAME_REQUEST,
|
||||
GET_VNODE_NAME_REPLY,
|
||||
READ_VNODE_REQUEST,
|
||||
READ_VNODE_REPLY,
|
||||
WRITE_VNODE_REQUEST,
|
||||
@@ -137,6 +139,8 @@ enum {
|
||||
WRITE_ATTR_REPLY,
|
||||
READ_ATTR_STAT_REQUEST,
|
||||
READ_ATTR_STAT_REPLY,
|
||||
WRITE_ATTR_STAT_REQUEST,
|
||||
WRITE_ATTR_STAT_REPLY,
|
||||
RENAME_ATTR_REQUEST,
|
||||
RENAME_ATTR_REPLY,
|
||||
REMOVE_ATTR_REQUEST,
|
||||
@@ -169,6 +173,8 @@ enum {
|
||||
FREE_QUERY_COOKIE_REPLY,
|
||||
READ_QUERY_REQUEST,
|
||||
READ_QUERY_REPLY,
|
||||
REWIND_QUERY_REQUEST,
|
||||
REWIND_QUERY_REPLY,
|
||||
|
||||
// userland -> kernel requests
|
||||
// notifications
|
||||
@@ -428,6 +434,23 @@ public:
|
||||
int type;
|
||||
};
|
||||
|
||||
// GetVNodeNameRequest
|
||||
class GetVNodeNameRequest : public NodeRequest {
|
||||
public:
|
||||
GetVNodeNameRequest() : NodeRequest(GET_VNODE_NAME_REQUEST) {}
|
||||
|
||||
size_t size;
|
||||
};
|
||||
|
||||
// GetVNodeNameReply
|
||||
class GetVNodeNameReply : public ReplyRequest {
|
||||
public:
|
||||
GetVNodeNameReply() : ReplyRequest(GET_VNODE_NAME_REPLY) {}
|
||||
status_t GetAddressInfos(AddressInfo* infos, int32* count);
|
||||
|
||||
Address buffer;
|
||||
};
|
||||
|
||||
// ReadVNodeRequest
|
||||
class ReadVNodeRequest : public VolumeRequest {
|
||||
public:
|
||||
@@ -1085,6 +1108,21 @@ public:
|
||||
struct stat st;
|
||||
};
|
||||
|
||||
// WriteAttrStatRequest
|
||||
class WriteAttrStatRequest : public AttributeRequest {
|
||||
public:
|
||||
WriteAttrStatRequest() : AttributeRequest(WRITE_ATTR_STAT_REQUEST) {}
|
||||
|
||||
struct stat st;
|
||||
uint32 mask;
|
||||
};
|
||||
|
||||
// WriteAttrStatReply
|
||||
class WriteAttrStatReply : public ReplyRequest {
|
||||
public:
|
||||
WriteAttrStatReply() : ReplyRequest(WRITE_ATTR_STAT_REPLY) {}
|
||||
};
|
||||
|
||||
// RenameAttrRequest
|
||||
class RenameAttrRequest : public VolumeRequest {
|
||||
public:
|
||||
@@ -1308,6 +1346,18 @@ public:
|
||||
Address buffer;
|
||||
};
|
||||
|
||||
// RewindQueryRequest
|
||||
class RewindQueryRequest : public QueryRequest {
|
||||
public:
|
||||
RewindQueryRequest() : QueryRequest(REWIND_QUERY_REQUEST) {}
|
||||
};
|
||||
|
||||
// RewindQueryReply
|
||||
class RewindQueryReply : public ReplyRequest {
|
||||
public:
|
||||
RewindQueryReply() : ReplyRequest(REWIND_QUERY_REPLY) {}
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- userland requests -----
|
||||
@@ -1552,6 +1602,10 @@ do_for_request(Request* request, Task& task)
|
||||
return task((LookupRequest*)request);
|
||||
case LOOKUP_REPLY:
|
||||
return task((LookupReply*)request);
|
||||
case GET_VNODE_NAME_REQUEST:
|
||||
return task((GetVNodeNameRequest*)request);
|
||||
case GET_VNODE_NAME_REPLY:
|
||||
return task((GetVNodeNameReply*)request);
|
||||
case READ_VNODE_REQUEST:
|
||||
return task((ReadVNodeRequest*)request);
|
||||
case READ_VNODE_REPLY:
|
||||
@@ -1721,6 +1775,10 @@ do_for_request(Request* request, Task& task)
|
||||
return task((ReadAttrStatRequest*)request);
|
||||
case READ_ATTR_STAT_REPLY:
|
||||
return task((ReadAttrStatReply*)request);
|
||||
case WRITE_ATTR_STAT_REQUEST:
|
||||
return task((WriteAttrStatRequest*)request);
|
||||
case WRITE_ATTR_STAT_REPLY:
|
||||
return task((WriteAttrStatReply*)request);
|
||||
case RENAME_ATTR_REQUEST:
|
||||
return task((RenameAttrRequest*)request);
|
||||
case RENAME_ATTR_REPLY:
|
||||
@@ -1779,6 +1837,10 @@ do_for_request(Request* request, Task& task)
|
||||
return task((ReadQueryRequest*)request);
|
||||
case READ_QUERY_REPLY:
|
||||
return task((ReadQueryReply*)request);
|
||||
case REWIND_QUERY_REQUEST:
|
||||
return task((RewindQueryRequest*)request);
|
||||
case REWIND_QUERY_REPLY:
|
||||
return task((RewindQueryReply*)request);
|
||||
|
||||
// userland -> kernel requests
|
||||
// notifications
|
||||
@@ -1869,6 +1931,8 @@ using UserlandFSUtil::WriteFSInfoReply;
|
||||
// vnodes
|
||||
using UserlandFSUtil::LookupRequest;
|
||||
using UserlandFSUtil::LookupReply;
|
||||
using UserlandFSUtil::GetVNodeNameRequest;
|
||||
using UserlandFSUtil::GetVNodeNameReply;
|
||||
using UserlandFSUtil::ReadVNodeRequest;
|
||||
using UserlandFSUtil::ReadVNodeReply;
|
||||
using UserlandFSUtil::WriteVNodeRequest;
|
||||
@@ -1956,6 +2020,8 @@ using UserlandFSUtil::WriteAttrRequest;
|
||||
using UserlandFSUtil::WriteAttrReply;
|
||||
using UserlandFSUtil::ReadAttrStatRequest;
|
||||
using UserlandFSUtil::ReadAttrStatReply;
|
||||
using UserlandFSUtil::WriteAttrStatRequest;
|
||||
using UserlandFSUtil::WriteAttrStatReply;
|
||||
using UserlandFSUtil::RenameAttrRequest;
|
||||
using UserlandFSUtil::RenameAttrReply;
|
||||
using UserlandFSUtil::RemoveAttrRequest;
|
||||
@@ -1986,6 +2052,8 @@ using UserlandFSUtil::FreeQueryCookieRequest;
|
||||
using UserlandFSUtil::FreeQueryCookieReply;
|
||||
using UserlandFSUtil::ReadQueryRequest;
|
||||
using UserlandFSUtil::ReadQueryReply;
|
||||
using UserlandFSUtil::RewindQueryRequest;
|
||||
using UserlandFSUtil::RewindQueryReply;
|
||||
|
||||
// userland -> kernel requests
|
||||
// notifications
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// Volume.cpp
|
||||
|
||||
#include "Volume.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -16,7 +19,6 @@
|
||||
#include "RequestPort.h"
|
||||
#include "Requests.h"
|
||||
#include "userlandfs_ioctl.h"
|
||||
#include "Volume.h"
|
||||
|
||||
// missing ioctl()s
|
||||
// TODO: Place somewhere else.
|
||||
@@ -402,6 +404,55 @@ Volume::Lookup(fs_vnode dir, const char* entryName, vnode_id* vnid, int* type)
|
||||
return error;
|
||||
}
|
||||
|
||||
// GetVNodeName
|
||||
status_t
|
||||
Volume::GetVNodeName(fs_vnode node, char* buffer, size_t bufferSize)
|
||||
{
|
||||
// We don't check the capability -- if not implemented by the client FS,
|
||||
// the functionality is emulated in userland.
|
||||
|
||||
// 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());
|
||||
GetVNodeNameRequest* request;
|
||||
status_t error = AllocateRequest(allocator, &request);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
request->volume = fUserlandVolume;
|
||||
request->node = node;
|
||||
request->size = bufferSize;
|
||||
|
||||
// send the request
|
||||
KernelRequestHandler handler(this, GET_VNODE_NAME_REPLY);
|
||||
GetVNodeNameReply* 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;
|
||||
|
||||
char* readBuffer = (char*)reply->buffer.GetData();
|
||||
size_t nameLen = reply->buffer.GetSize();
|
||||
nameLen = strnlen(readBuffer, nameLen);
|
||||
if (nameLen <= 1 || nameLen >= bufferSize)
|
||||
RETURN_ERROR(B_BAD_DATA);
|
||||
|
||||
memcpy(buffer, readBuffer, nameLen);
|
||||
buffer[nameLen] = '\0';
|
||||
|
||||
_SendReceiptAck(port);
|
||||
return error;
|
||||
}
|
||||
|
||||
// ReadVNode
|
||||
status_t
|
||||
Volume::ReadVNode(vnode_id vnid, bool reenter, fs_vnode* node)
|
||||
@@ -2099,6 +2150,48 @@ Volume::ReadAttrStat(fs_vnode node, fs_cookie cookie, struct stat *st)
|
||||
return error;
|
||||
}
|
||||
|
||||
// WriteAttrStat
|
||||
status_t
|
||||
Volume::WriteAttrStat(fs_vnode node, fs_cookie cookie, const struct stat *st,
|
||||
int statMask)
|
||||
{
|
||||
// check capability
|
||||
if (!fFileSystem->HasCapability(FS_CAPABILITY_WRITE_ATTR_STAT))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// 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());
|
||||
WriteAttrStatRequest* request;
|
||||
status_t error = AllocateRequest(allocator, &request);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
request->volume = fUserlandVolume;
|
||||
request->node = node;
|
||||
request->attrCookie = cookie;
|
||||
request->st = *st;
|
||||
request->mask = statMask;
|
||||
|
||||
// send the request
|
||||
KernelRequestHandler handler(this, WRITE_ATTR_STAT_REPLY);
|
||||
WriteAttrStatReply* 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;
|
||||
}
|
||||
|
||||
// RenameAttr
|
||||
status_t
|
||||
Volume::RenameAttr(fs_vnode oldNode, const char* oldName, fs_vnode newNode,
|
||||
@@ -2632,6 +2725,44 @@ Volume::ReadQuery(fs_cookie cookie, void* buffer, size_t bufferSize,
|
||||
return error;
|
||||
}
|
||||
|
||||
// RewindQuery
|
||||
status_t
|
||||
Volume::RewindQuery(fs_cookie cookie)
|
||||
{
|
||||
// check capability
|
||||
if (!fFileSystem->HasCapability(FS_CAPABILITY_REWIND_QUERY))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// 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());
|
||||
RewindQueryRequest* request;
|
||||
status_t error = AllocateRequest(allocator, &request);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
request->volume = fUserlandVolume;
|
||||
request->queryCookie = cookie;
|
||||
|
||||
// send the request
|
||||
KernelRequestHandler handler(this, REWIND_QUERY_REPLY);
|
||||
RewindQueryReply* 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;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark ----- private implementations -----
|
||||
|
||||
|
||||
@@ -12,15 +12,18 @@ namespace UserlandFSUtil {
|
||||
class Request;
|
||||
class RequestAllocator;
|
||||
class RequestHandler;
|
||||
class RequestPort;
|
||||
struct userlandfs_ioctl;
|
||||
|
||||
}
|
||||
|
||||
using UserlandFSUtil::Request;
|
||||
using UserlandFSUtil::RequestAllocator;
|
||||
using UserlandFSUtil::RequestHandler;
|
||||
using UserlandFSUtil::RequestPort;
|
||||
using UserlandFSUtil::userlandfs_ioctl;
|
||||
|
||||
class FileSystem;
|
||||
struct userlandfs_ioctl;
|
||||
|
||||
class Volume : public Referencable {
|
||||
public:
|
||||
@@ -55,6 +58,8 @@ public:
|
||||
// vnodes
|
||||
status_t Lookup(fs_vnode dir, const char* entryName,
|
||||
vnode_id* vnid, int* type);
|
||||
status_t GetVNodeName(fs_vnode node, char* buffer,
|
||||
size_t bufferSize);
|
||||
status_t ReadVNode(vnode_id vnid, bool reenter,
|
||||
fs_vnode* node);
|
||||
status_t WriteVNode(fs_vnode node, bool reenter);
|
||||
@@ -141,6 +146,8 @@ public:
|
||||
size_t bufferSize, size_t* bytesWritten);
|
||||
status_t ReadAttrStat(fs_vnode node, fs_cookie cookie,
|
||||
struct stat *st);
|
||||
status_t WriteAttrStat(fs_vnode node, fs_cookie cookie,
|
||||
const struct stat *st, int statMask);
|
||||
status_t RenameAttr(fs_vnode oldNode,
|
||||
const char* oldName, fs_vnode newNode,
|
||||
const char* newName);
|
||||
@@ -169,6 +176,7 @@ public:
|
||||
status_t ReadQuery(fs_cookie cookie, void* buffer,
|
||||
size_t bufferSize, uint32 count,
|
||||
uint32* countRead);
|
||||
status_t RewindQuery(fs_cookie cookie);
|
||||
|
||||
private:
|
||||
status_t _Mount(const char* device, uint32 flags,
|
||||
|
||||
@@ -176,7 +176,19 @@ userlandfs_lookup(fs_volume fs, fs_vnode dir, const char *entryName,
|
||||
return error;
|
||||
}
|
||||
|
||||
// TODO: userlandfs_get_vnode_name()
|
||||
// userlandfs_get_vnode_name
|
||||
static status_t
|
||||
userlandfs_get_vnode_name(fs_volume fs, fs_vnode node, char *buffer,
|
||||
size_t bufferSize)
|
||||
{
|
||||
Volume* volume = (Volume*)fs;
|
||||
PRINT(("userlandfs_get_vnode_name(%p, %p, %p, %lu)\n", fs, node,
|
||||
buffer, bufferSize));
|
||||
status_t error = volume->GetVNodeName(node, buffer, bufferSize);
|
||||
PRINT(("userlandfs_get_vnode_name() done: (%lx, \"%.*s\")\n", error,
|
||||
(int)bufferSize, (error == B_OK ? buffer : NULL)));
|
||||
return error;
|
||||
}
|
||||
|
||||
// userlandfs_get_vnode
|
||||
static status_t
|
||||
@@ -546,7 +558,7 @@ userlandfs_read_dir(fs_volume fs, fs_vnode node, fs_cookie cookie,
|
||||
PRINT(("userlandfs_read_dir() done: (%lx, %lu)\n", error, *count));
|
||||
#if DEBUG
|
||||
dirent* entry = buffer;
|
||||
for (uint32 i = 0; i < *count; i++) {
|
||||
for (uint32 i = 0; error == B_OK && i < *count; i++) {
|
||||
// R5's kernel vsprintf() doesn't seem to know `%.<number>s', so
|
||||
// we need to work around.
|
||||
char name[B_FILE_NAME_LENGTH];
|
||||
@@ -722,14 +734,25 @@ userlandfs_read_attr_stat(fs_volume fs, fs_vnode node, fs_cookie cookie,
|
||||
struct stat *st)
|
||||
{
|
||||
Volume* volume = (Volume*)fs;
|
||||
PRINT(("userlandfs_read_attr_stat(%p, %p, %p', %p)\n", fs, node, cookie,
|
||||
PRINT(("userlandfs_read_attr_stat(%p, %p, %p, %p)\n", fs, node, cookie,
|
||||
st));
|
||||
status_t error = volume->ReadAttrStat(node, cookie, st);
|
||||
PRINT(("userlandfs_read_attr_stat() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// TODO: userlandfs_write_attr_stat
|
||||
// userlandfs_write_attr_stat
|
||||
static status_t
|
||||
userlandfs_write_attr_stat(fs_volume fs, fs_vnode node, fs_cookie cookie,
|
||||
const struct stat *st, int statMask)
|
||||
{
|
||||
Volume* volume = (Volume*)fs;
|
||||
PRINT(("userlandfs_write_attr_stat(%p, %p, %p, %p, 0x%x)\n", fs, node,
|
||||
cookie, st, statMask));
|
||||
status_t error = volume->WriteAttrStat(node, cookie, st, statMask);
|
||||
PRINT(("userlandfs_write_attr_stat() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
// userlandfs_rename_attr
|
||||
static status_t
|
||||
@@ -903,7 +926,7 @@ userlandfs_read_query(fs_volume fs, fs_cookie cookie,
|
||||
count);
|
||||
PRINT(("userlandfs_read_query() done: (%lx, %ld)\n", error, *count));
|
||||
#if DEBUG
|
||||
if (*count > 0) {
|
||||
if (error == B_OK && *count > 0) {
|
||||
// R5's kernel vsprintf() doesn't seem to know `%.<number>s', so
|
||||
// we need to work around.
|
||||
char name[B_FILE_NAME_LENGTH];
|
||||
@@ -919,7 +942,16 @@ userlandfs_read_query(fs_volume fs, fs_cookie cookie,
|
||||
return error;
|
||||
}
|
||||
|
||||
// TODO: userlandfs_rewind_query()
|
||||
// userlandfs_rewind_query
|
||||
static status_t
|
||||
userlandfs_rewind_query(fs_volume fs, fs_cookie cookie)
|
||||
{
|
||||
Volume* volume = (Volume*)fs;
|
||||
PRINT(("userlandfs_rewind_query(%p, %p)\n", fs, cookie));
|
||||
status_t error = volume->RewindQuery(cookie);
|
||||
PRINT(("userlandfs_rewind_query() done: (%lx)\n", error));
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
// userlandfs_initialize
|
||||
@@ -1017,7 +1049,7 @@ static file_system_module_info sUserlandFSModuleInfo = {
|
||||
|
||||
/* vnode operations */
|
||||
&userlandfs_lookup,
|
||||
NULL, // &userlandfs_get_vnode_name,
|
||||
&userlandfs_get_vnode_name,
|
||||
&userlandfs_get_vnode,
|
||||
&userlandfs_put_vnode,
|
||||
&userlandfs_remove_vnode,
|
||||
@@ -1079,7 +1111,7 @@ static file_system_module_info sUserlandFSModuleInfo = {
|
||||
&userlandfs_write_attr,
|
||||
|
||||
&userlandfs_read_attr_stat,
|
||||
NULL, // &userlandfs_write_attr_stat,
|
||||
&userlandfs_write_attr_stat,
|
||||
&userlandfs_rename_attr,
|
||||
&userlandfs_remove_attr,
|
||||
|
||||
@@ -1099,7 +1131,7 @@ static file_system_module_info sUserlandFSModuleInfo = {
|
||||
&userlandfs_close_query,
|
||||
&userlandfs_free_query_cookie,
|
||||
&userlandfs_read_query,
|
||||
NULL, // &userlandfs_rewind_query,
|
||||
&userlandfs_rewind_query
|
||||
};
|
||||
|
||||
module_info *modules[] = {
|
||||
|
||||
@@ -53,6 +53,14 @@ MountVolumeRequest::GetAddressInfos(AddressInfo* infos, int32* count)
|
||||
// return B_OK;
|
||||
//}
|
||||
|
||||
// GetVNodeNameReply
|
||||
status_t
|
||||
GetVNodeNameReply::GetAddressInfos(AddressInfo* infos, int32* count)
|
||||
{
|
||||
ADD_STRING(buffer);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// CreateRequest
|
||||
status_t
|
||||
CreateRequest::GetAddressInfos(AddressInfo* infos, int32* count)
|
||||
@@ -496,11 +504,13 @@ UserlandFSUtil::is_kernel_request(uint32 type)
|
||||
return false;
|
||||
// vnodes
|
||||
case LOOKUP_REQUEST:
|
||||
case GET_VNODE_NAME_REQUEST:
|
||||
case READ_VNODE_REQUEST:
|
||||
case WRITE_VNODE_REQUEST:
|
||||
case FS_REMOVE_VNODE_REQUEST:
|
||||
return true;
|
||||
case LOOKUP_REPLY:
|
||||
case GET_VNODE_NAME_REPLY:
|
||||
case READ_VNODE_REPLY:
|
||||
case WRITE_VNODE_REPLY:
|
||||
case FS_REMOVE_VNODE_REPLY:
|
||||
@@ -587,6 +597,7 @@ UserlandFSUtil::is_kernel_request(uint32 type)
|
||||
case READ_ATTR_REQUEST:
|
||||
case WRITE_ATTR_REQUEST:
|
||||
case READ_ATTR_STAT_REQUEST:
|
||||
case WRITE_ATTR_STAT_REQUEST:
|
||||
case RENAME_ATTR_REQUEST:
|
||||
case REMOVE_ATTR_REQUEST:
|
||||
return true;
|
||||
@@ -594,10 +605,10 @@ UserlandFSUtil::is_kernel_request(uint32 type)
|
||||
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:
|
||||
case WRITE_ATTR_STAT_REPLY:
|
||||
case RENAME_ATTR_REPLY:
|
||||
case REMOVE_ATTR_REPLY:
|
||||
return false;
|
||||
@@ -625,11 +636,13 @@ UserlandFSUtil::is_kernel_request(uint32 type)
|
||||
case CLOSE_QUERY_REQUEST:
|
||||
case FREE_QUERY_COOKIE_REQUEST:
|
||||
case READ_QUERY_REQUEST:
|
||||
case REWIND_QUERY_REQUEST:
|
||||
return true;
|
||||
case OPEN_QUERY_REPLY:
|
||||
case CLOSE_QUERY_REPLY:
|
||||
case FREE_QUERY_COOKIE_REPLY:
|
||||
case READ_QUERY_REPLY:
|
||||
case REWIND_QUERY_REPLY:
|
||||
return false;
|
||||
|
||||
// userland -> kernel requests
|
||||
@@ -697,11 +710,13 @@ UserlandFSUtil::is_userland_request(uint32 type)
|
||||
return true;
|
||||
// vnodes
|
||||
case LOOKUP_REQUEST:
|
||||
case GET_VNODE_NAME_REQUEST:
|
||||
case READ_VNODE_REQUEST:
|
||||
case WRITE_VNODE_REQUEST:
|
||||
case FS_REMOVE_VNODE_REQUEST:
|
||||
return false;
|
||||
case LOOKUP_REPLY:
|
||||
case GET_VNODE_NAME_REPLY:
|
||||
case READ_VNODE_REPLY:
|
||||
case WRITE_VNODE_REPLY:
|
||||
case FS_REMOVE_VNODE_REPLY:
|
||||
@@ -789,6 +804,7 @@ UserlandFSUtil::is_userland_request(uint32 type)
|
||||
case WRITE_ATTR_REQUEST:
|
||||
case RENAME_ATTR_REQUEST:
|
||||
case READ_ATTR_STAT_REQUEST:
|
||||
case WRITE_ATTR_STAT_REQUEST:
|
||||
case REMOVE_ATTR_REQUEST:
|
||||
return false;
|
||||
case CREATE_ATTR_REPLY:
|
||||
@@ -798,6 +814,7 @@ UserlandFSUtil::is_userland_request(uint32 type)
|
||||
case READ_ATTR_REPLY:
|
||||
case WRITE_ATTR_REPLY:
|
||||
case READ_ATTR_STAT_REPLY:
|
||||
case WRITE_ATTR_STAT_REPLY:
|
||||
case RENAME_ATTR_REPLY:
|
||||
case REMOVE_ATTR_REPLY:
|
||||
return true;
|
||||
@@ -825,11 +842,13 @@ UserlandFSUtil::is_userland_request(uint32 type)
|
||||
case CLOSE_QUERY_REQUEST:
|
||||
case FREE_QUERY_COOKIE_REQUEST:
|
||||
case READ_QUERY_REQUEST:
|
||||
case REWIND_QUERY_REQUEST:
|
||||
return false;
|
||||
case OPEN_QUERY_REPLY:
|
||||
case CLOSE_QUERY_REPLY:
|
||||
case FREE_QUERY_COOKIE_REPLY:
|
||||
case READ_QUERY_REPLY:
|
||||
case REWIND_QUERY_REPLY:
|
||||
return true;
|
||||
|
||||
// userland -> kernel requests
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// SingleReplyRequestHandler.cpp
|
||||
|
||||
#include "SingleReplyRequestHandler.h"
|
||||
|
||||
#include "Compatibility.h"
|
||||
#include "Debug.h"
|
||||
#include "Request.h"
|
||||
#include "SingleReplyRequestHandler.h"
|
||||
|
||||
// constructor
|
||||
SingleReplyRequestHandler::SingleReplyRequestHandler()
|
||||
|
||||
@@ -157,6 +157,16 @@ BeOSKernelVolume::Lookup(fs_vnode dir, const char* entryName, vnode_id* vnid,
|
||||
return error;
|
||||
}
|
||||
|
||||
// LookupNoType
|
||||
status_t
|
||||
BeOSKernelVolume::LookupNoType(fs_vnode dir, const char* entryName,
|
||||
vnode_id* vnid)
|
||||
{
|
||||
if (!fFSOps->walk)
|
||||
return B_BAD_VALUE;
|
||||
return fFSOps->walk(fVolumeCookie, dir, entryName, NULL, vnid);
|
||||
}
|
||||
|
||||
// ReadVNode
|
||||
status_t
|
||||
BeOSKernelVolume::ReadVNode(vnode_id vnid, bool reenter, fs_vnode* node)
|
||||
|
||||
@@ -27,6 +27,9 @@ public:
|
||||
// vnodes
|
||||
virtual status_t Lookup(fs_vnode dir, const char* entryName,
|
||||
vnode_id* vnid, int* type);
|
||||
virtual status_t LookupNoType(fs_vnode dir,
|
||||
const char* entryName, vnode_id* vnid);
|
||||
// not required
|
||||
virtual status_t ReadVNode(vnode_id vnid, bool reenter,
|
||||
fs_vnode* node);
|
||||
virtual status_t WriteVNode(fs_vnode node, bool reenter);
|
||||
|
||||
@@ -126,6 +126,17 @@ HaikuKernelVolume::Lookup(fs_vnode dir, const char* entryName, vnode_id* vnid,
|
||||
return fFSModule->lookup(fVolumeCookie, dir, entryName, vnid, type);
|
||||
}
|
||||
|
||||
// GetVNodeName
|
||||
status_t
|
||||
HaikuKernelVolume::GetVNodeName(fs_vnode node, char* buffer, size_t bufferSize)
|
||||
{
|
||||
// If not implemented by the client file system, we invoke our super class
|
||||
// version, which emulates the functionality.
|
||||
if (!fFSModule->get_vnode_name)
|
||||
return Volume::GetVNodeName(node, buffer, bufferSize);
|
||||
return fFSModule->get_vnode_name(fVolumeCookie, node, buffer, bufferSize);
|
||||
}
|
||||
|
||||
// ReadVNode
|
||||
status_t
|
||||
HaikuKernelVolume::ReadVNode(vnode_id vnid, bool reenter, fs_vnode* node)
|
||||
@@ -563,6 +574,17 @@ HaikuKernelVolume::ReadAttrStat(fs_vnode node, fs_cookie cookie,
|
||||
return fFSModule->read_attr_stat(fVolumeCookie, node, cookie, st);
|
||||
}
|
||||
|
||||
// WriteAttrStat
|
||||
status_t
|
||||
HaikuKernelVolume::WriteAttrStat(fs_vnode node, fs_cookie cookie,
|
||||
const struct stat* st, int statMask)
|
||||
{
|
||||
if (!fFSModule->write_attr_stat)
|
||||
return B_BAD_VALUE;
|
||||
return fFSModule->write_attr_stat(fVolumeCookie, node, cookie, st,
|
||||
statMask);
|
||||
}
|
||||
|
||||
// RenameAttr
|
||||
status_t
|
||||
HaikuKernelVolume::RenameAttr(fs_vnode oldNode, const char* oldName,
|
||||
@@ -710,3 +732,13 @@ HaikuKernelVolume::ReadQuery(fs_cookie cookie, void* buffer, size_t bufferSize,
|
||||
return fFSModule->read_query(fVolumeCookie, cookie, (struct dirent*)buffer,
|
||||
bufferSize, countRead);
|
||||
}
|
||||
|
||||
// RewindQuery
|
||||
status_t
|
||||
HaikuKernelVolume::RewindQuery(fs_cookie cookie)
|
||||
{
|
||||
if (!fFSModule->rewind_query)
|
||||
return B_BAD_VALUE;
|
||||
return fFSModule->rewind_query(fVolumeCookie, cookie);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ public:
|
||||
// vnodes
|
||||
virtual status_t Lookup(fs_vnode dir, const char* entryName,
|
||||
vnode_id* vnid, int* type);
|
||||
virtual status_t GetVNodeName(fs_vnode node, char* buffer,
|
||||
size_t bufferSize);
|
||||
virtual status_t ReadVNode(vnode_id vnid, bool reenter,
|
||||
fs_vnode* node);
|
||||
virtual status_t WriteVNode(fs_vnode node, bool reenter);
|
||||
@@ -119,6 +121,8 @@ public:
|
||||
size_t bufferSize, size_t* bytesWritten);
|
||||
virtual status_t ReadAttrStat(fs_vnode node, fs_cookie cookie,
|
||||
struct stat *st);
|
||||
virtual status_t WriteAttrStat(fs_vnode node, fs_cookie cookie,
|
||||
const struct stat* st, int statMask);
|
||||
virtual status_t RenameAttr(fs_vnode oldNode,
|
||||
const char* oldName, fs_vnode newNode,
|
||||
const char* newName);
|
||||
@@ -147,6 +151,7 @@ public:
|
||||
virtual status_t ReadQuery(fs_cookie cookie, void* buffer,
|
||||
size_t bufferSize, uint32 count,
|
||||
uint32* countRead);
|
||||
virtual status_t RewindQuery(fs_cookie cookie);
|
||||
|
||||
private:
|
||||
file_system_module_info* fFSModule;
|
||||
|
||||
@@ -60,6 +60,8 @@ UserlandRequestHandler::HandleRequest(Request* request)
|
||||
// vnodes
|
||||
case LOOKUP_REQUEST:
|
||||
return _HandleRequest((LookupRequest*)request);
|
||||
case GET_VNODE_NAME_REQUEST:
|
||||
return _HandleRequest((GetVNodeNameRequest*)request);
|
||||
case READ_VNODE_REQUEST:
|
||||
return _HandleRequest((ReadVNodeRequest*)request);
|
||||
case WRITE_VNODE_REQUEST:
|
||||
@@ -152,6 +154,8 @@ UserlandRequestHandler::HandleRequest(Request* request)
|
||||
return _HandleRequest((WriteAttrRequest*)request);
|
||||
case READ_ATTR_STAT_REQUEST:
|
||||
return _HandleRequest((ReadAttrStatRequest*)request);
|
||||
case WRITE_ATTR_STAT_REQUEST:
|
||||
return _HandleRequest((WriteAttrStatRequest*)request);
|
||||
case RENAME_ATTR_REQUEST:
|
||||
return _HandleRequest((RenameAttrRequest*)request);
|
||||
case REMOVE_ATTR_REQUEST:
|
||||
@@ -184,6 +188,8 @@ UserlandRequestHandler::HandleRequest(Request* request)
|
||||
return _HandleRequest((FreeQueryCookieRequest*)request);
|
||||
case READ_QUERY_REQUEST:
|
||||
return _HandleRequest((ReadQueryRequest*)request);
|
||||
case REWIND_QUERY_REQUEST:
|
||||
return _HandleRequest((RewindQueryRequest*)request);
|
||||
}
|
||||
PRINT(("UserlandRequestHandler::HandleRequest(): unexpected request: %lu\n",
|
||||
request->GetType()));
|
||||
@@ -394,6 +400,45 @@ UserlandRequestHandler::_HandleRequest(LookupRequest* request)
|
||||
return _SendReply(allocator, false);
|
||||
}
|
||||
|
||||
// _HandleRequest
|
||||
status_t
|
||||
UserlandRequestHandler::_HandleRequest(GetVNodeNameRequest* request)
|
||||
{
|
||||
// check and execute the request
|
||||
status_t result = B_OK;
|
||||
Volume* volume = (Volume*)request->volume;
|
||||
if (!volume)
|
||||
result = B_BAD_VALUE;
|
||||
|
||||
void* node = request->node;
|
||||
size_t bufferSize = request->size;
|
||||
|
||||
// allocate the reply
|
||||
RequestAllocator allocator(fPort->GetPort());
|
||||
GetVNodeNameReply* reply;
|
||||
status_t error = AllocateRequest(allocator, &reply);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
char* buffer;
|
||||
if (result == B_OK) {
|
||||
result = allocator.AllocateAddress(reply->buffer, bufferSize, 1,
|
||||
(void**)&buffer, true);
|
||||
}
|
||||
|
||||
// execute the request
|
||||
if (result == B_OK) {
|
||||
RequestThreadContext context(volume);
|
||||
result = volume->GetVNodeName(node, buffer, bufferSize);
|
||||
}
|
||||
|
||||
// reconstruct the reply, in case it has been overwritten
|
||||
reply = new(reply) GetVNodeNameReply;
|
||||
|
||||
// send the reply
|
||||
reply->error = result;
|
||||
return _SendReply(allocator, (result == B_OK));
|
||||
}
|
||||
|
||||
// _HandleRequest
|
||||
status_t
|
||||
UserlandRequestHandler::_HandleRequest(ReadVNodeRequest* request)
|
||||
@@ -1729,6 +1774,35 @@ UserlandRequestHandler::_HandleRequest(ReadAttrStatRequest* request)
|
||||
return _SendReply(allocator, false);
|
||||
}
|
||||
|
||||
// _HandleRequest
|
||||
status_t
|
||||
UserlandRequestHandler::_HandleRequest(WriteAttrStatRequest* 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->WriteAttrStat(request->node, request->attrCookie,
|
||||
&request->st, request->mask);
|
||||
}
|
||||
|
||||
// prepare the reply
|
||||
RequestAllocator allocator(fPort->GetPort());
|
||||
WriteAttrStatReply* 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(RenameAttrRequest* request)
|
||||
@@ -2173,6 +2247,34 @@ UserlandRequestHandler::_HandleRequest(ReadQueryRequest* request)
|
||||
return _SendReply(allocator, (result == B_OK));
|
||||
}
|
||||
|
||||
// _HandleRequest
|
||||
status_t
|
||||
UserlandRequestHandler::_HandleRequest(RewindQueryRequest* 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->RewindQuery(request->queryCookie);
|
||||
}
|
||||
|
||||
// prepare the reply
|
||||
RequestAllocator allocator(fPort->GetPort());
|
||||
RewindQueryReply* reply;
|
||||
status_t error = AllocateRequest(allocator, &reply);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
reply->error = result;
|
||||
|
||||
// send the reply
|
||||
return _SendReply(allocator, false);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - other
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ class ReadFSInfoRequest;
|
||||
class WriteFSInfoRequest;
|
||||
// vnodes
|
||||
class LookupRequest;
|
||||
class GetVNodeNameRequest;
|
||||
class ReadVNodeRequest;
|
||||
class WriteVNodeRequest;
|
||||
class FSRemoveVNodeRequest;
|
||||
@@ -61,6 +62,7 @@ class FreeAttrCookieRequest;
|
||||
class ReadAttrRequest;
|
||||
class WriteAttrRequest;
|
||||
class ReadAttrStatRequest;
|
||||
class WriteAttrStatRequest;
|
||||
class RenameAttrRequest;
|
||||
class RemoveAttrRequest;
|
||||
// indices
|
||||
@@ -77,6 +79,7 @@ class OpenQueryRequest;
|
||||
class CloseQueryRequest;
|
||||
class FreeQueryCookieRequest;
|
||||
class ReadQueryRequest;
|
||||
class RewindQueryRequest;
|
||||
|
||||
class RequestAllocator;
|
||||
|
||||
@@ -107,6 +110,7 @@ private:
|
||||
|
||||
// vnodes
|
||||
status_t _HandleRequest(LookupRequest* request);
|
||||
status_t _HandleRequest(GetVNodeNameRequest* request);
|
||||
status_t _HandleRequest(ReadVNodeRequest* request);
|
||||
status_t _HandleRequest(WriteVNodeRequest* request);
|
||||
status_t _HandleRequest(FSRemoveVNodeRequest* request);
|
||||
@@ -159,6 +163,7 @@ private:
|
||||
status_t _HandleRequest(ReadAttrRequest* request);
|
||||
status_t _HandleRequest(WriteAttrRequest* request);
|
||||
status_t _HandleRequest(ReadAttrStatRequest* request);
|
||||
status_t _HandleRequest(WriteAttrStatRequest* request);
|
||||
status_t _HandleRequest(RenameAttrRequest* request);
|
||||
status_t _HandleRequest(RemoveAttrRequest* request);
|
||||
|
||||
@@ -178,6 +183,7 @@ private:
|
||||
status_t _HandleRequest(CloseQueryRequest* request);
|
||||
status_t _HandleRequest(FreeQueryCookieRequest* request);
|
||||
status_t _HandleRequest(ReadQueryRequest* request);
|
||||
status_t _HandleRequest(RewindQueryRequest* request);
|
||||
|
||||
status_t _SendReply(RequestAllocator& allocator,
|
||||
bool expectsReceipt);
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
#include "Volume.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "kernel_emu.h"
|
||||
|
||||
// constructor
|
||||
Volume::Volume(FileSystem* fileSystem, mount_id id)
|
||||
: fFileSystem(fileSystem),
|
||||
@@ -79,6 +85,82 @@ Volume::Lookup(fs_vnode dir, const char* entryName, vnode_id* vnid, int* type)
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// LookupNoType
|
||||
status_t
|
||||
Volume::LookupNoType(fs_vnode dir, const char* entryName, vnode_id* vnid)
|
||||
{
|
||||
int type;
|
||||
return Lookup(dir, entryName, vnid, &type);
|
||||
}
|
||||
|
||||
// GetVNodeName
|
||||
status_t
|
||||
Volume::GetVNodeName(fs_vnode node, char* buffer, size_t bufferSize)
|
||||
{
|
||||
// stat the node to get its ID
|
||||
struct stat st;
|
||||
status_t error = ReadStat(node, &st);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// look up the parent directory
|
||||
vnode_id parentID;
|
||||
error = LookupNoType(node, "..", &parentID);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// get the parent node handle
|
||||
fs_vnode parentNode;
|
||||
error = UserlandFS::KernelEmu::get_vnode(GetID(), parentID, &parentNode);
|
||||
// Lookup() has already called get_vnode() for us, so we need to put it once
|
||||
UserlandFS::KernelEmu::put_vnode(GetID(), parentID);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// open the parent dir
|
||||
fs_cookie cookie;
|
||||
error = OpenDir(parentNode, &cookie);
|
||||
if (error == B_OK) {
|
||||
|
||||
while (true) {
|
||||
// read an entry
|
||||
char _entry[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
|
||||
struct dirent* entry = (struct dirent*)_entry;
|
||||
uint32 num;
|
||||
|
||||
error = ReadDir(parentNode, cookie, entry, sizeof(_entry), 1, &num);
|
||||
|
||||
if (error != B_OK)
|
||||
break;
|
||||
if (num == 0) {
|
||||
error = B_ENTRY_NOT_FOUND;
|
||||
break;
|
||||
}
|
||||
|
||||
// found an entry for our node?
|
||||
if (st.st_ino == entry->d_ino) {
|
||||
// yep, copy the entry name
|
||||
size_t nameLen = strnlen(entry->d_name, B_FILE_NAME_LENGTH);
|
||||
if (nameLen < bufferSize) {
|
||||
memcpy(buffer, entry->d_name, nameLen);
|
||||
buffer[nameLen] = '\0';
|
||||
} else
|
||||
error = B_BUFFER_OVERFLOW;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// close the parent dir
|
||||
CloseDir(parentNode, cookie);
|
||||
FreeDirCookie(parentNode, cookie);
|
||||
}
|
||||
|
||||
// put the parent node
|
||||
UserlandFS::KernelEmu::put_vnode(GetID(), parentID);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// ReadVNode
|
||||
status_t
|
||||
Volume::ReadVNode(vnode_id vnid, bool reenter, fs_vnode* node)
|
||||
@@ -393,13 +475,21 @@ Volume::WriteAttr(fs_vnode node, fs_cookie cookie, off_t pos,
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// StatAttr
|
||||
// ReadAttrStat
|
||||
status_t
|
||||
Volume::ReadAttrStat(fs_vnode node, fs_cookie cookie, struct stat *st)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// WriteAttrStat
|
||||
status_t
|
||||
Volume::WriteAttrStat(fs_vnode node, fs_cookie cookie, const struct stat* st,
|
||||
int statMask)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// RenameAttr
|
||||
status_t
|
||||
Volume::RenameAttr(fs_vnode oldNode, const char* oldName, fs_vnode newNode,
|
||||
@@ -510,3 +600,10 @@ Volume::ReadQuery(fs_cookie cookie, void* buffer, size_t bufferSize,
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// RewindQuery
|
||||
status_t
|
||||
Volume::RewindQuery(fs_cookie cookie)
|
||||
{
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,11 @@ public:
|
||||
// vnodes
|
||||
virtual status_t Lookup(fs_vnode dir, const char* entryName,
|
||||
vnode_id* vnid, int* type);
|
||||
virtual status_t LookupNoType(fs_vnode dir,
|
||||
const char* entryName, vnode_id* vnid);
|
||||
// not required
|
||||
virtual status_t GetVNodeName(fs_vnode node, char* buffer,
|
||||
size_t bufferSize);
|
||||
virtual status_t ReadVNode(vnode_id vnid, bool reenter,
|
||||
fs_vnode* node);
|
||||
virtual status_t WriteVNode(fs_vnode node, bool reenter);
|
||||
@@ -115,7 +120,9 @@ public:
|
||||
off_t pos, const void* buffer,
|
||||
size_t bufferSize, size_t* bytesWritten);
|
||||
virtual status_t ReadAttrStat(fs_vnode node, fs_cookie cookie,
|
||||
struct stat *st);
|
||||
struct stat* st);
|
||||
virtual status_t WriteAttrStat(fs_vnode node, fs_cookie cookie,
|
||||
const struct stat* st, int statMask);
|
||||
virtual status_t RenameAttr(fs_vnode oldNode,
|
||||
const char* oldName, fs_vnode newNode,
|
||||
const char* newName);
|
||||
@@ -144,6 +151,7 @@ public:
|
||||
virtual status_t ReadQuery(fs_cookie cookie, void* buffer,
|
||||
size_t bufferSize, uint32 count,
|
||||
uint32* countRead);
|
||||
virtual status_t RewindQuery(fs_cookie cookie);
|
||||
|
||||
protected:
|
||||
FileSystem* fFileSystem;
|
||||
|
||||
Reference in New Issue
Block a user