Description
What version of Go are you using (go version
)?
$ go version go version go1.12.5 linux/amd64
Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env GOARCH="amd64" GOBIN="" GOCACHE="/home/flamencoadmin/.cache/go-build" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOOS="linux" GOPATH="/home/flamencoadmin/go" GOPROXY="" GORACE="" GOROOT="/opt/go" GOTMPDIR="" GOTOOLDIR="/opt/go/pkg/tool/linux_amd64" GCCGO="gccgo" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="/home/flamencoadmin/gotouch/go.mod" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build400479428=/tmp/go-build -gno-record-gcc-switches"
What did you do?
Call os.Chtimes(filepath, now, now)
where filepath
is poining to a regular file on an SMB share and now := time.Now()
.
What did you expect to see?
No error, and the mtime of the file changed to 'now'.
What did you see instead?
An os.PathError
is returned as follows:
Error type: *os.PathError
Error msg: chtimes /mnt/flamenco-input/file-store/stored/d6/2d13ed80d57784d9c5113a4bb32541c2b23a1e7ef02117f49084985bee144d/8271557.blob: operation not permitted
op : chtimes
path: /mnt/flamenco-input/file-store/stored/d6/2d13ed80d57784d9c5113a4bb32541c2b23a1e7ef02117f49084985bee144d/8271557.blob
err : operation not permitted
The SMB share is served from a Microsoft SMB server (an Azure Files share), which apparently doesn't support setting the modification/access time to a specific timestamp. However, what it does support is setting the mtime to "now" using the Linux touch
CLI application. By using strace touch thefile
I found that it actually calls utimensat()
with NULL
as timestamp, rather than passing an explicit timestamp.
To test whether passing NULL
would work, I added the following function to src/syscall/syscall_linux.go
:
func UtimesNanoNow(path string) (err error) {
err = utimensat(_AT_FDCWD, path, nil, 0)
if err != ENOSYS {
return err
}
return utimes(path, nil)
}
The following now works fine on the SMB share:
func ChtimesNow(name string) error {
if e := syscall.UtimesNanoNow(name); e != nil {
return &os.PathError{"chtimes", name, e}
}
return nil
}
I tested this on Linux (4.18.0-1014-azure) on Ubuntu (18.04.2). The SMB share was mounted with the following options, as per the Microsoft documentation:
//${ACCOUNT_NAME}.file.core.windows.net/flamenco-resources on /mnt/flamenco-resources type cifs (rw,relatime,vers=3.0,sec=ntlmssp,cache=strict,username=${ACCOUNT_NAME},password=${ACCOUNT_PASSWORD},dir_mode=0770,file_mode=0775,gid=flamenco,forcegid,sec=ntlmssp,mfsymlinks)