diff --git a/cmd/cmount/fs.go b/cmd/cmount/fs.go index c9242e0cb..f155399ad 100644 --- a/cmd/cmount/fs.go +++ b/cmd/cmount/fs.go @@ -540,6 +540,8 @@ func translateError(err error) (errc int) { return -fuse.EROFS case vfs.ENOSYS: return -fuse.ENOSYS + case vfs.EINVAL: + return -fuse.EINVAL } fs.Errorf(nil, "IO error: %v", err) return -fuse.EIO diff --git a/cmd/mount/fs.go b/cmd/mount/fs.go index b892681d4..d8adb35b1 100644 --- a/cmd/mount/fs.go +++ b/cmd/mount/fs.go @@ -91,6 +91,8 @@ func translateError(err error) error { return fuse.Errno(syscall.EROFS) case vfs.ENOSYS: return fuse.ENOSYS + case vfs.EINVAL: + return fuse.Errno(syscall.EINVAL) } return err } diff --git a/vfs/errors.go b/vfs/errors.go index ac00ca9ad..564671a43 100644 --- a/vfs/errors.go +++ b/vfs/errors.go @@ -27,6 +27,7 @@ var ( ENOENT = os.ErrNotExist EEXIST = os.ErrExist EPERM = os.ErrPermission + EINVAL = os.ErrInvalid // ECLOSED see errors_{old,new}.go ) diff --git a/vfs/file.go b/vfs/file.go index a50abad1f..e44a0e512 100644 --- a/vfs/file.go +++ b/vfs/file.go @@ -292,7 +292,6 @@ func (f *File) openRead() (fh *ReadFileHandle, err error) { fh, err = newReadFileHandle(f, o) if err != nil { - err = errors.Wrap(err, "open for read") fs.Errorf(f, "File.openRead failed: %v", err) return nil, err } @@ -308,7 +307,6 @@ func (f *File) openWrite(flags int) (fh *WriteFileHandle, err error) { fh, err = newWriteFileHandle(f.d, f, f.Path(), flags) if err != nil { - err = errors.Wrap(err, "open for write") fs.Errorf(f, "File.openWrite failed: %v", err) return nil, err } @@ -327,7 +325,6 @@ func (f *File) openRW(flags int) (fh *RWFileHandle, err error) { fh, err = newRWFileHandle(f.d, f, f.Path(), flags) if err != nil { - err = errors.Wrap(err, "open for read write") fs.Errorf(f, "File.openRW failed: %v", err) return nil, err } @@ -400,9 +397,16 @@ func (f *File) Open(flags int) (fd Handle, err error) { var ( write bool // if set need write support read bool // if set need read support - rdwrMode = flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR) + rdwrMode = flags & accessModeMask ) + // http://pubs.opengroup.org/onlinepubs/7908799/xsh/open.html + // The result of using O_TRUNC with O_RDONLY is undefined. + // Linux seems to truncate the file, but we prefer to return EINVAL + if rdwrMode == os.O_RDONLY && flags&os.O_TRUNC != 0 { + return nil, EINVAL + } + // Figure out the read/write intents switch { case rdwrMode == os.O_RDONLY: diff --git a/vfs/open_test.go b/vfs/open_test.go index 6ff4b65e6..22f661606 100644 --- a/vfs/open_test.go +++ b/vfs/open_test.go @@ -36,13 +36,13 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_TRUNC, what: "os.O_RDONLY|os.O_TRUNC", - openNonExistentErr: ENOENT, + openNonExistentErr: EINVAL, readNonExistentErr: nil, writeNonExistentErr: nil, - openExistingErr: nil, - readExistingErr: io.EOF, - writeExistingErr: EBADF, - contents: "", + openExistingErr: EINVAL, + readExistingErr: nil, + writeExistingErr: nil, + contents: "hello", }, { flags: os.O_RDONLY | os.O_SYNC, what: "os.O_RDONLY|os.O_SYNC", @@ -56,13 +56,13 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_SYNC | os.O_TRUNC, what: "os.O_RDONLY|os.O_SYNC|os.O_TRUNC", - openNonExistentErr: ENOENT, + openNonExistentErr: EINVAL, readNonExistentErr: nil, writeNonExistentErr: nil, - openExistingErr: nil, - readExistingErr: io.EOF, - writeExistingErr: EBADF, - contents: "", + openExistingErr: EINVAL, + readExistingErr: nil, + writeExistingErr: nil, + contents: "hello", }, { flags: os.O_RDONLY | os.O_EXCL, what: "os.O_RDONLY|os.O_EXCL", @@ -76,13 +76,13 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_EXCL | os.O_TRUNC, what: "os.O_RDONLY|os.O_EXCL|os.O_TRUNC", - openNonExistentErr: ENOENT, + openNonExistentErr: EINVAL, readNonExistentErr: nil, writeNonExistentErr: nil, - openExistingErr: nil, - readExistingErr: io.EOF, - writeExistingErr: EBADF, - contents: "", + openExistingErr: EINVAL, + readExistingErr: nil, + writeExistingErr: nil, + contents: "hello", }, { flags: os.O_RDONLY | os.O_EXCL | os.O_SYNC, what: "os.O_RDONLY|os.O_EXCL|os.O_SYNC", @@ -96,13 +96,13 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_EXCL | os.O_SYNC | os.O_TRUNC, what: "os.O_RDONLY|os.O_EXCL|os.O_SYNC|os.O_TRUNC", - openNonExistentErr: ENOENT, + openNonExistentErr: EINVAL, readNonExistentErr: nil, writeNonExistentErr: nil, - openExistingErr: nil, - readExistingErr: io.EOF, - writeExistingErr: EBADF, - contents: "", + openExistingErr: EINVAL, + readExistingErr: nil, + writeExistingErr: nil, + contents: "hello", }, { flags: os.O_RDONLY | os.O_CREATE, what: "os.O_RDONLY|os.O_CREATE", @@ -116,13 +116,13 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_CREATE | os.O_TRUNC, what: "os.O_RDONLY|os.O_CREATE|os.O_TRUNC", - openNonExistentErr: nil, - readNonExistentErr: io.EOF, - writeNonExistentErr: EBADF, - openExistingErr: nil, - readExistingErr: io.EOF, - writeExistingErr: EBADF, - contents: "", + openNonExistentErr: EINVAL, + readNonExistentErr: nil, + writeNonExistentErr: nil, + openExistingErr: EINVAL, + readExistingErr: nil, + writeExistingErr: nil, + contents: "hello", }, { flags: os.O_RDONLY | os.O_CREATE | os.O_SYNC, what: "os.O_RDONLY|os.O_CREATE|os.O_SYNC", @@ -136,13 +136,13 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_CREATE | os.O_SYNC | os.O_TRUNC, what: "os.O_RDONLY|os.O_CREATE|os.O_SYNC|os.O_TRUNC", - openNonExistentErr: nil, - readNonExistentErr: io.EOF, - writeNonExistentErr: EBADF, - openExistingErr: nil, - readExistingErr: io.EOF, - writeExistingErr: EBADF, - contents: "", + openNonExistentErr: EINVAL, + readNonExistentErr: nil, + writeNonExistentErr: nil, + openExistingErr: EINVAL, + readExistingErr: nil, + writeExistingErr: nil, + contents: "hello", }, { flags: os.O_RDONLY | os.O_CREATE | os.O_EXCL, what: "os.O_RDONLY|os.O_CREATE|os.O_EXCL", @@ -156,10 +156,10 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_CREATE | os.O_EXCL | os.O_TRUNC, what: "os.O_RDONLY|os.O_CREATE|os.O_EXCL|os.O_TRUNC", - openNonExistentErr: nil, - readNonExistentErr: io.EOF, - writeNonExistentErr: EBADF, - openExistingErr: EEXIST, + openNonExistentErr: EINVAL, + readNonExistentErr: nil, + writeNonExistentErr: nil, + openExistingErr: EINVAL, readExistingErr: nil, writeExistingErr: nil, contents: "hello", @@ -176,10 +176,10 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_CREATE | os.O_EXCL | os.O_SYNC | os.O_TRUNC, what: "os.O_RDONLY|os.O_CREATE|os.O_EXCL|os.O_SYNC|os.O_TRUNC", - openNonExistentErr: nil, - readNonExistentErr: io.EOF, - writeNonExistentErr: EBADF, - openExistingErr: EEXIST, + openNonExistentErr: EINVAL, + readNonExistentErr: nil, + writeNonExistentErr: nil, + openExistingErr: EINVAL, readExistingErr: nil, writeExistingErr: nil, contents: "hello", @@ -196,13 +196,13 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_APPEND | os.O_TRUNC, what: "os.O_RDONLY|os.O_APPEND|os.O_TRUNC", - openNonExistentErr: ENOENT, + openNonExistentErr: EINVAL, readNonExistentErr: nil, writeNonExistentErr: nil, - openExistingErr: nil, - readExistingErr: io.EOF, - writeExistingErr: EBADF, - contents: "", + openExistingErr: EINVAL, + readExistingErr: nil, + writeExistingErr: nil, + contents: "hello", }, { flags: os.O_RDONLY | os.O_APPEND | os.O_SYNC, what: "os.O_RDONLY|os.O_APPEND|os.O_SYNC", @@ -216,13 +216,13 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_APPEND | os.O_SYNC | os.O_TRUNC, what: "os.O_RDONLY|os.O_APPEND|os.O_SYNC|os.O_TRUNC", - openNonExistentErr: ENOENT, + openNonExistentErr: EINVAL, readNonExistentErr: nil, writeNonExistentErr: nil, - openExistingErr: nil, - readExistingErr: io.EOF, - writeExistingErr: EBADF, - contents: "", + openExistingErr: EINVAL, + readExistingErr: nil, + writeExistingErr: nil, + contents: "hello", }, { flags: os.O_RDONLY | os.O_APPEND | os.O_EXCL, what: "os.O_RDONLY|os.O_APPEND|os.O_EXCL", @@ -236,13 +236,13 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_APPEND | os.O_EXCL | os.O_TRUNC, what: "os.O_RDONLY|os.O_APPEND|os.O_EXCL|os.O_TRUNC", - openNonExistentErr: ENOENT, + openNonExistentErr: EINVAL, readNonExistentErr: nil, writeNonExistentErr: nil, - openExistingErr: nil, - readExistingErr: io.EOF, - writeExistingErr: EBADF, - contents: "", + openExistingErr: EINVAL, + readExistingErr: nil, + writeExistingErr: nil, + contents: "hello", }, { flags: os.O_RDONLY | os.O_APPEND | os.O_EXCL | os.O_SYNC, what: "os.O_RDONLY|os.O_APPEND|os.O_EXCL|os.O_SYNC", @@ -256,13 +256,13 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_APPEND | os.O_EXCL | os.O_SYNC | os.O_TRUNC, what: "os.O_RDONLY|os.O_APPEND|os.O_EXCL|os.O_SYNC|os.O_TRUNC", - openNonExistentErr: ENOENT, + openNonExistentErr: EINVAL, readNonExistentErr: nil, writeNonExistentErr: nil, - openExistingErr: nil, - readExistingErr: io.EOF, - writeExistingErr: EBADF, - contents: "", + openExistingErr: EINVAL, + readExistingErr: nil, + writeExistingErr: nil, + contents: "hello", }, { flags: os.O_RDONLY | os.O_APPEND | os.O_CREATE, what: "os.O_RDONLY|os.O_APPEND|os.O_CREATE", @@ -276,13 +276,13 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_TRUNC, what: "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_TRUNC", - openNonExistentErr: nil, - readNonExistentErr: io.EOF, - writeNonExistentErr: EBADF, - openExistingErr: nil, - readExistingErr: io.EOF, - writeExistingErr: EBADF, - contents: "", + openNonExistentErr: EINVAL, + readNonExistentErr: nil, + writeNonExistentErr: nil, + openExistingErr: EINVAL, + readExistingErr: nil, + writeExistingErr: nil, + contents: "hello", }, { flags: os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_SYNC, what: "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_SYNC", @@ -296,13 +296,13 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_SYNC | os.O_TRUNC, what: "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_SYNC|os.O_TRUNC", - openNonExistentErr: nil, - readNonExistentErr: io.EOF, - writeNonExistentErr: EBADF, - openExistingErr: nil, - readExistingErr: io.EOF, - writeExistingErr: EBADF, - contents: "", + openNonExistentErr: EINVAL, + readNonExistentErr: nil, + writeNonExistentErr: nil, + openExistingErr: EINVAL, + readExistingErr: nil, + writeExistingErr: nil, + contents: "hello", }, { flags: os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_EXCL, what: "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_EXCL", @@ -316,10 +316,10 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_EXCL | os.O_TRUNC, what: "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_EXCL|os.O_TRUNC", - openNonExistentErr: nil, - readNonExistentErr: io.EOF, - writeNonExistentErr: EBADF, - openExistingErr: EEXIST, + openNonExistentErr: EINVAL, + readNonExistentErr: nil, + writeNonExistentErr: nil, + openExistingErr: EINVAL, readExistingErr: nil, writeExistingErr: nil, contents: "hello", @@ -336,10 +336,10 @@ var openTests = []openTest{ }, { flags: os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_EXCL | os.O_SYNC | os.O_TRUNC, what: "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_EXCL|os.O_SYNC|os.O_TRUNC", - openNonExistentErr: nil, - readNonExistentErr: io.EOF, - writeNonExistentErr: EBADF, - openExistingErr: EEXIST, + openNonExistentErr: EINVAL, + readNonExistentErr: nil, + writeNonExistentErr: nil, + openExistingErr: EINVAL, readExistingErr: nil, writeExistingErr: nil, contents: "hello", diff --git a/vfs/read_write_test.go b/vfs/read_write_test.go index 78acc332e..e0022d676 100644 --- a/vfs/read_write_test.go +++ b/vfs/read_write_test.go @@ -523,8 +523,10 @@ func testRWFileHandleOpenTest(t *testing.T, vfs *VFS, test *openTest) { require.NoError(t, err, test.what) // check + assert.Equal(t, test.openNonExistentErr, openNonExistentErr, "openNonExistentErr: %s: want=%v, got=%v", test.what, test.openNonExistentErr, openNonExistentErr) assert.Equal(t, test.readNonExistentErr, readNonExistentErr, "readNonExistentErr: %s: want=%v, got=%v", test.what, test.readNonExistentErr, readNonExistentErr) assert.Equal(t, test.writeNonExistentErr, writeNonExistentErr, "writeNonExistentErr: %s: want=%v, got=%v", test.what, test.writeNonExistentErr, writeNonExistentErr) + assert.Equal(t, test.openExistingErr, openExistingErr, "openExistingErr: %s: want=%v, got=%v", test.what, test.openExistingErr, openExistingErr) assert.Equal(t, test.readExistingErr, readExistingErr, "readExistingErr: %s: want=%v, got=%v", test.what, test.readExistingErr, readExistingErr) assert.Equal(t, test.writeExistingErr, writeExistingErr, "writeExistingErr: %s: want=%v, got=%v", test.what, test.writeExistingErr, writeExistingErr) assert.Equal(t, test.contents, contents, test.what) diff --git a/vfs/vfs.go b/vfs/vfs.go index 6726a637c..26a0b11b9 100644 --- a/vfs/vfs.go +++ b/vfs/vfs.go @@ -393,6 +393,14 @@ func decodeOpenFlags(flags int) string { // OpenFile a file according to the flags and perm provided func (vfs *VFS) OpenFile(name string, flags int, perm os.FileMode) (fd Handle, err error) { defer log.Trace(name, "flags=%s, perm=%v", decodeOpenFlags(flags), perm)("fd=%v, err=%v", &fd, &err) + + // http://pubs.opengroup.org/onlinepubs/7908799/xsh/open.html + // The result of using O_TRUNC with O_RDONLY is undefined. + // Linux seems to truncate the file, but we prefer to return EINVAL + if flags&accessModeMask == os.O_RDONLY && flags&os.O_TRUNC != 0 { + return nil, EINVAL + } + node, err := vfs.Stat(name) if err != nil { if err != ENOENT || flags&os.O_CREATE == 0 {