vfs: Make OpenFile and friends return EINVAL if O_RDONLY and O_TRUNC

Before this change Open("name", os.O_RDONLY|os.O_TRUNC) would have
truncated the file.  This is what Linux does, but is counterintuitive.
POSIX states this is undefined, so return an error in this case
instead.  This preserves the invariant O_RDONLY => file is not
changed.
s3-about
Nick Craig-Wood 2018-02-23 22:39:28 +00:00
parent 3282fd26af
commit 54deb01f00
7 changed files with 107 additions and 88 deletions

View File

@ -540,6 +540,8 @@ func translateError(err error) (errc int) {
return -fuse.EROFS return -fuse.EROFS
case vfs.ENOSYS: case vfs.ENOSYS:
return -fuse.ENOSYS return -fuse.ENOSYS
case vfs.EINVAL:
return -fuse.EINVAL
} }
fs.Errorf(nil, "IO error: %v", err) fs.Errorf(nil, "IO error: %v", err)
return -fuse.EIO return -fuse.EIO

View File

@ -91,6 +91,8 @@ func translateError(err error) error {
return fuse.Errno(syscall.EROFS) return fuse.Errno(syscall.EROFS)
case vfs.ENOSYS: case vfs.ENOSYS:
return fuse.ENOSYS return fuse.ENOSYS
case vfs.EINVAL:
return fuse.Errno(syscall.EINVAL)
} }
return err return err
} }

View File

@ -27,6 +27,7 @@ var (
ENOENT = os.ErrNotExist ENOENT = os.ErrNotExist
EEXIST = os.ErrExist EEXIST = os.ErrExist
EPERM = os.ErrPermission EPERM = os.ErrPermission
EINVAL = os.ErrInvalid
// ECLOSED see errors_{old,new}.go // ECLOSED see errors_{old,new}.go
) )

View File

