github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/dokan/filesystem.go (about) 1 // Copyright 2016 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package dokan 6 7 import ( 8 "context" 9 "strconv" 10 "time" 11 12 "github.com/keybase/client/go/kbfs/dokan/winacl" 13 ) 14 15 // Config is the configuration used for a mount. 16 type Config struct { 17 // Path is the path to mount, e.g. `L:`. Must be set. 18 Path string 19 // FileSystem is the filesystem implementation. Must be set. 20 FileSystem FileSystem 21 // MountFlags for this filesystem instance. Is optional. 22 MountFlags MountFlag 23 // DllPath is the optional full path to dokan1.dll. 24 // Empty causes dokan1.dll to be loaded from the system directory. 25 // Only the first load of a dll determines the path - 26 // further instances in the same process will use 27 // the same instance regardless of path. 28 DllPath string 29 } 30 31 // FileSystem is the inteface for filesystems in Dokan. 32 type FileSystem interface { 33 // WithContext returns a context for a new request. If the CancelFunc 34 // is not null, it is called after the request is done. The most minimal 35 // implementation is 36 // `func (*T)WithContext(c context.Context) { return c, nil }`. 37 WithContext(context.Context) (context.Context, context.CancelFunc) 38 39 // CreateFile is called to open and create files. 40 CreateFile(ctx context.Context, fi *FileInfo, data *CreateData) (file File, status CreateStatus, err error) 41 42 // GetDiskFreeSpace returns information about disk free space. 43 // Called quite often by Explorer. 44 GetDiskFreeSpace(ctx context.Context) (FreeSpace, error) 45 46 // GetVolumeInformation returns information about the volume. 47 GetVolumeInformation(ctx context.Context) (VolumeInformation, error) 48 49 // MoveFile corresponds to rename. 50 MoveFile(ctx context.Context, sourceHandle File, sourceFileInfo *FileInfo, targetPath string, replaceExisting bool) error 51 52 // ErrorPrint is called when dokan needs notify the program of an error message. 53 // A sensible approach is to print the error. 54 ErrorPrint(error) 55 56 // Printf is for information level messages. 57 Printf(format string, v ...interface{}) 58 } 59 60 // CreateStatus marks status of successfull create/open operations. 61 type CreateStatus uint32 62 63 const ( 64 // 1 Bit 0 == always set for valid values, 65 // 2 Bit 1 == directory or not 66 // 4 Bit 2 == new or not 67 isValid = 1 68 isDir = 2 69 isNew = 4 70 71 // NewDir for newly created directories. 72 NewDir = CreateStatus(isNew | isDir | isValid) 73 // NewFile for newly created files. 74 NewFile = CreateStatus(isNew | isValid) 75 // ExistingDir for newly created directories. 76 ExistingDir = CreateStatus(isDir | isValid) 77 // ExistingFile for newly created files. 78 ExistingFile = CreateStatus(isValid) 79 ) 80 81 // IsDir tells whether a CreateStatus is about a directory or a file. 82 func (cst CreateStatus) IsDir() bool { 83 return (cst & 2) != 0 84 } 85 86 // IsNew tells whether a CreateStatus is about a new or existing object. 87 func (cst CreateStatus) IsNew() bool { 88 return (cst & 4) != 0 89 } 90 91 // MountFlag is the type for Dokan mount flags. 92 type MountFlag uint32 93 94 // Flags for mounting the filesystem. See Dokan documentation for these. 95 const ( 96 CDebug = kbfsLibdokanDebug 97 CStderr = kbfsLibdokanStderr 98 Removable = kbfsLibdokanRemovable 99 MountManager = kbfsLibdokanMountManager 100 CurrentSession = kbfsLibdokanCurrentSession 101 // UseFindFilesWithPattern enables FindFiles calls to be with a search 102 // pattern string. Otherwise the string will be empty in all calls. 103 UseFindFilesWithPattern = kbfsLibdokanUseFindFilesWithPattern 104 ) 105 106 // CreateData contains all the info needed to create a file. 107 type CreateData struct { 108 DesiredAccess uint32 109 FileAttributes FileAttribute 110 ShareAccess uint32 111 CreateDisposition CreateDisposition 112 CreateOptions uint32 113 } 114 115 // ReturningFileAllowed answers whether returning a file is allowed by 116 // CreateOptions. 117 func (cd *CreateData) ReturningFileAllowed() error { 118 if cd.CreateOptions&FileDirectoryFile != 0 { 119 return ErrNotADirectory 120 } 121 return nil 122 } 123 124 // ReturningDirAllowed answers whether returning a directory is allowed by 125 // CreateOptions. 126 func (cd *CreateData) ReturningDirAllowed() error { 127 if cd.CreateOptions&FileNonDirectoryFile != 0 { 128 return ErrFileIsADirectory 129 } 130 return nil 131 } 132 133 // CreateDisposition marks whether to create or open a file. Not a bitmask. 134 type CreateDisposition uint32 135 136 // File creation flags for CreateFile. This is not a bitmask. 137 const ( 138 FileSupersede = CreateDisposition(0) 139 FileOpen = CreateDisposition(1) 140 FileCreate = CreateDisposition(2) 141 FileOpenIf = CreateDisposition(3) 142 FileOverwrite = CreateDisposition(4) 143 FileOverwriteIf = CreateDisposition(5) 144 ) 145 146 // CreateOptions flags. These are bitmask flags. 147 const ( 148 FileDirectoryFile = 0x1 149 FileNonDirectoryFile = 0x40 150 FileOpenReparsePoint = 0x00200000 151 ) 152 153 // FileAttribute is the type of a directory entry in Stat. 154 type FileAttribute uint32 155 156 // File attribute bit masks - same as syscall but provided for all platforms. 157 const ( 158 FileAttributeReadonly = FileAttribute(0x00000001) 159 FileAttributeHidden = FileAttribute(0x00000002) 160 FileAttributeSystem = FileAttribute(0x00000004) 161 FileAttributeDirectory = FileAttribute(0x00000010) 162 FileAttributeArchive = FileAttribute(0x00000020) 163 FileAttributeNormal = FileAttribute(0x00000080) 164 FileAttributeReparsePoint = FileAttribute(0x00000400) 165 IOReparseTagSymlink = 0xA000000C 166 ) 167 168 // File is the interface for files and directories. 169 type File interface { 170 // ReadFile implements read for dokan. 171 ReadFile(ctx context.Context, fi *FileInfo, bs []byte, offset int64) (int, error) 172 // WriteFile implements write for dokan. 173 WriteFile(ctx context.Context, fi *FileInfo, bs []byte, offset int64) (int, error) 174 // FlushFileBuffers corresponds to fsync. 175 FlushFileBuffers(ctx context.Context, fi *FileInfo) error 176 177 // GetFileInformation - corresponds to stat. 178 GetFileInformation(ctx context.Context, fi *FileInfo) (*Stat, error) 179 180 // FindFiles is the readdir. The function is a callback that should be called 181 // with each file. The same NamedStat may be reused for subsequent calls. 182 // 183 // Pattern will be an empty string unless UseFindFilesWithPattern is enabled - then 184 // it may be a pattern like `*.png` to match. All implementations must be prepared 185 // to handle empty strings as patterns. 186 FindFiles(ctx context.Context, fi *FileInfo, pattern string, fillStatCallback func(*NamedStat) error) error 187 188 // SetFileTime sets the file time. Test times with .IsZero 189 // whether they should be set. 190 SetFileTime(ctx context.Context, fi *FileInfo, creation time.Time, lastAccess time.Time, lastWrite time.Time) error 191 // SetFileAttributes is for setting file attributes. 192 SetFileAttributes(ctx context.Context, fi *FileInfo, fileAttributes FileAttribute) error 193 194 // SetEndOfFile truncates the file. May be used to extend a file with zeros. 195 SetEndOfFile(ctx context.Context, fi *FileInfo, length int64) error 196 // SetAllocationSize see FILE_ALLOCATION_INFORMATION on MSDN. 197 // For simple semantics if length > filesize then ignore else truncate(length). 198 SetAllocationSize(ctx context.Context, fi *FileInfo, length int64) error 199 200 LockFile(ctx context.Context, fi *FileInfo, offset int64, length int64) error 201 UnlockFile(ctx context.Context, fi *FileInfo, offset int64, length int64) error 202 203 GetFileSecurity(ctx context.Context, fi *FileInfo, si winacl.SecurityInformation, sd *winacl.SecurityDescriptor) error 204 SetFileSecurity(ctx context.Context, fi *FileInfo, si winacl.SecurityInformation, sd *winacl.SecurityDescriptor) error 205 206 // CanDeleteFile and CanDeleteDirectory should check whether the file/directory 207 // can be deleted. The actual deletion should be done by checking 208 // FileInfo.IsDeleteOnClose in Cleanup. 209 CanDeleteFile(ctx context.Context, fi *FileInfo) error 210 CanDeleteDirectory(ctx context.Context, fi *FileInfo) error 211 // Cleanup is called after the last handle from userspace is closed. 212 // Cleanup must perform actual deletions marked from CanDelete* 213 // by checking FileInfo.IsDeleteOnClose if the filesystem supports 214 // deletions. 215 Cleanup(ctx context.Context, fi *FileInfo) 216 // CloseFile is called when closing a handle to the file. 217 CloseFile(ctx context.Context, fi *FileInfo) 218 } 219 220 // FreeSpace - semantics as with WINAPI GetDiskFreeSpaceEx 221 type FreeSpace struct { 222 FreeBytesAvailable, TotalNumberOfBytes, TotalNumberOfFreeBytes uint64 223 } 224 225 // VolumeInformation - see WINAPI GetVolumeInformation for hints 226 type VolumeInformation struct { 227 VolumeName string 228 VolumeSerialNumber uint32 229 MaximumComponentLength uint32 230 FileSystemFlags FileSystemFlags 231 FileSystemName string 232 } 233 234 // FileSystemFlags holds flags for filesystem features. 235 type FileSystemFlags uint32 236 237 // Various FileSystemFlags constants, see winapi documentation for details. 238 const ( 239 FileCasePreservedNames = FileSystemFlags(0x2) 240 FileCaseSensitiveSearch = FileSystemFlags(0x1) 241 FileFileCompression = FileSystemFlags(0x10) 242 FileNamedStreams = FileSystemFlags(0x40000) 243 FilePersistentAcls = FileSystemFlags(0x8) 244 FileReadOnlyVolume = FileSystemFlags(0x80000) 245 FileSequentalWriteOnce = FileSystemFlags(0x100000) 246 FileSupportsEncryption = FileSystemFlags(0x20000) 247 FileSupportsExtendedAttributes = FileSystemFlags(0x800000) 248 FileSupportsHardLinks = FileSystemFlags(0x400000) 249 FileSupportObjectIDs = FileSystemFlags(0x10000) 250 FileSupportsOpenByFileID = FileSystemFlags(0x1000000) 251 FileSupportsRemoteStorage = FileSystemFlags(0x100) 252 FileSupportsReparsePoints = FileSystemFlags(0x80) 253 FileSupportsSparseFiles = FileSystemFlags(0x40) 254 FileSupportsTransactions = FileSystemFlags(0x200000) 255 FileSupportsUsnJournal = FileSystemFlags(0x2000000) 256 FileUnicodeOnDisk = FileSystemFlags(0x4) 257 FileVolumeIsCompressed = FileSystemFlags(0x8000) 258 FileVolumeQuotas = FileSystemFlags(0x20) 259 ) 260 261 // Stat is for GetFileInformation and friends. 262 type Stat struct { 263 // Timestamps for the file 264 Creation, LastAccess, LastWrite time.Time 265 // FileSize is the size of the file in bytes 266 FileSize int64 267 // FileIndex is a 64 bit (nearly) unique ID of the file 268 FileIndex uint64 269 // FileAttributes bitmask holds the file attributes. 270 FileAttributes FileAttribute 271 // VolumeSerialNumber is the serial number of the volume (0 is fine) 272 VolumeSerialNumber uint32 273 // NumberOfLinks can be omitted, if zero set to 1. 274 NumberOfLinks uint32 275 // ReparsePointTag is for WIN32_FIND_DATA dwReserved0 for reparse point tags, typically it can be omitted. 276 ReparsePointTag uint32 277 } 278 279 // NamedStat is used to for stat responses that require file names. 280 // If the name is longer than a DOS-name, insert the corresponding 281 // DOS-name to ShortName. 282 type NamedStat struct { 283 Name string 284 ShortName string 285 Stat 286 } 287 288 // NtStatus is a type implementing error interface that corresponds 289 // to NTSTATUS. It can be used to set the exact error/status code 290 // from the filesystem. 291 type NtStatus uint32 292 293 func (n NtStatus) Error() string { 294 return "NTSTATUS=" + strconv.FormatUint(uint64(n), 16) 295 } 296 297 const ( 298 // ErrAccessDenied - access denied (EPERM) 299 ErrAccessDenied = NtStatus(0xC0000022) 300 // ErrObjectNameNotFound - filename does not exist (ENOENT) 301 ErrObjectNameNotFound = NtStatus(0xC0000034) 302 // ErrObjectNameCollision - a pathname already exists (EEXIST) 303 ErrObjectNameCollision = NtStatus(0xC0000035) 304 // ErrObjectPathNotFound - a pathname does not exist (ENOENT) 305 ErrObjectPathNotFound = NtStatus(0xC000003A) 306 // ErrNotSupported - not supported. 307 ErrNotSupported = NtStatus(0xC00000BB) 308 // ErrFileIsADirectory - file is a directory. 309 ErrFileIsADirectory = NtStatus(0xC00000BA) 310 // ErrDirectoryNotEmpty - wanted an empty dir - it is not empty. 311 ErrDirectoryNotEmpty = NtStatus(0xC0000101) 312 // ErrNotADirectory - wanted a directory - it is not a directory. 313 ErrNotADirectory = NtStatus(0xC0000103) 314 // ErrFileAlreadyExists - file already exists - fatal. 315 ErrFileAlreadyExists = NtStatus(0xC0000035) 316 // ErrNotSameDevice - MoveFile is denied, please use copy+delete. 317 ErrNotSameDevice = NtStatus(0xC00000D4) 318 // StatusBufferOverflow - buffer space too short for return value. 319 StatusBufferOverflow = NtStatus(0x80000005) 320 // StatusObjectNameExists - already exists, may be non-fatal... 321 StatusObjectNameExists = NtStatus(0x40000000) 322 )