Signed-off-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
117 lines
3.1 KiB
Go
117 lines
3.1 KiB
Go
//go:build windows && (amd64 || 386 || arm64)
|
|
|
|
package overlayfs
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"syscall"
|
|
"unsafe"
|
|
|
|
"github.com/aegistudio/go-winfsp"
|
|
"github.com/aegistudio/go-winfsp/gofs"
|
|
)
|
|
|
|
// Check if winfsp is available on the system
|
|
func OverlayfsAvaible() bool {
|
|
var dllName string
|
|
switch runtime.GOARCH {
|
|
case "386":
|
|
dllName = "winfsp-x86.dll"
|
|
case "amd64":
|
|
dllName = "winfsp-x64.dll"
|
|
case "arm64":
|
|
dllName = "winfsp-a64.dll"
|
|
default:
|
|
return false
|
|
}
|
|
|
|
dll, _ := syscall.LoadDLL(dllName)
|
|
if dll != nil {
|
|
_ = dll.Release()
|
|
return true
|
|
}
|
|
|
|
var keyReg syscall.Handle // HKLM\\Software\\WinFSP
|
|
keyName, err := syscall.UTF16PtrFromString("Software\\WinFsp")
|
|
if err != nil {
|
|
return false
|
|
} else if err := syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE, keyName, 0, syscall.KEY_READ|syscall.KEY_WOW64_32KEY, &keyReg); err != nil {
|
|
return false
|
|
}
|
|
defer syscall.RegCloseKey(keyReg)
|
|
valueName, err := syscall.UTF16PtrFromString("InstallDir")
|
|
if err != nil {
|
|
return false
|
|
}
|
|
var pathBuf [syscall.MAX_PATH]uint16
|
|
var valueType, valueSize uint32
|
|
valueSize = uint32(len(pathBuf)) * 2
|
|
if err := syscall.RegQueryValueEx(keyReg, valueName, nil, &valueType, (*byte)(unsafe.Pointer(&pathBuf)), &valueSize); err != nil {
|
|
return false
|
|
} else if valueType != syscall.REG_SZ {
|
|
return false
|
|
}
|
|
path := pathBuf[:int(valueSize/2)]
|
|
if len(path) > 0 && path[len(path)-1] == 0 {
|
|
path = path[:len(path)-1]
|
|
}
|
|
installPath := syscall.UTF16ToString(path)
|
|
|
|
// Attempt to load the DLL that we have found.
|
|
dll, err = syscall.LoadDLL(filepath.Join(installPath, "bin", dllName))
|
|
if err != nil {
|
|
return false
|
|
}
|
|
_ = dll.Release()
|
|
return true
|
|
}
|
|
|
|
type winfspMerge struct{ *Overlayfs }
|
|
|
|
func (winfsp winfspMerge) OpenFile(name string, flag int, perm os.FileMode) (gofs.File, error) {
|
|
return winfsp.Overlayfs.OpenFile(name, flag, perm)
|
|
}
|
|
|
|
func (fsp *Overlayfs) getWinfsp() (*winfsp.FileSystem, error) {
|
|
if fssp, ok := fsp.ProcessInternal.(*winfsp.FileSystem); ok {
|
|
return fssp, nil
|
|
}
|
|
return nil, ErrUnmounted
|
|
}
|
|
|
|
// Mount go-mergefs with winfsp
|
|
//
|
|
// This function supports drive letters (X:) or directories as mount points:
|
|
//
|
|
// - Drive letters: Refer to the documentation of the DefineDosDevice Windows API to better understand how they are created.
|
|
//
|
|
// - Directories: They can be used as mount points for disk based file systems. They cannot be used for network file systems. This is a limitation that Windows imposes on junctions.
|
|
func (overlay *Overlayfs) Mount() error {
|
|
_, err := overlay.getWinfsp()
|
|
if err != nil && err != ErrUnmounted {
|
|
return err
|
|
}
|
|
|
|
// Clean folder path to mount
|
|
if !filepath.IsAbs(overlay.Target) {
|
|
if overlay.Target, err = filepath.Abs(overlay.Target); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
overlay.ProcessInternal, err = winfsp.Mount(gofs.New(&winfspMerge{Overlayfs: overlay}), overlay.Target, winfsp.FileSystemName("go-mergefs"))
|
|
return err
|
|
}
|
|
|
|
// Umount winfsp filesystem if mounted
|
|
func (overlay *Overlayfs) Unmount() error {
|
|
fssp, err := overlay.getWinfsp()
|
|
if err == nil && fssp != nil {
|
|
fssp.Unmount()
|
|
overlay.ProcessInternal = nil
|
|
}
|
|
return nil
|
|
}
|