diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 9fc701fa5c..f11780ac9a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -151,6 +151,36 @@ Inode::LookUp(const char* name, ino_t* id) } +status_t +Inode::ReadLink(void* buffer, size_t* length) +{ + if (fType != NF4LNK) + return B_BAD_VALUE; + + Request request(fFilesystem->Server()); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.ReadLink(); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + result = reply.PutFH(); + if (result != B_OK) + return result; + + uint32 size; + result = reply.ReadLink(buffer, &size, *length); + *length = static_cast(size); + + return result; +} + + status_t Inode::Access(int mode) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 0e99e7cb72..43fb9bdef3 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -35,6 +35,7 @@ public: inline const char* Name() const; status_t LookUp(const char* name, ino_t* id); + status_t ReadLink(void* buffer, size_t* length); status_t Access(int mode); status_t Stat(struct stat* st); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index c8b71121e8..5dbe383151 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -33,6 +33,7 @@ enum Opcode { OpPutRootFH = 24, OpRead = 25, OpReadDir = 26, + OpReadLink = 27, OpRenew = 30, OpSetClientID = 35, OpSetClientIDConfirm = 36 diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index ece60c05c8..f7b62600d0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -257,6 +257,19 @@ ReplyInterpreter::ReadDir(uint64* cookie, DirEntry** dirents, uint32* _count, } +status_t +ReplyInterpreter::ReadLink(void* buffer, uint32* size, uint32 maxSize) +{ + status_t res = _OperationError(OpReadLink); + if (res != B_OK) + return res; + + const void* ptr = fReply->Stream().GetOpaque(size); + memcpy(buffer, ptr, min_c(*size, maxSize)); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + status_t ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier) { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index c513b81ca7..4e8ae6e4f6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -58,6 +58,7 @@ public: status_t Read(void* buffer, uint32* size, bool* eof); status_t ReadDir(uint64* cookie, DirEntry** dirents, uint32* count, bool* eof); + status_t ReadLink(void* buffer, uint32* size, uint32 maxSize); inline status_t Renew(); status_t SetClientID(uint64* clientid, uint64* verifier); inline status_t SetClientIDConfirm(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index b7dc398eba..d361b861d6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -286,6 +286,22 @@ RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs, } +status_t +RequestBuilder::ReadLink() +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpReadLink); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::Renew(uint64 clientId) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 130c053511..21e2ecbf77 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -41,6 +41,7 @@ public: uint64 pos, uint32 len); status_t ReadDir(uint32 count, uint64* cookie, Attribute* attrs, uint32 attrCount); + status_t ReadLink(); status_t Renew(uint64 clientId); status_t SetClientID(const RPC::Server* serv); status_t SetClientIDConfirm(uint64 id, uint64 ver); diff --git a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp index ed922ad062..bd44f8dffd 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -145,6 +145,15 @@ nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) } +static status_t +nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, + size_t* _bufferSize) +{ + Inode* inode = reinterpret_cast(link->private_node); + return inode->ReadLink(buffer, _bufferSize); +} + + static status_t nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode) { @@ -342,7 +351,7 @@ fs_vnode_ops gNFSv4VnodeOps = { NULL, // fs_deselect() NULL, // fsync() - NULL, // read_link() + nfs4_read_symlink, NULL, // create_symlink() NULL, // link()