Commit 21ed6eb9 authored by Jan Pfeifer's avatar Jan Pfeifer Committed by Han-Wen Nienhuys

Make hiding the READONLY link switchable in AutoUnionFs.

parent 97d9f0ed
......@@ -17,6 +17,9 @@ func main() {
branchcache_ttl := flag.Float64("branchcache_ttl", 5.0, "Branch cache TTL in seconds.")
deldirname := flag.String(
"deletion_dirname", "GOUNIONFS_DELETIONS", "Directory name to use for deletions.")
hide_readonly_link := flag.Bool("hide_readonly_link", true,
"Hides READONLY link from the top mountpoints. " +
"Enabled by default.")
flag.Parse()
if *version {
......@@ -45,6 +48,7 @@ func main() {
PathNodeFsOptions: fuse.PathNodeFsOptions{
ClientInodes: *hardlinks,
},
HideReadonly: *hide_readonly_link,
}
fmt.Printf("AutoUnionFs - Go-FUSE Version %v.\n", fuse.Version())
......
......@@ -21,6 +21,7 @@ func main() {
branchcache_ttl := flag.Float64("branchcache_ttl", 5.0, "Branch cache TTL in seconds.")
deldirname := flag.String(
"deletion_dirname", "GOUNIONFS_DELETIONS", "Directory name to use for deletions.")
flag.Parse()
if len(flag.Args()) < 2 {
fmt.Println("Usage:\n unionfs MOUNTPOINT RW-DIRECTORY RO-DIRECTORY ...")
......
......@@ -44,6 +44,9 @@ type AutoUnionFsOptions struct {
// If set, run updateKnownFses() after mounting.
UpdateOnMount bool
// If set hides the _READONLY file.
HideReadonly bool
}
const (
......@@ -57,6 +60,9 @@ const (
)
func NewAutoUnionFs(directory string, options AutoUnionFsOptions) *AutoUnionFs {
if options.HideReadonly {
options.HiddenFiles = append(options.HiddenFiles, _READONLY)
}
a := new(AutoUnionFs)
a.knownFileSystems = make(map[string]knownFs)
a.nameRootMap = make(map[string]string)
......
......@@ -24,6 +24,7 @@ var testAOpts = AutoUnionFsOptions{
AttrTimeout: entryTtl,
NegativeTimeout: 0,
},
HideReadonly: true,
}
func WriteFile(name string, contents string) {
......
......@@ -14,6 +14,7 @@ import (
"time"
)
func filePathHash(path string) string {
dir, base := filepath.Split(path)
......@@ -65,6 +66,9 @@ type UnionFs struct {
// A file -> branch cache.
branchCache *TimedCache
// Map of files to hide.
hiddenFiles map[string]bool
options *UnionFsOptions
nodeFs *fuse.PathNodeFs
}
......@@ -73,6 +77,7 @@ type UnionFsOptions struct {
BranchCacheTTL time.Duration
DeletionCacheTTL time.Duration
DeletionDirName string
HiddenFiles []string
}
const (
......@@ -96,6 +101,12 @@ func NewUnionFs(fileSystems []fuse.FileSystem, options UnionFsOptions) *UnionFs
func(n string) (interface{}, bool) { return g.getBranchAttrNoCache(n), true },
options.BranchCacheTTL)
g.branchCache.RecurringPurge()
g.hiddenFiles = make(map[string]bool)
for _, name := range options.HiddenFiles {
g.hiddenFiles[name] = true
}
return g
}
......@@ -659,7 +670,8 @@ func (me *UnionFs) Create(name string, flags uint32, mode uint32, context *fuse.
}
func (me *UnionFs) GetAttr(name string, context *fuse.Context) (a *fuse.Attr, s fuse.Status) {
if name == _READONLY {
_, hidden := me.hiddenFiles[name]
if hidden {
return nil, fuse.ENOENT
}
if name == _DROP_CACHE {
......@@ -778,8 +790,9 @@ func (me *UnionFs) OpenDir(directory string, context *fuse.Context) (stream chan
}
if directory == "" {
delete(results, me.options.DeletionDirName)
// HACK.
delete(results, _READONLY)
for name, _ := range me.hiddenFiles {
delete(results, name)
}
}
stream = make(chan fuse.DirEntry, len(results))
......
......@@ -8,6 +8,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"
"syscall"
"testing"
"time"
......@@ -25,6 +26,7 @@ var testOpts = UnionFsOptions{
DeletionCacheTTL: entryTtl,
DeletionDirName: "DELETIONS",
BranchCacheTTL: entryTtl,
HiddenFiles: []string{ "hidden" },
}
func freezeRo(dir string) {
......@@ -37,6 +39,8 @@ func freezeRo(dir string) {
CheckSuccess(err)
}
// Creates 3 directories on a temporary dir: /mnt with the overlayed
// (unionfs) mount, rw with modifiable data, and ro on the bottom.
func setupUfs(t *testing.T) (workdir string, cleanup func()) {
// Make sure system setting does not affect test.
syscall.Umask(0)
......@@ -60,8 +64,8 @@ func setupUfs(t *testing.T) (workdir string, cleanup func()) {
// We configure timeouts are smaller, so we can check for
// UnionFs's cache consistency.
opts := &fuse.FileSystemOptions{
EntryTimeout: entryTtl / 2,
AttrTimeout: entryTtl / 2,
EntryTimeout: entryTtl / 2,
AttrTimeout: entryTtl / 2,
NegativeTimeout: entryTtl / 2,
}
......@@ -298,7 +302,7 @@ func TestUnionFsBasic(t *testing.T) {
names = dirNames(wd + "/rw")
checkMapEq(t, names, map[string]bool{
testOpts.DeletionDirName: true,
"rw": true, "ro1": true,
"rw": true, "ro1": true,
})
names = dirNames(wd + "/rw/" + testOpts.DeletionDirName)
if len(names) != 0 {
......@@ -742,6 +746,8 @@ func TestUnionFsRemoveAll(t *testing.T) {
}
}
// Warning: test fails under coreutils < 8.0 because of non-posix behaviour
// of the "rm" tool -- which relies on behaviour that doesn't work in fuse.
func TestUnionFsRmRf(t *testing.T) {
wd, clean := setupUfs(t)
defer clean()
......@@ -757,6 +763,10 @@ func TestUnionFsRmRf(t *testing.T) {
bin, err := exec.LookPath("rm")
CheckSuccess(err)
command := fmt.Sprintf("%s -f %s/mnt/dir", bin, wd);
log.Printf("Command: %s", command)
names, _ := Readdirnames(wd + "/mnt/dir")
log.Printf("Contents of %s/mnt/dir: %s", wd, strings.Join(names, ", "))
cmd := exec.Command(bin, "-rf", wd+"/mnt/dir")
err = cmd.Run()
if err != nil {
......@@ -769,7 +779,7 @@ func TestUnionFsRmRf(t *testing.T) {
}
}
names, err := Readdirnames(wd + "/rw/DELETIONS")
names, err = Readdirnames(wd + "/rw/DELETIONS")
CheckSuccess(err)
if len(names) != 3 {
t.Fatal("unexpected names", names)
......@@ -876,8 +886,8 @@ func TestUnionFsDisappearing(t *testing.T) {
ufs := NewUnionFs(fses, testOpts)
opts := &fuse.FileSystemOptions{
EntryTimeout: entryTtl,
AttrTimeout: entryTtl,
EntryTimeout: entryTtl,
AttrTimeout: entryTtl,
NegativeTimeout: entryTtl,
}
......@@ -1116,3 +1126,27 @@ func TestUnionFsPromoteDirTimeStamp(t *testing.T) {
t.Errorf("Changed mode ro: %v, rw: %v", fRo.Mode(), fRw.Mode())
}
}
func TestUnionFsCheckHiddenFiles(t *testing.T) {
wd, clean := setupUfs(t)
defer clean()
err := ioutil.WriteFile(wd+"/ro/hidden", []byte("bla"), 0644)
CheckSuccess(err)
err = ioutil.WriteFile(wd+"/ro/not_hidden", []byte("bla"), 0644)
CheckSuccess(err)
freezeRo(wd + "/ro")
fi, _ := os.Lstat(wd + "/mnt/hidden")
if fi != nil {
t.Fatal("Lstat() should have failed", fi)
}
_, err = os.Lstat(wd + "/mnt/not_hidden")
CheckSuccess(err)
names, err := Readdirnames(wd + "/mnt")
CheckSuccess(err)
if len(names) != 1 || names[0] != "not_hidden" {
t.Fatal("unexpected names", names)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment