From 187da99dd65948f9df2ab062a67143c30835ef57 Mon Sep 17 00:00:00 2001 From: Caleb Gardner Date: Tue, 17 Jan 2023 10:20:11 -0600 Subject: [PATCH] Added fuse2 mounting --- fuse2.go | 150 ++++++++++++++++++++++++++++++++++++++++++++ fuse.go => fuse3.go | 13 ++-- go.mod | 5 +- go.sum | 2 + reader.go | 3 + 5 files changed, 163 insertions(+), 10 deletions(-) create mode 100644 fuse2.go rename fuse.go => fuse3.go (91%) diff --git a/fuse2.go b/fuse2.go new file mode 100644 index 0000000..a7dcfff --- /dev/null +++ b/fuse2.go @@ -0,0 +1,150 @@ +package squashfs + +import ( + "bytes" + "context" + "errors" + "io" + + "github.com/CalebQ42/squashfs/internal/inode" + "github.com/seaweedfs/fuse" + "github.com/seaweedfs/fuse/fs" +) + +// Mounts the archive to the given mountpoint using fuse2. Non-blocking. +// If Unmount does not get called, the mount point must be unmounted using umount before the directory can be used again. +func (r *Reader) MountFuse2(mountpoint string) (err error) { + if r.con != nil { + return errors.New("squashfs archive already mounted") + } + r.con2, err = fuse.Mount(mountpoint, fuse.ReadOnly()) + if err != nil { + return + } + <-r.con.Ready + r.mount2Done = make(chan struct{}) + go func() { + fs.Serve(r.con2, squashFuse2{r: r}) + close(r.mount2Done) + }() + return +} + +// Blocks until the mount ends. +// Fuse2 version. +func (r *Reader) MountWaitFuse2() { + if r.mount2Done != nil { + <-r.mount2Done + } +} + +// Unmounts the archive. +// Fuse2 version. +func (r *Reader) UnmountFuse2() error { + if r.con != nil { + defer func() { r.con = nil }() + return r.con.Close() + } + return errors.New("squashfs archive is not mounted") +} + +type squashFuse2 struct { + r *Reader +} + +func (s squashFuse2) Root() (fs.Node, error) { + return fileNode2{File: s.r.FS.File}, nil +} + +type fileNode2 struct { + *File +} + +func (f fileNode2) Attr(ctx context.Context, attr *fuse.Attr) error { + attr.Blocks = f.r.s.Size / 512 + if f.r.s.Size%512 > 0 { + attr.Blocks++ + } + attr.Gid = f.r.ids[f.i.GidInd] + attr.Inode = uint64(f.i.Num) + attr.Mode = f.i.Mode() + attr.Nlink = f.i.LinkCount() + attr.Size = f.i.Size() + attr.Uid = f.r.ids[f.i.UidInd] + return nil +} + +func (f fileNode2) Id() uint64 { + return uint64(f.i.Num) +} + +func (f fileNode2) Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error) { + return f.SymlinkPath(), nil +} + +func (f fileNode2) Lookup(ctx context.Context, name string) (fs.Node, error) { + asFS, err := f.FS() + if err != nil { + return nil, fuse.ENOTDIR + } + ret, err := asFS.OpenFile(name) + if err != nil { + return nil, fuse.ENOENT + } + return fileNode2{File: ret}, nil +} + +func (f fileNode2) ReadAll(ctx context.Context) ([]byte, error) { + if f.IsRegular() { + var buf bytes.Buffer + _, err := f.WriteTo(&buf) + return buf.Bytes(), err + } + return nil, fuse.ENODATA +} + +func (f fileNode2) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { + if f.IsRegular() { + buf := make([]byte, req.Size) + n, err := f.File.ReadAt(buf, req.Offset) + if err == io.EOF { + resp.Data = buf[:n] + } + return nil + } + return fuse.ENODATA +} + +func (f fileNode2) ReadDirAll(ctx context.Context) (out []fuse.Dirent, err error) { + asFS, err := f.FS() + if err != nil { + return nil, fuse.ENOTDIR + } + var t fuse.DirentType + for i := range asFS.e { + switch asFS.e[i].Type { + case inode.Fil: + t = fuse.DT_File + case inode.Dir: + t = fuse.DT_Dir + case inode.Block: + t = fuse.DT_Block + case inode.Sym: + t = fuse.DT_Link + case inode.Char: + t = fuse.DT_Char + case inode.Fifo: + t = fuse.DT_FIFO + case inode.Sock: + t = fuse.DT_Socket + default: + t = fuse.DT_Unknown + } + out = append(out, fuse.Dirent{ + Inode: uint64(asFS.e[i].Num), + Type: t, + Name: asFS.e[i].Name, + }) + } + return +} diff --git a/fuse.go b/fuse3.go similarity index 91% rename from fuse.go rename to fuse3.go index 1970679..4b89c50 100644 --- a/fuse.go +++ b/fuse3.go @@ -24,7 +24,7 @@ func (r *Reader) Mount(mountpoint string) (err error) { <-r.con.Ready r.mountDone = make(chan struct{}) go func() { - fs.Serve(r.con, &SquashFuse{r: r}) + fs.Serve(r.con, squashFuse{r: r}) close(r.mountDone) }() return @@ -46,16 +46,11 @@ func (r *Reader) Unmount() error { return errors.New("squashfs archive is not mounted") } -func (r *Reader) SquashFuse() SquashFuse { - return SquashFuse{r: r} -} - -// A wrapper around squash.Reader that implements fuse/fs.FS -type SquashFuse struct { +type squashFuse struct { r *Reader } -func (s SquashFuse) Root() (fs.Node, error) { +func (s squashFuse) Root() (fs.Node, error) { return fileNode{File: s.r.FS.File}, nil } @@ -94,7 +89,7 @@ func (f fileNode) Lookup(ctx context.Context, name string) (fs.Node, error) { if err != nil { return nil, fuse.ENOENT } - return &fileNode{File: ret}, nil + return fileNode{File: ret}, nil } func (f fileNode) ReadAll(ctx context.Context) ([]byte, error) { diff --git a/go.mod b/go.mod index b1ee55b..9289296 100644 --- a/go.mod +++ b/go.mod @@ -11,4 +11,7 @@ require ( github.com/ulikunitz/xz v0.5.10 ) -require golang.org/x/sys v0.2.0 // indirect +require ( + github.com/seaweedfs/fuse v1.2.2 + golang.org/x/sys v0.2.0 // indirect +) diff --git a/go.sum b/go.sum index c29ecaa..d642564 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e h1:dCWirM5F3wMY+cmRda/B1BiPsFtmzXqV9b0hLWtVBMs= github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e/go.mod h1:9leZcVcItj6m9/CfHY5Em/iBrCz7js8LcRQGTKEEv2M= +github.com/seaweedfs/fuse v1.2.2 h1:01l8OjIdyATRNqVc/gDPgFobuC8ubQF3hRKOPColROw= +github.com/seaweedfs/fuse v1.2.2/go.mod h1:iwbDQv5BZACY54r6AO/6xsLNuMaYcBKSkLTZVfmK594= github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY= github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= diff --git a/reader.go b/reader.go index 97ddacc..746cd02 100644 --- a/reader.go +++ b/reader.go @@ -13,12 +13,15 @@ import ( "github.com/CalebQ42/squashfs/internal/inode" "github.com/CalebQ42/squashfs/internal/metadata" "github.com/CalebQ42/squashfs/internal/toreader" + fuse2 "github.com/seaweedfs/fuse" ) type Reader struct { *FS con *fuse.Conn + con2 *fuse2.Conn mountDone chan struct{} + mount2Done chan struct{} d decompress.Decompressor r io.ReaderAt fragEntries []fragEntry