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
Show 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
...
...
@@ -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
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
}
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
}
me
.
lock
.
Unlock
()
return
gofs
,
fuse
.
OK
}
func
(
me
*
AutoUnionFs
)
rmFs
(
name
string
)
(
code
fuse
.
Status
)
{
me
.
lock
.
Lock
()
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
)
}
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
)
...
...
@@ -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,7 +133,7 @@ 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"
)
...
...
@@ -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"
...
...
@@ -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