-
Notifications
You must be signed in to change notification settings - Fork 3
/
mountfs_disk.go
111 lines (98 loc) · 3.22 KB
/
mountfs_disk.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package dkango
import (
"errors"
"io/fs"
"os"
"path/filepath"
"strings"
"github.com/binzume/dkango/dokan"
)
type disk struct {
opt *MountOptions
fsys fs.FS
}
func (d *disk) GetVolumeInformation(finfo *dokan.FileInfo) (dokan.VolumeInformation, dokan.NTStatus) {
return d.opt.VolumeInfo, dokan.STATUS_SUCCESS
}
func (d *disk) GetDiskFreeSpace(availableBytes *uint64, totalBytes *uint64, freeBytes *uint64, finfo *dokan.FileInfo) dokan.NTStatus {
if (d.opt.DiskSpaceFunc) != nil {
space := d.opt.DiskSpaceFunc()
*availableBytes = space.FreeBytesAvailable
*totalBytes = space.TotalNumberOfBytes
*freeBytes = space.TotalNumberOfFreeBytes
return dokan.STATUS_SUCCESS
}
return dokan.STATUS_NOT_SUPPORTED
}
func (mi *disk) CreateFile(name string, secCtx uintptr, access, attrs, share, disposition, options uint32, finfo *dokan.FileInfo) (dokan.FileHandle, dokan.NTStatus) {
name = strings.TrimPrefix(filepath.ToSlash(name), "/")
if name == "" {
name = "."
}
create := disposition == dokan.FILE_CREATE || disposition == dokan.FILE_OPEN_IF || disposition == dokan.FILE_OVERWRITE_IF || disposition == dokan.FILE_SUPERSEDE
truncate := disposition == dokan.FILE_SUPERSEDE || disposition == dokan.FILE_OVERWRITE || disposition == dokan.FILE_OVERWRITE_IF
errIfExist := disposition == dokan.FILE_CREATE
openFlag := 0
if access&dokan.FILE_WRITE_DATA != 0 && access&dokan.FILE_READ_DATA != 0 {
openFlag = os.O_RDWR
} else if access&dokan.FILE_READ_DATA != 0 {
openFlag = os.O_RDONLY
} else if access&dokan.FILE_WRITE_DATA != 0 {
openFlag = os.O_WRONLY
} else if access&dokan.FILE_APPEND_DATA != 0 {
openFlag = os.O_WRONLY | os.O_APPEND
}
if openFlag == os.O_RDWR || openFlag == os.O_WRONLY {
if create {
openFlag |= os.O_CREATE
}
if truncate {
openFlag |= os.O_TRUNC
}
if errIfExist {
openFlag |= os.O_EXCL
}
}
stat, err := fs.Stat(mi.fsys, name)
if err != nil && !(create && errors.Is(err, fs.ErrNotExist)) {
return nil, dokan.ErrorToNTStatus(err) // Unexpected error
}
if err == nil && disposition == dokan.FILE_CREATE {
return nil, dokan.STATUS_OBJECT_NAME_COLLISION
}
if err == nil && stat.IsDir() && options&dokan.FILE_NON_DIRECTORY_FILE != 0 {
return nil, dokan.STATUS_FILE_IS_A_DIRECTORY
}
if err == nil && !stat.IsDir() && options&dokan.FILE_DIRECTORY_FILE != 0 {
return nil, dokan.STATUS_NOT_A_DIRECTORY
}
f := &openedFile{name: name, mi: mi, cachedStat: stat, openFlag: openFlag}
// Mkdir
if create && options&dokan.FILE_DIRECTORY_FILE != 0 {
if fsys, ok := mi.fsys.(MkdirFS); ok {
err = fsys.Mkdir(name, fs.ModePerm)
if err != nil {
return nil, dokan.ErrorToNTStatus(err)
}
} else {
return nil, dokan.STATUS_NOT_SUPPORTED
}
}
// NOTE: Reader is not opened here because sometimes it may only need GetFileInformantion()
if openFlag != os.O_RDONLY && options&dokan.FILE_DIRECTORY_FILE == 0 {
fsys, ok := f.mi.fsys.(OpenWriterFS)
if !ok {
// Readonly FS. TODO: Consider to return STATUS_NOT_SUPPORTED?
return nil, dokan.STATUS_ACCESS_DENIED
}
if truncate {
f.cachedStat = nil // file size will be cahnged
}
w, err := fsys.OpenWriter(name, openFlag)
if err != nil {
return nil, dokan.ErrorToNTStatus(err)
}
f.file = w
}
return f, dokan.STATUS_SUCCESS
}