winfsp / cgofuse

Cross-platform FUSE library for Go - Works on Windows, macOS, Linux, FreeBSD, NetBSD, OpenBSD

Home Page:https://winfsp.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Failing to mount: The service has failed to start (Status=c0000034)

marius-enlock opened this issue · comments

Hello,

On Windows 10 amd64, and winfsp installed from winfsp-2.0.23075.msi with development and fuse mode installed.
go version go1.22.2 windows/amd64

I have managed to run the examples folder (memfs) using cgo - it works as expected.

But when I launch my program in go I get the following error on mount (the only error message besides false returned from the mount call):

The service has failed to start (Status=c0000034).

I have checked the code and it corresponds to: STATUS_OBJECT_NAME_NOT_FOUND

The return value from mount is false.

My program is usable, but the filesystem is not mounted, as opposed to when I launch it via the memfs example.

I have tried the following flags

d.pathToMount = "Z:"
r:= &DirNode{}
d.winFSfileSystemHost.Mount = winfuse.NewFileSystemHost(r)
d.winFSfileSystemHost.SetCapReaddirPlus(true)
ok:= d.winFSfileSystemHost.Mount(d.pathToMount, []string{"-D -", "-d -1", "-i"})

&DirNode{} on linux get's mounted with bazil.org/fuse and works as expected.

&DirNode{} on windows implements most of the interfaces in cgofuse and gets mounted via winfsp.

The CC/CXX for go are the following:

Test 1:
/c/Strawberry/c/bin/(gcc|g++)

Test 2:
C:\ProgramData\mingw64\mingw64\bin\(gcc|g++)

Other details that might be relevant:
I launch the program that attempts the mount as a sub process that uses the stdin/stdout for grpc communication, which might interfere with winfsp (if winfsp requires stdin/stdout for communication).
For example:

in,out:=io.Pipe()
in2,out2:=io.Pipe()
cmd:= exec.Command("myProgramThatAttemptsTheMount.exe")
cmd.Stdin:= in
cmd.Stdout :=out2
cmd.Start()
// Handle the grpc setup using the out/in2 ends of the pipe

I am a bit stuck and do not know where to look for further clues that explains why the mount fails, any input is appreciated.

My implementations of init, statfs, getattr:

func (d *DirNode) Init() {
}

func (d *DirNode) Statfs(path string, stat *winfuse.Statfs_t) int {
	var freeBytesAvailable uint64
	var totalNumberOfBytes uint64
	var totalNumberOfFreeBytes uint64
	err := win.GetDiskFreeSpaceEx(win.StringToUTF16Ptr(d.rootCipherTextPath),
		&freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes)
	if err != nil {
		fmt.Println("Failed to get disk free space", "error", err)
		return -1
	}
	stat.Bavail = freeBytesAvailable / FileBlockSize
	stat.Bfree = totalNumberOfFreeBytes / FileBlockSize
	stat.Blocks = totalNumberOfBytes / FileBlockSize
	stat.Bsize = FileBlockSize
	stat.Frsize = FileBlockSize
        stat.Namemax = uint64(128) // We allow only 128 characters in the name.

	return 0
}
func (d *DirNode) Getattr(path string, stat *winfuse.Stat_t, fh uint64) int {
        /* .... */
        // mode = uint32(os.ModeDir | 0o750) if Dir
        // mode = uint32(0o700) if File
	fi, err := os.Stat(statPath)
	if err != nil {
		fmt.Println("Failed to stat file", "error", err)
		return int(convertOsErrToSyscallErrno(err))
	}

	finfo, ok := fi.Sys().(*syscall.Win32FileAttributeData)
	if !ok {
		fmt.Println("Failed to cast datastructure")
		return -1
	}
	stat.Atim = winfuse.Timespec{Nsec: finfo.LastAccessTime.Nanoseconds()}
	stat.Birthtim = winfuse.Timespec{Nsec: finfo.CreationTime.Nanoseconds()}
	stat.Ino = cipher.fileNode.nodeID
	stat.Mtim = winfuse.Timespec{Nsec: finfo.LastWriteTime.Nanoseconds()}
	stat.Size = cipherFileSizeToAttributeSize(fi.Size())
	stat.Mode = mode //fi.Mode
}

I figured it out,

The response code corresponds to ENOENT, which is thrown by the commented-out code not shown in my example of Getattr.

I got confused between the UNIX error codes and the windows ones.