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.