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
6aed6515
Commit
6aed6515
authored
Apr 17, 2019
by
Han-Wen Nienhuys
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
nodefs: make the examples package level examples
parent
6dae0ec7
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
155 additions
and
95 deletions
+155
-95
nodefs/example_test.go
nodefs/example_test.go
+25
-11
nodefs/inmemory_example_test.go
nodefs/inmemory_example_test.go
+93
-0
nodefs/zip_test.go
nodefs/zip_test.go
+37
-84
No files found.
nodefs/example_test.go
View file @
6aed6515
...
...
@@ -2,35 +2,49 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package
nodefs
package
nodefs
_test
import
(
"fmt"
"io/ioutil"
"log"
"os"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/nodefs"
)
// mountLoopback mounts dir under the given mountpoint
func
mountLoopback
(
dir
,
mntPoint
string
)
(
*
fuse
.
Server
,
error
)
{
root
,
err
:=
nodefs
.
NewLoopbackRoot
(
dir
)
if
err
!=
nil
{
return
nil
,
err
}
// Make the root available under mntDir
return
nodefs
.
Mount
(
mntPoint
,
root
,
&
nodefs
.
Options
{
MountOptions
:
fuse
.
MountOptions
{
Debug
:
true
},
})
}
// An example of creating a loopback file system, and mounting it onto
// a directory
func
Example
Mount
()
{
func
Example
_mountLoopback
()
{
mntDir
,
_
:=
ioutil
.
TempDir
(
""
,
""
)
home
:=
os
.
Getenv
(
"HOME"
)
root
,
err
:=
NewLoopbackRoot
(
home
)
if
err
!=
nil
{
log
.
Panic
(
err
)
}
server
,
err
:=
Mount
(
mntDir
,
root
,
&
Options
{
MountOptions
:
fuse
.
MountOptions
{
Debug
:
true
},
}
)
// Make $HOME available on a mount dir under /tmp/ . Caution:
// write operations are also mirrored.
server
,
err
:=
mountLoopback
(
mntDir
,
home
)
if
err
!=
nil
{
log
.
Panic
(
err
)
}
log
.
Printf
(
"Mounted %s as loopback on %s"
,
home
,
mntDir
)
log
.
Printf
(
"Unmount by calling 'fusermount -u %s'"
,
mntDir
)
fmt
.
Printf
(
"Mounted %s as loopback on %s
\n
"
,
home
,
mntDir
)
fmt
.
Printf
(
"
\n\n
CAUTION:
\n
write operations on %s will also affect $HOME (%s)
\n\n
"
,
mntDir
,
home
)
fmt
.
Printf
(
"Unmount by calling 'fusermount -u %s'
\n
"
,
mntDir
)
// Wait until the directory is unmounted
server
.
Wait
()
}
nodefs/inmemory_example_test.go
0 → 100644
View file @
6aed6515
// Copyright 2019 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
nodefs_test
import
(
"context"
"io/ioutil"
"log"
"path/filepath"
"strings"
"syscall"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/nodefs"
)
// files contains the files we will expose as a file system
var
files
=
map
[
string
]
string
{
"file"
:
"content"
,
"subdir/other-file"
:
"other-content"
,
}
// inMemoryFS is the root of the tree
type
inMemoryFS
struct
{
nodefs
.
Inode
}
// Ensure that we implement NodeOnAdder
var
_
=
(
nodefs
.
NodeOnAdder
)((
*
inMemoryFS
)(
nil
))
// OnAdd is called on mounting the file system. Use it to populate
// the file system tree.
func
(
root
*
inMemoryFS
)
OnAdd
(
ctx
context
.
Context
)
{
for
name
,
content
:=
range
files
{
dir
,
base
:=
filepath
.
Split
(
name
)
p
:=
&
root
.
Inode
// Add directories leading up to the file.
for
_
,
component
:=
range
strings
.
Split
(
dir
,
"/"
)
{
if
len
(
component
)
==
0
{
continue
}
ch
:=
p
.
GetChild
(
component
)
if
ch
==
nil
{
// Create a directory
ch
=
p
.
NewPersistentInode
(
ctx
,
&
nodefs
.
Inode
{},
nodefs
.
StableAttr
{
Mode
:
syscall
.
S_IFDIR
})
// Add it
p
.
AddChild
(
component
,
ch
,
true
)
}
p
=
ch
}
// Create the file. The Inode must be persistent,
// because its life time is not under control of the
// kernel.
child
:=
p
.
NewPersistentInode
(
ctx
,
&
nodefs
.
MemRegularFile
{
Data
:
[]
byte
(
content
),
},
nodefs
.
StableAttr
{})
// And add it
p
.
AddChild
(
base
,
child
,
true
)
}
}
// This demonstrates how to build a file system in memory.
func
Example
()
{
// This is where we'll mount the FS
mntDir
,
_
:=
ioutil
.
TempDir
(
""
,
""
)
root
:=
&
inMemoryFS
{}
server
,
err
:=
nodefs
.
Mount
(
mntDir
,
root
,
&
nodefs
.
Options
{
MountOptions
:
fuse
.
MountOptions
{
Debug
:
true
},
// This adds read permissions to the files and
// directories, which is necessary for doing a chdir
// into the mount.
DefaultPermissions
:
true
,
})
if
err
!=
nil
{
log
.
Panic
(
err
)
}
log
.
Printf
(
"Mounted on %s"
,
mntDir
)
log
.
Printf
(
"Unmount by calling 'fusermount -u %s'"
,
mntDir
)
// Wait until unmount before exiting
server
.
Wait
()
}
nodefs/zip_test.go
View file @
6aed6515
...
...
@@ -2,14 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package
nodefs
package
nodefs
_test
import
(
"archive/zip"
"bytes"
"context"
"io/ioutil"
"log"
"path/filepath"
"reflect"
"strings"
...
...
@@ -18,6 +17,7 @@ import (
"testing"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/nodefs"
)
var
testData
=
map
[
string
]
string
{
...
...
@@ -62,8 +62,15 @@ func TestZipFS(t *testing.T) {
}
root
:=
&
zipRoot
{
zr
:
r
}
mntDir
,
_
,
clean
:=
testMount
(
t
,
root
,
nil
)
defer
clean
()
mntDir
,
err
:=
ioutil
.
TempDir
(
""
,
"ZipFS"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
server
,
err
:=
nodefs
.
Mount
(
mntDir
,
root
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
server
.
Unmount
()
for
k
,
v
:=
range
testData
{
c
,
err
:=
ioutil
.
ReadFile
(
filepath
.
Join
(
mntDir
,
k
))
...
...
@@ -103,14 +110,22 @@ func TestZipFSOnAdd(t *testing.T) {
zr
:=
&
zipRoot
{
zr
:
r
}
root
:=
&
Inode
{}
mnt
,
_
,
clean
:=
testMount
(
t
,
root
,
&
Options
{
root
:=
&
nodefs
.
Inode
{}
mnt
,
err
:=
ioutil
.
TempDir
(
""
,
"ZipFS"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
server
,
err
:=
nodefs
.
Mount
(
mnt
,
root
,
&
nodefs
.
Options
{
OnAdd
:
func
(
ctx
context
.
Context
)
{
root
.
AddChild
(
"sub"
,
root
.
NewPersistentInode
(
ctx
,
zr
,
StableAttr
{
Mode
:
syscall
.
S_IFDIR
}),
false
)
root
.
NewPersistentInode
(
ctx
,
zr
,
nodefs
.
StableAttr
{
Mode
:
syscall
.
S_IFDIR
}),
false
)
},
})
defer
clean
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
server
.
Unmount
()
c
,
err
:=
ioutil
.
ReadFile
(
mnt
+
"/sub/dir/subdir/subfile"
)
if
err
!=
nil
{
t
.
Fatal
(
"ReadFile"
,
err
)
...
...
@@ -122,25 +137,25 @@ func TestZipFSOnAdd(t *testing.T) {
// zipFile is a file read from a zip archive.
type
zipFile
struct
{
Inode
nodefs
.
Inode
file
*
zip
.
File
mu
sync
.
Mutex
data
[]
byte
}
var
_
=
(
NodeOpener
)((
*
zipFile
)(
nil
))
var
_
=
(
NodeGetattrer
)((
*
zipFile
)(
nil
))
var
_
=
(
nodefs
.
NodeOpener
)((
*
zipFile
)(
nil
))
var
_
=
(
nodefs
.
NodeGetattrer
)((
*
zipFile
)(
nil
))
// Getattr sets the minimum, which is the size. A more full-featured
// FS would also set timestamps and permissions.
func
(
zf
*
zipFile
)
Getattr
(
ctx
context
.
Context
,
f
FileHandle
,
out
*
fuse
.
AttrOut
)
syscall
.
Errno
{
func
(
zf
*
zipFile
)
Getattr
(
ctx
context
.
Context
,
f
nodefs
.
FileHandle
,
out
*
fuse
.
AttrOut
)
syscall
.
Errno
{
out
.
Size
=
zf
.
file
.
UncompressedSize64
return
OK
return
0
}
// Open lazily unpacks zip data
func
(
zf
*
zipFile
)
Open
(
ctx
context
.
Context
,
flags
uint32
)
(
FileHandle
,
uint32
,
syscall
.
Errno
)
{
func
(
zf
*
zipFile
)
Open
(
ctx
context
.
Context
,
flags
uint32
)
(
nodefs
.
FileHandle
,
uint32
,
syscall
.
Errno
)
{
zf
.
mu
.
Lock
()
defer
zf
.
mu
.
Unlock
()
if
zf
.
data
==
nil
{
...
...
@@ -159,27 +174,27 @@ func (zf *zipFile) Open(ctx context.Context, flags uint32) (FileHandle, uint32,
// We don't return a filehandle since we don't really need
// one. The file content is immutable, so hint the kernel to
// cache the data.
return
nil
,
fuse
.
FOPEN_KEEP_CACHE
,
OK
return
nil
,
fuse
.
FOPEN_KEEP_CACHE
,
nodefs
.
OK
}
// Read simply returns the data that was already unpacked in the Open call
func
(
zf
*
zipFile
)
Read
(
ctx
context
.
Context
,
f
FileHandle
,
dest
[]
byte
,
off
int64
)
(
fuse
.
ReadResult
,
syscall
.
Errno
)
{
func
(
zf
*
zipFile
)
Read
(
ctx
context
.
Context
,
f
nodefs
.
FileHandle
,
dest
[]
byte
,
off
int64
)
(
fuse
.
ReadResult
,
syscall
.
Errno
)
{
end
:=
int
(
off
)
+
len
(
dest
)
if
end
>
len
(
zf
.
data
)
{
end
=
len
(
zf
.
data
)
}
return
fuse
.
ReadResultData
(
zf
.
data
[
off
:
end
]),
OK
return
fuse
.
ReadResultData
(
zf
.
data
[
off
:
end
]),
nodefs
.
OK
}
// zipRoot is the root of the Zip filesystem. Its only functionality
// is populating the filesystem.
type
zipRoot
struct
{
Inode
nodefs
.
Inode
zr
*
zip
.
Reader
}
var
_
=
(
NodeOnAdder
)((
*
zipRoot
)(
nil
))
var
_
=
(
nodefs
.
NodeOnAdder
)((
*
zipRoot
)(
nil
))
func
(
zr
*
zipRoot
)
OnAdd
(
ctx
context
.
Context
)
{
// OnAdd is called once we are attached to an Inode. We can
...
...
@@ -196,76 +211,14 @@ func (zr *zipRoot) OnAdd(ctx context.Context) {
}
ch
:=
p
.
GetChild
(
component
)
if
ch
==
nil
{
ch
=
p
.
NewPersistentInode
(
ctx
,
&
Inode
{},
StableAttr
{
Mode
:
fuse
.
S_IFDIR
})
ch
=
p
.
NewPersistentInode
(
ctx
,
&
nodefs
.
Inode
{},
nodefs
.
StableAttr
{
Mode
:
fuse
.
S_IFDIR
})
p
.
AddChild
(
component
,
ch
,
true
)
}
p
=
ch
}
ch
:=
p
.
NewPersistentInode
(
ctx
,
&
zipFile
{
file
:
f
},
StableAttr
{})
ch
:=
p
.
NewPersistentInode
(
ctx
,
&
zipFile
{
file
:
f
},
nodefs
.
StableAttr
{})
p
.
AddChild
(
base
,
ch
,
true
)
}
}
// Persistent inodes can be used to create an in-memory
// prefabricated file system tree.
func
ExampleInode_NewPersistentInode
()
{
// This is where we'll mount the FS
mntDir
,
_
:=
ioutil
.
TempDir
(
""
,
""
)
files
:=
map
[
string
]
string
{
"file"
:
"content"
,
"subdir/other-file"
:
"other-content"
,
}
root
:=
&
Inode
{}
populate
:=
func
(
ctx
context
.
Context
)
{
for
name
,
content
:=
range
files
{
dir
,
base
:=
filepath
.
Split
(
name
)
p
:=
root
// Add directories leading up to the file.
for
_
,
component
:=
range
strings
.
Split
(
dir
,
"/"
)
{
if
len
(
component
)
==
0
{
continue
}
ch
:=
p
.
GetChild
(
component
)
if
ch
==
nil
{
// Create a directory
ch
=
p
.
NewPersistentInode
(
ctx
,
&
Inode
{},
StableAttr
{
Mode
:
syscall
.
S_IFDIR
})
// Add it
p
.
AddChild
(
component
,
ch
,
true
)
}
p
=
ch
}
// Create the file
child
:=
p
.
NewPersistentInode
(
ctx
,
&
MemRegularFile
{
Data
:
[]
byte
(
content
),
},
StableAttr
{})
// And add it
p
.
AddChild
(
base
,
child
,
true
)
}
}
server
,
err
:=
Mount
(
mntDir
,
root
,
&
Options
{
MountOptions
:
fuse
.
MountOptions
{
Debug
:
true
},
// This adds read permissions to the files and
// directories, which is necessary for doing a chdir
// into the mount.
DefaultPermissions
:
true
,
OnAdd
:
populate
,
})
if
err
!=
nil
{
log
.
Panic
(
err
)
}
log
.
Printf
(
"Mounted on %s"
,
mntDir
)
log
.
Printf
(
"Unmount by calling 'fusermount -u %s'"
,
mntDir
)
server
.
Wait
()
}
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