From 2a73e4c578d91aa936a012a930d543154a94a1c0 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 28 Jun 2012 23:13:45 +0200 Subject: [PATCH] nfs4: Put file and dir specific code in separate files --- .../kernel/file_systems/nfs4/Inode.cpp | 657 ------------------ src/add-ons/kernel/file_systems/nfs4/Inode.h | 4 +- .../kernel/file_systems/nfs4/InodeDir.cpp | 283 ++++++++ .../kernel/file_systems/nfs4/InodeRegular.cpp | 413 +++++++++++ src/add-ons/kernel/file_systems/nfs4/Jamfile | 2 + 5 files changed, 700 insertions(+), 659 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp create mode 100644 src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 5c72de93c6..37f16c5b56 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -9,7 +9,6 @@ #include "Inode.h" -#include #include #include @@ -651,661 +650,6 @@ Inode::WriteStat(const struct stat* st, uint32 mask) } -static status_t -sConfirmOpen(Filesystem* fs, Filehandle& fh, OpenFileCookie* cookie) -{ - Request request(fs->Server()); - - RequestBuilder& req = request.Builder(); - - req.PutFH(fh); - req.OpenConfirm(cookie->fSequence++, cookie->fStateId, - cookie->fStateSeq); - - status_t result = request.Send(); - if (result != B_OK) { - fs->RemoveOpenFile(cookie); - return result; - } - - ReplyInterpreter& reply = request.Reply(); - - reply.PutFH(); - - result = reply.OpenConfirm(&cookie->fStateSeq); - if (result != B_OK) { - fs->RemoveOpenFile(cookie); - return result; - } - - return B_OK; -} - - -status_t -Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, - ino_t* id) -{ - bool confirm; - status_t result; - - cookie->fMode = mode; - cookie->fSequence = 0; - cookie->fLocks = NULL; - - Filehandle fh; - do { - cookie->fClientId = fFilesystem->NFSServer()->ClientId(); - - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); - - req.PutFH(fHandle); - - AttrValue cattr[2]; - uint32 i = 0; - if ((mode & O_TRUNC) == O_TRUNC) { - cattr[i].fAttribute = FATTR4_SIZE; - cattr[i].fFreePointer = false; - cattr[i].fData.fValue64 = 0; - i++; - } - cattr[i].fAttribute = FATTR4_MODE; - cattr[i].fFreePointer = false; - cattr[i].fData.fValue32 = perms; - req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), - cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, name, cattr, - i + 1, (mode & O_EXCL) == O_EXCL); - - req.GetFH(); - - if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { - Attribute attr[] = { FATTR4_FILEID }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - } - - result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); - reply.GetFH(&fh); - - uint64 fileId; - if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { - AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; - - fileId = values[1].fData.fValue64; - - delete[] values; - } else - fileId = fFilesystem->AllocFileId(); - - *id = _FileIdToInoT(fileId); - - FileInfo fi; - fi.fFileId = fileId; - fi.fFH = fh; - fi.fParent = fHandle; - fi.fName = strdup(name); - - char* path = reinterpret_cast(malloc(strlen(name) + 2 + - strlen(fPath))); - strcpy(path, fPath); - strcat(path, "/"); - strcat(path, name); - fi.fPath = path; - - fFilesystem->InoIdMap()->AddEntry(fi, *id); - - cookie->fFilesystem = fFilesystem; - cookie->fHandle = fh; - - break; - } while (true); - - fFilesystem->AddOpenFile(cookie); - - if (confirm) - return sConfirmOpen(fFilesystem, fh, cookie); - else - return B_OK; -} - - -status_t -Inode::Open(int mode, OpenFileCookie* cookie) -{ - bool confirm; - status_t result; - - cookie->fFilesystem = fFilesystem; - cookie->fHandle = fHandle; - cookie->fMode = mode; - cookie->fSequence = 0; - cookie->fLocks = NULL; - - do { - cookie->fClientId = fFilesystem->NFSServer()->ClientId(); - - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); - - // Since we are opening the file using a pair (parentFH, name) we - // need to check for race conditions. - if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { - req.PutFH(fParentFH); - req.LookUp(fName); - AttrValue attr; - attr.fAttribute = FATTR4_FILEID; - attr.fFreePointer = false; - attr.fData.fValue64 = fFileId; - req.Verify(&attr, 1); - } else if (fFilesystem->ExpireType() == FH4_PERSISTENT) { - req.PutFH(fParentFH); - req.LookUp(fName); - AttrValue attr; - attr.fAttribute = FATTR4_FILEHANDLE; - attr.fFreePointer = true; - attr.fData.fPointer = malloc(sizeof(fHandle)); - memcpy(attr.fData.fPointer, &fHandle, sizeof(fHandle)); - req.Verify(&attr, 1); - } - - req.PutFH(fParentFH); - if ((mode & O_TRUNC) == O_TRUNC) { - AttrValue attr; - attr.fAttribute = FATTR4_SIZE; - attr.fFreePointer = false; - attr.fData.fValue64 = 0; - req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), - cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, fName, &attr, - 1, false); - } else - req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), - cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, fName); - - result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - // Verify if the file we want to open is the file this Inode - // represents. - if (fFilesystem->IsAttrSupported(FATTR4_FILEID) || - fFilesystem->ExpireType() == FH4_PERSISTENT) { - reply.PutFH(); - result = reply.LookUp(); - if (result != B_OK) - return result; - result = reply.Verify(); - if (result != B_OK && reply.NFS4Error() == NFS4ERR_NOT_SAME) - return B_ENTRY_NOT_FOUND; - else if (result != B_OK) - return result; - } - - reply.PutFH(); - result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); - if (result != B_OK) - return result; - - break; - } while (true); - - fFilesystem->AddOpenFile(cookie); - - if (confirm) - return sConfirmOpen(fFilesystem, fHandle, cookie); - else - return B_OK; -} - - -status_t -Inode::Close(OpenFileCookie* cookie) -{ - fFilesystem->RemoveOpenFile(cookie); - - do { - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fHandle); - req.Close(cookie->fSequence++, cookie->fStateId, - cookie->fStateSeq); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv, cookie)) - continue; - - reply.PutFH(); - result = reply.Close(); - if (result != B_OK) - return result; - - return B_OK; - } while (true); - - return B_OK; -} - - -status_t -Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) -{ - bool eof = false; - uint32 size = 0; - uint32 len = 0; - - while (size < *_length && !eof) { - do { - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fHandle); - req.Read(cookie->fStateId, cookie->fStateSeq, pos + size, - *_length - size); - - status_t result = request.Send(cookie); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv, cookie)) - continue; - - reply.PutFH(); - result = reply.Read(reinterpret_cast(buffer) + size, &len, - &eof); - if (result != B_OK) - return result; - - size += len; - - break; - } while (true); - } - - *_length = size; - - return B_OK; -} - - -status_t -Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, - size_t *_length) -{ - uint32 size = 0; - uint32 len = 0; - uint64 fileSize; - const char* buffer = reinterpret_cast(_buffer); - - while (size < *_length) { - do { - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - if (size == 0 && (cookie->fMode & O_APPEND) == O_APPEND) { - struct stat st; - status_t result = Stat(&st); - if (result != B_OK) - return result; - - fileSize = st.st_size; - pos = fileSize; - } - - req.PutFH(fHandle); - if ((cookie->fMode & O_APPEND) == O_APPEND) { - AttrValue attr; - attr.fAttribute = FATTR4_SIZE; - attr.fFreePointer = false; - attr.fData.fValue64 = fileSize + size; - req.Verify(&attr, 1); - } - req.Write(cookie->fStateId, cookie->fStateSeq, buffer + size, - pos + size, *_length - size); - - status_t result = request.Send(cookie); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - // append: race condition - if (reply.NFS4Error() == NFS4ERR_NOT_SAME) { - if (size == 0) - continue; - else { - *_length = size; - return B_OK; - } - } - - if (_HandleErrors(reply.NFS4Error(), serv, cookie)) - continue; - - reply.PutFH(); - - if ((cookie->fMode & O_APPEND) == O_APPEND) { - result = reply.Verify(); - if (result != B_OK) - return result; - } - - result = reply.Write(&len); - if (result != B_OK) - return result; - - size += len; - - break; - } while (true); - } - - *_length = size; - - return B_OK; -} - - -status_t -Inode::CreateDir(const char* name, int mode) -{ - do { - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fHandle); - - AttrValue attr; - attr.fAttribute = FATTR4_MODE; - attr.fFreePointer = false; - attr.fData.fValue32 = mode; - req.Create(NF4DIR, name, &attr, 1); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - - return reply.Create(); - } while (true); -} - - -status_t -Inode::OpenDir(OpenDirCookie* cookie) -{ - if (fType != NF4DIR) - return B_NOT_A_DIRECTORY; - - do { - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fHandle); - req.Access(); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - - uint32 allowed; - result = reply.Access(NULL, &allowed); - if (result != B_OK) - return result; - - if (allowed & ACCESS4_READ != ACCESS4_READ) - return B_PERMISSION_DENIED; - - cookie->fFilesystem = fFilesystem; - cookie->fCookie = 0; - cookie->fCookieVerf = 2; - - return B_OK; - } while (true); -} - - -status_t -Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, - bool* eof) -{ - do { - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fHandle); - - Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID }; - req.ReadDir(*count, cookie->fCookie, cookie->fCookieVerf, attr, - sizeof(attr) / sizeof(Attribute)); - - status_t result = request.Send(cookie); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - return reply.ReadDir(&cookie->fCookie, &cookie->fCookieVerf, dirents, - count, eof); - } while (true); -} - - -status_t -Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, - uint32 size) -{ - uint32 nameSize = strlen(name); - const uint32 entSize = sizeof(struct dirent); - - if (pos + entSize + nameSize > size) - return B_BUFFER_OVERFLOW; - - de->d_dev = fFilesystem->DevId(); - de->d_ino = id; - de->d_reclen = entSize + nameSize; - if (de->d_reclen % 8 != 0) - de->d_reclen += 8 - de->d_reclen % 8; - - strcpy(de->d_name, name); - - return B_OK; -} - - -status_t -Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) -{ - do { - RPC::Server* serv = fFilesystem->Server(); - Request request(serv); - RequestBuilder& req = request.Builder(); - - req.PutFH(fHandle); - req.LookUpUp(); - req.GetFH(); - - if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { - Attribute attr[] = { FATTR4_FILEID }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - } - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - if (_HandleErrors(reply.NFS4Error(), serv)) - continue; - - reply.PutFH(); - result = reply.LookUpUp(); - if (result != B_OK) - return result; - - Filehandle fh; - reply.GetFH(&fh); - - uint64 fileId; - if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { - AttrValue* values; - uint32 count; - reply.GetAttr(&values, &count); - if (result != B_OK) - return result; - - fileId = values[0].fData.fValue64; - delete[] values; - } else - fileId = fFilesystem->AllocFileId(); - - return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); - } while (true); -} - -// TODO: Currently inode numbers returned by ReadDir are virtually random. -// Apparently Haiku does not use that information (contrary to inode number -// returned by LookUp) so fixing it can wait until directory caches are -// implemented. -// When directories are cached client should store inode numbers it assigned -// to directroy entries and use them consequently. -status_t -Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, - OpenDirCookie* cookie) -{ - uint32 count = 0; - uint32 pos = 0; - uint32 this_count; - bool eof = false; - - char* buffer = reinterpret_cast(_buffer); - - if (cookie->fCookie == 0 && cookie->fCookieVerf == 2 && count < *_count) { - struct dirent* de = reinterpret_cast(buffer + pos); - - _FillDirEntry(de, fFileId, ".", pos, size); - - pos += de->d_reclen; - count++; - cookie->fCookieVerf--; - } - - if (cookie->fCookie == 0 && cookie->fCookieVerf == 1 && count < *_count) { - struct dirent* de = reinterpret_cast(buffer + pos); - - if (strcmp(fName, "/")) - _ReadDirUp(de, pos, size); - else - _FillDirEntry(de, _FileIdToInoT(fFileId), "..", pos, size); - - pos += de->d_reclen; - count++; - cookie->fCookieVerf--; - } - - bool overflow = false; - while (count < *_count && !eof) { - this_count = *_count - count; - DirEntry* dirents; - - status_t result = _ReadDirOnce(&dirents, &this_count, cookie, &eof); - if (result != B_OK) - return result; - - uint32 i, entries = 0; - for (i = 0; i < min_c(this_count, *_count - count); i++) { - struct dirent* de = reinterpret_cast(buffer + pos); - - // FATTR4_FSID is mandatory - void* data = dirents[i].fAttrs[0].fData.fPointer; - FilesystemId* fsid = reinterpret_cast(data); - if (*fsid != fFilesystem->FsId()) - continue; - - ino_t id; - if (dirents[i].fAttrCount == 2) - id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); - else - id = _FileIdToInoT(fFilesystem->AllocFileId()); - - const char* name = dirents[i].fName; - if (_FillDirEntry(de, id, name, pos, size) == B_BUFFER_OVERFLOW) { - eof = true; - overflow = true; - break; - } - - pos += de->d_reclen; - entries++; - } - delete[] dirents; - count += entries; - } - - if (count == 0 && overflow) - return B_BUFFER_OVERFLOW; - - *_count = count; - - return B_OK; -} - - status_t Inode::TestLock(OpenFileCookie* cookie, struct flock* lock) { @@ -1501,7 +845,6 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie) } - bool Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, OpenFileCookie* cookie) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 56051913ca..4beed54e1f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -71,13 +71,13 @@ public: protected: Inode(); - bool _HandleErrors(uint32 nfs4Error, RPC::Server* serv, OpenFileCookie* cookie = NULL); - status_t _LookUpFilehandle(); + status_t _ConfirmOpen(OpenFileCookie* cookie); + status_t _ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, bool* eof); status_t _FillDirEntry(struct dirent* de, ino_t id, diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp new file mode 100644 index 0000000000..290c56fb6a --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp @@ -0,0 +1,283 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "Inode.h" + +#include +#include + +#include "Request.h" +#include "RootInode.h" + + +status_t +Inode::CreateDir(const char* name, int mode) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + + AttrValue attr; + attr.fAttribute = FATTR4_MODE; + attr.fFreePointer = false; + attr.fData.fValue32 = mode; + req.Create(NF4DIR, name, &attr, 1); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + + return reply.Create(); + } while (true); +} + + +status_t +Inode::OpenDir(OpenDirCookie* cookie) +{ + if (fType != NF4DIR) + return B_NOT_A_DIRECTORY; + + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.Access(); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + + uint32 allowed; + result = reply.Access(NULL, &allowed); + if (result != B_OK) + return result; + + if (allowed & ACCESS4_READ != ACCESS4_READ) + return B_PERMISSION_DENIED; + + cookie->fFilesystem = fFilesystem; + cookie->fCookie = 0; + cookie->fCookieVerf = 2; + + return B_OK; + } while (true); +} + + +status_t +Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, + bool* eof) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + + Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID }; + req.ReadDir(*count, cookie->fCookie, cookie->fCookieVerf, attr, + sizeof(attr) / sizeof(Attribute)); + + status_t result = request.Send(cookie); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + return reply.ReadDir(&cookie->fCookie, &cookie->fCookieVerf, dirents, + count, eof); + } while (true); +} + + +status_t +Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos, + uint32 size) +{ + uint32 nameSize = strlen(name); + const uint32 entSize = sizeof(struct dirent); + + if (pos + entSize + nameSize > size) + return B_BUFFER_OVERFLOW; + + de->d_dev = fFilesystem->DevId(); + de->d_ino = id; + de->d_reclen = entSize + nameSize; + if (de->d_reclen % 8 != 0) + de->d_reclen += 8 - de->d_reclen % 8; + + strcpy(de->d_name, name); + + return B_OK; +} + + +status_t +Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.LookUpUp(); + req.GetFH(); + + if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + } + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + result = reply.LookUpUp(); + if (result != B_OK) + return result; + + Filehandle fh; + reply.GetFH(&fh); + + uint64 fileId; + if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + AttrValue* values; + uint32 count; + reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + fileId = values[0].fData.fValue64; + delete[] values; + } else + fileId = fFilesystem->AllocFileId(); + + return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size); + } while (true); +} + +// TODO: Currently inode numbers returned by ReadDir are virtually random. +// Apparently Haiku does not use that information (contrary to inode number +// returned by LookUp) so fixing it can wait until directory caches are +// implemented. +// When directories are cached client should store inode numbers it assigned +// to directroy entries and use them consequently. +status_t +Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, + OpenDirCookie* cookie) +{ + uint32 count = 0; + uint32 pos = 0; + uint32 this_count; + bool eof = false; + + char* buffer = reinterpret_cast(_buffer); + + if (cookie->fCookie == 0 && cookie->fCookieVerf == 2 && count < *_count) { + struct dirent* de = reinterpret_cast(buffer + pos); + + _FillDirEntry(de, fFileId, ".", pos, size); + + pos += de->d_reclen; + count++; + cookie->fCookieVerf--; + } + + if (cookie->fCookie == 0 && cookie->fCookieVerf == 1 && count < *_count) { + struct dirent* de = reinterpret_cast(buffer + pos); + + if (strcmp(fName, "/")) + _ReadDirUp(de, pos, size); + else + _FillDirEntry(de, _FileIdToInoT(fFileId), "..", pos, size); + + pos += de->d_reclen; + count++; + cookie->fCookieVerf--; + } + + bool overflow = false; + while (count < *_count && !eof) { + this_count = *_count - count; + DirEntry* dirents; + + status_t result = _ReadDirOnce(&dirents, &this_count, cookie, &eof); + if (result != B_OK) + return result; + + uint32 i, entries = 0; + for (i = 0; i < min_c(this_count, *_count - count); i++) { + struct dirent* de = reinterpret_cast(buffer + pos); + + // FATTR4_FSID is mandatory + void* data = dirents[i].fAttrs[0].fData.fPointer; + FilesystemId* fsid = reinterpret_cast(data); + if (*fsid != fFilesystem->FsId()) + continue; + + ino_t id; + if (dirents[i].fAttrCount == 2) + id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64); + else + id = _FileIdToInoT(fFilesystem->AllocFileId()); + + const char* name = dirents[i].fName; + if (_FillDirEntry(de, id, name, pos, size) == B_BUFFER_OVERFLOW) { + eof = true; + overflow = true; + break; + } + + pos += de->d_reclen; + entries++; + } + delete[] dirents; + count += entries; + } + + if (count == 0 && overflow) + return B_BUFFER_OVERFLOW; + + *_count = count; + + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp new file mode 100644 index 0000000000..3e95ec1eb6 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp @@ -0,0 +1,413 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "Inode.h" + +#include + +#include + +#include "Request.h" + + +status_t +Inode::_ConfirmOpen(OpenFileCookie* cookie) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.OpenConfirm(cookie->fSequence++, cookie->fStateId, + cookie->fStateSeq); + + status_t result = request.Send(); + if (result != B_OK) { + fFilesystem->RemoveOpenFile(cookie); + return result; + } + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + result = reply.OpenConfirm(&cookie->fStateSeq); + if (result != B_OK) { + fFilesystem->RemoveOpenFile(cookie); + return result; + } + + break; + } while (true); + + return B_OK; +} + + +status_t +Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie, + ino_t* id) +{ + bool confirm; + status_t result; + + cookie->fMode = mode; + cookie->fSequence = 0; + cookie->fLocks = NULL; + + Filehandle fh; + do { + cookie->fClientId = fFilesystem->NFSServer()->ClientId(); + + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); + + req.PutFH(fHandle); + + AttrValue cattr[2]; + uint32 i = 0; + if ((mode & O_TRUNC) == O_TRUNC) { + cattr[i].fAttribute = FATTR4_SIZE; + cattr[i].fFreePointer = false; + cattr[i].fData.fValue64 = 0; + i++; + } + cattr[i].fAttribute = FATTR4_MODE; + cattr[i].fFreePointer = false; + cattr[i].fData.fValue32 = perms; + req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), + cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, name, cattr, + i + 1, (mode & O_EXCL) == O_EXCL); + + req.GetFH(); + + if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + Attribute attr[] = { FATTR4_FILEID }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + } + + result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); + reply.GetFH(&fh); + + uint64 fileId; + if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + AttrValue* values; + uint32 count; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + fileId = values[1].fData.fValue64; + + delete[] values; + } else + fileId = fFilesystem->AllocFileId(); + + *id = _FileIdToInoT(fileId); + + FileInfo fi; + fi.fFileId = fileId; + fi.fFH = fh; + fi.fParent = fHandle; + fi.fName = strdup(name); + + char* path = reinterpret_cast(malloc(strlen(name) + 2 + + strlen(fPath))); + strcpy(path, fPath); + strcat(path, "/"); + strcat(path, name); + fi.fPath = path; + + fFilesystem->InoIdMap()->AddEntry(fi, *id); + + cookie->fFilesystem = fFilesystem; + cookie->fHandle = fh; + + break; + } while (true); + + fFilesystem->AddOpenFile(cookie); + + if (confirm) + return _ConfirmOpen(cookie); + else + return B_OK; +} + + +status_t +Inode::Open(int mode, OpenFileCookie* cookie) +{ + bool confirm; + status_t result; + + cookie->fFilesystem = fFilesystem; + cookie->fHandle = fHandle; + cookie->fMode = mode; + cookie->fSequence = 0; + cookie->fLocks = NULL; + + do { + cookie->fClientId = fFilesystem->NFSServer()->ClientId(); + + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1); + + // Since we are opening the file using a pair (parentFH, name) we + // need to check for race conditions. + if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) { + req.PutFH(fParentFH); + req.LookUp(fName); + AttrValue attr; + attr.fAttribute = FATTR4_FILEID; + attr.fFreePointer = false; + attr.fData.fValue64 = fFileId; + req.Verify(&attr, 1); + } else if (fFilesystem->ExpireType() == FH4_PERSISTENT) { + req.PutFH(fParentFH); + req.LookUp(fName); + AttrValue attr; + attr.fAttribute = FATTR4_FILEHANDLE; + attr.fFreePointer = true; + attr.fData.fPointer = malloc(sizeof(fHandle)); + memcpy(attr.fData.fPointer, &fHandle, sizeof(fHandle)); + req.Verify(&attr, 1); + } + + req.PutFH(fParentFH); + if ((mode & O_TRUNC) == O_TRUNC) { + AttrValue attr; + attr.fAttribute = FATTR4_SIZE; + attr.fFreePointer = false; + attr.fData.fValue64 = 0; + req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), + cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, fName, &attr, + 1, false); + } else + req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode), + cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, fName); + + result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + // Verify if the file we want to open is the file this Inode + // represents. + if (fFilesystem->IsAttrSupported(FATTR4_FILEID) || + fFilesystem->ExpireType() == FH4_PERSISTENT) { + reply.PutFH(); + result = reply.LookUp(); + if (result != B_OK) + return result; + result = reply.Verify(); + if (result != B_OK && reply.NFS4Error() == NFS4ERR_NOT_SAME) + return B_ENTRY_NOT_FOUND; + else if (result != B_OK) + return result; + } + + reply.PutFH(); + result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm); + if (result != B_OK) + return result; + + break; + } while (true); + + fFilesystem->AddOpenFile(cookie); + + if (confirm) + return _ConfirmOpen(cookie); + else + return B_OK; +} + + +status_t +Inode::Close(OpenFileCookie* cookie) +{ + fFilesystem->RemoveOpenFile(cookie); + + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.Close(cookie->fSequence++, cookie->fStateId, + cookie->fStateSeq); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + + reply.PutFH(); + result = reply.Close(); + if (result != B_OK) + return result; + + return B_OK; + } while (true); + + return B_OK; +} + + +status_t +Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length) +{ + bool eof = false; + uint32 size = 0; + uint32 len = 0; + + while (size < *_length && !eof) { + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.Read(cookie->fStateId, cookie->fStateSeq, pos + size, + *_length - size); + + status_t result = request.Send(cookie); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + + reply.PutFH(); + result = reply.Read(reinterpret_cast(buffer) + size, &len, + &eof); + if (result != B_OK) + return result; + + size += len; + + break; + } while (true); + } + + *_length = size; + + return B_OK; +} + + +status_t +Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer, + size_t *_length) +{ + uint32 size = 0; + uint32 len = 0; + uint64 fileSize; + const char* buffer = reinterpret_cast(_buffer); + + while (size < *_length) { + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + if (size == 0 && (cookie->fMode & O_APPEND) == O_APPEND) { + struct stat st; + status_t result = Stat(&st); + if (result != B_OK) + return result; + + fileSize = st.st_size; + pos = fileSize; + } + + req.PutFH(fHandle); + if ((cookie->fMode & O_APPEND) == O_APPEND) { + AttrValue attr; + attr.fAttribute = FATTR4_SIZE; + attr.fFreePointer = false; + attr.fData.fValue64 = fileSize + size; + req.Verify(&attr, 1); + } + req.Write(cookie->fStateId, cookie->fStateSeq, buffer + size, + pos + size, *_length - size); + + status_t result = request.Send(cookie); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + // append: race condition + if (reply.NFS4Error() == NFS4ERR_NOT_SAME) { + if (size == 0) + continue; + else { + *_length = size; + return B_OK; + } + } + + if (_HandleErrors(reply.NFS4Error(), serv, cookie)) + continue; + + reply.PutFH(); + + if ((cookie->fMode & O_APPEND) == O_APPEND) { + result = reply.Verify(); + if (result != B_OK) + return result; + } + + result = reply.Write(&len); + if (result != B_OK) + return result; + + size += len; + + break; + } while (true); + } + + *_length = size; + + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 70b6749ad5..57060a135b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -8,6 +8,8 @@ KernelAddon nfs4 : Connection.cpp Filesystem.cpp Inode.cpp + InodeDir.cpp + InodeRegular.cpp kernel_interface.cpp NFS4Server.cpp ReplyInterpreter.cpp