mirror of
https://github.com/xiaoqidun/symfs.git
synced 2026-05-12 09:40:58 +08:00
Compare commits
5 Commits
3759059f3f
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 2439762607 | |||
| 93817f7114 | |||
| e174d81262 | |||
| eeff36d167 | |||
| 6612fcca2e |
@@ -25,6 +25,7 @@ type SymFS struct {
|
|||||||
fuse.FileSystemBase
|
fuse.FileSystemBase
|
||||||
root string
|
root string
|
||||||
host *fuse.FileSystemHost
|
host *fuse.FileSystemHost
|
||||||
|
done chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSymFS 创建 SymFS 实例
|
// NewSymFS 创建 SymFS 实例
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -33,6 +34,38 @@ type FileNotifyInformation struct {
|
|||||||
FileName [1]uint16
|
FileName [1]uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// winErrToFuse Windows 错误码到 FUSE POSIX errno 的映射表
|
||||||
|
var winErrToFuse = map[syscall.Errno]int{
|
||||||
|
windows.ERROR_FILE_NOT_FOUND: int(fuse.ENOENT),
|
||||||
|
windows.ERROR_PATH_NOT_FOUND: int(fuse.ENOENT),
|
||||||
|
windows.ERROR_ACCESS_DENIED: int(fuse.EACCES),
|
||||||
|
windows.ERROR_INVALID_HANDLE: int(fuse.EBADF),
|
||||||
|
windows.ERROR_NOT_ENOUGH_MEMORY: int(fuse.ENOMEM),
|
||||||
|
windows.ERROR_OUTOFMEMORY: int(fuse.ENOMEM),
|
||||||
|
windows.ERROR_INVALID_DRIVE: int(fuse.ENOENT),
|
||||||
|
windows.ERROR_NO_MORE_FILES: int(fuse.ENOENT),
|
||||||
|
windows.ERROR_WRITE_PROTECT: int(fuse.EROFS),
|
||||||
|
windows.ERROR_NOT_READY: int(fuse.EIO),
|
||||||
|
windows.ERROR_SHARING_VIOLATION: int(fuse.EBUSY),
|
||||||
|
windows.ERROR_LOCK_VIOLATION: int(fuse.EBUSY),
|
||||||
|
windows.ERROR_HANDLE_EOF: int(fuse.EIO),
|
||||||
|
windows.ERROR_HANDLE_DISK_FULL: int(fuse.ENOSPC),
|
||||||
|
windows.ERROR_NOT_SUPPORTED: int(fuse.ENOSYS),
|
||||||
|
windows.ERROR_INVALID_PARAMETER: int(fuse.EINVAL),
|
||||||
|
windows.ERROR_INSUFFICIENT_BUFFER: int(fuse.EINVAL),
|
||||||
|
windows.ERROR_INVALID_NAME: int(fuse.ENOENT),
|
||||||
|
windows.ERROR_DIR_NOT_EMPTY: int(fuse.ENOTEMPTY),
|
||||||
|
windows.ERROR_ALREADY_EXISTS: int(fuse.EEXIST),
|
||||||
|
windows.ERROR_FILE_EXISTS: int(fuse.EEXIST),
|
||||||
|
windows.ERROR_BROKEN_PIPE: int(fuse.EPIPE),
|
||||||
|
windows.ERROR_DISK_FULL: int(fuse.ENOSPC),
|
||||||
|
windows.ERROR_CALL_NOT_IMPLEMENTED: int(fuse.ENOSYS),
|
||||||
|
windows.ERROR_NEGATIVE_SEEK: int(fuse.EINVAL),
|
||||||
|
windows.ERROR_SEEK_ON_DEVICE: int(fuse.ESPIPE),
|
||||||
|
windows.ERROR_DIRECTORY: int(fuse.ENOTDIR),
|
||||||
|
windows.ERROR_NOT_EMPTY: int(fuse.ENOTEMPTY),
|
||||||
|
}
|
||||||
|
|
||||||
// errno 转换错误码
|
// errno 转换错误码
|
||||||
// 入参: err 错误对象
|
// 入参: err 错误对象
|
||||||
// 返回: int 错误码
|
// 返回: int 错误码
|
||||||
@@ -40,19 +73,24 @@ func errno(err error) int {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if sysErr, ok := err.(syscall.Errno); ok {
|
var sysErr syscall.Errno
|
||||||
return -int(sysErr)
|
if errors.As(err, &sysErr) {
|
||||||
|
if fuseErr, ok := winErrToFuse[sysErr]; ok {
|
||||||
|
return -fuseErr
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return -int(fuse.ENOENT)
|
return -int(fuse.EIO)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init 初始化文件系统
|
// Init 初始化文件系统
|
||||||
func (s *SymFS) Init() {
|
func (s *SymFS) Init() {
|
||||||
|
s.done = make(chan struct{})
|
||||||
go s.watch()
|
go s.watch()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy 销毁文件系统
|
// Destroy 销毁文件系统
|
||||||
func (s *SymFS) Destroy() {
|
func (s *SymFS) Destroy() {
|
||||||
|
close(s.done)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statfs 获取文件系统统计信息
|
// Statfs 获取文件系统统计信息
|
||||||
@@ -253,7 +291,13 @@ func (s *SymFS) Write(path string, buff []byte, ofst int64, fh uint64) int {
|
|||||||
// 入参: path 路径, fh 文件句柄
|
// 入参: path 路径, fh 文件句柄
|
||||||
// 返回: int 错误码
|
// 返回: int 错误码
|
||||||
func (s *SymFS) Flush(path string, fh uint64) int {
|
func (s *SymFS) Flush(path string, fh uint64) int {
|
||||||
syscall.FlushFileBuffers(syscall.Handle(fh))
|
err := syscall.FlushFileBuffers(syscall.Handle(fh))
|
||||||
|
if err != nil {
|
||||||
|
if sysErr, ok := err.(syscall.Errno); ok && sysErr == syscall.ERROR_ACCESS_DENIED {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return errno(err)
|
||||||
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,7 +450,7 @@ func (s *SymFS) open(path string, flags int, mode uint32) (int, uint64) {
|
|||||||
return errno(err), ^uint64(0)
|
return errno(err), ^uint64(0)
|
||||||
}
|
}
|
||||||
if needTruncate {
|
if needTruncate {
|
||||||
err := windows.SetEndOfFile(h)
|
err = windows.SetEndOfFile(h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
windows.CloseHandle(h)
|
windows.CloseHandle(h)
|
||||||
h, err = windows.CreateFile(pathPtr, access, shareMode, nil, windows.TRUNCATE_EXISTING, attrs, 0)
|
h, err = windows.CreateFile(pathPtr, access, shareMode, nil, windows.TRUNCATE_EXISTING, attrs, 0)
|
||||||
@@ -430,16 +474,27 @@ func (s *SymFS) watch() {
|
|||||||
windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE,
|
windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE,
|
||||||
nil,
|
nil,
|
||||||
windows.OPEN_EXISTING,
|
windows.OPEN_EXISTING,
|
||||||
windows.FILE_FLAG_BACKUP_SEMANTICS,
|
windows.FILE_FLAG_BACKUP_SEMANTICS|windows.FILE_FLAG_OVERLAPPED,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer windows.CloseHandle(h)
|
defer windows.CloseHandle(h)
|
||||||
|
event, err := windows.CreateEvent(nil, 0, 0, nil)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer windows.CloseHandle(event)
|
||||||
buf := make([]byte, 16384)
|
buf := make([]byte, 16384)
|
||||||
for {
|
for {
|
||||||
var bytesReturned uint32
|
select {
|
||||||
|
case <-s.done:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
var overlapped windows.Overlapped
|
||||||
|
overlapped.HEvent = event
|
||||||
err = windows.ReadDirectoryChanges(
|
err = windows.ReadDirectoryChanges(
|
||||||
h,
|
h,
|
||||||
&buf[0],
|
&buf[0],
|
||||||
@@ -452,16 +507,40 @@ func (s *SymFS) watch() {
|
|||||||
windows.FILE_NOTIFY_CHANGE_LAST_WRITE|
|
windows.FILE_NOTIFY_CHANGE_LAST_WRITE|
|
||||||
windows.FILE_NOTIFY_CHANGE_CREATION|
|
windows.FILE_NOTIFY_CHANGE_CREATION|
|
||||||
windows.FILE_NOTIFY_CHANGE_SECURITY,
|
windows.FILE_NOTIFY_CHANGE_SECURITY,
|
||||||
&bytesReturned,
|
|
||||||
nil,
|
nil,
|
||||||
|
(*windows.Overlapped)(unsafe.Pointer(&overlapped)),
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
|
if err != nil && err != windows.ERROR_IO_PENDING {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
result, _ := windows.WaitForSingleObject(event, 100)
|
||||||
|
if result == uint32(windows.WAIT_OBJECT_0) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-s.done:
|
||||||
|
windows.CancelIo(h)
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var bytesReturned uint32
|
||||||
|
err = windows.GetOverlappedResult(h, (*windows.Overlapped)(unsafe.Pointer(&overlapped)), &bytesReturned, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
headerSize := uint32(unsafe.Offsetof(FileNotifyInformation{}.FileName))
|
||||||
var offset uint32
|
var offset uint32
|
||||||
for {
|
for {
|
||||||
|
if offset+headerSize > bytesReturned {
|
||||||
|
break
|
||||||
|
}
|
||||||
info := (*FileNotifyInformation)(unsafe.Pointer(&buf[offset]))
|
info := (*FileNotifyInformation)(unsafe.Pointer(&buf[offset]))
|
||||||
|
if offset+headerSize+info.FileNameLength > bytesReturned {
|
||||||
|
break
|
||||||
|
}
|
||||||
length := info.FileNameLength / 2
|
length := info.FileNameLength / 2
|
||||||
nameSlice := (*[1 << 16]uint16)(unsafe.Pointer(&info.FileName[0]))[:length:length]
|
nameSlice := (*[1 << 16]uint16)(unsafe.Pointer(&info.FileName[0]))[:length:length]
|
||||||
fileName := syscall.UTF16ToString(nameSlice)
|
fileName := syscall.UTF16ToString(nameSlice)
|
||||||
|
|||||||
Reference in New Issue
Block a user