root/src/add-ons/kernel/file_systems/nfs4/Delegation.cpp
/*
 * Copyright 2012 Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              Paweł Dziepak, pdziepak@quarnos.org
 */


#include "Delegation.h"

#include "Inode.h"
#include "Request.h"


Delegation::Delegation(const OpenDelegationData& data, Inode* inode,
        uint64 clientID, bool attribute)
        :
        fClientID(clientID),
        fData(data),
        fInode(inode),
        fAttribute(attribute),
        fStateSeq(data.fStateSeq),
        fUid(geteuid()),
        fGid(getegid()),
        fRecalled(false)
{
        ASSERT(inode != NULL);
        memcpy(fStateID, data.fStateID, sizeof(fStateID));
}


status_t
Delegation::GiveUp(bool truncate)
{
        PrepareGiveUp(truncate);

        return DoGiveUp(truncate);
}


status_t
Delegation::PrepareGiveUp(bool truncate)
{
        status_t status = B_OK;
        if (!fAttribute && !truncate)
                status = fInode->Sync(true, false);

        return status;
}


status_t
Delegation::DoGiveUp(bool truncate, bool wait)
{
        if (!fAttribute && !truncate && wait)
                fInode->WaitAIOComplete();

        status_t status = ReturnDelegation();

        fInode->Commit(fUid, fGid);

        return status;
}


void
Delegation::GetStateIDandSeq(uint32* stateID, uint32& stateSeq) const
{
        memcpy(stateID, fStateID, sizeof(uint32) * 3);
        stateSeq = fStateSeq;
}


void
Delegation::Dump(void (*xprintf)(const char*, ...)) const
{
        xprintf("Delegation at %p for Inode at %p (ino %" B_PRIdINO ")\n", this, fInode, fInode->ID());
        if (fData.fType == OPEN_DELEGATE_READ)
                xprintf("\ttype OPEN_DELEGATE_READ, ");
        else if (fData.fType == OPEN_DELEGATE_WRITE)
                xprintf("\ttype OPEN_DELEGATE_WRITE, ");
        xprintf("attribute %d, uid %" B_PRIu32 ", gid %" B_PRIu32 "\n", fAttribute, fUid, fGid);
        xprintf("\tstate id and sequence %" B_PRIu32 " %" B_PRIu32 " %" B_PRIu32 " %" B_PRIu32 "\n",
                fData.fStateID[0], fData.fStateID[1], fData.fStateID[2], fData.fStateSeq);

        return;
}


status_t
Delegation::ReturnDelegation()
{
        uint32 attempt = 0;
        do {
                RPC::Server* serv = fFileSystem->Server();
                Request request(serv, fFileSystem, fUid, fGid);
                RequestBuilder& req = request.Builder();

                req.PutFH(fInfo.fHandle);
                req.DelegReturn(fData.fStateID, fData.fStateSeq);

                status_t result = request.Send();
                if (result != B_OK)
                        return result;

                ReplyInterpreter& reply = request.Reply();

                if (HandleErrors(attempt, reply.NFS4Error(), serv, NULL,
                                fInode->GetOpenState())) {
                        continue;
                }

                reply.PutFH();

                return reply.DelegReturn();
        } while (true);
}