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  )