From e288824155e4ff8ab561180b3135621c59507e02 Mon Sep 17 00:00:00 2001 From: mhiles Date: Wed, 24 Apr 2019 07:40:27 -0700 Subject: [PATCH 1/2] Add support for NFS3 Readlink --- nfs/file.go | 41 +++++++++++++++++++++++++++++++++++++++++ nfs/nfs.go | 1 + 2 files changed, 42 insertions(+) diff --git a/nfs/file.go b/nfs/file.go index e4f33a7..a8ddae1 100644 --- a/nfs/file.go +++ b/nfs/file.go @@ -26,6 +26,47 @@ type File struct { fh []byte } +// Readlink gets the target of a symlink +func (f *File) Readlink() (string, error) { + type ReadlinkArgs struct { + rpc.Header + FH []byte + } + + type ReadlinkRes struct { + Attr PostOpAttr + data []byte + } + + r, err := f.call(&ReadlinkArgs{ + Header: rpc.Header{ + Rpcvers: 2, + Prog: Nfs3Prog, + Vers: Nfs3Vers, + Proc: NFSProc3Readlink, + Cred: f.auth, + Verf: rpc.AuthNull, + }, + FH: f.fh, + }) + + if err != nil { + util.Debugf("readlink(%x): %s", f.fh, err.Error()) + return "", err + } + + readlinkres := &ReadlinkRes{} + if err = xdr.Read(r, readlinkres); err != nil { + return "", err + } + + if readlinkres.data, err = xdr.ReadOpaque(r); err != nil { + return "", err + } + + return string(readlinkres.data), err +} + func (f *File) Read(p []byte) (int, error) { type ReadArgs struct { rpc.Header diff --git a/nfs/nfs.go b/nfs/nfs.go index fb7ea1f..1ba7150 100644 --- a/nfs/nfs.go +++ b/nfs/nfs.go @@ -22,6 +22,7 @@ const ( // program methods NFSProc3Lookup = 3 + NFSProc3Readlink = 5 NFSProc3Read = 6 NFSProc3Write = 7 NFSProc3Create = 8 From a472b22eb7238b7abbcfe65c68fd3216d7788b51 Mon Sep 17 00:00:00 2001 From: mhiles Date: Thu, 5 Dec 2019 13:58:42 -0500 Subject: [PATCH 2/2] add support for NFS3PROC_Symlink --- nfs/file.go | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++ nfs/nfs.go | 1 + 2 files changed, 71 insertions(+) diff --git a/nfs/file.go b/nfs/file.go index a8ddae1..6f2e8a2 100644 --- a/nfs/file.go +++ b/nfs/file.go @@ -7,6 +7,7 @@ import ( "errors" "io" "os" + "path/filepath" "github.com/vmware/go-nfs-client/nfs/rpc" "github.com/vmware/go-nfs-client/nfs/util" @@ -286,6 +287,75 @@ func (v *Target) Open(path string) (*File, error) { return f, nil } +// Symlink creates a symlink as where pointing to symlink +func (v *Target) Symlink(where, symlink string) (*File, error) { + type symlinkdata3 struct { + SymlinkAttr Sattr3 + SymlinkData []byte + } + + type SymlinkArgs struct { + rpc.Header + Where Diropargs3 + Symlink symlinkdata3 + } + + type SymlinkRes struct { + obj PostOpFH3 + objAttr PostOpAttr + Wcc WccData + } + + symlinkName := filepath.Base(where) + symlinkDir := filepath.Dir(where) + + _, fh, err := v.Lookup(symlinkDir) + if err != nil { + return nil, err + } + + r, err := v.call(&SymlinkArgs{ + Header: rpc.Header{ + Rpcvers: 2, + Prog: Nfs3Prog, + Vers: Nfs3Vers, + Proc: NFSProc3Symlink, + Cred: v.auth, + Verf: rpc.AuthNull, + }, + Where: Diropargs3{ + FH: fh, + Filename: symlinkName, + }, + Symlink: symlinkdata3{ + SymlinkAttr: Sattr3{}, + SymlinkData: []byte(symlink), + }, + }) + + if err != nil { + util.Debugf("Symlink(%s): %s", where, err.Error()) + return nil, err + } + + symlinkres := &SymlinkRes{} + if err = xdr.Read(r, symlinkres); err != nil { + return nil, err + } + + if !symlinkres.obj.IsSet { + return nil, errors.New("fh not set") + } + + symFile := &File{ + Target: v, + fsinfo: v.fsinfo, + fh: symlinkres.obj.FH, + } + + return symFile, nil +} + func min(x, y uint32) uint32 { if x > y { return y diff --git a/nfs/nfs.go b/nfs/nfs.go index 1ba7150..2bafe8e 100644 --- a/nfs/nfs.go +++ b/nfs/nfs.go @@ -27,6 +27,7 @@ const ( NFSProc3Write = 7 NFSProc3Create = 8 NFSProc3Mkdir = 9 + NFSProc3Symlink = 10 NFSProc3Remove = 12 NFSProc3RmDir = 13 NFSProc3ReadDirPlus = 17