diff --git a/Dokan.pas b/Dokan.pas index 24836cb..2558613 100644 --- a/Dokan.pas +++ b/Dokan.pas @@ -1,12 +1,12 @@ (* - Dokan API wrapper for Delphi based on Release 1.4.1.1000 - https://github.com/dokan-dev/dokany/releases/tag/v1.4.1.1000 - Copyright (C) 2019 - 2021 Sven Harazim + Dokan API wrapper for Delphi based on Release 2.0.5.1000 + https://github.com/dokan-dev/dokany/releases/tag/v2.0.5.1000 + Copyright (C) 2019 - 2023 Sven Harazim Dokan : user-mode file system library for Windows Copyright (C) 2015 - 2019 Adrien J. and Maxime C. - Copyright (C) 2020 Google, Inc. + Copyright (C) 2020 - 2022 Google, Inc. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -26,6 +26,8 @@ unit Dokan; +{.$DEFINE DOKAN_EXPLICIT_LINK} + {$ifdef FPC} {$mode delphi} {$endif FPC} @@ -39,12 +41,12 @@ interface Windows, DokanWin; const - DokanLibrary = 'dokan1.dll'; + DokanLibrary = 'dokan2.dll'; - //The current Dokan version (140 means ver 1.4.0). - DOKAN_VERSION = 141; - //Minimum Dokan version (ver 1.1.0) accepted - DOKAN_MINIMUM_COMPATIBLE_VERSION = 110; + //The current Dokan version (200 means ver 2.0.0). + DOKAN_VERSION = 206; + //Minimum Dokan version (ver 2.0.0) accepted + DOKAN_MINIMUM_COMPATIBLE_VERSION = 200; //Enable ouput debug message DOKAN_OPTION_DEBUG = 1; @@ -56,7 +58,7 @@ interface DOKAN_OPTION_ALT_STREAM = 4; //Enable mount drive as write-protected DOKAN_OPTION_WRITE_PROTECT = 8; - //Use network drive - Dokan network provider needs to be installed + //Use network drive - Dokan network provider needs to be installed and a DOKAN_OPTIONS.UNCName provided DOKAN_OPTION_NETWORK = 16; //Use removable drive //Be aware that on some environments, the userland application will be denied @@ -69,30 +71,28 @@ interface DOKAN_OPTION_CURRENT_SESSION = 128; //Enable Lockfile/Unlockfile operations. Otherwise Dokan will take care of it DOKAN_OPTION_FILELOCK_USER_MODE = 256; - //Whether DokanNotifyXXX functions should be enabled, which requires this - //library to maintain a special handle while the file system is mounted. - //Without this flag, the functions always return FALSE if invoked. - DOKAN_OPTION_ENABLE_NOTIFICATION_API = 512; - //Whether to disable any oplock support on the volume. - //Regular range locks are enabled regardless. - DOKAN_OPTION_DISABLE_OPLOCKS = 1024; - //The advantage of the FCB GC approach is that it prevents filter drivers (Anti-virus) - //from exponentially slowing down procedures like zip file extraction due to - //repeatedly rebuilding state that they attach to the FCB header. - DOKAN_OPTION_ENABLE_FCB_GARBAGE_COLLECTION = 2048; //Enable Case sensitive path. //By default all path are case insensitive. //For case sensitive: \dir\File & \diR\file are different files //but for case insensitive they are the same. - DOKAN_OPTION_CASE_SENSITIVE = 4096; + DOKAN_OPTION_CASE_SENSITIVE = 512; //Allows unmounting of network drive via explorer */ - DOKAN_OPTION_ENABLE_UNMOUNT_NETWORK_DRIVE = 8192; + DOKAN_OPTION_ENABLE_UNMOUNT_NETWORK_DRIVE = 1024; + //Forward the kernel driver global and volume logs to the userland. + //Can be very slow if single thread is enabled. + DOKAN_OPTION_DISPATCH_DRIVER_LOGS = 2048; + //Pull batches of events from the driver instead of a single one and execute them parallelly. + //This option should only be used on computers with low cpu count + //and userland filesystem taking time to process requests (like remote storage). + DOKAN_OPTION_ALLOW_IPC_BATCHING = 4096; type + DOKAN_HANDLE = THandle; + //Dokan mount options used to describe Dokan device behavior. _DOKAN_OPTIONS = record Version: USHORT; //Version of the Dokan features requested without dots (version "123" is equal to Dokan version 1.2.3). - ThreadCount: USHORT; //Number of threads to be used by Dokan library internally. More threads will handle more events at the same time. + SingleThread: ByteBool; //Only use a single thread to process events. This is highly not recommended as can easily create a bottleneck. Options: ULONG; //Features enabled for the mount. See \ref DOKAN_OPTION. GlobalContext: ULONG64; //FileSystem can store anything here. MountPoint: LPCWSTR; //Mount point. It can be a driver letter like "M:\" or a folder path "C:\mount\dokan" on a NTFS partition. @@ -100,6 +100,8 @@ _DOKAN_OPTIONS = record Timeout: ULONG; //Max timeout in milliseconds of each request before Dokan gives up to wait events to complete. The default timeout value is 15 seconds. AllocationUnitSize: ULONG;//Allocation Unit Size of the volume. This will affect the file size. SectorSize: ULONG; //Sector Size of the volume. This will affect the file size. + VolumeSecurityDescriptorLength : ULONG; //Length of the optional VolumeSecurityDescriptor provided. Set 0 will disable the option. + VolumeSecurityDescriptor : array [0..VOLUME_SECURITY_DESCRIPTOR_MAX_SIZE-1] of AnsiChar;//Optional Volume Security descriptor. See InitializeSecurityDescriptor end; DOKAN_OPTIONS = _DOKAN_OPTIONS; PDOKAN_OPTIONS = ^_DOKAN_OPTIONS; @@ -111,6 +113,7 @@ _DOKAN_FILE_INFO = record Context: ULONG64; DokanContext: ULONG64; DokanOptions: PDOKAN_OPTIONS; + ProcessingContext : PVOID; ProcessId: ULONG; IsDirectory: ByteBool; DeleteOnClose: ByteBool; @@ -124,19 +127,25 @@ _DOKAN_FILE_INFO = record TDokanFileInfo = DOKAN_FILE_INFO; PDokanFileInfo = PDOKAN_FILE_INFO; +const + DOKAN_EXCEPTION_NOT_INITIALIZED = $0f0ff0ff; + DOKAN_EXCEPTION_INITIALIZATION_FAILED = $0fbadbad; + DOKAN_EXCEPTION_SHUTDOWN_FAILED = $0fbadf00; + +type //FillFindData Used to add an entry in FindFiles operation //return 1 if buffer is full, otherwise 0 (currently it never returns 1) TDokanFillFindData = function ( - var FindData: WIN32_FIND_DATAW; - var DokanFileInfo: DOKAN_FILE_INFO + FindData: PWin32FindData; + DokanFileInfo: PDOKAN_FILE_INFO ): Integer; stdcall; //FillFindStreamData Used to add an entry in FindStreams - //return 1 if buffer is full, otherwise 0 (currently it never returns 1) + //return FALSE if the buffer is full, otherwise TRUE TDokanFillFindStreamData = function ( - var FindStreamData: WIN32_FIND_STREAM_DATA; - var DokanFileInfo: DOKAN_FILE_INFO - ): Integer; stdcall; + FindStreamData: PWIN32_FIND_STREAM_DATA; + FindStreamContext: PVOID + ): BOOL; stdcall; _DOKAN_ACCESS_STATE = record SecurityEvaluated: ByteBool; @@ -167,71 +176,71 @@ _DOKAN_IO_SECURITY_CONTEXT = record TDokanZwCreateFile = function ( FileName: LPCWSTR; - var SecurityContext: DOKAN_IO_SECURITY_CONTEXT; + SecurityContext: PDOKAN_IO_SECURITY_CONTEXT; DesiredAccess: ACCESS_MASK; FileAttributes: ULONG; ShareAccess: ULONG; CreateDisposition: ULONG; CreateOptions: ULONG; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanCleanup = procedure ( FileName: LPCWSTR; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ); stdcall; TDokanCloseFile = procedure ( FileName: LPCWSTR; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ); stdcall; TDokanReadFile = function ( FileName: LPCWSTR; var Buffer; BufferLength: DWORD; - var ReadLength: DWORD; + ReadLength: PDWORD; Offset: LONGLONG; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanWriteFile = function ( FileName: LPCWSTR; const Buffer; NumberOfBytesToWrite: DWORD; - var NumberOfBytesWritten: DWORD; + NumberOfBytesWritten: PDWORD; Offset: LONGLONG; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanFlushFileBuffers = function ( FileName: LPCWSTR; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanGetFileInformation = function ( FileName: LPCWSTR; - var Buffer: BY_HANDLE_FILE_INFORMATION; - var DokanFileInfo: DOKAN_FILE_INFO + Buffer: PByHandleFileInformation; + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanFindFiles = function ( PathName: LPCWSTR; FillFindData: TDokanFillFindData; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanFindFilesWithPattern = function ( PathName: LPCWSTR; SearchPattern: LPCWSTR; FillFindData: TDokanFillFindData; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanSetFileAttributes = function ( FileName: LPCWSTR; FileAttributes: DWORD; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanSetFileTime = function ( @@ -239,99 +248,101 @@ _DOKAN_IO_SECURITY_CONTEXT = record var CreationTime: FILETIME; var LastAccessTime: FILETIME; var LastWriteTime: FILETIME; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanDeleteFile = function ( FileName: LPCWSTR; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanDeleteDirectory = function ( FileName: LPCWSTR; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanMoveFile = function ( FileName: LPCWSTR; NewFileName: LPCWSTR; ReplaceIfExisting: BOOL; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanSetEndOfFile = function ( FileName: LPCWSTR; ByteOffset: LONGLONG; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanSetAllocationSize = function ( FileName: LPCWSTR; AllocSize: LONGLONG; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanLockFile = function ( FileName: LPCWSTR; ByteOffset: LONGLONG; Length: LONGLONG; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanUnlockFile = function ( FileName: LPCWSTR; ByteOffset: LONGLONG; Length: LONGLONG; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanGetDiskFreeSpace = function ( - var FreeBytesAvailable: ULONGLONG; - var TotalNumberOfBytes: ULONGLONG; - var TotalNumberOfFreeBytes: ULONGLONG; - var DokanFileInfo: DOKAN_FILE_INFO + FreeBytesAvailable: PULONGLONG; + TotalNumberOfBytes: PULONGLONG; + TotalNumberOfFreeBytes: PULONGLONG; + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanGetVolumeInformation = function ( VolumeNameBuffer: LPWSTR; VolumeNameSize: DWORD; - var VolumeSerialNumber: DWORD; - var MaximumComponentLength: DWORD; - var FileSystemFlags: DWORD; + VolumeSerialNumber: PDWORD; + MaximumComponentLength: PDWORD; + FileSystemFlags: PDWORD; FileSystemNameBuffer: LPWSTR; FileSystemNameSize: DWORD; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanMounted = function ( - var DokanFileInfo: DOKAN_FILE_INFO + MountPoint: LPCWSTR; + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanUnmounted = function ( - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanGetFileSecurity = function ( FileName: LPCWSTR; - var SecurityInformation: SECURITY_INFORMATION; + SecurityInformation: PSECURITY_INFORMATION; SecurityDescriptor: PSECURITY_DESCRIPTOR; BufferLength: ULONG; - var LengthNeeded: ULONG; - var DokanFileInfo: DOKAN_FILE_INFO + LengthNeeded: PULONG; + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanSetFileSecurity = function ( FileName: LPCWSTR; - var SecurityInformation: SECURITY_INFORMATION; + SecurityInformation: PSECURITY_INFORMATION; SecurityDescriptor: PSECURITY_DESCRIPTOR; BufferLength: ULONG; - var DokanFileInfo: DOKAN_FILE_INFO + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; TDokanFindStreams = function ( FileName: LPCWSTR; FillFindStreamData: TDokanFillFindStreamData; - var DokanFileInfo: DOKAN_FILE_INFO + FindStreamContext : PVOID; + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; _DOKAN_OPERATIONS = record @@ -366,17 +377,18 @@ _DOKAN_OPERATIONS = record TDokanOperations = DOKAN_OPERATIONS; PDokanOperations = PDOKAN_OPERATIONS; - _DOKAN_CONTROL = record - Type_: ULONG; + _DOKAN_MOUNT_POINT_INFO = record + Type_ : ULONG; MountPoint: array [0 .. MAX_PATH - 1] of WCHAR; UNCName: array [0 .. 63] of WCHAR; DeviceName: array [0 .. 63] of WCHAR; - DeviceObject: Pointer; + SessionId : ULONG; + MountOptions : ULONG; end; - DOKAN_CONTROL = _DOKAN_CONTROL; - PDOKAN_CONTROL = ^_DOKAN_CONTROL; - TDokanControl = DOKAN_CONTROL; - PDokanControl = PDOKAN_CONTROL; + DOKAN_MOUNT_POINT_INFO = _DOKAN_MOUNT_POINT_INFO; + PDOKAN_MOUNT_POINT_INFO = ^DOKAN_MOUNT_POINT_INFO; + TDokanMountPointInfo = _DOKAN_MOUNT_POINT_INFO; + PDokanMountPointInfo = PDOKAN_MOUNT_POINT_INFO; const DOKAN_SUCCESS = 0; @@ -392,25 +404,31 @@ _DOKAN_CONTROL = record var DokanLibHandle: HMODULE = 0; - DokanMain: function (var Options: DOKAN_OPTIONS; var Operations: DOKAN_OPERATIONS): Integer; stdcall = nil; + DokanInit: procedure; stdcall = nil; + DokanShutdown: procedure; stdcall = nil; + DokanMain: function (Options: DOKAN_OPTIONS; Operations: DOKAN_OPERATIONS): Integer; stdcall = nil; + DokanCreateFileSystem: function (DokanOptions : DOKAN_OPTIONS; DokanOperations : DOKAN_OPERATIONS; var DokanInstance : DOKAN_HANDLE) : Integer; stdcall = nil; + DokanIsFileSystemRunning: function (DokanInstance : DOKAN_HANDLE) : BOOL; stdcall = nil; + DokanWaitForFileSystemClosed: function (DokanInstance : DOKAN_HANDLE; dwMilliseconds : DWORD) : DWORD; stdcall = nil; + DokanCloseHandle: procedure (DokanInstance : DOKAN_HANDLE); stdcall = nil; DokanUnmount: function (DriveLetter: WCHAR): BOOL; stdcall = nil; DokanRemoveMountPoint: function (MountPoint: LPCWSTR): BOOL; stdcall = nil; DokanIsNameInExpression: function (Expression, Name: LPCWSTR; IgnoreCase: BOOL): BOOL; stdcall = nil; DokanVersion: function (): ULONG; stdcall = nil; DokanDriverVersion: function (): ULONG; stdcall = nil; - DokanResetTimeout: function (Timeout: ULONG; var DokanFileInfo: DOKAN_FILE_INFO): BOOL; stdcall = nil; - DokanOpenRequestorToken: function (var DokanFileInfo: DOKAN_FILE_INFO): THandle; stdcall = nil; - DokanGetMountPointList: function (uncOnly: BOOL; var nbRead: ULONG): PDOKAN_CONTROL; stdcall = nil; - DokanReleaseMountPointList: procedure (list: PDOKAN_CONTROL); stdcall = nil; + DokanResetTimeout: function (Timeout: ULONG; DokanFileInfo: PDOKAN_FILE_INFO): BOOL; stdcall = nil; + DokanOpenRequestorToken: function (DokanFileInfo: PDOKAN_FILE_INFO): THandle; stdcall = nil; + DokanGetMountPointList: function (uncOnly: BOOL; var nbRead: ULONG): PDOKAN_MOUNT_POINT_INFO; stdcall = nil; + DokanReleaseMountPointList: procedure (list: PDOKAN_MOUNT_POINT_INFO); stdcall = nil; DokanMapKernelToUserCreateFileFlags: procedure (DesiredAccess: ACCESS_MASK; FileAttributes, CreateOptions, CreateDisposition: ULONG;outDesiredAccess: PACCESS_MASK; outFileAttributesAndFlags, outCreationDisposition: PDWORD); stdcall = nil; - DokanNotifyCreate: function (FilePath: LPCWSTR; IsDirectory : BOOL) : BOOL; - DokanNotifyDelete: function (FilePath : LPCWSTR; BOOL IsDirectory) : BOOL; - DokanNotifyUpdate: function (FilePath : LPCWSTR) : BOOL; - DokanNotifyXAttrUpdate: function (FilePath : LPCWSTR) : BOOL; + DokanNotifyCreate: function (FilePath: LPCWSTR; IsDirectory : BOOL) : BOOL; stdcall = nil; + DokanNotifyDelete: function (DokanInstance : DOKAN_HANDLE; FilePath : LPCWSTR; IsDirectory : BOOL) : BOOL; stdcall = nil; + DokanNotifyUpdate: function (FilePath : LPCWSTR) : BOOL; stdcall = nil; + DokanNotifyXAttrUpdate: function (FilePath : LPCWSTR) : BOOL; stdcall = nil; DokanNotifyRename: function (OldPath: LPCWSTR; NewPath : LPCWSTR; IsDirectory : BOOL; - IsInSameDirectory: BOOL) : BOOL; + IsInSameDirectory: BOOL) : BOOL; stdcall = nil; DokanNtStatusFromWin32: function (Error: DWORD): NTSTATUS; stdcall = nil; function DokanLoad(const LibFileName: string = DokanLibrary): Boolean; @@ -418,24 +436,30 @@ procedure DokanFree(); {$else DOKAN_EXPLICIT_LINK} -function DokanMain(var Options: DOKAN_OPTIONS; var Operations: DOKAN_OPERATIONS): Integer; stdcall; +procedure DokanInit; stdcall; +procedure DokanShutdown; stdcall; +function DokanMain(Options: PDOKAN_OPTIONS; Operations: PDOKAN_OPERATIONS): Integer; stdcall; +function DokanCreateFileSystem(DokanOptions : PDOKAN_OPTIONS; DokanOperations : PDOKAN_OPERATIONS; var DokanInstance : DOKAN_HANDLE) : Integer; stdcall; +function DokanIsFileSystemRunning(DokanInstance : DOKAN_HANDLE) : BOOL; stdcall; +function DokanWaitForFileSystemClosed(DokanInstance : DOKAN_HANDLE; dwMilliseconds : DWORD) : DWORD; stdcall; +procedure DokanCloseHandle(DokanInstance : DOKAN_HANDLE); stdcall; function DokanUnmount(DriveLetter: WCHAR): BOOL; stdcall; function DokanRemoveMountPoint(MountPoint: LPCWSTR): BOOL; stdcall; function DokanIsNameInExpression(Expression, Name: LPCWSTR; IgnoreCase: BOOL): BOOL; stdcall; function DokanVersion(): ULONG; stdcall; function DokanDriverVersion(): ULONG; stdcall; -function DokanResetTimeout(Timeout: ULONG; var DokanFileInfo: DOKAN_FILE_INFO): BOOL; stdcall; -function DokanOpenRequestorToken(var DokanFileInfo: DOKAN_FILE_INFO): THandle; stdcall; -function DokanGetMountPointList(uncOnly: BOOL; var nbRead: ULONG): PDOKAN_CONTROL; stdcall; -procedure DokanReleaseMountPointList(list: PDOKAN_CONTROL); +function DokanResetTimeout(Timeout: ULONG; DokanFileInfo: PDOKAN_FILE_INFO): BOOL; stdcall; +function DokanOpenRequestorToken(DokanFileInfo: PDOKAN_FILE_INFO): THandle; stdcall; +function DokanGetMountPointList(uncOnly: BOOL; var nbRead: ULONG): PDOKAN_MOUNT_POINT_INFO; stdcall; +procedure DokanReleaseMountPointList(list: PDOKAN_MOUNT_POINT_INFO); stdcall; procedure DokanMapKernelToUserCreateFileFlags(DesiredAccess: ACCESS_MASK; FileAttributes, CreateOptions, CreateDisposition: ULONG; outDesiredAccess: PACCESS_MASK; outFileAttributesAndFlags, outCreationDisposition: PDWORD); stdcall; -function DokanNotifyCreate(FilePath: LPCWSTR; IsDirectory : BOOL) : BOOL; stdcall; -function DokanNotifyDelete(FilePath : LPCWSTR; IsDirectory : BOOL) : BOOL; stdcall; -function DokanNotifyUpdate(FilePath : LPCWSTR) : BOOL; stdcall; -function DokanNotifyXAttrUpdate(FilePath : LPCWSTR) : BOOL; stdcall; -function DokanNotifyRename(OldPath: LPCWSTR; NewPath : LPCWSTR; IsDirectory : BOOL; +function DokanNotifyCreate(DokanInstance : DOKAN_HANDLE; FilePath: LPCWSTR; IsDirectory : BOOL) : BOOL; stdcall; +function DokanNotifyDelete(DokanInstance : DOKAN_HANDLE; FilePath : LPCWSTR; IsDirectory : BOOL) : BOOL; stdcall; +function DokanNotifyUpdate(DokanInstance : DOKAN_HANDLE; FilePath : LPCWSTR) : BOOL; stdcall; +function DokanNotifyXAttrUpdate(DokanInstance : DOKAN_HANDLE; FilePath : LPCWSTR) : BOOL; stdcall; +function DokanNotifyRename(DokanInstance : DOKAN_HANDLE; OldPath: LPCWSTR; NewPath : LPCWSTR; IsDirectory : BOOL; IsInSameDirectory: BOOL) : BOOL; stdcall; function DokanNtStatusFromWin32(Error: DWORD): NTSTATUS; stdcall; @@ -466,7 +490,13 @@ function DokanLoad(const LibFileName: string = DokanLibrary): Boolean; Result := True; + DokanInit := GetProc('DokanInit'); + DokanShutdown := GetProc('DokanShutdown'); DokanMain := GetProc('DokanMain'); + DokanCreateFileSystem := GetProc('DokanCreateFileSystem'); + DokanIsFileSystemRunning := GetProc('DokanIsFileSystemRunning'); + DokanWaitForFileSystemClosed := GetProc('DokanWaitForFileSystemClosed'); + DokanCloseHandle := GetProc('DokanCloseHandle'); DokanUnmount := GetProc('DokanUnmount'); DokanRemoveMountPoint := GetProc('DokanRemoveMountPoint'); //DokanRemoveMountPointEx := GetProc('DokanRemoveMountPointEx'); @@ -494,7 +524,13 @@ procedure DokanFree(); if DokanLibHandle = 0 then Exit; + DokanInit := nil; + DokanShutdown := nil; DokanMain := nil; + DokanCreateFileSystem := nil; + DokanIsFileSystemRunning := nil; + DokanWaitForFileSystemClosed := nil; + DokanCloseHandle := nil; DokanUnmount := nil; DokanRemoveMountPoint := nil; //DokanRemoveMountPointEx := nil; @@ -519,7 +555,13 @@ procedure DokanFree(); {$else DOKAN_EXPLICIT_LINK} +procedure DokanInit; external DokanLibrary; +procedure DokanShutdown; external DokanLibrary; function DokanMain; external DokanLibrary; +function DokanCreateFileSystem; external DokanLibrary; +function DokanIsFileSystemRunning; external DokanLibrary; +function DokanWaitForFileSystemClosed; external DokanLibrary; +procedure DokanCloseHandle; external DokanLibrary; function DokanUnmount; external DokanLibrary; function DokanRemoveMountPoint; external DokanLibrary; //function DokanRemoveMountPointEx; external DokanLibrary; diff --git a/DokanWin.pas b/DokanWin.pas index 4efb88f..a35e94e 100644 --- a/DokanWin.pas +++ b/DokanWin.pas @@ -1,7 +1,7 @@ (* - Dokan API wrapper for Delphi based on Release 1.4.1.1000 - https://github.com/dokan-dev/dokany/releases/tag/v1.4.1.1000 - Copyright (C) 2019 - 2021 Sven Harazim + Dokan API wrapper for Delphi based on Release 2.0.5.1000 + https://github.com/dokan-dev/dokany/releases/tag/v2.0.5.1000 + Copyright (C) 2019 - 2023 Sven Harazim Dokan : user-mode file system library for Windows @@ -43,6 +43,9 @@ interface ULONG64 = UInt64; PACCESS_MASK = ^ACCESS_MASK; + LPVOID = Pointer; + PVOID = Pointer; + _UNICODE_STRING = record Length: USHORT; MaximumLength: USHORT; @@ -267,6 +270,8 @@ _WIN32_FIND_STREAM_DATA = record STATUS_CANNOT_DELETE = NTSTATUS($C0000121); STATUS_NOT_FOUND = NTSTATUS($C0000225); + VOLUME_SECURITY_DESCRIPTOR_MAX_SIZE = 1024 * 16; + implementation end. diff --git a/LICENSE.md b/LICENSE.md index 598defa..1bb7d61 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (C) 2015 - 2021 Adrien J. and Maxime C. +Copyright (C) 2015 - 2022 Adrien J. and Maxime C. Copyright (C) 2007 - 2011 Hiroki Asakawa Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/README.md b/README.md index abc5950..aae699d 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,13 @@ Delphi/FreePascal and Dokan library ## Supported Dokan Version https://github.com/dokan-dev/dokany -1.4.1.1000 +2.0.6.1000 -https://github.com/dokan-dev/dokany/releases/tag/v1.4.1.1000 +https://github.com/dokan-dev/dokany/releases/tag/v2.0.6.1000 + +## Update Dokan 1.1.0 application to Dokany 2.x.x + +https://github.com/dokan-dev/dokany/wiki/Update-Dokan-1.1.0-application-to-Dokany-2.0.0 ## How to write a file system To make a file system, an application needs to implement IDokanOperations interface. diff --git a/Samples/Mirror/Mirror.dpr b/Samples/Mirror/Mirror.dpr index d6618ed..9854cda 100644 --- a/Samples/Mirror/Mirror.dpr +++ b/Samples/Mirror/Mirror.dpr @@ -1,12 +1,12 @@ (* - Dokan API wrapper for Delphi based on Release 1.4.0.1000 - https://github.com/dokan-dev/dokany/releases/tag/v1.4.0.1000 - Copyright (C) 2019 - 2020 Sven Harazim + Dokan API wrapper for Delphi based on Release 2.0.5.1000 + https://github.com/dokan-dev/dokany/releases/tag/v2.0.5.1000 + Copyright (C) 2019 - 2023 Sven Harazim Dokan : user-mode file system library for Windows Copyright (C) 2015 - 2019 Adrien J. and Maxime C. - Copyright (C) 2020 Google, Inc. + Copyright (C) 2020 - 2022 Google, Inc. Copyright (C) 2007 - 2011 Hiroki Asakawa http://dokan-dev.github.io @@ -47,7 +47,6 @@ const LOCALE_NAME_SYSTEM_DEFAULT = '!x-sys-default-locale'; type - LPVOID = Pointer; size_t = NativeUInt; _TOKEN_USER = record @@ -151,7 +150,7 @@ begin SetLength(Result, j - 1); end; -//{$define WIN10_ENABLE_LONG_PATH} +{.$define WIN10_ENABLE_LONG_PATH} {$ifdef WIN10_ENABLE_LONG_PATH} //dirty but should be enough const @@ -162,7 +161,7 @@ const {$endif} // DEBUG type - WCHAR_PATH = array [0 .. DOKAN_MAX_PATH-1] of WCHAR; + WCHAR_PATH = array [0..DOKAN_MAX_PATH-1] of WCHAR; var g_UseStdErr: Boolean; @@ -191,18 +190,19 @@ begin end; var - RootDirectory: WCHAR_PATH; - MountPoint: WCHAR_PATH; - UNCName: WCHAR_PATH; + gRootDirectory: WCHAR_PATH; + gMountPoint: WCHAR_PATH; + gUNCName: WCHAR_PATH; + gVolumeName: WCHAR_PATH; procedure GetFilePath(filePath: PWCHAR; numberOfElements: ULONG; const FileName: LPCWSTR); var unclen: size_t; begin - lstrcpynW(filePath, RootDirectory, numberOfElements); - unclen := lstrlenW(UNCName); - if (unclen > 0) and (_wcsnicmp(FileName, UNCName, unclen) = 0) then begin + lstrcpynW(filePath, gRootDirectory, numberOfElements); + unclen := lstrlenW(gUNCName); + if (unclen > 0) and (_wcsnicmp(FileName, gUNCName, unclen) = 0) then begin if (_wcsnicmp(FileName + unclen, '.', 1) <> 0) then begin wcsncat_s(filePath, numberOfElements, FileName + unclen, size_t(lstrlenW(FileName)) - unclen); @@ -212,7 +212,7 @@ begin end; end; -procedure PrintUserName(var DokanFileInfo: DOKAN_FILE_INFO); +procedure PrintUserName(DokanFileInfo: PDOKAN_FILE_INFO); var handle: THandle; buffer: array [0 .. 1023] of UCHAR; @@ -271,7 +271,7 @@ begin token := 0; DbgPrint( '## Attempting to add SE_SECURITY_NAME privilege to process token ##\n'); - if (not LookupPrivilegeValueW(nil, 'SeSecurityPrivilege', luid)) then begin + if (not LookupPrivilegeValueW(nil, SE_SECURITY_NAME, luid)) then begin err := GetLastError(); if (err <> ERROR_SUCCESS) then begin DbgPrint(' failed: Unable to lookup privilege value. error = %u\n', @@ -326,10 +326,10 @@ begin DbgPrint('\t%s\n', [flagname]); end; -function MirrorCreateFile(FileName: LPCWSTR; var SecurityContext: DOKAN_IO_SECURITY_CONTEXT; +function MirrorCreateFile(FileName: LPCWSTR; SecurityContext: PDOKAN_IO_SECURITY_CONTEXT; DesiredAccess: ACCESS_MASK; FileAttributes: ULONG; ShareAccess: ULONG; CreateDisposition: ULONG; - CreateOptions: ULONG; var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + CreateOptions: ULONG; DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; handle: THandle; @@ -347,7 +347,7 @@ begin securityAttrib.nLength := SizeOf(securityAttrib); securityAttrib.lpSecurityDescriptor := - SecurityContext.AccessState.SecurityDescriptor; + SecurityContext^.AccessState.SecurityDescriptor; securityAttrib.bInheritHandle := False; DokanMapKernelToUserCreateFileFlags( @@ -403,7 +403,7 @@ begin if (fileAttr <> INVALID_FILE_ATTRIBUTES) then begin if (fileAttr and FILE_ATTRIBUTE_DIRECTORY <> 0) then begin if (CreateOptions and FILE_NON_DIRECTORY_FILE = 0) then begin - DokanFileInfo.IsDirectory := True; + DokanFileInfo^.IsDirectory := true; // Needed by FindFirstFile to list files in it // TODO: use ReOpenFile in MirrorFindFiles to set share read temporary ShareAccess := ShareAccess or FILE_SHARE_READ; @@ -478,7 +478,7 @@ begin end else userTokenHandle := INVALID_HANDLE_VALUE; //to prevent compiler-warning - if (DokanFileInfo.IsDirectory) then begin + if (DokanFileInfo^.IsDirectory) then begin // It is a create directory request if (creationDisposition = CREATE_NEW) or @@ -543,7 +543,7 @@ begin status := DokanNtStatusFromWin32(error); end else begin - DokanFileInfo.Context := + DokanFileInfo^.Context := ULONG64(handle); // save the file handle in Context // Open succeed but we need to inform the driver @@ -615,7 +615,7 @@ begin SetFileAttributesW(filePath, fileAttributesAndFlags or fileAttr); end; - DokanFileInfo.Context := + DokanFileInfo^.Context := ULONG64(handle); // save the file handle in Context if (creationDisposition = OPEN_ALWAYS) or @@ -636,42 +636,42 @@ begin end; procedure MirrorCloseFile(FileName: LPCWSTR; - var DokanFileInfo: DOKAN_FILE_INFO); stdcall; + DokanFileInfo: PDOKAN_FILE_INFO); stdcall; var filePath: WCHAR_PATH; begin GetFilePath(filePath, DOKAN_MAX_PATH, FileName); - if (DokanFileInfo.Context <> 0) then begin + if (DokanFileInfo^.Context <> 0) then begin DbgPrint('CloseFile: %s\n', [filePath]); DbgPrint('\terror : not cleanuped file\n\n'); - CloseHandle(THandle(DokanFileInfo.Context)); - DokanFileInfo.Context := 0; + CloseHandle(THandle(DokanFileInfo^.Context)); + DokanFileInfo^.Context := 0; end else begin DbgPrint('Close: %s\n\n', [filePath]); end; end; procedure MirrorCleanup(FileName: LPCWSTR; - var DokanFileInfo: DOKAN_FILE_INFO); stdcall; + DokanFileInfo: PDOKAN_FILE_INFO); stdcall; var filePath: WCHAR_PATH; begin GetFilePath(filePath, DOKAN_MAX_PATH, FileName); - if (DokanFileInfo.Context <> 0) then begin + if (DokanFileInfo^.Context <> 0) then begin DbgPrint('Cleanup: %s\n\n', [filePath]); - CloseHandle(THandle(DokanFileInfo.Context)); - DokanFileInfo.Context := 0; + CloseHandle(THandle(DokanFileInfo^.Context)); + DokanFileInfo^.Context := 0; end else begin DbgPrint('Cleanup: %s\n\tinvalid handle\n\n', [filePath]); end; - if (DokanFileInfo.DeleteOnClose) then begin + if (DokanFileInfo^.DeleteOnClose) then begin // Should already be deleted by CloseHandle // if open with FILE_FLAG_DELETE_ON_CLOSE DbgPrint('\tDeleteOnClose\n'); - if (DokanFileInfo.IsDirectory) then begin + if (DokanFileInfo^.IsDirectory) then begin DbgPrint(' DeleteDirectory '); if (not RemoveDirectoryW(filePath)) then begin DbgPrint('error code = %d\n\n', [GetLastError()]); @@ -691,9 +691,9 @@ end; function MirrorReadFile(FileName: LPCWSTR; var Buffer; BufferLength: DWORD; - var ReadLength: DWORD; + ReadLength: PDWORD; Offset: LONGLONG; - var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; handle: THandle; @@ -702,7 +702,7 @@ var error: DWORD; distanceToMove: LARGE_INTEGER; begin - handle := THandle(DokanFileInfo.Context); + handle := THandle(DokanFileInfo^.Context); offset_ := ULONG(Offset); opened := False; @@ -731,17 +731,17 @@ begin Result := DokanNtStatusFromWin32(error); Exit; end; - if (not ReadFile(handle, Buffer, BufferLength, ReadLength, nil)) then begin + if (not ReadFile(handle, Buffer, BufferLength, ReadLength^, nil)) then begin error := GetLastError(); DbgPrint('\tread error = %u, buffer length = %d, read length = %d\n\n', - [error, BufferLength, ReadLength]); + [error, BufferLength, ReadLength^]); if (opened) then CloseHandle(handle); Result := DokanNtStatusFromWin32(error); Exit; end else begin DbgPrint('\tByte to read: %d, Byte read %d, offset %d\n\n', [BufferLength, - ReadLength, offset_]); + ReadLength^, offset_]); end; if (opened) then @@ -752,9 +752,9 @@ end; function MirrorWriteFile(FileName: LPCWSTR; const Buffer; NumberOfBytesToWrite: DWORD; - var NumberOfBytesWritten: DWORD; + NumberOfBytesWritten: PDWORD; Offset: LONGLONG; - var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; handle: THandle; @@ -767,7 +767,7 @@ var bytes: UINT64; distanceToMove: LARGE_INTEGER; begin - handle := THandle(DokanFileInfo.Context); + handle := THandle(DokanFileInfo^.Context); opened := False; GetFilePath(filePath, DOKAN_MAX_PATH, FileName); @@ -800,7 +800,7 @@ begin fileSize := (UINT64(fileSizeHigh) shl 32) or fileSizeLow; - if (DokanFileInfo.WriteToEndOfFile) then begin + if (DokanFileInfo^.WriteToEndOfFile) then begin z.QuadPart := 0; if (not SetFilePointerEx(handle, z, nil, FILE_END)) then begin error := GetLastError(); @@ -811,9 +811,9 @@ begin end; end else begin // Paging IO cannot write after allocate file size. - if (DokanFileInfo.PagingIo) then begin + if (DokanFileInfo^.PagingIo) then begin if (UINT64(Offset) >= fileSize) then begin - NumberOfBytesWritten := 0; + NumberOfBytesWritten^ := 0; if (opened) then CloseHandle(handle); Result := STATUS_SUCCESS; Exit; @@ -846,17 +846,17 @@ begin end; end; - if (not WriteFile(handle, Buffer, NumberOfBytesToWrite, NumberOfBytesWritten, + if (not WriteFile(handle, Buffer, NumberOfBytesToWrite, NumberOfBytesWritten^, nil)) then begin error := GetLastError(); DbgPrint('\twrite error = %u, buffer length = %d, write length = %d\n', - [error, NumberOfBytesToWrite, NumberOfBytesWritten]); + [error, NumberOfBytesToWrite, NumberOfBytesWritten^]); if (opened) then CloseHandle(handle); Result := DokanNtStatusFromWin32(error); Exit; end else begin - DbgPrint('\twrite %d, offset %d\n\n', [NumberOfBytesWritten, Offset]); + DbgPrint('\twrite %d, offset %d\n\n', [NumberOfBytesWritten^, Offset]); end; // close the file when it is reopened @@ -866,13 +866,13 @@ begin Result := STATUS_SUCCESS; Exit; end; -function MirrorFlushFileBuffers(FileName: LPCWSTR; var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; +function MirrorFlushFileBuffers(FileName: LPCWSTR; DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; handle: THandle; error: DWORD; begin - handle := THandle(DokanFileInfo.Context); + handle := THandle(DokanFileInfo^.Context); GetFilePath(filePath, DOKAN_MAX_PATH, FileName); @@ -893,8 +893,8 @@ begin end; function MirrorGetFileInformation( - FileName: LPCWSTR; var HandleFileInformation: BY_HANDLE_FILE_INFORMATION; - var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + FileName: LPCWSTR; HandleFileInformation: PByHandleFileInformation; + DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; handle: THandle; @@ -903,7 +903,7 @@ var findHandle: THandle; opened: Boolean; begin - handle := THandle(DokanFileInfo.Context); + handle := THandle(DokanFileInfo^.Context); opened := False; GetFilePath(filePath, DOKAN_MAX_PATH, FileName); @@ -922,14 +922,14 @@ begin opened := True; end; - if (not GetFileInformationByHandle(handle, HandleFileInformation)) then begin + if (not GetFileInformationByHandle(handle, HandleFileInformation^)) then begin DbgPrint('\terror code = %d\n', [GetLastError()]); // FileName is a root directory // in this case, FindFirstFile can't get directory information if (lstrlenW(FileName) = 1) then begin DbgPrint(' root dir\n'); - HandleFileInformation.dwFileAttributes := GetFileAttributesW(filePath); + HandleFileInformation^.dwFileAttributes := GetFileAttributesW(filePath); end else begin ZeroMemory(@find, SizeOf(WIN32_FIND_DATAW)); @@ -941,21 +941,21 @@ begin CloseHandle(handle); Result := DokanNtStatusFromWin32(error); Exit; end; - HandleFileInformation.dwFileAttributes := find.dwFileAttributes; - HandleFileInformation.ftCreationTime := find.ftCreationTime; - HandleFileInformation.ftLastAccessTime := find.ftLastAccessTime; - HandleFileInformation.ftLastWriteTime := find.ftLastWriteTime; - HandleFileInformation.nFileSizeHigh := find.nFileSizeHigh; - HandleFileInformation.nFileSizeLow := find.nFileSizeLow; + HandleFileInformation^.dwFileAttributes := find.dwFileAttributes; + HandleFileInformation^.ftCreationTime := find.ftCreationTime; + HandleFileInformation^.ftLastAccessTime := find.ftLastAccessTime; + HandleFileInformation^.ftLastWriteTime := find.ftLastWriteTime; + HandleFileInformation^.nFileSizeHigh := find.nFileSizeHigh; + HandleFileInformation^.nFileSizeLow := find.nFileSizeLow; DbgPrint('\tFindFiles OK, file size = %d\n', [find.nFileSizeLow]); Windows.FindClose(findHandle); end; end else begin DbgPrint('\tGetFileInformationByHandle success, file size = %d\n', - [HandleFileInformation.nFileSizeLow]); + [HandleFileInformation^.nFileSizeLow]); end; - DbgPrint('FILE ATTRIBUTE = %d\n', [HandleFileInformation.dwFileAttributes]); + DbgPrint('FILE ATTRIBUTE = %d\n', [HandleFileInformation^.dwFileAttributes]); if (opened) then CloseHandle(handle); @@ -965,7 +965,7 @@ end; function MirrorFindFiles(FileName: LPCWSTR; FillFindData: TDokanFillFindData; // function pointer - var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; fileLen: size_t; @@ -1002,7 +1002,7 @@ begin repeat if (not rootFolder) or ((lstrcmpW(findData.cFileName, '.') <> 0) and (lstrcmpW(findData.cFileName, '..') <> 0)) then - FillFindData(findData, DokanFileInfo); + FillFindData(@findData, DokanFileInfo); Inc(count); until( FindNextFileW(hFind, findData) = False); @@ -1019,17 +1019,17 @@ begin Result := STATUS_SUCCESS; Exit; end; -function MirrorDeleteFile(FileName: LPCWSTR; var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; +function MirrorDeleteFile(FileName: LPCWSTR; DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; handle: THandle; dwAttrib: DWORD; fdi: FILE_DISPOSITION_INFO; begin - handle := THandle(DokanFileInfo.Context); + handle := THandle(DokanFileInfo^.Context); GetFilePath(filePath, DOKAN_MAX_PATH, FileName); - DbgPrint('DeleteFile %s - %d\n', [filePath, Byte(DokanFileInfo.DeleteOnClose)]); + DbgPrint('DeleteFile %s - %d\n', [filePath, Byte(DokanFileInfo^.DeleteOnClose)]); dwAttrib := GetFileAttributesW(filePath); @@ -1039,7 +1039,7 @@ begin end; if (handle <> 0) and (handle <> INVALID_HANDLE_VALUE) then begin - fdi.DeleteFile := DokanFileInfo.DeleteOnClose; + fdi.DeleteFile := DokanFileInfo^.DeleteOnClose; if (not SetFileInformationByHandle(handle, FileDispositionInfo, @fdi, sizeof(FILE_DISPOSITION_INFO))) then begin Result := DokanNtStatusFromWin32(GetLastError()); Exit; @@ -1049,7 +1049,7 @@ begin Result := STATUS_SUCCESS; Exit; end; -function MirrorDeleteDirectory(FileName: LPCWSTR; var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; +function MirrorDeleteDirectory(FileName: LPCWSTR; DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; hFind: THandle; @@ -1061,9 +1061,9 @@ begin GetFilePath(filePath, DOKAN_MAX_PATH, FileName); DbgPrint('DeleteDirectory %s - %d\n', [filePath, - Byte(DokanFileInfo.DeleteOnClose)]); + Byte(DokanFileInfo^.DeleteOnClose)]); - if (not DokanFileInfo.DeleteOnClose) then begin + if (not DokanFileInfo^.DeleteOnClose) then begin //Dokan notify that the file is requested not to be deleted. Result := STATUS_SUCCESS; Exit; end; @@ -1107,7 +1107,7 @@ end; function MirrorMoveFile(FileName: LPCWSTR; // existing file name NewFileName: LPCWSTR; ReplaceIfExisting: BOOL; - var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; newFilePath: WCHAR_PATH; @@ -1122,7 +1122,7 @@ begin GetFilePath(newFilePath, DOKAN_MAX_PATH, NewFileName); DbgPrint('MoveFile %s -> %s\n\n', [filePath, newFilePath]); - handle := THandle(DokanFileInfo.Context); + handle := THandle(DokanFileInfo^.Context); if (handle = 0) or (handle = INVALID_HANDLE_VALUE) then begin DbgPrint('\tinvalid handle\n\n'); Result := STATUS_INVALID_HANDLE; Exit; @@ -1168,7 +1168,7 @@ end; function MirrorLockFile(FileName: LPCWSTR; ByteOffset: LONGLONG; Length: LONGLONG; - var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; handle: THandle; @@ -1180,7 +1180,7 @@ begin DbgPrint('LockFile %s\n', [filePath]); - handle := THandle(DokanFileInfo.Context); + handle := THandle(DokanFileInfo^.Context); if (handle = 0) or (handle = INVALID_HANDLE_VALUE) then begin DbgPrint('\tinvalid handle\n\n'); Result := STATUS_INVALID_HANDLE; Exit; @@ -1201,7 +1201,7 @@ begin end; function MirrorSetEndOfFile( - FileName: LPCWSTR; ByteOffset: LONGLONG; var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + FileName: LPCWSTR; ByteOffset: LONGLONG; DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; handle: THandle; @@ -1212,7 +1212,7 @@ begin DbgPrint('SetEndOfFile %s, %d\n', [filePath, ByteOffset]); - handle := THandle(DokanFileInfo.Context); + handle := THandle(DokanFileInfo^.Context); if (handle = 0) or (handle = INVALID_HANDLE_VALUE) then begin DbgPrint('\tinvalid handle\n\n'); Result := STATUS_INVALID_HANDLE; Exit; @@ -1236,7 +1236,7 @@ begin end; function MirrorSetAllocationSize( - FileName: LPCWSTR; AllocSize: LONGLONG; var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + FileName: LPCWSTR; AllocSize: LONGLONG; DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; handle: THandle; @@ -1247,7 +1247,7 @@ begin DbgPrint('SetAllocationSize %s, %d\n', [filePath, AllocSize]); - handle := THandle(DokanFileInfo.Context); + handle := THandle(DokanFileInfo^.Context); if (handle = 0) or (handle = INVALID_HANDLE_VALUE) then begin DbgPrint('\tinvalid handle\n\n'); Result := STATUS_INVALID_HANDLE; Exit; @@ -1278,7 +1278,7 @@ begin end; function MirrorSetFileAttributes( - FileName: LPCWSTR; FileAttributes: DWORD; var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + FileName: LPCWSTR; FileAttributes: DWORD; DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; error: DWORD; @@ -1307,7 +1307,7 @@ end; function MirrorSetFileTime(FileName: LPCWSTR; var CreationTime: FILETIME; var LastAccessTime: FILETIME; var LastWriteTime: FILETIME; - var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; handle: THandle; @@ -1317,7 +1317,7 @@ begin DbgPrint('SetFileTime %s\n', [filePath]); - handle := THandle(DokanFileInfo.Context); + handle := THandle(DokanFileInfo^.Context); if (handle = 0) or (handle = INVALID_HANDLE_VALUE) then begin DbgPrint('\tinvalid handle\n\n'); @@ -1335,7 +1335,7 @@ begin end; function MirrorUnlockFile(FileName: LPCWSTR; ByteOffset: LONGLONG; Length: LONGLONG; - var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; handle: THandle; @@ -1347,7 +1347,7 @@ begin DbgPrint('UnlockFile %s\n', [filePath]); - handle := THandle(DokanFileInfo.Context); + handle := THandle(DokanFileInfo^.Context); if (handle = 0) or (handle = INVALID_HANDLE_VALUE) then begin DbgPrint('\tinvalid handle\n\n'); Result := STATUS_INVALID_HANDLE; Exit; @@ -1368,9 +1368,9 @@ begin end; function MirrorGetFileSecurity( - FileName: LPCWSTR; var SecurityInformation: SECURITY_INFORMATION; + FileName: LPCWSTR; SecurityInformation: PSECURITY_INFORMATION; SecurityDescriptor: PSECURITY_DESCRIPTOR; BufferLength: ULONG; - var LengthNeeded: ULONG; var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + LengthNeeded: PULONG; DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; requestingSaclInfo: Boolean; @@ -1383,28 +1383,27 @@ begin DbgPrint('GetFileSecurity %s\n', [filePath]); - MirrorCheckFlag(SecurityInformation, FILE_SHARE_READ, 'FILE_SHARE_READ'); - MirrorCheckFlag(SecurityInformation, OWNER_SECURITY_INFORMATION, 'OWNER_SECURITY_INFORMATION'); - MirrorCheckFlag(SecurityInformation, GROUP_SECURITY_INFORMATION, 'GROUP_SECURITY_INFORMATION'); - MirrorCheckFlag(SecurityInformation, DACL_SECURITY_INFORMATION, 'DACL_SECURITY_INFORMATION'); - MirrorCheckFlag(SecurityInformation, SACL_SECURITY_INFORMATION, 'SACL_SECURITY_INFORMATION'); - MirrorCheckFlag(SecurityInformation, LABEL_SECURITY_INFORMATION, 'LABEL_SECURITY_INFORMATION'); - MirrorCheckFlag(SecurityInformation, ATTRIBUTE_SECURITY_INFORMATION, 'ATTRIBUTE_SECURITY_INFORMATION'); - MirrorCheckFlag(SecurityInformation, SCOPE_SECURITY_INFORMATION, 'SCOPE_SECURITY_INFORMATION'); - MirrorCheckFlag(SecurityInformation, - PROCESS_TRUST_LABEL_SECURITY_INFORMATION, 'PROCESS_TRUST_LABEL_SECURITY_INFORMATION'); - MirrorCheckFlag(SecurityInformation, BACKUP_SECURITY_INFORMATION, 'BACKUP_SECURITY_INFORMATION'); - MirrorCheckFlag(SecurityInformation, PROTECTED_DACL_SECURITY_INFORMATION, 'PROTECTED_DACL_SECURITY_INFORMATION'); - MirrorCheckFlag(SecurityInformation, PROTECTED_SACL_SECURITY_INFORMATION, 'PROTECTED_SACL_SECURITY_INFORMATION'); - MirrorCheckFlag(SecurityInformation, UNPROTECTED_DACL_SECURITY_INFORMATION, 'UNPROTECTED_DACL_SECURITY_INFORMATION'); - MirrorCheckFlag(SecurityInformation, UNPROTECTED_SACL_SECURITY_INFORMATION, 'UNPROTECTED_SACL_SECURITY_INFORMATION'); - - requestingSaclInfo := ((SecurityInformation and SACL_SECURITY_INFORMATION <> 0) or - (SecurityInformation and BACKUP_SECURITY_INFORMATION <> 0)); + MirrorCheckFlag(SecurityInformation^, FILE_SHARE_READ, 'FILE_SHARE_READ'); + MirrorCheckFlag(SecurityInformation^, OWNER_SECURITY_INFORMATION, 'OWNER_SECURITY_INFORMATION'); + MirrorCheckFlag(SecurityInformation^, GROUP_SECURITY_INFORMATION, 'GROUP_SECURITY_INFORMATION'); + MirrorCheckFlag(SecurityInformation^, DACL_SECURITY_INFORMATION, 'DACL_SECURITY_INFORMATION'); + MirrorCheckFlag(SecurityInformation^, SACL_SECURITY_INFORMATION, 'SACL_SECURITY_INFORMATION'); + MirrorCheckFlag(SecurityInformation^, LABEL_SECURITY_INFORMATION, 'LABEL_SECURITY_INFORMATION'); + MirrorCheckFlag(SecurityInformation^, ATTRIBUTE_SECURITY_INFORMATION, 'ATTRIBUTE_SECURITY_INFORMATION'); + MirrorCheckFlag(SecurityInformation^, SCOPE_SECURITY_INFORMATION, 'SCOPE_SECURITY_INFORMATION'); + MirrorCheckFlag(SecurityInformation^, PROCESS_TRUST_LABEL_SECURITY_INFORMATION, 'PROCESS_TRUST_LABEL_SECURITY_INFORMATION'); + MirrorCheckFlag(SecurityInformation^, BACKUP_SECURITY_INFORMATION, 'BACKUP_SECURITY_INFORMATION'); + MirrorCheckFlag(SecurityInformation^, PROTECTED_DACL_SECURITY_INFORMATION, 'PROTECTED_DACL_SECURITY_INFORMATION'); + MirrorCheckFlag(SecurityInformation^, PROTECTED_SACL_SECURITY_INFORMATION, 'PROTECTED_SACL_SECURITY_INFORMATION'); + MirrorCheckFlag(SecurityInformation^, UNPROTECTED_DACL_SECURITY_INFORMATION, 'UNPROTECTED_DACL_SECURITY_INFORMATION'); + MirrorCheckFlag(SecurityInformation^, UNPROTECTED_SACL_SECURITY_INFORMATION, 'UNPROTECTED_SACL_SECURITY_INFORMATION'); + + requestingSaclInfo := ((SecurityInformation^ and SACL_SECURITY_INFORMATION) <> 0) or + ((SecurityInformation^ and BACKUP_SECURITY_INFORMATION) <> 0); if (not g_HasSeSecurityPrivilege) then begin - SecurityInformation := SecurityInformation and not SACL_SECURITY_INFORMATION; - SecurityInformation := SecurityInformation and not BACKUP_SECURITY_INFORMATION; + SecurityInformation^ := SecurityInformation^ and not SACL_SECURITY_INFORMATION; + SecurityInformation^ := SecurityInformation^ and not BACKUP_SECURITY_INFORMATION; end; DesiredAccess := READ_CONTROL; @@ -1427,8 +1426,8 @@ begin Result := DokanNtStatusFromWin32(error); Exit; end; - if (not GetUserObjectSecurity(handle, SecurityInformation, SecurityDescriptor, - BufferLength, LengthNeeded)) then begin + if (not GetUserObjectSecurity(handle, SecurityInformation^, SecurityDescriptor, + BufferLength, LengthNeeded^)) then begin error := GetLastError(); if (error = ERROR_INSUFFICIENT_BUFFER) then begin DbgPrint(' GetUserObjectSecurity error: ERROR_INSUFFICIENT_BUFFER\n'); @@ -1446,7 +1445,7 @@ begin GetSecurityDescriptorLength(SecurityDescriptor); DbgPrint(' GetUserObjectSecurity return true, *LengthNeeded = ' + 'securityDescriptorLength \n'); - LengthNeeded := securityDescriptorLength; + LengthNeeded^ := securityDescriptorLength; CloseHandle(handle); @@ -1454,9 +1453,9 @@ begin end; function MirrorSetFileSecurity( - FileName: LPCWSTR; var SecurityInformation: SECURITY_INFORMATION; + FileName: LPCWSTR; SecurityInformation: PSECURITY_INFORMATION; SecurityDescriptor: PSECURITY_DESCRIPTOR; SecurityDescriptorLength: ULONG; - var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var handle: THandle; filePath: WCHAR_PATH; @@ -1466,68 +1465,69 @@ begin DbgPrint('SetFileSecurity %s\n', [filePath]); - handle := THandle(DokanFileInfo.Context); + handle := THandle(DokanFileInfo^.Context); if (handle = 0) or (handle = INVALID_HANDLE_VALUE) then begin DbgPrint('\tinvalid handle\n\n'); Result := STATUS_INVALID_HANDLE; Exit; end; - if (not SetUserObjectSecurity(handle, SecurityInformation, SecurityDescriptor)) then begin + if (not SetUserObjectSecurity(handle, SecurityInformation^, SecurityDescriptor)) then begin error := GetLastError(); DbgPrint(' SetUserObjectSecurity error: %d\n', [error]); Result := DokanNtStatusFromWin32(error); Exit; end; + Result := STATUS_SUCCESS; Exit; end; function MirrorGetVolumeInformation( - VolumeNameBuffer: LPWSTR; VolumeNameSize: DWORD; var VolumeSerialNumber: DWORD; - var MaximumComponentLength: DWORD; var FileSystemFlags: DWORD; + VolumeNameBuffer: LPWSTR; VolumeNameSize: DWORD; VolumeSerialNumber: PDWORD; + MaximumComponentLength: PDWORD; FileSystemFlags: PDWORD; FileSystemNameBuffer: LPWSTR; FileSystemNameSize: DWORD; - var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var volumeRoot: array [0 .. 3] of WCHAR; fsFlags: DWORD; begin fsFlags := 0; - lstrcpynW(VolumeNameBuffer, 'DOKAN', VolumeNameSize); - if (@VolumeSerialNumber <> nil) then - VolumeSerialNumber := $19831116; - if (@MaximumComponentLength <> nil) then - MaximumComponentLength := 255; - if (@FileSystemFlags <> nil) then + lstrcpynW(VolumeNameBuffer, gVolumeName, VolumeNameSize); + if (VolumeSerialNumber <> nil) then + VolumeSerialNumber^ := $19831116; + if (MaximumComponentLength <> nil) then + MaximumComponentLength^ := 255; + if (FileSystemFlags <> nil) then begin - FileSystemFlags := FILE_SUPPORTS_REMOTE_STORAGE or FILE_UNICODE_ON_DISK or + FileSystemFlags^ := FILE_SUPPORTS_REMOTE_STORAGE or FILE_UNICODE_ON_DISK or FILE_PERSISTENT_ACLS or FILE_NAMED_STREAMS; if (g_CaseSensitive) then - FileSystemFlags := FILE_CASE_SENSITIVE_SEARCH or FILE_CASE_PRESERVED_NAMES; + FileSystemFlags^ := FILE_CASE_SENSITIVE_SEARCH or FILE_CASE_PRESERVED_NAMES; end; - volumeRoot[0] := RootDirectory[0]; + volumeRoot[0] := gRootDirectory[0]; volumeRoot[1] := ':'; volumeRoot[2] := '\'; volumeRoot[3] := #0; - if (GetVolumeInformationW(@volumeRoot[0], nil, 0, nil, MaximumComponentLength, + if (GetVolumeInformationW(@volumeRoot[0], nil, 0, nil, MaximumComponentLength^, fsFlags, FileSystemNameBuffer, FileSystemNameSize)) then begin - if (@FileSystemFlags <> nil) then - FileSystemFlags := FileSystemFlags and fsFlags; + if (FileSystemFlags <> nil) then + FileSystemFlags^ := FileSystemFlags^ and fsFlags; - if (@MaximumComponentLength <> nil) then begin + if (MaximumComponentLength <> nil) then begin DbgPrint('GetVolumeInformation: max component length %u\n', - [MaximumComponentLength]); + [MaximumComponentLength^]); end; - if (@FileSystemNameBuffer <> nil) then begin + if (FileSystemNameBuffer <> nil) then begin DbgPrint('GetVolumeInformation: file system name %s\n', - [FileSystemNameBuffer]); + [FileSystemNameBuffer^]); end; - if (@FileSystemFlags <> nil) then begin + if (FileSystemFlags <> nil) then begin DbgPrint('GetVolumeInformation: got file system flags 0x%08x,' + ' returning 0x%08x\n', - [fsFlags, FileSystemFlags]); + [fsFlags, FileSystemFlags^]); end; end else begin @@ -1544,20 +1544,17 @@ begin Result := STATUS_SUCCESS; Exit; end; -(* -//Uncomment for personalize disk space function MirrorDokanGetDiskFreeSpace( - var FreeBytesAvailable: ULONGLONG; var TotalNumberOfBytes: ULONGLONG; - var TotalNumberOfFreeBytes: ULONGLONG; var DokanFileInfo: DOKAN_FILE_INFO + FreeBytesAvailable: PULONGLONG; TotalNumberOfBytes: PULONGLONG; + TotalNumberOfFreeBytes: PULONGLONG; DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; begin - FreeBytesAvailable := (512 * 1024 * 1024); - TotalNumberOfBytes := 9223372036854775807; - TotalNumberOfFreeBytes := 9223372036854775807; + FreeBytesAvailable^ := (512 * 1024 * 1024); + TotalNumberOfBytes^ := 9223372036854775807; + TotalNumberOfFreeBytes^ := 9223372036854775807; Result := STATUS_SUCCESS; Exit; end; -*) (** * Avoid #include which as conflict with FILE_INFORMATION_CLASS @@ -1586,13 +1583,14 @@ NTSYSCALLAPI NTSTATUS NTAPI NtQueryInformationFile( *) function MirrorFindStreams(FileName: LPCWSTR; FillFindStreamData: TDokanFillFindStreamData; - var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + FindStreamContext: PVOID;DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; hFind: THandle; findData: WIN32_FIND_STREAM_DATA; error: DWORD; - count: Integer; + bufferFull: Boolean; + count : Integer; begin count := 0; @@ -1608,17 +1606,30 @@ begin Result := DokanNtStatusFromWin32(error); Exit; end; - FillFindStreamData(findData, DokanFileInfo); - Inc(count); - - while (FindNextStreamW(hFind, @findData) <> False) do begin - FillFindStreamData(findData, DokanFileInfo); + bufferFull := FillFindStreamData(@findData, FindStreamContext); + if bufferFull then + begin Inc(count); + while (FindNextStreamW(hFind, @findData) <> False) do begin + bufferFull := FillFindStreamData(@findData, FindStreamContext); + if not bufferFull then + break; + Inc(count); + end; end; error := GetLastError(); Windows.FindClose(hFind); + if not bufferFull then + begin + DbgPrint('\tFindStreams returned %d\n\n entries in %s with ', + [STATUS_BUFFER_OVERFLOW,count, filePath]); + // https://msdn.microsoft.com/en-us/library/windows/hardware/ff540364(v=vs.85).aspx + Result := STATUS_BUFFER_OVERFLOW; + exit; + end; + if (error <> ERROR_HANDLE_EOF) then begin DbgPrint('\tFindNextStreamW error. Error is %u\n\n', [error]); Result := DokanNtStatusFromWin32(error); Exit; @@ -1629,13 +1640,13 @@ begin Result := STATUS_SUCCESS; Exit; end; -function MirrorMounted(var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; +function MirrorMounted(MountPoint: LPCWSTR; DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; begin - DbgPrint('Mounted\n'); + DbgPrint('Mounted as %s\n',[MountPoint]); Result := STATUS_SUCCESS; Exit; end; -function MirrorUnmounted(var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; +function MirrorUnmounted(DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; begin DbgPrint('Unmounted\n'); Result := STATUS_SUCCESS; Exit; @@ -1650,7 +1661,7 @@ begin CTRL_LOGOFF_EVENT, CTRL_SHUTDOWN_EVENT: begin SetConsoleCtrlHandler(@CtrlHandler, False); - DokanRemoveMountPoint(MountPoint); + DokanRemoveMountPoint(gMountPoint); Result := True; end; else @@ -1663,24 +1674,24 @@ begin Write(ErrOutput, escape_replace('mirror.exe\n' + ' /r RootDirectory (ex. /r c:\\test)\t\t Directory source to mirror.\n' + ' /l MountPoint (ex. /l m)\t\t\t Mount point. Can be M:\\ (drive letter) or empty NTFS folder C:\\mount\\dokan .\n' + - ' /t ThreadCount (ex. /t 5)\t\t\t Number of threads to be used internally by Dokan library.\n\t\t\t\t\t\t More threads will handle more event at the same time.\n' + + ' /t Single thread\t\t\t\t Only use a single thread to process events.\n\t\t\t\t\t\t This is highly not recommended as can easily create a bottleneck.\n' + ' /d (enable debug output)\t\t\t Enable debug output to an attached debugger.\n' + ' /s (use stderr for output)\t\t\t Enable debug output to stderr.\n' + - ' /n (use network drive)\t\t\t Show device as network device.\n' + ' /m (use removable drive)\t\t\t Show device as removable media.\n' + ' /w (write-protect drive)\t\t\t Read only filesystem.\n' + ' /b (case sensitive drive)\t\t\t Supports case-sensitive file names.\n'+ ' /o (use mount manager)\t\t\t Register device to Windows mount manager.\n\t\t\t\t\t\t This enables advanced Windows features like recycle bin and more...\n' + ' /c (mount for current session only)\t\t Device only visible for current user session.\n' + - ' /u (UNC provider name ex. \\localhost\\myfs)\t UNC name used for network volume.\n' + + ' /n (Network drive with UNC name ex. \\myfs\\fs1) Show device as network device with a UNC name.\n' + ' /p (Impersonate Caller User)\t\t\t Impersonate Caller User when getting the handle in CreateFile for operations.\n\t\t\t\t\t\t This option requires administrator right to work properly.\n' + ' /a Allocation unit size (ex. /a 512)\t\t Allocation Unit Size of the volume. This will behave on the disk file size.\n' + ' /k Sector size (ex. /k 512)\t\t\t Sector Size of the volume. This will behave on the disk file size.\n' + ' /f User mode Lock\t\t\t\t Enable Lockfile/Unlockfile operations. Otherwise Dokan will take care of it.\n' + - ' /e Disable OpLocks\t\t\t\t Disable OpLocks kernel operations. Otherwise Dokan will take care of it.\n'+ - ' /i (Timeout in Milliseconds ex. /i 30000)\t Timeout until a running operation is aborted and the device is unmounted.\n\n' + - ' /z Enabled FCB GC. Might speed up on env with filter drivers (Anti-virus) slowing down the system.\n'+ - ' /x (network unmount)\t\t\t Allows unmounting network drive from file explorer\n'+ + ' /i Timeout in Milliseconds (ex. /i 30000)\t Timeout until a running operation is aborted and the device is unmounted.\n' + + ' /z Enabled FCB GCt\t\t\t\t Might speed up on env with filter drivers (Anti-virus) slowing down the system.\n' + + ' /x Network unmount\t\t\t\t Allows unmounting network drive from file explorer.\n' + + ' /e Enable Driver Logs\t\t\t\t Forward Driver logs to userland.\n' + + ' /v Volume name\t\t\t\t Personalize the volume name.\n\n' + 'Examples:\n' + '\tmirror.exe /r C:\\Users /l M:\t\t\t# Mirror C:\\Users as RootDirectory into a drive of letter M:\\.\n' + '\tmirror.exe /r C:\\Users /l C:\\mount\\dokan\t# Mirror C:\\Users as RootDirectory into NTFS folder C:\\mount\\dokan.\n' + @@ -1692,23 +1703,11 @@ function wmain(argc: ULONG; argv: array of string): Integer; var status: Integer; command: ULONG; - dokanOperations: PDOKAN_OPERATIONS; - dokanOptions: PDOKAN_OPTIONS; + dokanOperations: DOKAN_OPERATIONS; + dokanOptions: DOKAN_OPTIONS; begin - New(dokanOperations); - if (dokanOperations = nil) then begin - Result := EXIT_FAILURE; Exit; - end; - New(dokanOptions); - if (dokanOptions = nil) then begin - Dispose(dokanOperations); - Result := EXIT_FAILURE; Exit; - end; - if (argc < 3) then begin ShowUsage(); - Dispose(dokanOperations); - Dispose(dokanOptions); Result := EXIT_FAILURE; Exit; end; @@ -1716,21 +1715,34 @@ begin g_UseStdErr := False; g_CaseSensitive := False; - ZeroMemory(dokanOptions, SizeOf(DOKAN_OPTIONS)); - dokanOptions^.Version := DOKAN_VERSION; - dokanOptions^.ThreadCount := 0; // use default + ZeroMemory(@dokanOptions, SizeOf(DOKAN_OPTIONS)); + dokanOptions.Version := DOKAN_VERSION; + dokanOptions.SingleThread:= false; + dokanOptions.Options:= 0; + //dokanOptions.GlobalContext: ULONG64; //FileSystem can store anything here. + //dokanOptions.MountPoint: LPCWSTR; //Mount point. It can be a driver letter like "M:\" or a folder path "C:\mount\dokan" on a NTFS partition. + //dokanOptions.UNCName: LPCWSTR; //UNC Name for the Network Redirector + dokanOptions.Timeout:= 15;// + //dokanOptions.AllocationUnitSize: ULONG;//Allocation Unit Size of the volume. This will affect the file size. + //dokanOptions.SectorSize: ULONG; //Sector Size of the volume. This will affect the file size. + dokanOptions.VolumeSecurityDescriptorLength := 0; + //dokanOptions.VolumeSecurityDescriptor : array [0..VOLUME_SECURITY_DESCRIPTOR_MAX_SIZE-1] of AnsiChar;//Optional Volume Security descriptor. See InitializeSecurityDescriptor command := 1; while (command < argc) do begin case (UpCase(argv[command][2])) of + 'R': begin + Inc(command); + lstrcpynW(gRootDirectory, PWideChar(WideString(argv[command])), DOKAN_MAX_PATH); + DbgPrint('RootDirectory: %s\n', [gRootDirectory]); + end; 'L': begin Inc(command); - lstrcpynW(MountPoint, PWideChar(WideString(argv[command])), DOKAN_MAX_PATH); - dokanOptions^.MountPoint := MountPoint; + lstrcpynW(gMountPoint, PWideChar(WideString(argv[command])), DOKAN_MAX_PATH); + dokanOptions.MountPoint := gMountPoint; end; 'T': begin - Inc(command); - dokanOptions^.ThreadCount := StrToInt(argv[command]); + dokanOptions.SingleThread := true; end; 'D': begin g_DebugMode := True; @@ -1738,101 +1750,88 @@ begin 'S': begin g_UseStdErr := True; end; - 'N': begin - dokanOptions^.Options := dokanOptions^.Options or DOKAN_OPTION_NETWORK; - end; 'M': begin - dokanOptions^.Options := dokanOptions^.Options or DOKAN_OPTION_REMOVABLE; + dokanOptions.Options := dokanOptions.Options or DOKAN_OPTION_REMOVABLE; end; 'W': begin - dokanOptions^.Options := dokanOptions^.Options or DOKAN_OPTION_WRITE_PROTECT; + dokanOptions.Options := dokanOptions.Options or DOKAN_OPTION_WRITE_PROTECT; end; 'O': begin - dokanOptions^.Options := dokanOptions^.Options or DOKAN_OPTION_MOUNT_MANAGER; + dokanOptions.Options := dokanOptions.Options or DOKAN_OPTION_MOUNT_MANAGER; end; 'C': begin - dokanOptions^.Options := dokanOptions^.Options or DOKAN_OPTION_CURRENT_SESSION; + dokanOptions.Options := dokanOptions.Options or DOKAN_OPTION_CURRENT_SESSION; end; 'F': begin - dokanOptions^.Options := dokanOptions^.Options or DOKAN_OPTION_FILELOCK_USER_MODE; - end; - 'E': begin - dokanOptions^.Options := dokanOptions^.Options or DOKAN_OPTION_DISABLE_OPLOCKS; - end; - 'Z': begin - dokanOptions^.Options := dokanOptions^.Options or DOKAN_OPTION_ENABLE_FCB_GARBAGE_COLLECTION; + dokanOptions.Options := dokanOptions.Options or DOKAN_OPTION_FILELOCK_USER_MODE; end; 'X': begin - dokanOptions^.Options := dokanOptions^.Options or DOKAN_OPTION_ENABLE_UNMOUNT_NETWORK_DRIVE; + dokanOptions.Options := dokanOptions.Options or DOKAN_OPTION_ENABLE_UNMOUNT_NETWORK_DRIVE; + end; + 'E': begin + dokanOptions.Options := dokanOptions.Options or DOKAN_OPTION_DISPATCH_DRIVER_LOGS; end; 'B': begin - dokanOptions^.Options := dokanOptions^.Options or DOKAN_OPTION_CASE_SENSITIVE; + dokanOptions.Options := dokanOptions.Options or DOKAN_OPTION_CASE_SENSITIVE; g_CaseSensitive := true; end; - 'U': begin + 'N': begin + Inc(command); + dokanOptions.Options := dokanOptions.Options or DOKAN_OPTION_NETWORK; + lstrcpynW(gUNCName, PWideChar(WideString(argv[command])), DOKAN_MAX_PATH); + dokanOptions.UNCName := gUNCName; + DbgPrint('UNC Name: %s\n', [gUNCName]); + end; + 'V': begin Inc(command); - lstrcpynW(UNCName, PWideChar(WideString(argv[command])), DOKAN_MAX_PATH); - dokanOptions^.UNCName := UNCName; - DbgPrint('UNC Name: %s\n', [UNCName]); + lstrcpynW(gVolumeName, PWideChar(WideString(argv[command])), DOKAN_MAX_PATH); + DbgPrint('Volume Name: %s\n', [gVolumeName]); end; 'P': begin g_ImpersonateCallerUser := True; end; 'I': begin Inc(command); - dokanOptions^.Timeout := StrToInt(argv[command]); + dokanOptions.Timeout := StrToInt(argv[command]); end; 'A': begin Inc(command); - dokanOptions^.AllocationUnitSize := StrToInt(argv[command]); + dokanOptions.AllocationUnitSize := StrToInt(argv[command]); end; 'K': begin Inc(command); - dokanOptions^.SectorSize := StrToInt(argv[command]); - end; - 'R': begin - Inc(command); - lstrcpynW(RootDirectory, PWideChar(WideString(argv[command])), DOKAN_MAX_PATH); - DbgPrint('RootDirectory: %s\n', [RootDirectory]); + dokanOptions.SectorSize := StrToInt(argv[command]); end; else Writeln(ErrOutput, 'unknown command: ', argv[command]); - Dispose(dokanOperations); - Dispose(dokanOptions); Result := EXIT_FAILURE; Exit; end; Inc(command); end; - if (UNCName <> '') and - (dokanOptions^.Options and DOKAN_OPTION_NETWORK = 0) then begin + if (gUNCName <> '') and + (dokanOptions.Options and DOKAN_OPTION_NETWORK = 0) then begin Writeln( ErrOutput, ' Warning: UNC provider name should be set on network drive only.'); end; - if (dokanOptions^.Options and DOKAN_OPTION_NETWORK <> 0) and - (dokanOptions^.Options and DOKAN_OPTION_MOUNT_MANAGER <> 0) then begin + if (dokanOptions.Options and DOKAN_OPTION_NETWORK <> 0) and + (dokanOptions.Options and DOKAN_OPTION_MOUNT_MANAGER <> 0) then begin Writeln(ErrOutput, 'Mount manager cannot be used on network drive.'); - Dispose(dokanOperations); - Dispose(dokanOptions); Result := EXIT_FAILURE; Exit; end; - if (dokanOptions^.Options and DOKAN_OPTION_MOUNT_MANAGER = 0) and - (MountPoint = '') then begin + if (dokanOptions.Options and DOKAN_OPTION_MOUNT_MANAGER = 0) and + (gMountPoint = '') then begin Writeln(ErrOutput, 'Mount Point required.'); - Dispose(dokanOperations); - Dispose(dokanOptions); Result := EXIT_FAILURE; Exit; end; - if (dokanOptions^.Options and DOKAN_OPTION_MOUNT_MANAGER <> 0) and - (dokanOptions^.Options and DOKAN_OPTION_CURRENT_SESSION <> 0) then begin + if (dokanOptions.Options and DOKAN_OPTION_MOUNT_MANAGER <> 0) and + (dokanOptions.Options and DOKAN_OPTION_CURRENT_SESSION <> 0) then begin Writeln(ErrOutput, 'Mount Manager always mount the drive for all user sessions.'); - Dispose(dokanOperations); - Dispose(dokanOptions); Result := EXIT_FAILURE; Exit; end; @@ -1860,42 +1859,44 @@ begin end; if (g_DebugMode) then begin - dokanOptions^.Options := dokanOptions^.Options or DOKAN_OPTION_DEBUG; + dokanOptions.Options := dokanOptions.Options or DOKAN_OPTION_DEBUG; end; if (g_UseStdErr) then begin - dokanOptions^.Options := dokanOptions^.Options or DOKAN_OPTION_STDERR; - end; - - dokanOptions^.Options := dokanOptions^.Options or DOKAN_OPTION_ALT_STREAM; - - ZeroMemory(dokanOperations, SizeOf(DOKAN_OPERATIONS)); - dokanOperations^.ZwCreateFile := MirrorCreateFile; - dokanOperations^.Cleanup := MirrorCleanup; - dokanOperations^.CloseFile := MirrorCloseFile; - dokanOperations^.ReadFile := MirrorReadFile; - dokanOperations^.WriteFile := MirrorWriteFile; - dokanOperations^.FlushFileBuffers := MirrorFlushFileBuffers; - dokanOperations^.GetFileInformation := MirrorGetFileInformation; - dokanOperations^.FindFiles := MirrorFindFiles; - dokanOperations^.FindFilesWithPattern := nil; - dokanOperations^.SetFileAttributes := MirrorSetFileAttributes; - dokanOperations^.SetFileTime := MirrorSetFileTime; - dokanOperations^.DeleteFile := MirrorDeleteFile; - dokanOperations^.DeleteDirectory := MirrorDeleteDirectory; - dokanOperations^.MoveFile := MirrorMoveFile; - dokanOperations^.SetEndOfFile := MirrorSetEndOfFile; - dokanOperations^.SetAllocationSize := MirrorSetAllocationSize; - dokanOperations^.LockFile := MirrorLockFile; - dokanOperations^.UnlockFile := MirrorUnlockFile; - dokanOperations^.GetFileSecurity := MirrorGetFileSecurity; - dokanOperations^.SetFileSecurity := MirrorSetFileSecurity; - dokanOperations^.GetDiskFreeSpace := nil; // MirrorDokanGetDiskFreeSpace; - dokanOperations^.GetVolumeInformation := MirrorGetVolumeInformation; - dokanOperations^.Unmounted := MirrorUnmounted; - dokanOperations^.FindStreams := MirrorFindStreams; - dokanOperations^.Mounted := MirrorMounted; - - status := DokanMain(dokanOptions^, dokanOperations^); + dokanOptions.Options := dokanOptions.Options or DOKAN_OPTION_STDERR; + end; + + dokanOptions.Options := dokanOptions.Options or DOKAN_OPTION_ALT_STREAM; + + ZeroMemory(@dokanOperations, SizeOf(DOKAN_OPERATIONS)); + dokanOperations.ZwCreateFile := MirrorCreateFile; + dokanOperations.Cleanup := MirrorCleanup; + dokanOperations.CloseFile := MirrorCloseFile; + dokanOperations.ReadFile := MirrorReadFile; + dokanOperations.WriteFile := MirrorWriteFile; + dokanOperations.FlushFileBuffers := MirrorFlushFileBuffers; + dokanOperations.GetFileInformation := MirrorGetFileInformation; + dokanOperations.FindFiles := MirrorFindFiles; + dokanOperations.FindFilesWithPattern := nil; + dokanOperations.SetFileAttributes := MirrorSetFileAttributes; + dokanOperations.SetFileTime := MirrorSetFileTime; + dokanOperations.DeleteFile := MirrorDeleteFile; + dokanOperations.DeleteDirectory := MirrorDeleteDirectory; + dokanOperations.MoveFile := MirrorMoveFile; + dokanOperations.SetEndOfFile := MirrorSetEndOfFile; + dokanOperations.SetAllocationSize := MirrorSetAllocationSize; + dokanOperations.LockFile := MirrorLockFile; + dokanOperations.UnlockFile := MirrorUnlockFile; + dokanOperations.GetFileSecurity := MirrorGetFileSecurity; + dokanOperations.SetFileSecurity := MirrorSetFileSecurity; + dokanOperations.GetDiskFreeSpace := MirrorDokanGetDiskFreeSpace; + dokanOperations.GetVolumeInformation := MirrorGetVolumeInformation; + dokanOperations.Unmounted := MirrorUnmounted; + dokanOperations.FindStreams := MirrorFindStreams; + dokanOperations.Mounted := MirrorMounted; + + DokanInit; + status := DokanMain(@dokanOptions, @dokanOperations); + DokanShutdown; case (status) of DOKAN_SUCCESS: Writeln(ErrOutput, 'Success'); @@ -1917,8 +1918,6 @@ begin Writeln(ErrOutput, 'Unknown error: ', status); end; - Dispose(dokanOptions); - Dispose(dokanOperations); Result := EXIT_SUCCESS; Exit; end; @@ -1930,9 +1929,10 @@ var begin IsMultiThread := True; - lstrcpyW(RootDirectory, 'C:'); - lstrcpyW(MountPoint, 'M:\'); - lstrcpyW(UNCName, ''); + lstrcpyW(gRootDirectory, 'C:'); + lstrcpyW(gMountPoint, 'M:\'); + lstrcpyW(gUNCName, ''); + lstrcpyW(gVolumeName, 'DOKAN'); argc := 1 + ParamCount(); SetLength(argv, argc); diff --git a/Samples/Mirror/Mirror.dproj b/Samples/Mirror/Mirror.dproj index 574869b..81a8247 100644 --- a/Samples/Mirror/Mirror.dproj +++ b/Samples/Mirror/Mirror.dproj @@ -7,12 +7,22 @@ 3 Console None - 19.1 + 19.5 Win64 true + + true + Base + true + + + true + Base + true + true Base @@ -28,6 +38,24 @@ Base true + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + true Cfg_2 @@ -51,27 +79,43 @@ $(BDS)\bin\delphi_PROJECTICON.ico $(BDS)\bin\delphi_PROJECTICNS.icns + + CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers + Debug + + + CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers + Debug + System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 1033 CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) - /R d:\test /L k /D /S System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) 1033 CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) - /R d:\test /L k /D /S true DEBUG;$(DCC_Define) false + + true + + + true + + + /R d:\test /L k:\ /D /S /O + 1033 None CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName) + /R d:\test /L k:\ /D /S /O @@ -79,13 +123,13 @@ + + Base + Cfg_2 Base - - Base - Delphi.Personality.12 @@ -143,6 +187,8 @@ + False + False True True diff --git a/Samples/Mirror/Mirror.res b/Samples/Mirror/Mirror.res index 5e585f0..4219520 100644 Binary files a/Samples/Mirror/Mirror.res and b/Samples/Mirror/Mirror.res differ diff --git a/Tools/enableDokanDebugMode.bat b/Tools/enableDokanDebugMode.bat new file mode 100644 index 0000000..dbcacc2 --- /dev/null +++ b/Tools/enableDokanDebugMode.bat @@ -0,0 +1,2 @@ +"C:\Program Files\Dokan\Dokan Library-2.0.6\dokanctl.exe" /d 7 +pause \ No newline at end of file