bazil / fuse

FUSE library for Go.  go get bazil.org/fuse  
http://bazil.org/fuse
Other
1.6k stars 266 forks source link

Directory entries having "/" character - input/output error. #304

Closed prasad83 closed 4 months ago

prasad83 commented 6 months ago

When Directory has filename with "/" - results of ls randomly shows input/output error.

prasad83 commented 6 months ago

main.go

package main

import (
    "context"
    "fmt"
    "os"
    "os/exec"
    "os/signal"
    "syscall"
    "time"

    "bazil.org/fuse"
    "bazil.org/fuse/fs"
)

type EntryGetter interface {
    GetDirentType() fuse.DirentType
}

type myFS struct {
}

func (mfs *myFS) Root() (fs.Node, error) {
    return newDir()
}

type myNode struct {
    Type  fuse.DirentType
    Attrs fuse.Attr
}

func (n *myNode) GetDirentType() fuse.DirentType {
    return n.Type
}

func (n *myNode) Attr(ctx context.Context, a *fuse.Attr) error {
    *a = n.Attrs
    return nil
}

type myDir struct {
    myNode
    Entries map[string]interface{}
}

func (d *myDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
    if node, ok := d.Entries[name]; ok {
        return node.(fs.Node), nil
    }
    return nil, syscall.ENOENT
}

func (d *myDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
    var entries []fuse.Dirent
    for k, v := range d.Entries {
        var a fuse.Attr
        v.(fs.Node).Attr(ctx, &a)
        entries = append(entries, fuse.Dirent{
            Name:  k,
            Inode: a.Inode,
            Type:  v.(EntryGetter).GetDirentType(),
        })
    }

    return entries, nil
}

type myFile struct {
    myNode
    content []byte
}

func (f *myFile) ReadAll(ctx context.Context) ([]byte, error) {
    return f.content, nil
}

func newFS() fs.FS {
    return &myFS{}
}

func newDir() (fs.Node, error) {
    filenames := []string{
        "ABC",
        "ABC/def",
    }

    dir := &myDir{
        myNode: myNode{
            Type: fuse.DT_Dir,
            Attrs: fuse.Attr{
                Inode: 1,
                Atime: time.Now(),
                Mtime: time.Now(),
                Ctime: time.Now(),
                Mode:  os.ModeDir | 0o777,
            },
        },
        Entries: make(map[string]interface{}),
    }

    for findex, fname := range filenames {
                fcontent := []byte(fname)
        dir.Entries[fname] = &myFile{
            myNode: myNode{
                Type: fuse.DT_File,
                Attrs: fuse.Attr{
                    Inode: uint64(findex + 1),
                    Mode:  0o644,
                                        Size: uint64(len(fcontent)),
                    Atime: time.Now(),
                    Mtime: time.Now(),
                    Ctime: time.Now(),
                },
            },
            content: fcontent,
        }
    }

    return dir, nil
}

func main() {
    mountpoint := "/mnt"

    c, err := fuse.Mount(mountpoint, fuse.FSName("myfs"), fuse.Subtype("myfs"))
    if err != nil {
        panic(err)
    }
    defer c.Close()

    sigc := make(chan os.Signal, 1)
    signal.Notify(sigc, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
    go func() {
        switch <-sigc {
        case syscall.SIGHUP:
            println("signal: hangup")
        case syscall.SIGINT:
            println("signal: interrupt")
        case syscall.SIGTERM:
            println("signal: terminate")
        case syscall.SIGQUIT:
            println("signal: quit")
        }

        // unmount safely
        if err := exec.Command("fusermount3", "-u", mountpoint).Run(); err != nil {
            println("error: could not unmount, use [sudo fusermount -u " + mountpoint + "]")
        }
        os.Exit(0)
    }()

    fmt.Println("filesystem mounted at " + mountpoint + ", use CRTL+C to stop")
    server := fs.New(c, &fs.Config{
        Debug: func(msg interface{}) {
            fmt.Printf("[DEBUG] %v\n", msg)
        },
    })

    if err := server.Serve(newFS()); err != nil {
        panic(err)
    }
}
prasad83 commented 6 months ago
go build main.go
sudo ./main

ls /mnt

ls: reading directory '/mnt': Input/output error
ABC

ABC/def is not listed.

tv42 commented 5 months ago

Linux/UNIX directory entry names cannot contain slashes. I do not expect the IO errors to be "random", at all, but very consistent.

What are you trying to do here?

tv42 commented 4 months ago

This seems to be a misunderstanding of UNIX filesystems, with nothing actionable here.