Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go-fuse
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Levin Zimmermann
go-fuse
Commits
b8b6c4e8
Commit
b8b6c4e8
authored
May 04, 2011
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
AutoUnionFs: Allow removal of symlinks too.
Add a test for AutoUnionFs.
parent
75f62dbe
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
208 additions
and
38 deletions
+208
-38
example/autounionfs/main.go
example/autounionfs/main.go
+1
-0
fuse/pathfilesystem.go
fuse/pathfilesystem.go
+1
-2
unionfs/autounion.go
unionfs/autounion.go
+69
-17
unionfs/autounion_test.go
unionfs/autounion_test.go
+119
-0
unionfs/unionfs_test.go
unionfs/unionfs_test.go
+18
-19
No files found.
example/autounionfs/main.go
View file @
b8b6c4e8
...
...
@@ -35,6 +35,7 @@ func main() {
AttrTimeout
:
1.0
,
NegativeTimeout
:
1.0
,
},
UpdateOnMount
:
true
,
}
gofs
:=
unionfs
.
NewAutoUnionFs
(
flag
.
Arg
(
1
),
options
)
...
...
fuse/pathfilesystem.go
View file @
b8b6c4e8
...
...
@@ -5,7 +5,7 @@ package fuse
PathFilesystemConnector is a lowlevel FUSE filesystem that translates
from inode numbers (as delivered by the kernel) to traditional path
names. The paths are then used as arguments for methods of
PathFilesystem instances.
PathFilesystem instances.
PathFilesystemConnector supports mounts of different PathFilesystem
on top of each other's directories.
...
...
@@ -535,5 +535,4 @@ func (me *FileSystemConnector) getOpenFileData(nodeid uint64, fh uint64) (f File
}
return
}
unionfs/autounion.go
View file @
b8b6c4e8
...
...
@@ -32,6 +32,9 @@ type AutoUnionFs struct {
type
AutoUnionFsOptions
struct
{
UnionFsOptions
fuse
.
MountOptions
// If set, run updateKnownFses() after mounting.
UpdateOnMount
bool
}
const
(
...
...
@@ -52,7 +55,9 @@ func NewAutoUnionFs(directory string, options AutoUnionFsOptions) *AutoUnionFs {
func
(
me
*
AutoUnionFs
)
Mount
(
connector
*
fuse
.
FileSystemConnector
)
fuse
.
Status
{
me
.
connector
=
connector
time
.
AfterFunc
(
0.1e9
,
func
()
{
me
.
updateKnownFses
()
})
if
me
.
options
.
UpdateOnMount
{
time
.
AfterFunc
(
0.1e9
,
func
()
{
me
.
updateKnownFses
()
})
}
return
fuse
.
OK
}
...
...
@@ -62,25 +67,61 @@ func (me *AutoUnionFs) addAutomaticFs(roots []string) {
me
.
addFs
(
name
,
roots
)
}
func
(
me
*
AutoUnionFs
)
addFs
(
name
string
,
roots
[]
string
)
bool
{
if
name
==
_CONFIG
||
name
==
_STATUS
{
log
.
Println
(
"Illegal name for overlay"
,
roots
)
return
false
}
func
(
me
*
AutoUnionFs
)
createFs
(
name
string
,
roots
[]
string
)
(
*
UnionFs
,
fuse
.
Status
)
{
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
used
:=
make
(
map
[
string
]
string
)
for
workspace
,
v
:=
range
me
.
knownFileSystems
{
used
[
v
.
Roots
()[
0
]]
=
workspace
}
workspace
,
ok
:=
used
[
roots
[
0
]]
if
ok
{
log
.
Printf
(
"Already have a union FS for directory %s in workspace %s"
,
roots
[
0
],
workspace
)
return
nil
,
fuse
.
EBUSY
}
var
gofs
*
UnionFs
if
me
.
knownFileSystems
[
name
]
==
nil
{
log
.
Println
(
"Adding UnionFs for roots"
,
roots
)
gofs
=
NewUnionFs
(
roots
,
me
.
options
.
UnionFsOptions
)
me
.
knownFileSystems
[
name
]
=
gofs
}
return
gofs
,
fuse
.
OK
}
func
(
me
*
AutoUnionFs
)
rmFs
(
name
string
)
(
code
fuse
.
Status
)
{
me
.
lock
.
Lock
()
var
gofs
*
UnionFs
if
me
.
knownFileSystems
[
name
]
==
nil
{
log
.
Println
(
"Adding UnionFs for roots"
,
roots
)
gofs
=
NewUnionFs
(
roots
,
me
.
options
.
UnionFsOptions
)
me
.
knownFileSystems
[
name
]
=
gofs
defer
me
.
lock
.
Unlock
()
fs
:=
me
.
knownFileSystems
[
name
]
if
fs
==
nil
{
return
fuse
.
ENOENT
}
code
=
me
.
connector
.
Unmount
(
name
)
if
code
.
Ok
()
{
me
.
knownFileSystems
[
name
]
=
nil
,
false
}
else
{
log
.
Println
(
"Unmount failed for %s. Code %v"
,
name
,
code
)
}
me
.
lock
.
Unlock
()
return
code
}
func
(
me
*
AutoUnionFs
)
addFs
(
name
string
,
roots
[]
string
)
(
code
fuse
.
Status
)
{
if
name
==
_CONFIG
||
name
==
_STATUS
{
log
.
Println
(
"Illegal name for overlay"
,
roots
)
return
fuse
.
EINVAL
}
gofs
,
code
:=
me
.
createFs
(
name
,
roots
)
if
gofs
!=
nil
{
me
.
connector
.
Mount
(
"/"
+
name
,
gofs
,
&
me
.
options
.
MountOptions
)
}
return
tru
e
return
cod
e
}
// TODO - should hide these methods.
...
...
@@ -152,15 +193,26 @@ func (me *AutoUnionFs) Symlink(pointedTo string, linkName string) (code fuse.Sta
}
name
:=
comps
[
1
]
if
!
me
.
addFs
(
name
,
roots
)
{
return
fuse
.
EPERM
}
return
fuse
.
OK
return
me
.
addFs
(
name
,
roots
)
}
return
fuse
.
EPERM
}
func
(
me
*
AutoUnionFs
)
Unlink
(
path
string
)
(
code
fuse
.
Status
)
{
comps
:=
strings
.
Split
(
path
,
"/"
,
-
1
)
if
len
(
comps
)
!=
2
{
return
fuse
.
EPERM
}
if
comps
[
0
]
==
_CONFIG
{
code
=
me
.
rmFs
(
comps
[
1
])
}
else
{
code
=
fuse
.
ENOENT
}
return
code
}
// Must define this, because ENOSYS will suspend all GetXAttr calls.
func
(
me
*
AutoUnionFs
)
GetXAttr
(
name
string
,
attr
string
)
([]
byte
,
fuse
.
Status
)
{
return
nil
,
syscall
.
ENODATA
...
...
unionfs/autounion_test.go
0 → 100644
View file @
b8b6c4e8
package
unionfs
import
(
"os"
"github.com/hanwen/go-fuse/fuse"
"io/ioutil"
"fmt"
"log"
"testing"
"time"
)
var
_
=
fmt
.
Print
var
_
=
log
.
Print
const
entryTtl
=
0.1
var
testAOpts
=
AutoUnionFsOptions
{
UnionFsOptions
:
testOpts
,
MountOptions
:
fuse
.
MountOptions
{
EntryTimeout
:
entryTtl
,
AttrTimeout
:
entryTtl
,
NegativeTimeout
:
0
,
},
}
func
WriteFile
(
name
string
,
contents
string
)
{
err
:=
ioutil
.
WriteFile
(
name
,
[]
byte
(
contents
),
0644
)
CheckSuccess
(
err
)
}
func
setup
(
t
*
testing
.
T
)
(
workdir
string
,
state
*
fuse
.
MountState
)
{
wd
:=
fuse
.
MakeTempDir
()
err
:=
os
.
Mkdir
(
wd
+
"/mount"
,
0700
)
fuse
.
CheckSuccess
(
err
)
err
=
os
.
Mkdir
(
wd
+
"/store"
,
0700
)
fuse
.
CheckSuccess
(
err
)
os
.
Mkdir
(
wd
+
"/ro"
,
0700
)
fuse
.
CheckSuccess
(
err
)
WriteFile
(
wd
+
"/ro/file1"
,
"file1"
)
WriteFile
(
wd
+
"/ro/file2"
,
"file2"
)
fs
:=
NewAutoUnionFs
(
wd
+
"/store"
,
testAOpts
)
connector
:=
fuse
.
NewFileSystemConnector
(
fs
,
&
testAOpts
.
MountOptions
)
state
=
fuse
.
NewMountState
(
connector
)
state
.
Mount
(
wd
+
"/mount"
)
state
.
Debug
=
true
go
state
.
Loop
(
false
)
return
wd
,
state
}
func
TestAutoFsSymlink
(
t
*
testing
.
T
)
{
wd
,
state
:=
setup
(
t
)
defer
state
.
Unmount
()
err
:=
os
.
Mkdir
(
wd
+
"/store/foo"
,
0755
)
CheckSuccess
(
err
)
os
.
Symlink
(
wd
+
"/ro"
,
wd
+
"/store/foo/READONLY"
)
CheckSuccess
(
err
)
err
=
os
.
Symlink
(
wd
+
"/store/foo"
,
wd
+
"/mount/config/bar"
)
CheckSuccess
(
err
)
fi
,
err
:=
os
.
Lstat
(
wd
+
"/mount/bar/file1"
)
CheckSuccess
(
err
)
err
=
os
.
Remove
(
wd
+
"/mount/config/bar"
)
CheckSuccess
(
err
)
// Need time for the unmount to be noticed.
log
.
Println
(
"sleeping..."
)
time
.
Sleep
(
entryTtl
*
2e9
)
fi
,
_
=
os
.
Lstat
(
wd
+
"/mount/foo"
)
if
fi
!=
nil
{
t
.
Error
(
"Should not have file:"
,
fi
)
}
_
,
err
=
ioutil
.
ReadDir
(
wd
+
"/mount/config"
)
CheckSuccess
(
err
)
_
,
err
=
os
.
Lstat
(
wd
+
"/mount/foo/file1"
)
CheckSuccess
(
err
)
}
func
TestCreationChecks
(
t
*
testing
.
T
)
{
wd
,
state
:=
setup
(
t
)
defer
state
.
Unmount
()
err
:=
os
.
Mkdir
(
wd
+
"/store/foo"
,
0755
)
CheckSuccess
(
err
)
os
.
Symlink
(
wd
+
"/ro"
,
wd
+
"/store/foo/READONLY"
)
CheckSuccess
(
err
)
err
=
os
.
Mkdir
(
wd
+
"/store/ws2"
,
0755
)
CheckSuccess
(
err
)
os
.
Symlink
(
wd
+
"/ro"
,
wd
+
"/store/ws2/READONLY"
)
CheckSuccess
(
err
)
err
=
os
.
Symlink
(
wd
+
"/store/foo"
,
wd
+
"/mount/config/bar"
)
CheckSuccess
(
err
)
err
=
os
.
Symlink
(
wd
+
"/store/foo"
,
wd
+
"/mount/config/foo"
)
code
:=
fuse
.
OsErrorToErrno
(
err
)
if
code
!=
fuse
.
EBUSY
{
t
.
Error
(
"Should return EBUSY"
,
err
)
}
err
=
os
.
Symlink
(
wd
+
"/store/ws2"
,
wd
+
"/mount/config/config"
)
code
=
fuse
.
OsErrorToErrno
(
err
)
if
code
!=
fuse
.
EINVAL
{
t
.
Error
(
"Should return EINVAL"
,
err
)
}
}
unionfs/unionfs_test.go
View file @
b8b6c4e8
...
...
@@ -12,6 +12,7 @@ import (
var
_
=
fmt
.
Print
var
_
=
log
.
Print
var
CheckSuccess
=
fuse
.
CheckSuccess
func
TestFilePathHash
(
t
*
testing
.
T
)
{
...
...
@@ -19,15 +20,13 @@ func TestFilePathHash(t *testing.T) {
t
.
Log
(
filePathHash
(
"xyz/abc"
))
}
const
entryTtl
=
1
var
testOpts
=
UnionFsOptions
{
DeletionCacheTTLSecs
:
entryTtl
,
DeletionDirName
:
"DELETIONS"
,
BranchCacheTTLSecs
:
entryTtl
,
}
func
setup
(
t
*
testing
.
T
)
(
workdir
string
,
state
*
fuse
.
MountState
)
{
func
setup
Ufs
(
t
*
testing
.
T
)
(
workdir
string
,
state
*
fuse
.
MountState
)
{
wd
:=
fuse
.
MakeTempDir
()
err
:=
os
.
Mkdir
(
wd
+
"/mount"
,
0700
)
fuse
.
CheckSuccess
(
err
)
...
...
@@ -48,7 +47,7 @@ func setup(t *testing.T) (workdir string, state *fuse.MountState) {
AttrTimeout
:
entryTtl
,
NegativeTimeout
:
entryTtl
,
}
connector
:=
fuse
.
NewFileSystemConnector
(
ufs
,
opts
)
state
=
fuse
.
NewMountState
(
connector
)
state
.
Mount
(
wd
+
"/mount"
)
...
...
@@ -119,7 +118,7 @@ func remove(path string) {
}
func
TestSymlink
(
t
*
testing
.
T
)
{
wd
,
state
:=
setup
(
t
)
wd
,
state
:=
setup
Ufs
(
t
)
defer
state
.
Unmount
()
err
:=
os
.
Symlink
(
"/foobar"
,
wd
+
"/mount/link"
)
...
...
@@ -134,9 +133,9 @@ func TestSymlink(t *testing.T) {
}
func
TestChtimes
(
t
*
testing
.
T
)
{
wd
,
state
:=
setup
(
t
)
wd
,
state
:=
setup
Ufs
(
t
)
defer
state
.
Unmount
()
writeToFile
(
wd
+
"/ro/file"
,
"a"
)
err
:=
os
.
Chtimes
(
wd
+
"/ro/file"
,
42e9
,
43e9
)
CheckSuccess
(
err
)
...
...
@@ -151,7 +150,7 @@ func TestChtimes(t *testing.T) {
}
func
TestChmod
(
t
*
testing
.
T
)
{
wd
,
state
:=
setup
(
t
)
wd
,
state
:=
setup
Ufs
(
t
)
defer
state
.
Unmount
()
ro_fn
:=
wd
+
"/ro/file"
...
...
@@ -165,7 +164,7 @@ func TestChmod(t *testing.T) {
if
code
!=
fuse
.
EPERM
{
t
.
Error
(
"Unexpected error code"
,
code
,
err
)
}
fi
,
err
:=
os
.
Lstat
(
m_fn
)
CheckSuccess
(
err
)
if
fi
.
Mode
&
07777
!=
07070
{
...
...
@@ -178,7 +177,7 @@ func TestChmod(t *testing.T) {
}
func
TestBasic
(
t
*
testing
.
T
)
{
wd
,
state
:=
setup
(
t
)
wd
,
state
:=
setup
Ufs
(
t
)
defer
state
.
Unmount
()
writeToFile
(
wd
+
"/rw/rw"
,
"a"
)
...
...
@@ -241,7 +240,7 @@ func TestBasic(t *testing.T) {
}
func
TestPromote
(
t
*
testing
.
T
)
{
wd
,
state
:=
setup
(
t
)
wd
,
state
:=
setup
Ufs
(
t
)
defer
state
.
Unmount
()
err
:=
os
.
Mkdir
(
wd
+
"/ro/subdir"
,
0755
)
...
...
@@ -251,7 +250,7 @@ func TestPromote(t *testing.T) {
}
func
TestCreate
(
t
*
testing
.
T
)
{
wd
,
state
:=
setup
(
t
)
wd
,
state
:=
setup
Ufs
(
t
)
defer
state
.
Unmount
()
err
:=
os
.
MkdirAll
(
wd
+
"/ro/subdir/sub2"
,
0755
)
...
...
@@ -262,7 +261,7 @@ func TestCreate(t *testing.T) {
}
func
TestOpenUndeletes
(
t
*
testing
.
T
)
{
wd
,
state
:=
setup
(
t
)
wd
,
state
:=
setup
Ufs
(
t
)
defer
state
.
Unmount
()
writeToFile
(
wd
+
"/ro/file"
,
"X"
)
...
...
@@ -274,7 +273,7 @@ func TestOpenUndeletes(t *testing.T) {
}
func
TestMkdir
(
t
*
testing
.
T
)
{
wd
,
state
:=
setup
(
t
)
wd
,
state
:=
setup
Ufs
(
t
)
defer
state
.
Unmount
()
dirname
:=
wd
+
"/mount/subdir"
...
...
@@ -286,7 +285,7 @@ func TestMkdir(t *testing.T) {
}
func
TestMkdirPromote
(
t
*
testing
.
T
)
{
wd
,
state
:=
setup
(
t
)
wd
,
state
:=
setup
Ufs
(
t
)
defer
state
.
Unmount
()
dirname
:=
wd
+
"/ro/subdir/subdir2"
...
...
@@ -321,7 +320,7 @@ func TestRename(t *testing.T) {
for
i
,
c
:=
range
configs
{
t
.
Log
(
"Config"
,
i
,
c
)
wd
,
state
:=
setup
(
t
)
wd
,
state
:=
setup
Ufs
(
t
)
if
c
.
f1_ro
{
writeToFile
(
wd
+
"/ro/file1"
,
"c1"
)
}
...
...
@@ -361,7 +360,7 @@ func TestRename(t *testing.T) {
func
TestWritableDir
(
t
*
testing
.
T
)
{
t
.
Log
(
"TestWritableDir"
)
wd
,
state
:=
setup
(
t
)
wd
,
state
:=
setup
Ufs
(
t
)
defer
state
.
Unmount
()
dirname
:=
wd
+
"/ro/subdir"
...
...
@@ -377,7 +376,7 @@ func TestWritableDir(t *testing.T) {
func
TestTruncate
(
t
*
testing
.
T
)
{
t
.
Log
(
"TestTruncate"
)
wd
,
state
:=
setup
(
t
)
wd
,
state
:=
setup
Ufs
(
t
)
defer
state
.
Unmount
()
writeToFile
(
wd
+
"/ro/file"
,
"hello"
)
...
...
@@ -394,7 +393,7 @@ func TestTruncate(t *testing.T) {
func
TestCopyChmod
(
t
*
testing
.
T
)
{
t
.
Log
(
"TestCopyChmod"
)
wd
,
state
:=
setup
(
t
)
wd
,
state
:=
setup
Ufs
(
t
)
defer
state
.
Unmount
()
contents
:=
"hello"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment