From 815666ab119f4b2e6ac801c66d4b5c06a970f1cc Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Mon, 24 Sep 2018 10:09:49 +0200 Subject: [PATCH] fuse/test: clarify umask semantics Improve test to eliminate backing FS semantics --- fuse/test/loopback_test.go | 28 +----------- fuse/test/umask_test.go | 91 ++++++++++++++++++++++++++++++++++++++ fuse/types.go | 3 ++ fuse/types_linux.go | 14 ++++-- 4 files changed, 105 insertions(+), 31 deletions(-) create mode 100644 fuse/test/umask_test.go diff --git a/fuse/test/loopback_test.go b/fuse/test/loopback_test.go index 36cdea4f0..b672deb56 100644 --- a/fuse/test/loopback_test.go +++ b/fuse/test/loopback_test.go @@ -11,7 +11,6 @@ import ( "io/ioutil" "math/rand" "os" - "os/exec" "path/filepath" "reflect" "runtime" @@ -25,8 +24,6 @@ import ( "github.com/hanwen/go-fuse/internal/testutil" ) -const mode uint32 = 0757 - type testCase struct { tmpDir string orig string @@ -148,6 +145,7 @@ func TestReadThrough(t *testing.T) { content := randomData(125) tc.WriteFile(tc.origFile, content, 0700) + var mode uint32 = 0757 err := os.Chmod(tc.mountFile, os.FileMode(mode)) if err != nil { t.Fatalf("Chmod failed: %v", err) @@ -916,31 +914,7 @@ func TestDoubleOpen(t *testing.T) { t.Fatalf("OpenFile failed: %v", err) } defer rwFile.Close() -} -func TestUmask(t *testing.T) { - tc := NewTestCase(t) - defer tc.Cleanup() - - // Make sure system setting does not affect test. - fn := tc.mnt + "/file" - mask := 020 - cmd := exec.Command("/bin/sh", "-c", - fmt.Sprintf("umask %o && mkdir %s", mask, fn)) - if err := cmd.Run(); err != nil { - t.Fatalf("cmd.Run: %v", err) - } - - fi, err := os.Lstat(fn) - if err != nil { - t.Fatalf("Lstat failed: %v", err) - } - - expect := mask ^ 0777 - got := int(fi.Mode().Perm()) - if got != expect { - t.Errorf("got %o, expect mode %o for file %s", got, expect, fn) - } } // Check that chgrp(1) works diff --git a/fuse/test/umask_test.go b/fuse/test/umask_test.go new file mode 100644 index 000000000..941fa596f --- /dev/null +++ b/fuse/test/umask_test.go @@ -0,0 +1,91 @@ +// Copyright 2016 the Go-FUSE Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package test + +import ( + "fmt" + "os" + "os/exec" + "testing" + + "github.com/hanwen/go-fuse/fuse" + "github.com/hanwen/go-fuse/fuse/nodefs" + "github.com/hanwen/go-fuse/fuse/pathfs" + "github.com/hanwen/go-fuse/internal/testutil" +) + +type umaskFS struct { + pathfs.FileSystem + + mkdirMode uint32 + createMode uint32 +} + +func (fs *umaskFS) Create(name string, flags uint32, mode uint32, context *fuse.Context) (file nodefs.File, code fuse.Status) { + fs.createMode = mode + return fs.FileSystem.Create(name, flags, mode, context) +} + +func (fs *umaskFS) Mkdir(name string, mode uint32, context *fuse.Context) (code fuse.Status) { + fs.mkdirMode = mode + return fs.FileSystem.Mkdir(name, mode, context) +} + +func TestUmask(t *testing.T) { + tmpDir := testutil.TempDir() + orig := tmpDir + "/orig" + mnt := tmpDir + "/mnt" + + os.Mkdir(orig, 0700) + os.Mkdir(mnt, 0700) + + var pfs pathfs.FileSystem + pfs = pathfs.NewLoopbackFileSystem(orig) + pfs = pathfs.NewLockingFileSystem(pfs) + ufs := &umaskFS{FileSystem: pfs} + + pathFs := pathfs.NewPathNodeFs(ufs, &pathfs.PathNodeFsOptions{ + ClientInodes: true}) + connector := nodefs.NewFileSystemConnector(pathFs.Root(), + &nodefs.Options{ + EntryTimeout: testTtl, + AttrTimeout: testTtl, + NegativeTimeout: 0.0, + Debug: testutil.VerboseTest(), + LookupKnownChildren: true, + }) + server, err := fuse.NewServer( + fuse.NewRawFileSystem(connector.RawFS()), mnt, &fuse.MountOptions{ + SingleThreaded: true, + Debug: testutil.VerboseTest(), + }) + if err != nil { + t.Fatal("NewServer:", err) + } + + go server.Serve() + if err := server.WaitMount(); err != nil { + t.Fatal("WaitMount", err) + } + + // Make sure system setting does not affect test. + mask := 020 + cmd := exec.Command("/bin/sh", "-c", + fmt.Sprintf("umask %o && cd %s && mkdir x && touch y", mask, mnt)) + if err := cmd.Run(); err != nil { + t.Fatalf("cmd.Run: %v", err) + } + + if err := server.Unmount(); err != nil { + t.Fatalf("Unmount %v", err) + } + + if got, want := ufs.mkdirMode&0777, uint32(0757); got != want { + t.Errorf("got dirMode %o want %o", got, want) + } + if got, want := ufs.createMode&0666, uint32(0646); got != want { + t.Errorf("got createMode %o want %o", got, want) + } +} diff --git a/fuse/types.go b/fuse/types.go index 8b1fa2217..f2d63c4c6 100644 --- a/fuse/types.go +++ b/fuse/types.go @@ -86,6 +86,9 @@ type _BatchForgetIn struct { type MkdirIn struct { InHeader + + // The mode for the new directory. The calling process' umask + // is already factored into the mode. Mode uint32 Umask uint32 } diff --git a/fuse/types_linux.go b/fuse/types_linux.go index dc5db794f..02bdb4ad2 100644 --- a/fuse/types_linux.go +++ b/fuse/types_linux.go @@ -61,14 +61,20 @@ func (g *GetAttrIn) Fh() uint64 { type CreateIn struct { InHeader - Flags uint32 - Mode uint32 - Umask uint32 - Pading uint32 + Flags uint32 + + // Mode for the new file; already takes Umask into account. + Mode uint32 + + // Umask used for this create call. + Umask uint32 + Padding uint32 } type MknodIn struct { InHeader + + // Mode to use, including the Umask value Mode uint32 Rdev uint32 Umask uint32