diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 2d73127b89..a73837e37d 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -383,6 +383,49 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) } +status_t +Inode::CreateLink(const char* name, const char* path, 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(NF4LNK, name, path, &attr, 1); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + _LookUpFilehandle(); + continue; + } + + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + fFilesystem->Migrate(fHandle, serv); + continue; + } + + result = reply.PutFH(); + if (result != B_OK) + return result; + + return reply.Create(); + } while (true); +} + + status_t Inode::ReadLink(void* buffer, size_t* length) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 1809604c27..89caa2c39c 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -31,7 +31,11 @@ public: inline Filesystem* FileSystem() const; status_t LookUp(const char* name, ino_t* id); + + status_t CreateLink(const char* name, const char* path, + int mode); status_t ReadLink(void* buffer, size_t* length); + status_t Link(Inode* dir, const char* name); status_t Remove(const char* name, FileType type); static status_t Rename(Inode* from, Inode* to, diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 8a07f035c9..548992be91 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -23,6 +23,7 @@ enum Procedure { enum Opcode { OpAccess = 3, OpClose = 4, + OpCreate = 6, OpGetAttr = 9, OpGetFH = 10, OpLink = 11, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 3e133faf48..dd03e0ef81 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -122,6 +122,25 @@ ReplyInterpreter::Close() } +status_t +ReplyInterpreter::Create() +{ + status_t res = _OperationError(OpCreate); + if (res != B_OK) + return res; + + fReply->Stream().GetBoolean(); + fReply->Stream().GetUHyper(); + fReply->Stream().GetUHyper(); + uint32 count = fReply->Stream().GetUInt(); + for (uint32 i; i < count; i++) + fReply->Stream().GetUInt(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + + // Bit Twiddling Hacks // http://graphics.stanford.edu/~seander/bithacks.html static inline uint32 sCountBits(uint32 v) diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 51fd364514..9c22a5e55b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -66,6 +66,7 @@ public: status_t Access(uint32* supported, uint32* allowed); status_t Close(); + status_t Create(); status_t GetAttr(AttrValue** attrs, uint32* count); status_t GetFH(Filehandle* fh); status_t Link(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 4ce72edc8e..e45eafb6b8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -86,6 +86,33 @@ RequestBuilder::Close(uint32 seq, const uint32* id, uint32 stateSeq) } +status_t +RequestBuilder::Create(FileType type, const char* name, const char* path, + AttrValue* attr, uint32 count) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + if (path == NULL) + return B_BAD_VALUE; + if (name == NULL) + return B_BAD_VALUE; + if (type != NF4LNK) + return B_BAD_VALUE; + + fRequest->Stream().AddUInt(OpCreate); + fRequest->Stream().AddUInt(type); + fRequest->Stream().AddString(path); + fRequest->Stream().AddString(name); + _EncodeAttrs(fRequest->Stream(), attr, count); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::GetAttr(Attribute* attrs, uint32 count) { @@ -459,22 +486,8 @@ RequestBuilder::Verify(AttrValue* attr, uint32 count) return B_NO_MEMORY; fRequest->Stream().AddUInt(OpVerify); + _EncodeAttrs(fRequest->Stream(), attr, count); - Attribute* attrs = - reinterpret_cast(malloc(sizeof(Attribute) * count)); - for (uint32 i = 0; i < count; i++) - attrs[i] = static_cast(attr[i].fAttribute); - _AttrBitmap(fRequest->Stream(), attrs, count); - free(attrs); - - uint32 i = 0; - XDR::WriteStream str; - if (i < count && attr[i].fAttribute == FATTR4_TYPE) { - str.AddUInt(attr[i].fData.fValue32); - i++; - } - - fRequest->Stream().AddOpaque(str); fOpCount++; return B_OK; @@ -511,3 +524,30 @@ RequestBuilder::_AttrBitmap(XDR::WriteStream& stream, Attribute* attrs, stream.AddUInt(bitmap[i]); } + +void +RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, + uint32 count) +{ + Attribute* attrs = + reinterpret_cast(malloc(sizeof(Attribute) * count)); + for (uint32 i = 0; i < count; i++) + attrs[i] = static_cast(attr[i].fAttribute); + _AttrBitmap(stream, attrs, count); + free(attrs); + + uint32 i = 0; + XDR::WriteStream str; + if (i < count && attr[i].fAttribute == FATTR4_TYPE) { + str.AddUInt(attr[i].fData.fValue32); + i++; + } + + if (i < count && attr[i].fAttribute == FATTR4_MODE) { + str.AddUInt(attr[i].fData.fValue32); + i++; + } + + stream.AddOpaque(str); +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 9710cf171e..8101cd4059 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -28,6 +28,9 @@ public: status_t Access(); status_t Close(uint32 seq, const uint32* id, uint32 stateSeq); + status_t Create(FileType type, const char* name, + const char* path, AttrValue* attr, + uint32 count); status_t GetAttr(Attribute* attrs, uint32 count); status_t GetFH(); status_t Link(const char* name); @@ -59,6 +62,8 @@ public: private: void _InitHeader(); + void _EncodeAttrs(XDR::WriteStream& stream, + AttrValue* attr, uint32 count); void _AttrBitmap(XDR::WriteStream& stream, Attribute* attrs, uint32 count); 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 e8f7b2949f..8a5781cac8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -212,6 +212,15 @@ nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, } +static status_t +nfs4_create_symlink(fs_volume* volume, fs_vnode* dir, const char* name, + const char* path, int mode) +{ + Inode* inode = reinterpret_cast(dir->private_node); + return inode->CreateLink(name, path, mode); +} + + static status_t nfs4_link(fs_volume* volume, fs_vnode* dir, const char* name, fs_vnode* vnode) { @@ -456,7 +465,7 @@ fs_vnode_ops gNFSv4VnodeOps = { NULL, // fsync() nfs4_read_symlink, - NULL, // create_symlink() + nfs4_create_symlink, nfs4_link, nfs4_unlink,