Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
J
jacobsa-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
Kirill Smelkov
jacobsa-fuse
Commits
d650fe34
Commit
d650fe34
authored
Mar 15, 2017
by
Ka-Hing Cheung
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added tests and enhanced comments
parent
cbeaa550
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
206 additions
and
17 deletions
+206
-17
conversions.go
conversions.go
+7
-3
errors.go
errors.go
+1
-0
fuseops/ops.go
fuseops/ops.go
+28
-13
samples/memfs/inode.go
samples/memfs/inode.go
+5
-1
samples/memfs/memfs.go
samples/memfs/memfs.go
+86
-0
samples/memfs/memfs_test.go
samples/memfs/memfs_test.go
+79
-0
No files found.
conversions.go
View file @
d650fe34
...
...
@@ -475,9 +475,10 @@ func convertInMessage(
return
}
o
=
&
fuseops
.
ListXattrOp
{
to
:
=
&
fuseops
.
ListXattrOp
{
Inode
:
fuseops
.
InodeID
(
inMsg
.
Header
()
.
Nodeid
),
}
o
=
to
readSize
:=
int
(
in
.
Size
)
if
readSize
!=
0
{
...
...
@@ -486,6 +487,10 @@ func convertInMessage(
err
=
fmt
.
Errorf
(
"Can't grow for %d-byte read"
,
readSize
)
return
}
sh
:=
(
*
reflect
.
SliceHeader
)(
unsafe
.
Pointer
(
&
to
.
Dst
))
sh
.
Data
=
uintptr
(
p
)
sh
.
Len
=
readSize
sh
.
Cap
=
readSize
}
case
fusekernel
.
OpSetxattr
:
type
input
fusekernel
.
SetxattrIn
...
...
@@ -508,12 +513,11 @@ func convertInMessage(
}
name
,
value
:=
payload
[
:
i
],
payload
[
i
+
1
:
len
(
payload
)]
fmt
.
Printf
(
"Setting %v to %v
\n
"
,
name
,
value
)
o
=
&
fuseops
.
SetXattrOp
{
Inode
:
fuseops
.
InodeID
(
inMsg
.
Header
()
.
Nodeid
),
Name
:
string
(
name
),
Data
:
value
,
Value
:
value
,
Flags
:
in
.
Flags
,
}
...
...
errors.go
View file @
d650fe34
...
...
@@ -22,6 +22,7 @@ const (
EEXIST
=
syscall
.
EEXIST
EINVAL
=
syscall
.
EINVAL
EIO
=
syscall
.
EIO
ENOATTR
=
syscall
.
ENODATA
ENOENT
=
syscall
.
ENOENT
ENOSYS
=
syscall
.
ENOSYS
ENOTDIR
=
syscall
.
ENOTDIR
...
...
fuseops/ops.go
View file @
d650fe34
...
...
@@ -772,21 +772,27 @@ type ReadSymlinkOp struct {
// eXtended attributes
////////////////////////////////////////////////////////////////////////
// Remove an extended attribute
// Remove an extended attribute.
//
// This is sent in response to removexattr(2). Return ENOATTR if the
// extended attribute does not exist.
type
RemoveXattrOp
struct
{
// The inode that we are re
ading
// The inode that we are re
moving an extended attribute from.
Inode
InodeID
// The name of the extended attribute
// The name of the extended attribute
.
Name
string
}
// Get an extended attribute
// Get an extended attribute.
//
// This is sent in response to getxattr(2). Return ENOATTR if the
// extended attribute does not exist.
type
GetXattrOp
struct
{
// The inode
that we are reading
// The inode
whose extended attribute we are reading.
Inode
InodeID
// The name of the extended attribute
// The name of the extended attribute
.
Name
string
// The destination buffer. If the size is too small for the
...
...
@@ -795,38 +801,47 @@ type GetXattrOp struct {
// Set by the file system: the number of bytes read into Dst, or
// the number of bytes that would have been read into Dst if Dst was
// big enough
// big enough
(return ERANGE in this case).
BytesRead
int
}
// List all the extended attributes for a file.
//
// This is sent in response to listxattr(2).
type
ListXattrOp
struct
{
// The inode
that we are reading
// The inode
whose extended attributes we are listing.
Inode
InodeID
// The destination buffer. If the size is too small for the
// value, the ERANGE error should be sent.
//
// The output data should consist of a sequence of NUL-terminated strings,
// one for each xattr
// one for each xattr
.
Dst
[]
byte
// Set by the file system: the number of bytes read into Dst, or
// the number of bytes that would have been read into Dst if Dst was
// big enough
// big enough
(return ERANGE in this case).
BytesRead
int
}
// Set an extended attribute.
//
// This is sent in response to setxattr(2). Return ENOSPC if there is
// insufficient space remaining to store the extended attribute.
type
SetXattrOp
struct
{
// The inode
that we are changing
// The inode
whose extended attribute we are setting.
Inode
InodeID
// The name of the extended attribute
Name
string
// The
data
to for the extened attribute.
Data
[]
byte
// The
value
to for the extened attribute.
Value
[]
byte
// If Flags is 0x1, and the attribute exists already, EEXIST should be returned.
// If Flags is 0x2, and the attribute does not exist, ENOATTR should be returned.
// If Flags is 0x0, the extended attribute will be created if need be, or will
// simply replace the value if the attribute exists.
Flags
uint32
}
samples/memfs/inode.go
View file @
d650fe34
...
...
@@ -61,6 +61,9 @@ type inode struct {
//
// INVARIANT: If !isSymlink(), len(target) == 0
target
string
// extended attributes and values
xattrs
map
[
string
][]
byte
}
////////////////////////////////////////////////////////////////////////
...
...
@@ -78,7 +81,8 @@ func newInode(
// Create the object.
in
=
&
inode
{
attrs
:
attrs
,
attrs
:
attrs
,
xattrs
:
make
(
map
[
string
][]
byte
),
}
return
...
...
samples/memfs/memfs.go
View file @
d650fe34
...
...
@@ -18,6 +18,7 @@ import (
"fmt"
"io"
"os"
"syscall"
"time"
"golang.org/x/net/context"
...
...
@@ -628,3 +629,88 @@ func (fs *memFS) ReadSymlink(
return
}
func
(
fs
*
memFS
)
GetXattr
(
ctx
context
.
Context
,
op
*
fuseops
.
GetXattrOp
)
(
err
error
)
{
fs
.
mu
.
Lock
()
defer
fs
.
mu
.
Unlock
()
inode
:=
fs
.
getInodeOrDie
(
op
.
Inode
)
if
value
,
ok
:=
inode
.
xattrs
[
op
.
Name
];
ok
{
op
.
BytesRead
=
len
(
value
)
if
len
(
op
.
Dst
)
>=
len
(
value
)
{
copy
(
op
.
Dst
,
value
)
}
else
{
err
=
syscall
.
ERANGE
}
}
else
{
err
=
fuse
.
ENOATTR
}
return
}
func
(
fs
*
memFS
)
ListXattr
(
ctx
context
.
Context
,
op
*
fuseops
.
ListXattrOp
)
(
err
error
)
{
fs
.
mu
.
Lock
()
defer
fs
.
mu
.
Unlock
()
inode
:=
fs
.
getInodeOrDie
(
op
.
Inode
)
dst
:=
op
.
Dst
[
:
]
for
key
:=
range
inode
.
xattrs
{
keyLen
:=
len
(
key
)
+
1
if
err
==
nil
&&
len
(
dst
)
>=
keyLen
{
copy
(
dst
,
key
)
dst
=
dst
[
keyLen
:
]
}
else
{
err
=
syscall
.
ERANGE
}
op
.
BytesRead
+=
keyLen
}
return
}
func
(
fs
*
memFS
)
RemoveXattr
(
ctx
context
.
Context
,
op
*
fuseops
.
RemoveXattrOp
)
(
err
error
)
{
fs
.
mu
.
Lock
()
defer
fs
.
mu
.
Unlock
()
inode
:=
fs
.
getInodeOrDie
(
op
.
Inode
)
if
_
,
ok
:=
inode
.
xattrs
[
op
.
Name
];
ok
{
delete
(
inode
.
xattrs
,
op
.
Name
)
}
else
{
err
=
fuse
.
ENOATTR
}
return
}
func
(
fs
*
memFS
)
SetXattr
(
ctx
context
.
Context
,
op
*
fuseops
.
SetXattrOp
)
(
err
error
)
{
fs
.
mu
.
Lock
()
defer
fs
.
mu
.
Unlock
()
inode
:=
fs
.
getInodeOrDie
(
op
.
Inode
)
_
,
ok
:=
inode
.
xattrs
[
op
.
Name
]
switch
op
.
Flags
{
case
0x1
:
if
ok
{
err
=
fuse
.
EEXIST
}
case
0x2
:
if
!
ok
{
err
=
fuse
.
ENOATTR
}
}
if
err
==
nil
{
value
:=
make
([]
byte
,
len
(
op
.
Value
))
copy
(
value
,
op
.
Value
)
inode
.
xattrs
[
op
.
Name
]
=
value
}
return
}
samples/memfs/memfs_test.go
View file @
d650fe34
...
...
@@ -27,6 +27,8 @@ import (
"testing"
"time"
"github.com/ivaxer/go-xattr"
"github.com/jacobsa/fuse"
"github.com/jacobsa/fuse/fusetesting"
"github.com/jacobsa/fuse/samples"
"github.com/jacobsa/fuse/samples/memfs"
...
...
@@ -1611,6 +1613,83 @@ func (t *MemFSTest) RenameNonExistentFile() {
ExpectThat
(
err
,
Error
(
HasSubstr
(
"no such file"
)))
}
func
(
t
*
MemFSTest
)
GetListNoXAttr
()
{
var
err
error
// Create a file
filePath
:=
path
.
Join
(
t
.
Dir
,
"foo"
)
err
=
ioutil
.
WriteFile
(
filePath
,
[]
byte
(
"taco"
),
0400
)
AssertEq
(
nil
,
err
)
names
,
err
:=
xattr
.
List
(
filePath
)
AssertEq
(
nil
,
err
)
AssertEq
(
0
,
len
(
names
))
_
,
err
=
xattr
.
Getxattr
(
filePath
,
"foo"
,
nil
)
AssertEq
(
fuse
.
ENOATTR
,
err
)
}
func
(
t
*
MemFSTest
)
SetXAttr
()
{
var
err
error
// Create a file
filePath
:=
path
.
Join
(
t
.
Dir
,
"foo"
)
err
=
ioutil
.
WriteFile
(
filePath
,
[]
byte
(
"taco"
),
0600
)
AssertEq
(
nil
,
err
)
err
=
xattr
.
Setxattr
(
filePath
,
"foo"
,
[]
byte
(
"bar"
),
0x2
)
AssertEq
(
fuse
.
ENOATTR
,
err
)
err
=
xattr
.
Setxattr
(
filePath
,
"foo"
,
[]
byte
(
"bar"
),
0x1
)
AssertEq
(
nil
,
err
)
value
,
err
:=
xattr
.
Get
(
filePath
,
"foo"
)
AssertEq
(
nil
,
err
)
AssertEq
(
"bar"
,
string
(
value
))
err
=
xattr
.
Setxattr
(
filePath
,
"foo"
,
[]
byte
(
"hello world"
),
0x2
)
AssertEq
(
nil
,
err
)
value
,
err
=
xattr
.
Get
(
filePath
,
"foo"
)
AssertEq
(
nil
,
err
)
AssertEq
(
"hello world"
,
string
(
value
))
names
,
err
:=
xattr
.
List
(
filePath
)
AssertEq
(
nil
,
err
)
AssertEq
(
1
,
len
(
names
))
AssertEq
(
"foo"
,
names
[
0
])
err
=
xattr
.
Setxattr
(
filePath
,
"bar"
,
[]
byte
(
"hello world"
),
0x0
)
AssertEq
(
nil
,
err
)
names
,
err
=
xattr
.
List
(
filePath
)
AssertEq
(
nil
,
err
)
AssertEq
(
2
,
len
(
names
))
ExpectThat
(
names
,
Contains
(
"foo"
))
ExpectThat
(
names
,
Contains
(
"bar"
))
}
func
(
t
*
MemFSTest
)
RemoveXAttr
()
{
var
err
error
// Create a file
filePath
:=
path
.
Join
(
t
.
Dir
,
"foo"
)
err
=
ioutil
.
WriteFile
(
filePath
,
[]
byte
(
"taco"
),
0600
)
AssertEq
(
nil
,
err
)
err
=
xattr
.
Removexattr
(
filePath
,
"foo"
)
AssertEq
(
fuse
.
ENOATTR
,
err
)
err
=
xattr
.
Setxattr
(
filePath
,
"foo"
,
[]
byte
(
"bar"
),
0x1
)
AssertEq
(
nil
,
err
)
err
=
xattr
.
Removexattr
(
filePath
,
"foo"
)
AssertEq
(
nil
,
err
)
_
,
err
=
xattr
.
Getxattr
(
filePath
,
"foo"
,
nil
)
AssertEq
(
fuse
.
ENOATTR
,
err
)
}
////////////////////////////////////////////////////////////////////////
// Mknod
////////////////////////////////////////////////////////////////////////
...
...
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