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
ad9d8a5b
Commit
ad9d8a5b
authored
Mar 02, 2011
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move MultiZipFs into examplelib, and provide a test. Document.
parent
efce7afc
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
324 additions
and
206 deletions
+324
-206
examplelib/Makefile
examplelib/Makefile
+4
-3
examplelib/multizip.go
examplelib/multizip.go
+227
-0
examplelib/multizip_test.go
examplelib/multizip_test.go
+92
-0
zipfs/multizip.go
zipfs/multizip.go
+1
-203
No files found.
examplelib/Makefile
View file @
ad9d8a5b
...
...
@@ -5,9 +5,10 @@ TARG=github.com/hanwen/go-fuse/examplelib
DEPS
=
../fuse
GOFILES
=
passthrough.go
\
stackfs.go
\
zipfs.go
\
GOFILES
=
passthrough.go
\
stackfs.go
\
zipfs.go
\
multizip.go
\
misc.go
include
$(GOROOT)/src/Make.pkg
...
...
examplelib/multizip.go
0 → 100644
View file @
ad9d8a5b
package
examplelib
/*
This provides a practical example of mounting Go-fuse path filesystems
on top of each other.
It is a file system that configures a Zip filesystem at /zipmount when writing
path/to/zipfile to /config/zipmount
*/
import
(
"github.com/hanwen/go-fuse/fuse"
"log"
"os"
"path"
"sync"
"strings"
)
var
_
=
log
.
Printf
const
(
CONFIG_PREFIX
=
"config/"
)
// zipCreateFile is a placeholder file to receive the write containing
// the path to the zip file.
type
zipCreateFile
struct
{
// Basename of the entry in the FS.
Basename
string
zfs
*
MultiZipFs
fuse
.
DefaultRawFuseFile
}
func
(
me
*
zipCreateFile
)
Write
(
input
*
fuse
.
WriteIn
,
nameBytes
[]
byte
)
(
uint32
,
fuse
.
Status
)
{
if
me
.
zfs
==
nil
{
// TODO
return
0
,
fuse
.
EPERM
}
zipFile
:=
string
(
nameBytes
)
zipFile
=
strings
.
Trim
(
zipFile
,
"
\n
"
)
fs
:=
NewZipFileFuse
(
zipFile
)
if
fs
==
nil
{
// TODO
log
.
Println
(
"NewZipFileFuse returned nil"
)
me
.
zfs
.
pendingZips
[
me
.
Basename
]
=
false
,
false
return
0
,
fuse
.
ENOSYS
}
code
:=
me
.
zfs
.
Connector
.
Mount
(
"/"
+
path
.
Base
(
me
.
Basename
),
fs
)
if
code
!=
fuse
.
OK
{
return
0
,
code
}
// TODO. locks?
me
.
zfs
.
zips
[
me
.
Basename
]
=
fs
me
.
zfs
.
pendingZips
[
me
.
Basename
]
=
false
,
false
me
.
zfs
=
nil
return
uint32
(
len
(
nameBytes
)),
code
}
////////////////////////////////////////////////////////////////
// MultiZipFs is a path filesystem that mounts zipfiles. It needs a
// reference to the PathFileSystemConnector to be able to execute
// mounts.
type
MultiZipFs
struct
{
Connector
*
fuse
.
PathFileSystemConnector
lock
sync
.
RWMutex
zips
map
[
string
]
*
ZipFileFuse
pendingZips
map
[
string
]
bool
zipFileNames
map
[
string
]
string
fuse
.
DefaultPathFilesystem
}
func
NewMultiZipFs
()
*
MultiZipFs
{
m
:=
new
(
MultiZipFs
)
m
.
zips
=
make
(
map
[
string
]
*
ZipFileFuse
)
m
.
pendingZips
=
make
(
map
[
string
]
bool
)
m
.
zipFileNames
=
make
(
map
[
string
]
string
)
m
.
Connector
=
fuse
.
NewPathFileSystemConnector
(
m
)
return
m
}
func
(
me
*
MultiZipFs
)
OpenDir
(
name
string
)
(
stream
chan
fuse
.
DirEntry
,
code
fuse
.
Status
)
{
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
// We don't use a goroutine, since we don't want to hold the
// lock.
stream
=
make
(
chan
fuse
.
DirEntry
,
len
(
me
.
pendingZips
)
+
len
(
me
.
zips
)
+
2
)
submode
:=
uint32
(
fuse
.
S_IFDIR
|
0700
)
if
name
==
"config"
{
submode
=
fuse
.
S_IFREG
|
0600
}
for
k
,
_
:=
range
me
.
zips
{
var
d
fuse
.
DirEntry
d
.
Name
=
k
d
.
Mode
=
submode
stream
<-
fuse
.
DirEntry
(
d
)
}
for
k
,
_
:=
range
me
.
pendingZips
{
var
d
fuse
.
DirEntry
d
.
Name
=
k
d
.
Mode
=
submode
stream
<-
fuse
.
DirEntry
(
d
)
}
if
name
==
""
{
var
d
fuse
.
DirEntry
d
.
Name
=
"config"
d
.
Mode
=
fuse
.
S_IFDIR
|
0700
stream
<-
fuse
.
DirEntry
(
d
)
}
stream
<-
fuse
.
DirEntry
{
Name
:
""
}
return
stream
,
fuse
.
OK
}
func
(
me
*
MultiZipFs
)
GetAttr
(
name
string
)
(
*
fuse
.
Attr
,
fuse
.
Status
)
{
a
:=
new
(
fuse
.
Attr
)
if
name
==
""
{
// Should not write in top dir.
a
.
Mode
=
fuse
.
S_IFDIR
|
0500
return
a
,
fuse
.
OK
}
if
name
==
"config"
{
// TODO
a
.
Mode
=
fuse
.
S_IFDIR
|
0700
return
a
,
fuse
.
OK
}
dir
,
base
:=
path
.
Split
(
name
)
if
dir
!=
""
&&
dir
!=
CONFIG_PREFIX
{
return
nil
,
fuse
.
ENOENT
}
submode
:=
uint32
(
fuse
.
S_IFDIR
|
0700
)
if
dir
==
CONFIG_PREFIX
{
submode
=
fuse
.
S_IFREG
|
0600
}
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
a
.
Mode
=
submode
entry
,
hasDir
:=
me
.
zips
[
base
]
if
hasDir
{
a
.
Size
=
uint64
(
len
(
entry
.
ZipFileName
))
return
a
,
fuse
.
OK
}
_
,
hasDir
=
me
.
pendingZips
[
base
]
if
hasDir
{
return
a
,
fuse
.
OK
}
return
nil
,
fuse
.
ENOENT
}
func
(
me
*
MultiZipFs
)
Unlink
(
name
string
)
(
code
fuse
.
Status
)
{
dir
,
basename
:=
path
.
Split
(
name
)
if
dir
==
CONFIG_PREFIX
{
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
_
,
ok
:=
me
.
zips
[
basename
]
if
ok
{
me
.
zips
[
basename
]
=
nil
,
false
return
fuse
.
OK
}
else
{
return
fuse
.
ENOENT
}
}
return
fuse
.
EPERM
}
func
(
me
*
MultiZipFs
)
Open
(
name
string
,
flags
uint32
)
(
file
fuse
.
RawFuseFile
,
code
fuse
.
Status
)
{
if
0
!=
flags
&
uint32
(
os
.
O_WRONLY
|
os
.
O_RDWR
|
os
.
O_APPEND
)
{
return
nil
,
fuse
.
EPERM
}
dir
,
basename
:=
path
.
Split
(
name
)
if
dir
==
CONFIG_PREFIX
{
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
entry
,
ok
:=
me
.
zips
[
basename
]
if
!
ok
{
return
nil
,
fuse
.
ENOENT
}
return
fuse
.
NewReadOnlyFile
([]
byte
(
entry
.
ZipFileName
)),
fuse
.
OK
}
return
nil
,
fuse
.
ENOENT
}
func
(
me
*
MultiZipFs
)
Create
(
name
string
,
flags
uint32
,
mode
uint32
)
(
file
fuse
.
RawFuseFile
,
code
fuse
.
Status
)
{
dir
,
base
:=
path
.
Split
(
name
)
if
dir
!=
CONFIG_PREFIX
{
return
nil
,
fuse
.
EPERM
}
z
:=
new
(
zipCreateFile
)
z
.
Basename
=
base
z
.
zfs
=
me
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
me
.
pendingZips
[
z
.
Basename
]
=
true
return
z
,
fuse
.
OK
}
examplelib/multizip_test.go
0 → 100644
View file @
ad9d8a5b
package
examplelib
import
(
"github.com/hanwen/go-fuse/fuse"
"os"
"testing"
"time"
)
func
TestMultiZipFs
(
t
*
testing
.
T
)
{
var
err
os
.
Error
wd
,
err
:=
os
.
Getwd
()
zipFile
:=
wd
+
"/test.zip"
fs
:=
NewMultiZipFs
()
state
:=
fuse
.
NewMountState
(
fs
.
Connector
)
mountPoint
:=
fuse
.
MakeTempDir
()
state
.
Debug
=
true
err
=
state
.
Mount
(
mountPoint
)
CheckSuccess
(
err
)
go
state
.
Loop
(
true
)
f
,
err
:=
os
.
Open
(
mountPoint
+
""
,
os
.
O_RDONLY
,
0
)
CheckSuccess
(
err
)
names
,
err
:=
f
.
Readdirnames
(
-
1
)
CheckSuccess
(
err
)
if
len
(
names
)
!=
1
||
string
(
names
[
0
])
!=
"config"
{
t
.
Errorf
(
"wrong names return. %v"
,
names
)
}
err
=
f
.
Close
()
CheckSuccess
(
err
)
f
,
err
=
os
.
Open
(
mountPoint
+
"/random"
,
os
.
O_WRONLY
|
os
.
O_CREATE
,
0
)
if
err
==
nil
{
t
.
Error
(
"Must fail writing in root."
)
}
f
,
err
=
os
.
Open
(
mountPoint
+
"/config/zipmount"
,
os
.
O_WRONLY
,
0
)
if
err
==
nil
{
t
.
Error
(
"Must fail without O_CREATE"
)
}
f
,
err
=
os
.
Open
(
mountPoint
+
"/config/zipmount"
,
os
.
O_WRONLY
|
os
.
O_CREATE
,
0
)
CheckSuccess
(
err
)
// Directory exists, but is empty.
if
!
IsDir
(
mountPoint
+
"/zipmount"
)
{
t
.
Errorf
(
"Expect directory at /zipmount"
)
}
// Open the zip file.
_
,
err
=
f
.
Write
([]
byte
(
zipFile
))
CheckSuccess
(
err
)
_
,
err
=
f
.
Write
([]
byte
(
zipFile
))
if
err
==
nil
{
t
.
Error
(
"Must fail second write."
)
}
err
=
f
.
Close
()
CheckSuccess
(
err
)
if
!
IsDir
(
mountPoint
+
"/zipmount"
)
{
t
.
Errorf
(
"Expect directory at /zipmount"
)
}
// Check that zipfs itself works.
fi
,
err
:=
os
.
Stat
(
mountPoint
+
"/zipmount/subdir"
)
CheckSuccess
(
err
)
if
!
fi
.
IsDirectory
()
{
t
.
Error
(
"directory type"
,
fi
)
}
// Removing the config dir unmount
err
=
os
.
Remove
(
mountPoint
+
"/config/zipmount"
)
CheckSuccess
(
err
)
// This is ugly but necessary: We don't have ways to signal
// back to FUSE that the file disappeared.
time
.
Sleep
(
1.5e9
)
fi
,
err
=
os
.
Stat
(
mountPoint
+
"/zipmount"
)
if
err
==
nil
{
t
.
Error
(
"stat should fail after unmount."
,
fi
)
}
state
.
Unmount
()
}
zipfs/multizip.go
View file @
ad9d8a5b
...
...
@@ -7,212 +7,10 @@ import (
"flag"
"log"
"os"
"path"
"sync"
"strings"
)
var
_
=
log
.
Printf
const
(
CONFIG_PREFIX
=
"config/"
)
type
ZipCreateFile
struct
{
// Basename of the entry in the FS.
Basename
string
zfs
*
MultiZipFs
fuse
.
DefaultRawFuseFile
}
func
(
me
*
ZipCreateFile
)
Write
(
input
*
fuse
.
WriteIn
,
nameBytes
[]
byte
)
(
uint32
,
fuse
.
Status
)
{
if
me
.
zfs
==
nil
{
// TODO
return
0
,
fuse
.
EPERM
}
zipFile
:=
string
(
nameBytes
)
zipFile
=
strings
.
Trim
(
zipFile
,
"
\n
"
)
fs
:=
examplelib
.
NewZipFileFuse
(
zipFile
)
if
fs
==
nil
{
// TODO
log
.
Println
(
"NewZipFileFuse returned nil"
)
me
.
zfs
.
pendingZips
[
me
.
Basename
]
=
false
,
false
return
0
,
fuse
.
ENOSYS
}
code
:=
me
.
zfs
.
Connector
.
Mount
(
"/"
+
path
.
Base
(
me
.
Basename
),
fs
)
if
code
!=
fuse
.
OK
{
return
0
,
code
}
// TODO. locks?
me
.
zfs
.
zips
[
me
.
Basename
]
=
fs
me
.
zfs
.
pendingZips
[
me
.
Basename
]
=
false
,
false
me
.
zfs
=
nil
return
uint32
(
len
(
nameBytes
)),
code
}
////////////////////////////////////////////////////////////////
type
MultiZipFs
struct
{
Connector
*
fuse
.
PathFileSystemConnector
lock
sync
.
RWMutex
zips
map
[
string
]
*
examplelib
.
ZipFileFuse
pendingZips
map
[
string
]
bool
zipFileNames
map
[
string
]
string
fuse
.
DefaultPathFilesystem
}
func
NewMultiZipFs
()
*
MultiZipFs
{
m
:=
new
(
MultiZipFs
)
m
.
zips
=
make
(
map
[
string
]
*
examplelib
.
ZipFileFuse
)
m
.
pendingZips
=
make
(
map
[
string
]
bool
)
m
.
zipFileNames
=
make
(
map
[
string
]
string
)
m
.
Connector
=
fuse
.
NewPathFileSystemConnector
(
m
)
return
m
}
func
(
me
*
MultiZipFs
)
OpenDir
(
name
string
)
(
stream
chan
fuse
.
DirEntry
,
code
fuse
.
Status
)
{
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
// We don't use a goroutine, since we don't want to hold the
// lock.
stream
=
make
(
chan
fuse
.
DirEntry
,
len
(
me
.
pendingZips
)
+
len
(
me
.
zips
)
+
2
)
submode
:=
uint32
(
fuse
.
S_IFDIR
|
0700
)
if
name
==
"config"
{
submode
=
fuse
.
S_IFREG
|
0600
}
for
k
,
_
:=
range
me
.
zips
{
var
d
fuse
.
DirEntry
d
.
Name
=
k
d
.
Mode
=
submode
stream
<-
fuse
.
DirEntry
(
d
)
}
for
k
,
_
:=
range
me
.
pendingZips
{
var
d
fuse
.
DirEntry
d
.
Name
=
k
d
.
Mode
=
submode
stream
<-
fuse
.
DirEntry
(
d
)
}
if
name
==
""
{
var
d
fuse
.
DirEntry
d
.
Name
=
"config"
d
.
Mode
=
fuse
.
S_IFDIR
|
0700
stream
<-
fuse
.
DirEntry
(
d
)
}
stream
<-
fuse
.
DirEntry
{
Name
:
""
}
return
stream
,
fuse
.
OK
}
func
(
me
*
MultiZipFs
)
GetAttr
(
name
string
)
(
*
fuse
.
Attr
,
fuse
.
Status
)
{
a
:=
new
(
fuse
.
Attr
)
if
name
==
""
{
// Should not write in top dir.
a
.
Mode
=
fuse
.
S_IFDIR
|
0500
return
a
,
fuse
.
OK
}
if
name
==
"config"
{
// TODO
a
.
Mode
=
fuse
.
S_IFDIR
|
0700
return
a
,
fuse
.
OK
}
dir
,
base
:=
path
.
Split
(
name
)
if
dir
!=
""
&&
dir
!=
CONFIG_PREFIX
{
return
nil
,
fuse
.
ENOENT
}
submode
:=
uint32
(
fuse
.
S_IFDIR
|
0700
)
if
dir
==
CONFIG_PREFIX
{
submode
=
fuse
.
S_IFREG
|
0600
}
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
a
.
Mode
=
submode
entry
,
hasDir
:=
me
.
zips
[
base
]
if
hasDir
{
a
.
Size
=
uint64
(
len
(
entry
.
ZipFileName
))
return
a
,
fuse
.
OK
}
_
,
hasDir
=
me
.
pendingZips
[
base
]
if
hasDir
{
return
a
,
fuse
.
OK
}
return
nil
,
fuse
.
ENOENT
}
func
(
me
*
MultiZipFs
)
Unlink
(
name
string
)
(
code
fuse
.
Status
)
{
dir
,
basename
:=
path
.
Split
(
name
)
if
dir
==
CONFIG_PREFIX
{
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
_
,
ok
:=
me
.
zips
[
basename
]
if
ok
{
me
.
zips
[
basename
]
=
nil
,
false
return
fuse
.
OK
}
else
{
return
fuse
.
ENOENT
}
}
return
fuse
.
EPERM
}
func
(
me
*
MultiZipFs
)
Open
(
name
string
,
flags
uint32
)
(
file
fuse
.
RawFuseFile
,
code
fuse
.
Status
)
{
if
0
!=
flags
&
uint32
(
os
.
O_WRONLY
|
os
.
O_RDWR
|
os
.
O_APPEND
)
{
return
nil
,
fuse
.
EPERM
}
dir
,
basename
:=
path
.
Split
(
name
)
if
dir
==
CONFIG_PREFIX
{
me
.
lock
.
RLock
()
defer
me
.
lock
.
RUnlock
()
entry
,
ok
:=
me
.
zips
[
basename
]
if
!
ok
{
return
nil
,
fuse
.
ENOENT
}
return
fuse
.
NewReadOnlyFile
([]
byte
(
entry
.
ZipFileName
)),
fuse
.
OK
}
return
nil
,
fuse
.
ENOENT
}
func
(
me
*
MultiZipFs
)
Create
(
name
string
,
flags
uint32
,
mode
uint32
)
(
file
fuse
.
RawFuseFile
,
code
fuse
.
Status
)
{
dir
,
base
:=
path
.
Split
(
name
)
if
dir
!=
CONFIG_PREFIX
{
return
nil
,
fuse
.
EPERM
}
z
:=
new
(
ZipCreateFile
)
z
.
Basename
=
base
z
.
zfs
=
me
me
.
lock
.
Lock
()
defer
me
.
lock
.
Unlock
()
me
.
pendingZips
[
z
.
Basename
]
=
true
return
z
,
fuse
.
OK
}
func
main
()
{
// Scans the arg list and sets up flags
flag
.
Parse
()
...
...
@@ -222,7 +20,7 @@ func main() {
os
.
Exit
(
2
)
}
fs
:=
NewMultiZipFs
()
fs
:=
examplelib
.
NewMultiZipFs
()
state
:=
fuse
.
NewMountState
(
fs
.
Connector
)
mountPoint
:=
flag
.
Arg
(
0
)
...
...
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