root/src/add-ons/kernel/file_systems/userlandfs/server/UserlandRequestHandler.cpp
/*
 * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */

#include "UserlandRequestHandler.h"

#include <algorithm>

#include <util/KMessage.h>

#include <Notifications.h>

#include "AutoDeleter.h"
#include "Compatibility.h"
#include "Debug.h"
#include "FileSystem.h"
#include "IORequestInfo.h"
#include "RequestPort.h"
#include "Requests.h"
#include "RequestThread.h"
#include "SingleReplyRequestHandler.h"
#include "Volume.h"


// constructor
UserlandRequestHandler::UserlandRequestHandler(FileSystem* fileSystem)
        : RequestHandler(),
          fFileSystem(fileSystem),
          fExpectReply(false),
          fExpectedReply(0)
{
}

// constructor
UserlandRequestHandler::UserlandRequestHandler(FileSystem* fileSystem,
        uint32 expectedReply)
        : RequestHandler(),
          fFileSystem(fileSystem),
          fExpectReply(true),
          fExpectedReply(expectedReply)
{
}

// destructor
UserlandRequestHandler::~UserlandRequestHandler()
{
}

// HandleRequest
status_t
UserlandRequestHandler::HandleRequest(Request* request)
{
        if (fExpectReply && request->GetType() == fExpectedReply) {
                fDone = true;
                return B_OK;
        }

        switch (request->GetType()) {
                // FS
                case MOUNT_VOLUME_REQUEST:
                        return _HandleRequest((MountVolumeRequest*)request);
                case UNMOUNT_VOLUME_REQUEST:
                        return _HandleRequest((UnmountVolumeRequest*)request);
                case SYNC_VOLUME_REQUEST:
                        return _HandleRequest((SyncVolumeRequest*)request);
                case READ_FS_INFO_REQUEST:
                        return _HandleRequest((ReadFSInfoRequest*)request);
                case WRITE_FS_INFO_REQUEST:
                        return _HandleRequest((WriteFSInfoRequest*)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:
                        return _HandleRequest((WriteVNodeRequest*)request);
                case FS_REMOVE_VNODE_REQUEST:
                        return _HandleRequest((FSRemoveVNodeRequest*)request);

                // asynchronous I/O
                case DO_IO_REQUEST:
                        return _HandleRequest((DoIORequest*)request);
                case CANCEL_IO_REQUEST:
                        return _HandleRequest((CancelIORequest*)request);
                case ITERATIVE_IO_GET_VECS_REQUEST:
                        return _HandleRequest((IterativeIOGetVecsRequest*)request);
                case ITERATIVE_IO_FINISHED_REQUEST:
                        return _HandleRequest((IterativeIOFinishedRequest*)request);

                // nodes
                case IOCTL_REQUEST:
                        return _HandleRequest((IOCtlRequest*)request);
                case SET_FLAGS_REQUEST:
                        return _HandleRequest((SetFlagsRequest*)request);
                case SELECT_REQUEST:
                        return _HandleRequest((SelectRequest*)request);
                case DESELECT_REQUEST:
                        return _HandleRequest((DeselectRequest*)request);
                case FSYNC_REQUEST:
                        return _HandleRequest((FSyncRequest*)request);
                case READ_SYMLINK_REQUEST:
                        return _HandleRequest((ReadSymlinkRequest*)request);
                case CREATE_SYMLINK_REQUEST:
                        return _HandleRequest((CreateSymlinkRequest*)request);
                case LINK_REQUEST:
                        return _HandleRequest((LinkRequest*)request);
                case UNLINK_REQUEST:
                        return _HandleRequest((UnlinkRequest*)request);
                case RENAME_REQUEST:
                        return _HandleRequest((RenameRequest*)request);
                case ACCESS_REQUEST:
                        return _HandleRequest((AccessRequest*)request);
                case READ_STAT_REQUEST:
                        return _HandleRequest((ReadStatRequest*)request);
                case WRITE_STAT_REQUEST:
                        return _HandleRequest((WriteStatRequest*)request);

                // files
                case CREATE_REQUEST:
                        return _HandleRequest((CreateRequest*)request);
                case OPEN_REQUEST:
                        return _HandleRequest((OpenRequest*)request);
                case CLOSE_REQUEST:
                        return _HandleRequest((CloseRequest*)request);
                case FREE_COOKIE_REQUEST:
                        return _HandleRequest((FreeCookieRequest*)request);
                case READ_REQUEST:
                        return _HandleRequest((ReadRequest*)request);
                case WRITE_REQUEST:
                        return _HandleRequest((WriteRequest*)request);

                // directories
                case CREATE_DIR_REQUEST:
                        return _HandleRequest((CreateDirRequest*)request);
                case REMOVE_DIR_REQUEST:
                        return _HandleRequest((RemoveDirRequest*)request);
                case OPEN_DIR_REQUEST:
                        return _HandleRequest((OpenDirRequest*)request);
                case CLOSE_DIR_REQUEST:
                        return _HandleRequest((CloseDirRequest*)request);
                case FREE_DIR_COOKIE_REQUEST:
                        return _HandleRequest((FreeDirCookieRequest*)request);
                case READ_DIR_REQUEST:
                        return _HandleRequest((ReadDirRequest*)request);
                case REWIND_DIR_REQUEST:
                        return _HandleRequest((RewindDirRequest*)request);

                // attribute directories
                case OPEN_ATTR_DIR_REQUEST:
                        return _HandleRequest((OpenAttrDirRequest*)request);
                case CLOSE_ATTR_DIR_REQUEST:
                        return _HandleRequest((CloseAttrDirRequest*)request);
                case FREE_ATTR_DIR_COOKIE_REQUEST:
                        return _HandleRequest((FreeAttrDirCookieRequest*)request);
                case READ_ATTR_DIR_REQUEST:
                        return _HandleRequest((ReadAttrDirRequest*)request);
                case REWIND_ATTR_DIR_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:
                        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:
                        return _HandleRequest((RemoveAttrRequest*)request);

                // indices
                case OPEN_INDEX_DIR_REQUEST:
                        return _HandleRequest((OpenIndexDirRequest*)request);
                case CLOSE_INDEX_DIR_REQUEST:
                        return _HandleRequest((CloseIndexDirRequest*)request);
                case FREE_INDEX_DIR_COOKIE_REQUEST:
                        return _HandleRequest((FreeIndexDirCookieRequest*)request);
                case READ_INDEX_DIR_REQUEST:
                        return _HandleRequest((ReadIndexDirRequest*)request);
                case REWIND_INDEX_DIR_REQUEST:
                        return _HandleRequest((RewindIndexDirRequest*)request);
                case CREATE_INDEX_REQUEST:
                        return _HandleRequest((CreateIndexRequest*)request);
                case REMOVE_INDEX_REQUEST:
                        return _HandleRequest((RemoveIndexRequest*)request);
                case READ_INDEX_STAT_REQUEST:
                        return _HandleRequest((ReadIndexStatRequest*)request);

                // queries
                case OPEN_QUERY_REQUEST:
                        return _HandleRequest((OpenQueryRequest*)request);
                case CLOSE_QUERY_REQUEST:
                        return _HandleRequest((CloseQueryRequest*)request);
                case FREE_QUERY_COOKIE_REQUEST:
                        return _HandleRequest((FreeQueryCookieRequest*)request);
                case READ_QUERY_REQUEST:
                        return _HandleRequest((ReadQueryRequest*)request);
                case REWIND_QUERY_REQUEST:
                        return _HandleRequest((RewindQueryRequest*)request);

                // node monitoring
                case NODE_MONITORING_EVENT_REQUEST:
                        return _HandleRequest((NodeMonitoringEventRequest*)request);
        }
        PRINT(("UserlandRequestHandler::HandleRequest(): unexpected request: %"
                B_PRIu32 "\n", request->GetType()));
        return B_BAD_DATA;
}


// #pragma mark - FS


// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(MountVolumeRequest* request)
{
        // check and execute the request
        status_t result = B_OK;

        // if the device path is relative, make it absolute by appending the
        // provided CWD
        const char* device = (const char*)request->device.GetData();
        char stackDevice[B_PATH_NAME_LENGTH];
        if (result == B_OK) {
                if (device && device[0] != '/') {
                        if (const char* cwd = (const char*)request->cwd.GetData()) {
                                int32 deviceLen = strlen(device);
                                int32 cwdLen = strlen(cwd);
                                if (cwdLen + 1 + deviceLen < (int32)sizeof(stackDevice)) {
                                        strcpy(stackDevice, cwd);
                                        strcat(stackDevice, "/");
                                        strcat(stackDevice, device);
                                        device = stackDevice;
                                } else
                                        result = B_NAME_TOO_LONG;
                        } else
                                result = B_BAD_VALUE;
                }
        }

        // create the volume
        Volume* volume = NULL;
        if (result == B_OK)
                result = fFileSystem->CreateVolume(&volume, request->nsid);

        // mount it
        ino_t rootID;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->Mount(device, request->flags,
                        (const char*)request->parameters.GetData(), &rootID);
                if (result != B_OK)
                        fFileSystem->DeleteVolume(volume);
        }
        if (result != B_OK)
                volume = NULL;

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        MountVolumeReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);
        reply->error = result;
        reply->volume = volume;
        reply->rootID = rootID;
        if (volume != NULL)
                volume->GetCapabilities(reply->capabilities);

        // send the reply
        return _SendReply(allocator, false);
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(UnmountVolumeRequest* request)
{
        // check and execute the request
        status_t result = B_BAD_VALUE;
        if (Volume* volume = (Volume*)request->volume) {
                RequestThreadContext context(volume, request);
                result = volume->Unmount();
                fFileSystem->DeleteVolume(volume);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        UnmountVolumeReply* 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(SyncVolumeRequest* 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, request);
                result = volume->Sync();
        }
        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        SyncVolumeReply* 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(ReadFSInfoRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;
        fs_info info;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->ReadFSInfo(&info);
        }
        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        ReadFSInfoReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);
        reply->error = result;
        reply->info = info;

        // send the reply
        return _SendReply(allocator, false);
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(WriteFSInfoRequest* 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, request);
                result = volume->WriteFSInfo(&request->info, request->mask);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        WriteFSInfoReply* 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 - vnodes


// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(LookupRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        ino_t vnid = 0;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->Lookup(request->node,
                        (const char*)request->entryName.GetData(), &vnid);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        LookupReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->vnid = vnid;
        reply->error = result;

        // send the reply
        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, request);
                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)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        void* node;
        int type;
        uint32 flags;
        FSVNodeCapabilities capabilities;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->ReadVNode(request->vnid, request->reenter, &node,
                        &type, &flags, &capabilities);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        ReadVNodeReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = result;
        reply->node = node;
        reply->type = type;
        reply->flags = flags;
        reply->capabilities = capabilities;

        // send the reply
        return _SendReply(allocator, false);
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(WriteVNodeRequest* 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, request);
                result = volume->WriteVNode(request->node, request->reenter);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        WriteVNodeReply* 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(FSRemoveVNodeRequest* 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, request);
                result = volume->RemoveVNode(request->node, request->reenter);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        FSRemoveVNodeReply* 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 - asynchronous I/O


status_t
UserlandRequestHandler::_HandleRequest(DoIORequest* 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, request);
                IORequestInfo requestInfo(request->request, request->isWrite,
                        request->offset, request->length, request->isVIP);
                result = volume->DoIO(request->node, request->fileCookie, requestInfo);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        DoIOReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = result;

        // send the reply
        return _SendReply(allocator, false);
}


status_t
UserlandRequestHandler::_HandleRequest(CancelIORequest* 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, request);
                result = volume->CancelIO(request->node, request->fileCookie,
                        request->request);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        CancelIOReply* 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(IterativeIOGetVecsRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        file_io_vec vecs[IterativeIOGetVecsReply::MAX_VECS];
        size_t vecCount = IterativeIOGetVecsReply::MAX_VECS;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->IterativeIOGetVecs(request->cookie, request->request,
                        request->offset, request->size, vecs, &vecCount);
                if (result == B_OK) {
                        vecCount = std::min(vecCount,
                                (size_t)IterativeIOGetVecsReply::MAX_VECS);
                }
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        IterativeIOGetVecsReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = result;
        if (result == B_OK) {
                memcpy(reply->vecs, vecs, vecCount * sizeof(file_io_vec));
                reply->vecCount = vecCount;
        } else
                reply->vecCount = 0;

        // send the reply
        return _SendReply(allocator, false);
}


// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(IterativeIOFinishedRequest* 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, request);
                result = volume->IterativeIOFinished(request->cookie, request->request,
                        request->status, request->partialTransfer,
                        request->bytesTransferred);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        IterativeIOFinishedReply* 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 - nodes


// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(IOCtlRequest* request)
{
        // get the request parameters
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        void* buffer = request->bufferParameter;
        size_t len = request->lenParameter;
        bool isBuffer = request->isBuffer;
        int32 bufferSize = 0;
        int32 writeSize = request->writeSize;
        if (isBuffer) {
                buffer = request->buffer.GetData();
                bufferSize = request->buffer.GetSize();
        }

        // allocate the reply
        RequestAllocator allocator(fPort->GetPort());
        IOCtlReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        // allocate the writable buffer for the call
        void* writeBuffer = NULL;
        if (result == B_OK && isBuffer && writeSize > 0) {
                if (writeSize < bufferSize)
                        writeSize = bufferSize;
                result = allocator.AllocateAddress(reply->buffer, writeSize, 8,
                        (void**)&writeBuffer, true);
                if (result == B_OK && bufferSize > 0)
                        memcpy(writeBuffer, buffer, bufferSize);
                buffer = writeBuffer;
        }

        // execute the request
        status_t ioctlError = B_OK;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                ioctlError = volume->IOCtl(request->node, request->fileCookie,
                        request->command, buffer, len);
        }

        // reconstruct the reply, in case it has been overwritten
        reply = new(reply) IOCtlReply;

        // send the reply
        reply->error = result;
        reply->ioctlError = ioctlError;
        return _SendReply(allocator, (result == B_OK && writeBuffer));
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(SetFlagsRequest* 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, request);
                result = volume->SetFlags(request->node, request->fileCookie,
                        request->flags);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        SetFlagsReply* 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(SelectRequest* 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, request);
                result = volume->Select(request->node, request->fileCookie,
                        request->event, request->sync);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        SelectReply* 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(DeselectRequest* 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, request);
                result = volume->Deselect(request->node, request->fileCookie,
                        request->event, request->sync);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        DeselectReply* 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(FSyncRequest* 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, request);
                result = volume->FSync(request->node);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        FSyncReply* 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(ReadSymlinkRequest* 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());
        ReadSymlinkReply* 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
        size_t bytesRead;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->ReadSymlink(node, buffer, bufferSize, &bytesRead);
        }

        // reconstruct the reply, in case it has been overwritten
        reply = new(reply) ReadSymlinkReply;

        // send the reply
        reply->error = result;
        reply->bytesRead = bytesRead;
        return _SendReply(allocator, (result == B_OK));
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(CreateSymlinkRequest* 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, request);
                result = volume->CreateSymlink(request->node,
                        (const char*)request->name.GetData(),
                        (const char*)request->target.GetData(), request->mode);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        CreateSymlinkReply* 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(LinkRequest* 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, request);
                result = volume->Link(request->node,
                        (const char*)request->name.GetData(), request->target);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        LinkReply* 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(UnlinkRequest* 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, request);
                result = volume->Unlink(request->node,
                        (const char*)request->name.GetData());
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        UnlinkReply* 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(RenameRequest* 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, request);
                result = volume->Rename(request->oldDir,
                        (const char*)request->oldName.GetData(), request->newDir,
                        (const char*)request->newName.GetData());
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        RenameReply* 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(AccessRequest* 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, request);
                result = volume->Access(request->node, request->mode);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        AccessReply* 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(ReadStatRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        struct stat st;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->ReadStat(request->node, &st);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        ReadStatReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = result;
        reply->st = st;

        // send the reply
        return _SendReply(allocator, false);
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(WriteStatRequest* 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, request);
                result = volume->WriteStat(request->node, &request->st, request->mask);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        WriteStatReply* 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 - files


// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(CreateRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        ino_t vnid;
        void* fileCookie;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->Create(request->node,
                        (const char*)request->name.GetData(), request->openMode,
                        request->mode, &fileCookie, &vnid);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        CreateReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = result;
        reply->vnid = vnid;
        reply->fileCookie = fileCookie;

        // send the reply
        return _SendReply(allocator, false);
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(OpenRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        void* fileCookie;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->Open(request->node, request->openMode, &fileCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        OpenReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = result;
        reply->fileCookie = fileCookie;

        // send the reply
        return _SendReply(allocator, false);
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(CloseRequest* 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, request);
                result = volume->Close(request->node, request->fileCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        CloseReply* 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(FreeCookieRequest* 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, request);
                result = volume->FreeCookie(request->node, request->fileCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        FreeCookieReply* 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(ReadRequest* 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;
        void* fileCookie = request->fileCookie;
        off_t pos = request->pos;
        size_t size = request->size;

        // allocate the reply
        RequestAllocator allocator(fPort->GetPort());
        ReadReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        void* buffer;
        if (result == B_OK) {
                result = allocator.AllocateAddress(reply->buffer, size, 1, &buffer,
                        true, sizeof(FileCacheReadRequest) + sizeof(ReceiptAckReply));
        }

        // execute the request
        size_t bytesRead;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->Read(node, fileCookie, pos, buffer, size, &bytesRead);
        }

        // reconstruct the reply, in case it has been overwritten
        reply = new(reply) ReadReply;

        // send the reply
        reply->error = result;
        reply->bytesRead = bytesRead;
        return _SendReply(allocator, (result == B_OK));
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(WriteRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        size_t bytesWritten;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->Write(request->node, request->fileCookie,
                        request->pos, request->buffer.GetData(), request->buffer.GetSize(),
                        &bytesWritten);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        WriteReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = result;
        reply->bytesWritten = bytesWritten;

        // send the reply
        return _SendReply(allocator, false);
}


// #pragma mark - directories


// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(CreateDirRequest* 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, request);
                result = volume->CreateDir(request->node,
                        (const char*)request->name.GetData(), request->mode);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        CreateDirReply* 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(RemoveDirRequest* 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, request);
                result = volume->RemoveDir(request->node,
                        (const char*)request->name.GetData());
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        RemoveDirReply* 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(OpenDirRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        void* dirCookie = NULL;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->OpenDir(request->node, &dirCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        OpenDirReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = result;
        reply->dirCookie = dirCookie;

        // send the reply
        return _SendReply(allocator, false);
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(CloseDirRequest* 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, request);
                result = volume->CloseDir(request->node, request->dirCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        CloseDirReply* 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(FreeDirCookieRequest* 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, request);
                result = volume->FreeDirCookie(request->node, request->dirCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        FreeDirCookieReply* 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(ReadDirRequest* request)
{
        // check the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        void* node = request->node;
        void* dirCookie = request->dirCookie;
        size_t bufferSize = request->bufferSize;
        uint32 count = request->count;

        // allocate the reply
        RequestAllocator allocator(fPort->GetPort());
        ReadDirReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        void* buffer;
        if (result == B_OK) {
                result = allocator.AllocateAddress(reply->buffer, bufferSize, 1,
                        &buffer, true);
        }

        // execute the request
        uint32 countRead;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->ReadDir(node, dirCookie, buffer, bufferSize, count,
                        &countRead);
        }

        D(
                if (result == B_OK && countRead > 0) {
                        dirent* entry = (dirent*)buffer;
                        PRINT(("  entry: d_dev: %" B_PRIdDEV ", d_pdev: %" B_PRIdDEV ", "
                                "d_ino: %" B_PRIdINO ", d_pino: %" B_PRIdINO ", "
                                "d_reclen: %hu, d_name: %.32s\n",
                        entry->d_dev, entry->d_pdev,
                        entry->d_ino, entry->d_pino,
                        entry->d_reclen, entry->d_name));
                }
        )

        // reconstruct the reply, in case it has been overwritten
        reply = new(reply) ReadDirReply;

        // send the reply
        reply->error = result;
        reply->count = countRead;
        return _SendReply(allocator, (result == B_OK));
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(RewindDirRequest* 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, request);
                result = volume->RewindDir(request->node, request->dirCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        RewindDirReply* 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 - attribute directories


// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(OpenAttrDirRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        void* attrDirCookie;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->OpenAttrDir(request->node, &attrDirCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        OpenAttrDirReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = result;
        reply->attrDirCookie = attrDirCookie;

        // send the reply
        return _SendReply(allocator, false);
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(CloseAttrDirRequest* 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, request);
                result = volume->CloseAttrDir(request->node, request->attrDirCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        CloseAttrDirReply* 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(FreeAttrDirCookieRequest* 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, request);
                result = volume->FreeAttrDirCookie(request->node,
                        request->attrDirCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        FreeAttrDirCookieReply* 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(ReadAttrDirRequest* 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;
        void* attrDirCookie = request->attrDirCookie;
        size_t bufferSize = request->bufferSize;
        uint32 count = request->count;

        // allocate the reply
        RequestAllocator allocator(fPort->GetPort());
        ReadAttrDirReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        void* buffer;
        if (result == B_OK) {
                result = allocator.AllocateAddress(reply->buffer, bufferSize, 1,
                        &buffer, true);
        }

        // execute the request
        uint32 countRead;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->ReadAttrDir(node, attrDirCookie, buffer, bufferSize,
                        count, &countRead);
        }

        // reconstruct the reply, in case it has been overwritten
        reply = new(reply) ReadAttrDirReply;

        // send the reply
        reply->error = result;
        reply->count = countRead;
        return _SendReply(allocator, (result == B_OK));
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(RewindAttrDirRequest* 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, request);
                result = volume->RewindAttrDir(request->node, request->attrDirCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        RewindAttrDirReply* 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 - 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;

        void* attrCookie;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                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;

        void* attrCookie;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                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, request);
                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, request);
                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)
{
        // 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;
        void* attrCookie = request->attrCookie;
        off_t pos = request->pos;
        size_t size = request->size;

        // allocate the reply
        RequestAllocator allocator(fPort->GetPort());
        ReadAttrReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        void* buffer;
        if (result == B_OK) {
                result = allocator.AllocateAddress(reply->buffer, size, 1, &buffer,
                        true);
        }

        // execute the request
        size_t bytesRead;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->ReadAttr(node, attrCookie, pos, buffer, size,
                        &bytesRead);
        }

        // reconstruct the reply, in case it has been overwritten
        reply = new(reply) ReadAttrReply;

        // send the reply
        reply->error = result;
        reply->bytesRead = bytesRead;
        return _SendReply(allocator, (result == B_OK));
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(WriteAttrRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        size_t bytesWritten;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->WriteAttr(request->node, request->attrCookie,
                        request->pos, request->buffer.GetData(), request->buffer.GetSize(),
                        &bytesWritten);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        WriteAttrReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = result;
        reply->bytesWritten = bytesWritten;

        // send the reply
        return _SendReply(allocator, false);
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(ReadAttrStatRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        struct stat st;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->ReadAttrStat(request->node, request->attrCookie,
                        &st);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        ReadAttrStatReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = result;
        reply->st = st;

        // send the reply
        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, request);
                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)
{
        // 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, request);
                result = volume->RenameAttr(
                        request->oldNode, (const char*)request->oldName.GetData(),
                        request->newNode, (const char*)request->newName.GetData());
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        RenameAttrReply* 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(RemoveAttrRequest* 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, request);
                result = volume->RemoveAttr(request->node,
                        (const char*)request->name.GetData());
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        RemoveAttrReply* 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 - indices


// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(OpenIndexDirRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        void* indexDirCookie;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->OpenIndexDir(&indexDirCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        OpenIndexDirReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = result;
        reply->indexDirCookie = indexDirCookie;

        // send the reply
        return _SendReply(allocator, false);
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(CloseIndexDirRequest* 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, request);
                result = volume->CloseIndexDir(request->indexDirCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        CloseIndexDirReply* 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(FreeIndexDirCookieRequest* 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, request);
                result = volume->FreeIndexDirCookie(request->indexDirCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        FreeIndexDirCookieReply* 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(ReadIndexDirRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        void* indexDirCookie = request->indexDirCookie;
        size_t bufferSize = request->bufferSize;
        uint32 count = request->count;

        // allocate the reply
        RequestAllocator allocator(fPort->GetPort());
        ReadIndexDirReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        void* buffer;
        if (result == B_OK) {
                result = allocator.AllocateAddress(reply->buffer, bufferSize, 1,
                        &buffer, true);
        }

        // execute the request
        uint32 countRead;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->ReadIndexDir(indexDirCookie, buffer, bufferSize,
                        count, &countRead);
        }

        // reconstruct the reply, in case it has been overwritten
        reply = new(reply) ReadIndexDirReply;

        // send the reply
        reply->error = result;
        reply->count = countRead;
        return _SendReply(allocator, (result == B_OK));
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(RewindIndexDirRequest* 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, request);
                result = volume->RewindIndexDir(request->indexDirCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        RewindIndexDirReply* 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(CreateIndexRequest* 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, request);
                result = volume->CreateIndex((const char*)request->name.GetData(),
                        request->type, request->flags);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        CreateIndexReply* 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(RemoveIndexRequest* 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, request);
                result = volume->RemoveIndex((const char*)request->name.GetData());
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        RemoveIndexReply* 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(ReadIndexStatRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        struct stat st;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->ReadIndexStat((const char*)request->name.GetData(),
                        &st);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        ReadIndexStatReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = result;
        reply->st = st;

        // send the reply
        return _SendReply(allocator, false);
}


// #pragma mark - queries


// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(OpenQueryRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        void* queryCookie;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->OpenQuery((const char*)request->queryString.GetData(),
                        request->flags, request->port, request->token, &queryCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        OpenQueryReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = result;
        reply->queryCookie = queryCookie;

        // send the reply
        return _SendReply(allocator, false);
}

// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(CloseQueryRequest* 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, request);
                result = volume->CloseQuery(request->queryCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        CloseQueryReply* 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(FreeQueryCookieRequest* 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, request);
                result = volume->FreeQueryCookie(request->queryCookie);
        }

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        FreeQueryCookieReply* 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(ReadQueryRequest* request)
{
        // check and execute the request
        status_t result = B_OK;
        Volume* volume = (Volume*)request->volume;
        if (!volume)
                result = B_BAD_VALUE;

        void* queryCookie = request->queryCookie;
        size_t bufferSize = request->bufferSize;
        uint32 count = request->count;

        // allocate the reply
        RequestAllocator allocator(fPort->GetPort());
        ReadQueryReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        void* buffer;
        if (result == B_OK) {
                result = allocator.AllocateAddress(reply->buffer, bufferSize, 1,
                        &buffer, true);
        }

        // execute the request
        uint32 countRead;
        if (result == B_OK) {
                RequestThreadContext context(volume, request);
                result = volume->ReadQuery(queryCookie, buffer, bufferSize,
                        count, &countRead);
        }

        // reconstruct the reply, in case it has been overwritten
        reply = new(reply) ReadQueryReply;

        // send the reply
        reply->error = result;
        reply->count = countRead;
        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, request);
                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 - node monitoring


// _HandleRequest
status_t
UserlandRequestHandler::_HandleRequest(NodeMonitoringEventRequest* request)
{
        // check and execute the request
        KMessage event;
        event.SetTo(request->event.GetData(), request->event.GetSize());
        ((NotificationListener*)request->listener)->EventOccurred(
                *(NotificationService*)NULL, &event);

        // prepare the reply
        RequestAllocator allocator(fPort->GetPort());
        NodeMonitoringEventReply* reply;
        status_t error = AllocateRequest(allocator, &reply);
        if (error != B_OK)
                RETURN_ERROR(error);

        reply->error = B_OK;

        // send the reply
        return _SendReply(allocator, false);
}


// #pragma mark - other


// _SendReply
status_t
UserlandRequestHandler::_SendReply(RequestAllocator& allocator,
        bool expectsReceipt)
{
        if (expectsReceipt) {
                SingleReplyRequestHandler handler(RECEIPT_ACK_REPLY);
                return fPort->SendRequest(&allocator, &handler);
        } else
                return fPort->SendRequest(&allocator);
}