summaryrefslogtreecommitdiffhomepage
path: root/pkg/abi
diff options
context:
space:
mode:
authorRidwan Sharif <ridwanmsharif@google.com>2020-07-27 14:42:31 -0400
committerAndrei Vagin <avagin@gmail.com>2020-09-11 13:35:25 -0700
commiteccdd440899113c229f4abea53c03364d7f9875c (patch)
treea3187c9512e9e7c89d121a7103e6c54a67a213b3 /pkg/abi
parenta94377620401aee2b3e37d16f90054f7ddc756da (diff)
fuse: Implement IterDirents for directory file description
Fixes #3255. This change adds support for IterDirents. You can now use `ls` in the FUSE sandbox. Co-authored-by: Craig Chi <craigchi@google.com>
Diffstat (limited to 'pkg/abi')
-rw-r--r--pkg/abi/linux/fuse.go131
1 files changed, 127 insertions, 4 deletions
diff --git a/pkg/abi/linux/fuse.go b/pkg/abi/linux/fuse.go
index c75debb8c..e7b5f45de 100644
--- a/pkg/abi/linux/fuse.go
+++ b/pkg/abi/linux/fuse.go
@@ -14,7 +14,10 @@
package linux
-import "gvisor.dev/gvisor/tools/go_marshal/marshal"
+import (
+ "gvisor.dev/gvisor/tools/go_marshal/marshal"
+ "gvisor.dev/gvisor/tools/go_marshal/primitive"
+)
// +marshal
type FUSEOpcode uint32
@@ -186,9 +189,9 @@ const (
// Constants relevant to FUSE operations.
const (
- FUSE_NAME_MAX = 1024
- FUSE_PAGE_SIZE = 4096
- FUSE_DIRENT_ALIGN = 8
+ FUSE_NAME_MAX = 1024
+ FUSE_PAGE_SIZE = 4096
+ FUSE_DIRENT_ALIGN = 8
)
// FUSEInitIn is the request sent by the kernel to the daemon,
@@ -595,3 +598,123 @@ func (r *FUSERmDirIn) SizeBytes() int {
func (r *FUSERmDirIn) UnmarshalUnsafe(src []byte) {
r.Name = string(src)
}
+
+// FUSEDirents is a list of Dirents received from the FUSE daemon server.
+// It is used for FUSE_READDIR.
+//
+// Dynamically-sized objects cannot be marshalled.
+type FUSEDirents struct {
+ marshal.StubMarshallable
+
+ Dirents []*FUSEDirent
+}
+
+// FUSEDirent is a Dirent received from the FUSE daemon server.
+// It is used for FUSE_READDIR.
+//
+// Dynamically-sized objects cannot be marshalled.
+type FUSEDirent struct {
+ marshal.StubMarshallable
+
+ // Meta contains all the static fields of FUSEDirent.
+ Meta FUSEDirentMeta
+
+ // Name is the filename of the dirent.
+ Name string
+}
+
+// FUSEDirentMeta contains all the static fields of FUSEDirent.
+// It is used for FUSE_READDIR.
+//
+// +marshal
+type FUSEDirentMeta struct {
+ // Inode of the dirent.
+ Ino uint64
+
+ // Offset of the dirent.
+ Off uint64
+
+ // NameLen is the length of the dirent name.
+ NameLen uint32
+
+ // Type of the dirent.
+ Type uint32
+}
+
+// MarshalUnsafe serializes FUSEDirents to the dst buffer.
+func (r *FUSEDirents) MarshalUnsafe(dst []byte) {
+ for _, dirent := range r.Dirents {
+ dirent.MarshalUnsafe(dst)
+ dst = dst[dirent.SizeBytes():]
+ }
+}
+
+// SizeBytes is the size of the memory representation of FUSEDirents.
+func (r *FUSEDirents) SizeBytes() int {
+ var sizeBytes int
+ for _, dirent := range r.Dirents {
+ sizeBytes += dirent.SizeBytes()
+ }
+
+ return sizeBytes
+}
+
+// UnmarshalUnsafe deserializes FUSEDirents from the src buffer.
+func (r *FUSEDirents) UnmarshalUnsafe(src []byte) {
+ for {
+ if len(src) <= (*FUSEDirentMeta)(nil).SizeBytes() {
+ break
+ }
+
+ // Its unclear how many dirents there are in src. Each dirent is dynamically
+ // sized and so we can't make assumptions about how many dirents we can allocate.
+ if r.Dirents == nil {
+ r.Dirents = make([]*FUSEDirent, 0)
+ }
+
+ // We have to allocate a struct for each dirent - there must be a better way
+ // to do this. Linux allocates 1 page to store all the dirents and then
+ // simply reads them from the page.
+ var dirent FUSEDirent
+ dirent.UnmarshalUnsafe(src)
+ r.Dirents = append(r.Dirents, &dirent)
+
+ src = src[dirent.SizeBytes():]
+ }
+}
+
+// MarshalUnsafe serializes FUSEDirent to the dst buffer.
+func (r *FUSEDirent) MarshalUnsafe(dst []byte) {
+ r.Meta.MarshalUnsafe(dst)
+ dst = dst[r.Meta.SizeBytes():]
+
+ name := primitive.ByteSlice(r.Name)
+ name.MarshalUnsafe(dst)
+}
+
+// SizeBytes is the size of the memory representation of FUSEDirent.
+func (r *FUSEDirent) SizeBytes() int {
+ dataSize := r.Meta.SizeBytes() + len(r.Name)
+
+ // Each Dirent must be padded such that its size is a multiple
+ // of FUSE_DIRENT_ALIGN. Similar to the fuse dirent alignment
+ // in linux/fuse.h.
+ return (dataSize + (FUSE_DIRENT_ALIGN - 1)) & ^(FUSE_DIRENT_ALIGN - 1)
+}
+
+// UnmarshalUnsafe deserializes FUSEDirent from the src buffer.
+func (r *FUSEDirent) UnmarshalUnsafe(src []byte) {
+ r.Meta.UnmarshalUnsafe(src)
+ src = src[r.Meta.SizeBytes():]
+
+ if r.Meta.NameLen > FUSE_NAME_MAX {
+ // The name is too long and therefore invalid. We don't
+ // need to unmarshal the name since it'll be thrown away.
+ return
+ }
+
+ buf := make([]byte, r.Meta.NameLen)
+ name := primitive.ByteSlice(buf)
+ name.UnmarshalUnsafe(src[:r.Meta.NameLen])
+ r.Name = string(name)
+}