@ -292,7 +292,6 @@ func (f *File) openRead() (fh *ReadFileHandle, err error) {
fh, err = newReadFileHandle(f, o) fh, err = newReadFileHandle(f, o)
if err != nil { if err != nil {
err = errors.Wrap(err, "open for read")
fs.Errorf(f, "File.openRead failed: %v", err) fs.Errorf(f, "File.openRead failed: %v", err)
return nil, 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) fh, err = newWriteFileHandle(f.d, f, f.Path(), flags)
if err != nil { if err != nil {
err = errors.Wrap(err, "open for write")
fs.Errorf(f, "File.openWrite failed: %v", err) fs.Errorf(f, "File.openWrite failed: %v", err)
return nil, 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) fh, err = newRWFileHandle(f.d, f, f.Path(), flags)
if err != nil { if err != nil {
err = errors.Wrap(err, "open for read write")
fs.Errorf(f, "File.openRW failed: %v", err) fs.Errorf(f, "File.openRW failed: %v", err)
return nil, err return nil, err
} }
@ -400,9 +397,16 @@ func (f *File) Open(flags int) (fd Handle, err error) {
var ( var (
write bool // if set need write support write bool // if set need write support
read bool // if set need read 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 // Figure out the read/write intents
switch { switch {
case rdwrMode == os.O_RDONLY: case rdwrMode == os.O_RDONLY:

View File

@ -36,13 +36,13 @@ var openTests = []openTest{
}, { }, {
flags: os.O_RDONLY | os.O_TRUNC, flags: os.O_RDONLY | os.O_TRUNC,
what: "os.O_RDONLY|os.O_TRUNC", what: "os.O_RDONLY|os.O_TRUNC",
openNonExistentErr: ENOENT, openNonExistentErr: EINVAL,
readNonExistentErr: nil, readNonExistentErr: nil,
writeNonExistentErr: nil, writeNonExistentErr: nil,
openExistingErr: nil, openExistingErr: EINVAL,
readExistingErr: io.EOF, readExistingErr: nil,
writeExistingErr: EBADF, writeExistingErr: nil,
contents: "", contents: "hello",
}, { }, {
flags: os.O_RDONLY | os.O_SYNC, flags: os.O_RDONLY | os.O_SYNC,
what: "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, flags: os.O_RDONLY | os.O_SYNC | os.O_TRUNC,
what: "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, readNonExistentErr: nil,
writeNonExistentErr: nil, writeNonExistentErr: nil,
openExistingErr: nil, openExistingErr: EINVAL,
readExistingErr: io.EOF, readExistingErr: nil,
writeExistingErr: EBADF, writeExistingErr: nil,
contents: "", contents: "hello",
}, { }, {
flags: os.O_RDONLY | os.O_EXCL, flags: os.O_RDONLY | os.O_EXCL,
what: "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, flags: os.O_RDONLY | os.O_EXCL | os.O_TRUNC,
what: "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, readNonExistentErr: nil,
writeNonExistentErr: nil, writeNonExistentErr: nil,
openExistingErr: nil, openExistingErr: EINVAL,
readExistingErr: io.EOF, readExistingErr: nil,
writeExistingErr: EBADF, writeExistingErr: nil,
contents: "", contents: "hello",
}, { }, {
flags: os.O_RDONLY | os.O_EXCL | os.O_SYNC, flags: os.O_RDONLY | os.O_EXCL | os.O_SYNC,
what: "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, 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", what: "os.O_RDONLY|os.O_EXCL|os.O_SYNC|os.O_TRUNC",
openNonExistentErr: ENOENT, openNonExistentErr: EINVAL,
readNonExistentErr: nil, readNonExistentErr: nil,
writeNonExistentErr: nil, writeNonExistentErr: nil,
openExistingErr: nil, openExistingErr: EINVAL,
readExistingErr: io.EOF, readExistingErr: nil,
writeExistingErr: EBADF, writeExistingErr: nil,
contents: "", contents: "hello",
}, { }, {
flags: os.O_RDONLY | os.O_CREATE, flags: os.O_RDONLY | os.O_CREATE,
what: "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, flags: os.O_RDONLY | os.O_CREATE | os.O_TRUNC,
what: "os.O_RDONLY|os.O_CREATE|os.O_TRUNC", what: "os.O_RDONLY|os.O_CREATE|os.O_TRUNC",
openNonExistentErr: nil, openNonExistentErr: EINVAL,
readNonExistentErr: io.EOF, readNonExistentErr: nil,
writeNonExistentErr: EBADF, writeNonExistentErr: nil,
openExistingErr: nil, openExistingErr: EINVAL,
readExistingErr: io.EOF, readExistingErr: nil,
writeExistingErr: EBADF, writeExistingErr: nil,
contents: "", contents: "hello",
}, { }, {
flags: os.O_RDONLY | os.O_CREATE | os.O_SYNC, flags: os.O_RDONLY | os.O_CREATE | os.O_SYNC,
what: "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, 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", what: "os.O_RDONLY|os.O_CREATE|os.O_SYNC|os.O_TRUNC",
openNonExistentErr: nil, openNonExistentErr: EINVAL,
readNonExistentErr: io.EOF, readNonExistentErr: nil,
writeNonExistentErr: EBADF, writeNonExistentErr: nil,
openExistingErr: nil, openExistingErr: EINVAL,
readExistingErr: io.EOF, readExistingErr: nil,
writeExistingErr: EBADF, writeExistingErr: nil,
contents: "", contents: "hello",
}, { }, {
flags: os.O_RDONLY | os.O_CREATE | os.O_EXCL, flags: os.O_RDONLY | os.O_CREATE | os.O_EXCL,
what: "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, 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", what: "os.O_RDONLY|os.O_CREATE|os.O_EXCL|os.O_TRUNC",
openNonExistentErr: nil, openNonExistentErr: EINVAL,
readNonExistentErr: io.EOF, readNonExistentErr: nil,
writeNonExistentErr: EBADF, writeNonExistentErr: nil,
openExistingErr: EEXIST, openExistingErr: EINVAL,
readExistingErr: nil, readExistingErr: nil,
writeExistingErr: nil, writeExistingErr: nil,
contents: "hello", 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, 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", what: "os.O_RDONLY|os.O_CREATE|os.O_EXCL|os.O_SYNC|os.O_TRUNC",
openNonExistentErr: nil, openNonExistentErr: EINVAL,
readNonExistentErr: io.EOF, readNonExistentErr: nil,
writeNonExistentErr: EBADF, writeNonExistentErr: nil,
openExistingErr: EEXIST, openExistingErr: EINVAL,
readExistingErr: nil, readExistingErr: nil,
writeExistingErr: nil, writeExistingErr: nil,
contents: "hello", contents: "hello",
@ -196,13 +196,13 @@ var openTests = []openTest{
}, { }, {
flags: os.O_RDONLY | os.O_APPEND | os.O_TRUNC, flags: os.O_RDONLY | os.O_APPEND | os.O_TRUNC,
what: "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, readNonExistentErr: nil,
writeNonExistentErr: nil, writeNonExistentErr: nil,
openExistingErr: nil, openExistingErr: EINVAL,
readExistingErr: io.EOF, readExistingErr: nil,
writeExistingErr: EBADF, writeExistingErr: nil,
contents: "", contents: "hello",
}, { }, {
flags: os.O_RDONLY | os.O_APPEND | os.O_SYNC, flags: os.O_RDONLY | os.O_APPEND | os.O_SYNC,
what: "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, 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", what: "os.O_RDONLY|os.O_APPEND|os.O_SYNC|os.O_TRUNC",
openNonExistentErr: ENOENT, openNonExistentErr: EINVAL,
readNonExistentErr: nil, readNonExistentErr: nil,
writeNonExistentErr: nil, writeNonExistentErr: nil,
openExistingErr: nil, openExistingErr: EINVAL,
readExistingErr: io.EOF, readExistingErr: nil,
writeExistingErr: EBADF, writeExistingErr: nil,
contents: "", contents: "hello",
}, { }, {
flags: os.O_RDONLY | os.O_APPEND | os.O_EXCL, flags: os.O_RDONLY | os.O_APPEND | os.O_EXCL,
what: "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, 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", what: "os.O_RDONLY|os.O_APPEND|os.O_EXCL|os.O_TRUNC",
openNonExistentErr: ENOENT, openNonExistentErr: EINVAL,
readNonExistentErr: nil, readNonExistentErr: nil,
writeNonExistentErr: nil, writeNonExistentErr: nil,
openExistingErr: nil, openExistingErr: EINVAL,
readExistingErr: io.EOF, readExistingErr: nil,
writeExistingErr: EBADF, writeExistingErr: nil,
contents: "", contents: "hello",
}, { }, {
flags: os.O_RDONLY | os.O_APPEND | os.O_EXCL | os.O_SYNC, 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", 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, 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", what: "os.O_RDONLY|os.O_APPEND|os.O_EXCL|os.O_SYNC|os.O_TRUNC",
openNonExistentErr: ENOENT, openNonExistentErr: EINVAL,
readNonExistentErr: nil, readNonExistentErr: nil,
writeNonExistentErr: nil, writeNonExistentErr: nil,
openExistingErr: nil, openExistingErr: EINVAL,
readExistingErr: io.EOF, readExistingErr: nil,
writeExistingErr: EBADF, writeExistingErr: nil,
contents: "", contents: "hello",
}, { }, {
flags: os.O_RDONLY | os.O_APPEND | os.O_CREATE, flags: os.O_RDONLY | os.O_APPEND | os.O_CREATE,
what: "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, 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", what: "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_TRUNC",
openNonExistentErr: nil, openNonExistentErr: EINVAL,
readNonExistentErr: io.EOF, readNonExistentErr: nil,
writeNonExistentErr: EBADF, writeNonExistentErr: nil,
openExistingErr: nil, openExistingErr: EINVAL,
readExistingErr: io.EOF, readExistingErr: nil,
writeExistingErr: EBADF, writeExistingErr: nil,
contents: "", contents: "hello",
}, { }, {
flags: os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_SYNC, 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", 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, 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", what: "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_SYNC|os.O_TRUNC",
openNonExistentErr: nil, openNonExistentErr: EINVAL,
readNonExistentErr: io.EOF, readNonExistentErr: nil,
writeNonExistentErr: EBADF, writeNonExistentErr: nil,
openExistingErr: nil, openExistingErr: EINVAL,
readExistingErr: io.EOF, readExistingErr: nil,
writeExistingErr: EBADF, writeExistingErr: nil,
contents: "", contents: "hello",
}, { }, {
flags: os.O_RDONLY | os.O_APPEND | os.O_CREATE | os.O_EXCL, 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", 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, 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", what: "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_EXCL|os.O_TRUNC",
openNonExistentErr: nil, openNonExistentErr: EINVAL,
readNonExistentErr: io.EOF, readNonExistentErr: nil,
writeNonExistentErr: EBADF, writeNonExistentErr: nil,
openExistingErr: EEXIST, openExistingErr: EINVAL,
readExistingErr: nil, readExistingErr: nil,
writeExistingErr: nil, writeExistingErr: nil,
contents: "hello", 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, 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", what: "os.O_RDONLY|os.O_APPEND|os.O_CREATE|os.O_EXCL|os.O_SYNC|os.O_TRUNC",
openNonExistentErr: nil, openNonExistentErr: EINVAL,
readNonExistentErr: io.EOF, readNonExistentErr: nil,
writeNonExistentErr: EBADF, writeNonExistentErr: nil,
openExistingErr: EEXIST, openExistingErr: EINVAL,
readExistingErr: nil, readExistingErr: nil,
writeExistingErr: nil, writeExistingErr: nil,
contents: "hello", contents: "hello",

View File

@ -523,8 +523,10 @@ func testRWFileHandleOpenTest(t *testing.T, vfs *VFS, test *openTest) {
require.NoError(t, err, test.what) require.NoError(t, err, test.what)
// check // 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.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.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.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.writeExistingErr, writeExistingErr, "writeExistingErr: %s: want=%v, got=%v", test.what, test.writeExistingErr, writeExistingErr)
assert.Equal(t, test.contents, contents, test.what) assert.Equal(t, test.contents, contents, test.what)

View File

@ -393,6 +393,14 @@ func decodeOpenFlags(flags int) string {
// OpenFile a file according to the flags and perm provided // 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) { 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) 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) node, err := vfs.Stat(name)
if err != nil { if err != nil {
if err != ENOENT || flags&os.O_CREATE == 0 { if err != ENOENT || flags&os.O_CREATE == 0 {