Skip to content

Commit 61cde16

Browse files
Fixed bug causing SETATTR to always fail when guard is supplied
... due to guard's ctime not matching relevant entry's Ctimespec field. The reason why the guard's ctime will never match is due to function `ToNFSTime` converting `time.Time.UnixNano()` to `uint32` *before* removing seconds part from the value via a modulo operation. Since the ctime value in the guard should be coming from a LOOKUP response (or perhaps from some other response that contains entry stats, e.g. GETATTR or READDIRPLUS), and the ctime field in all those responses has been "formatted" via `ToNFSTime`, there will be no way for a remote call to SETATTR to succeed when guard is being supplied. This commit fixes the bug in `ToNFSTime` but also changes the guard check in the SETATTR implementation to use the same struct as the one that is being sent in responses that contain entry stats. This change to the SETATTR implementation is technically unnecessary but (IMO) it should be cleaner and safer.
1 parent e04a5b5 commit 61cde16

File tree

2 files changed

+4
-19
lines changed

2 files changed

+4
-19
lines changed

nfs_onsetattr.go

+3-18
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ package nfs
33
import (
44
"bytes"
55
"context"
6-
"log"
76
"os"
8-
"reflect"
9-
"syscall"
107

118
"github.com/go-git/go-billy/v5"
129
"github.com/willscott/go-nfs-client/nfs/xdr"
@@ -45,22 +42,10 @@ func onSetAttr(ctx context.Context, w *response, userHandle Handler) error {
4542
if err := xdr.Read(w.req.Body, &t); err != nil {
4643
return &NFSStatusError{NFSStatusInval, err}
4744
}
48-
if info.Sys() != nil {
49-
extra := reflect.ValueOf(info.Sys())
50-
if extra.Kind() == reflect.Struct {
51-
ctimeField := extra.FieldByName("Ctimespec")
52-
if ts, ok := ctimeField.Interface().(syscall.Timespec); ok {
53-
if !t.EqualTimespec(ts.Unix()) {
54-
return &NFSStatusError{NFSStatusNotSync, nil}
55-
}
56-
goto TIME_GOOD
57-
} else {
58-
log.Printf("Ctimespec field isn't a timespec")
59-
}
60-
}
45+
attr := ToFileAttribute(info)
46+
if t != attr.Ctime {
47+
return &NFSStatusError{NFSStatusNotSync, nil}
6148
}
62-
return &NFSStatusError{NFSStatusNotSupp, nil}
63-
TIME_GOOD:
6449
}
6550

6651
if !billy.CapabilityCheck(fs, billy.WriteCapability) {

time.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ type FileTime struct {
1515
func ToNFSTime(t time.Time) FileTime {
1616
return FileTime{
1717
Seconds: uint32(t.Unix()),
18-
Nseconds: uint32(t.UnixNano()) % uint32(time.Second),
18+
Nseconds: uint32(t.UnixNano() % int64(time.Second)),
1919
}
2020
}
2121

0 commit comments

Comments
 (0)