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 5package dokan 6 7import ( 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. 16type 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. 32type 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. 61type CreateStatus uint32 62 63const ( 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. 82func (cst CreateStatus) IsDir() bool { 83 return (cst & 2) != 0 84} 85 86// IsNew tells whether a CreateStatus is about a new or existing object. 87func (cst CreateStatus) IsNew() bool { 88 return (cst & 4) != 0 89} 90 91// MountFlag is the type for Dokan mount flags. 92type MountFlag uint32 93 94// Flags for mounting the filesystem. See Dokan documentation for these. 95const ( 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. 107type 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. 117func (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. 126func (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. 134type CreateDisposition uint32 135 136// File creation flags for CreateFile. This is not a bitmask. 137const ( 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. 147const ( 148 FileDirectoryFile = 0x1 149 FileNonDirectoryFile = 0x40 150 FileOpenReparsePoint = 0x00200000 151) 152 153// FileAttribute is the type of a directory entry in Stat. 154type FileAttribute uint32 155 156// File attribute bit masks - same as syscall but provided for all platforms. 157const ( 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. 169type 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 221type FreeSpace struct { 222 FreeBytesAvailable, TotalNumberOfBytes, TotalNumberOfFreeBytes uint64 223} 224 225// VolumeInformation - see WINAPI GetVolumeInformation for hints 226type 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. 235type FileSystemFlags uint32 236 237// Various FileSystemFlags constants, see winapi documentation for details. 238const ( 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. 262type 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. 282type 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. 291type NtStatus uint32 292 293func (n NtStatus) Error() string { 294 return "NTSTATUS=" + strconv.FormatUint(uint64(n), 16) 295} 296 297const ( 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) 323