fuse icon indicating copy to clipboard operation
fuse copied to clipboard

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

Open prasad83 opened this issue 1 year ago • 3 comments

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

prasad83 avatar Apr 05 '24 07:04 prasad83

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 avatar Apr 05 '24 08:04 prasad83

go build main.go
sudo ./main

ls /mnt

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

ABC/def is not listed.

prasad83 avatar Apr 05 '24 08:04 prasad83

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 avatar Apr 10 '24 18:04 tv42

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

tv42 avatar May 22 '24 20:05 tv42