X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/7d4e2e418a987a454d18902a937fc91bed69ce75..32c63d03d45d231768eb1497dfc5e9f4a0d23c16:/lib/mount/fs.go diff --git a/lib/mount/fs.go b/lib/mount/fs.go index 5b6fc0012f..3c2e628d01 100644 --- a/lib/mount/fs.go +++ b/lib/mount/fs.go @@ -5,6 +5,7 @@ package mount import ( + "errors" "io" "log" "os" @@ -36,7 +37,7 @@ type keepFS struct { root arvados.CustomFileSystem open map[uint64]*sharedFile lastFH uint64 - sync.Mutex + sync.RWMutex // If non-nil, this channel will be closed by Init() to notify // other goroutines that the mount is ready. @@ -62,8 +63,8 @@ func (fs *keepFS) newFH(f arvados.File) uint64 { } func (fs *keepFS) lookupFH(fh uint64) *sharedFile { - fs.Lock() - defer fs.Unlock() + fs.RLock() + defer fs.RUnlock() return fs.open[fh] } @@ -121,23 +122,25 @@ func (fs *keepFS) Utimens(path string, tmsp []fuse.Timespec) int { } func (fs *keepFS) errCode(err error) int { - if os.IsNotExist(err) { + if err == nil { + return 0 + } + if errors.Is(err, os.ErrNotExist) { return -fuse.ENOENT } - switch err { - case os.ErrExist: + if errors.Is(err, os.ErrExist) { return -fuse.EEXIST - case arvados.ErrInvalidArgument: + } + if errors.Is(err, arvados.ErrInvalidArgument) { return -fuse.EINVAL - case arvados.ErrInvalidOperation: + } + if errors.Is(err, arvados.ErrInvalidOperation) { return -fuse.ENOSYS - case arvados.ErrDirectoryNotEmpty: + } + if errors.Is(err, arvados.ErrDirectoryNotEmpty) { return -fuse.ENOTEMPTY - case nil: - return 0 - default: - return -fuse.EIO } + return -fuse.EIO } func (fs *keepFS) Mkdir(path string, mode uint32) int { @@ -252,11 +255,18 @@ func (fs *keepFS) Chmod(path string, mode uint32) (errc int) { } if fi, err := fs.root.Stat(path); err != nil { return fs.errCode(err) - } else if mode & ^uint32(fuse.S_IFREG|fuse.S_IFDIR|0777) != 0 || (fi.Mode()&os.ModeDir != 0) != (mode&fuse.S_IFDIR != 0) { + } else if mode & ^uint32(fuse.S_IFREG|fuse.S_IFDIR|0777) != 0 { + // Refuse to set mode bits other than + // regfile/dir/perms + return -fuse.ENOSYS + } else if (fi.Mode()&os.ModeDir != 0) != (mode&fuse.S_IFDIR != 0) { + // Refuse to transform a regular file to a dir, or + // vice versa return -fuse.ENOSYS - } else { - return 0 } + // As long as the change isn't nonsense, chmod is a no-op, + // because we don't save permission bits. + return 0 } func (fs *keepFS) fillStat(stat *fuse.Stat_t, fi os.FileInfo) { @@ -320,6 +330,16 @@ func (fs *keepFS) Read(path string, buf []byte, ofst int64, fh uint64) (n int) { return fs.errCode(err) } n, err := f.Read(buf) + for err == nil && n < len(buf) { + // f is an io.Reader ("If some data is available but + // not len(p) bytes, Read conventionally returns what + // is available instead of waiting for more") -- but + // our caller requires us to either fill buf or reach + // EOF. + done := n + n, err = f.Read(buf[done:]) + n += done + } if err != nil && err != io.EOF { log.Printf("error reading %q: %s", path, err) return fs.errCode(err)