From 2a54e089d528140df2b1944402454d66574b3965 Mon Sep 17 00:00:00 2001 From: Sven Harazim Date: Thu, 16 Mar 2023 14:44:26 +0100 Subject: [PATCH 1/6] new dokan.h header translation --- Dokan.pas | 142 ++++++++++++++++++++++++------------ DokanWin.pas | 11 ++- LICENSE.md | 2 +- README.md | 8 +- Samples/Mirror/Mirror.dpr | 139 +++++++++++++++++++---------------- Samples/Mirror/Mirror.dproj | 58 +++++++++++++-- Samples/Mirror/Mirror.res | Bin 109732 -> 109940 bytes 7 files changed, 239 insertions(+), 121 deletions(-) diff --git a/Dokan.pas b/Dokan.pas index 24836cb..1730196 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 - 2022 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 @@ -39,12 +39,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 +56,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 +69,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: BOOL; //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 +98,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 WChar;//Optional Volume Security descriptor. See InitializeSecurityDescriptor end; DOKAN_OPTIONS = _DOKAN_OPTIONS; PDOKAN_OPTIONS = ^_DOKAN_OPTIONS; @@ -111,6 +111,7 @@ _DOKAN_FILE_INFO = record Context: ULONG64; DokanContext: ULONG64; DokanOptions: PDOKAN_OPTIONS; + ProcessingContext : PVOID; ProcessId: ULONG; IsDirectory: ByteBool; DeleteOnClose: ByteBool; @@ -124,6 +125,12 @@ _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 ( @@ -132,11 +139,11 @@ _DOKAN_FILE_INFO = record ): 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; + var FindStreamContext: PVOID + ): BOOL; stdcall; _DOKAN_ACCESS_STATE = record SecurityEvaluated: ByteBool; @@ -304,6 +311,7 @@ _DOKAN_IO_SECURITY_CONTEXT = record ): NTSTATUS; stdcall; TDokanMounted = function ( + var MountPoint: LPCWSTR; var DokanFileInfo: DOKAN_FILE_INFO ): NTSTATUS; stdcall; @@ -331,6 +339,7 @@ _DOKAN_IO_SECURITY_CONTEXT = record TDokanFindStreams = function ( FileName: LPCWSTR; FillFindStreamData: TDokanFillFindStreamData; + var FindStreamContext : PVOID; var DokanFileInfo: DOKAN_FILE_INFO ): NTSTATUS; stdcall; @@ -366,17 +375,19 @@ _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; @@ -390,9 +401,24 @@ _DOKAN_CONTROL = record {$ifdef DOKAN_EXPLICIT_LINK} + +DokanDebugMode 0x0000000180004d30 0x00004d30 3 (0x3) dokan2.dll C:\Windows\System32\dokan2.dll Exported Function +DokanNetworkProviderInstall 0x000000018000d2c0 0x0000d2c0 11 (0xb) dokan2.dll C:\Windows\System32\dokan2.dll Exported Function +DokanNetworkProviderUninstall 0x000000018000d540 0x0000d540 12 (0xc) dokan2.dll C:\Windows\System32\dokan2.dll Exported Function +DokanServiceDelete 0x000000018000d170 0x0000d170 23 (0x17) dokan2.dll C:\Windows\System32\dokan2.dll Exported Function +DokanServiceInstall 0x000000018000d030 0x0000d030 24 (0x18) dokan2.dll C:\Windows\System32\dokan2.dll Exported Function +DokanSetDebugMode 0x0000000180008000 0x00008000 25 (0x19) dokan2.dll C:\Windows\System32\dokan2.dll Exported Function +DokanUseStdErr 0x0000000180004d20 0x00004d20 28 (0x1c) dokan2.dll C:\Windows\System32\dokan2.dll Exported Function + var DokanLibHandle: HMODULE = 0; + DokanInit: procedure; stdcall = nil; + DokanShutdown procedure; stdcall = nil; DokanMain: function (var Options: DOKAN_OPTIONS; var 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; @@ -405,12 +431,12 @@ _DOKAN_CONTROL = record 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 (FilePath : LPCWSTR; BOOL IsDirectory) : 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,7 +444,13 @@ 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: DOKAN_OPTIONS; Operations: DOKAN_OPERATIONS): Integer; stdcall; +function DokanCreateFileSystem(DokanOptions : DOKAN_OPTIONS; DokanOperations : DOKAN_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; @@ -426,16 +458,16 @@ 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 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 +498,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 +532,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 +563,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..c8194d7 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 - 2022 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..9ab961f 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 - 2022 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 @@ -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); @@ -1491,7 +1491,7 @@ var begin fsFlags := 0; - lstrcpynW(VolumeNameBuffer, 'DOKAN', VolumeNameSize); + lstrcpynW(VolumeNameBuffer, gVolumeName, VolumeNameSize); if (@VolumeSerialNumber <> nil) then VolumeSerialNumber := $19831116; if (@MaximumComponentLength <> nil) then @@ -1504,7 +1504,7 @@ begin 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; @@ -1544,8 +1544,6 @@ 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 @@ -1557,7 +1555,6 @@ begin 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; + var FindStreamContext: PVOID;var DokanFileInfo: DOKAN_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,9 +1640,9 @@ begin Result := STATUS_SUCCESS; Exit; end; -function MirrorMounted(var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; +function MirrorMounted(var MountPoint: LPCWSTR; var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; begin - DbgPrint('Mounted\n'); + DbgPrint('Mounted as %s\n',[MountPoint]); Result := STATUS_SUCCESS; Exit; end; @@ -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' + @@ -1718,19 +1729,22 @@ begin ZeroMemory(dokanOptions, SizeOf(DOKAN_OPTIONS)); dokanOptions^.Version := DOKAN_VERSION; - dokanOptions^.ThreadCount := 0; // use default 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,9 +1752,6 @@ 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; end; @@ -1756,24 +1767,27 @@ begin '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; - end; 'X': begin 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; 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; @@ -1790,11 +1804,6 @@ 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]); - end; else Writeln(ErrOutput, 'unknown command: ', argv[command]); Dispose(dokanOperations); @@ -1804,7 +1813,7 @@ begin Inc(command); end; - if (UNCName <> '') and + if (gUNCName <> '') and (dokanOptions^.Options and DOKAN_OPTION_NETWORK = 0) then begin Writeln( ErrOutput, @@ -1820,7 +1829,7 @@ begin end; if (dokanOptions^.Options and DOKAN_OPTION_MOUNT_MANAGER = 0) and - (MountPoint = '') then begin + (gMountPoint = '') then begin Writeln(ErrOutput, 'Mount Point required.'); Dispose(dokanOperations); Dispose(dokanOptions); @@ -1889,13 +1898,15 @@ begin dokanOperations^.UnlockFile := MirrorUnlockFile; dokanOperations^.GetFileSecurity := MirrorGetFileSecurity; dokanOperations^.SetFileSecurity := MirrorSetFileSecurity; - dokanOperations^.GetDiskFreeSpace := nil; // MirrorDokanGetDiskFreeSpace; + 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'); @@ -1919,6 +1930,7 @@ begin Dispose(dokanOptions); Dispose(dokanOperations); + Readln; Result := EXIT_SUCCESS; Exit; end; @@ -1930,9 +1942,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..7ff2cc6 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 5e585f0053e689d4915f18a6428ff4827b6b199b..42195207a18f6be955a2e840dd42e6211bcd92c1 100644 GIT binary patch literal 109940 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
8{ANffi>JY8gRp~PmZm^D|e2D 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 literal 109732 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

B-#XG%bh)N?gxawfA-%;B>1=SY0-I@Lc% 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 From 145fa2001dbb60533b3815d45281489a51c6d870 Mon Sep 17 00:00:00 2001 From: Sven Harazim Date: Fri, 17 Mar 2023 12:52:25 +0100 Subject: [PATCH 2/6] change type of VolumeSecurityDescriptor to AnsiChar --- Dokan.pas | 27 ++++++++++----------------- Samples/Mirror/Mirror.dpr | 14 ++++++++++++-- Samples/Mirror/Mirror.dproj | 2 +- Tools/enableDokanDebugMode.bat | 2 ++ 4 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 Tools/enableDokanDebugMode.bat diff --git a/Dokan.pas b/Dokan.pas index 1730196..39273b9 100644 --- a/Dokan.pas +++ b/Dokan.pas @@ -26,6 +26,8 @@ unit Dokan; +{.$DEFINE DOKAN_EXPLICIT_LINK} + {$ifdef FPC} {$mode delphi} {$endif FPC} @@ -42,7 +44,7 @@ interface DokanLibrary = 'dokan2.dll'; //The current Dokan version (200 means ver 2.0.0). - DOKAN_VERSION = 206; + DOKAN_VERSION = 200; //Minimum Dokan version (ver 2.0.0) accepted DOKAN_MINIMUM_COMPATIBLE_VERSION = 200; @@ -99,7 +101,7 @@ _DOKAN_OPTIONS = record 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 WChar;//Optional Volume Security descriptor. See InitializeSecurityDescriptor + 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; @@ -401,20 +403,11 @@ _DOKAN_MOUNT_POINT_INFO = record {$ifdef DOKAN_EXPLICIT_LINK} - -DokanDebugMode 0x0000000180004d30 0x00004d30 3 (0x3) dokan2.dll C:\Windows\System32\dokan2.dll Exported Function -DokanNetworkProviderInstall 0x000000018000d2c0 0x0000d2c0 11 (0xb) dokan2.dll C:\Windows\System32\dokan2.dll Exported Function -DokanNetworkProviderUninstall 0x000000018000d540 0x0000d540 12 (0xc) dokan2.dll C:\Windows\System32\dokan2.dll Exported Function -DokanServiceDelete 0x000000018000d170 0x0000d170 23 (0x17) dokan2.dll C:\Windows\System32\dokan2.dll Exported Function -DokanServiceInstall 0x000000018000d030 0x0000d030 24 (0x18) dokan2.dll C:\Windows\System32\dokan2.dll Exported Function -DokanSetDebugMode 0x0000000180008000 0x00008000 25 (0x19) dokan2.dll C:\Windows\System32\dokan2.dll Exported Function -DokanUseStdErr 0x0000000180004d20 0x00004d20 28 (0x1c) dokan2.dll C:\Windows\System32\dokan2.dll Exported Function - var DokanLibHandle: HMODULE = 0; DokanInit: procedure; stdcall = nil; - DokanShutdown procedure; stdcall = nil; - DokanMain: function (var Options: DOKAN_OPTIONS; var Operations: DOKAN_OPERATIONS): Integer; 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; @@ -426,13 +419,13 @@ _DOKAN_MOUNT_POINT_INFO = record 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; + 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; stdcall = nil; - DokanNotifyDelete: function (FilePath : LPCWSTR; BOOL IsDirectory) : 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; @@ -532,7 +525,7 @@ procedure DokanFree(); if DokanLibHandle = 0 then Exit; - DokanInit := nil + DokanInit := nil; DokanShutdown := nil; DokanMain := nil; DokanCreateFileSystem := nil; diff --git a/Samples/Mirror/Mirror.dpr b/Samples/Mirror/Mirror.dpr index 9ab961f..1fa5039 100644 --- a/Samples/Mirror/Mirror.dpr +++ b/Samples/Mirror/Mirror.dpr @@ -161,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; @@ -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', @@ -1729,6 +1729,16 @@ begin 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 diff --git a/Samples/Mirror/Mirror.dproj b/Samples/Mirror/Mirror.dproj index 7ff2cc6..08851ef 100644 --- a/Samples/Mirror/Mirror.dproj +++ b/Samples/Mirror/Mirror.dproj @@ -115,7 +115,7 @@ 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 + /R d:\test /L k:\ /D /S 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 From 724a3935a8c6ec7d5f309a3104c0d59256bb0235 Mon Sep 17 00:00:00 2001 From: Conrad Vermeulen Date: Fri, 17 Mar 2023 13:04:32 +0000 Subject: [PATCH 3/6] DokanMain and DokanCreateFileSystem require Options and Operations to be pointers. --- Dokan.pas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dokan.pas b/Dokan.pas index 39273b9..e152844 100644 --- a/Dokan.pas +++ b/Dokan.pas @@ -439,8 +439,8 @@ procedure DokanFree(); procedure DokanInit; stdcall; procedure DokanShutdown; stdcall; -function DokanMain(Options: DOKAN_OPTIONS; Operations: DOKAN_OPERATIONS): Integer; stdcall; -function DokanCreateFileSystem(DokanOptions : DOKAN_OPTIONS; DokanOperations : DOKAN_OPERATIONS; var DokanInstance : DOKAN_HANDLE) : Integer; stdcall; +function DokanMain(var Options: DOKAN_OPTIONS; var Operations: DOKAN_OPERATIONS): Integer; stdcall; +function DokanCreateFileSystem(var DokanOptions : DOKAN_OPTIONS; var DokanOperations : DOKAN_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; From 5edb71ecec7ccf3c74e90122435d801099edac40 Mon Sep 17 00:00:00 2001 From: Conrad Vermeulen Date: Fri, 17 Mar 2023 13:10:21 +0000 Subject: [PATCH 4/6] Bump DOKAN_VERSION --- Dokan.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dokan.pas b/Dokan.pas index e152844..aa77386 100644 --- a/Dokan.pas +++ b/Dokan.pas @@ -44,7 +44,7 @@ interface DokanLibrary = 'dokan2.dll'; //The current Dokan version (200 means ver 2.0.0). - DOKAN_VERSION = 200; + DOKAN_VERSION = 206; //Minimum Dokan version (ver 2.0.0) accepted DOKAN_MINIMUM_COMPATIBLE_VERSION = 200; From 4570344a07c5f57176997a2694964abae9aaff91 Mon Sep 17 00:00:00 2001 From: Sven Harazim Date: Sat, 18 Mar 2023 06:50:53 +0100 Subject: [PATCH 5/6] first working version --- Dokan.pas | 103 +++++---- Samples/Mirror/Mirror.dpr | 415 +++++++++++++++++------------------- Samples/Mirror/Mirror.dproj | 2 +- 3 files changed, 248 insertions(+), 272 deletions(-) diff --git a/Dokan.pas b/Dokan.pas index aa77386..a6dd203 100644 --- a/Dokan.pas +++ b/Dokan.pas @@ -92,7 +92,7 @@ interface //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). - SingleThread: BOOL; //Only use a single thread to process events. This is highly not recommended as can easily create a bottleneck. + 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. @@ -136,15 +136,15 @@ _DOKAN_FILE_INFO = record //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 FALSE if the buffer is full, otherwise TRUE TDokanFillFindStreamData = function ( - var FindStreamData: WIN32_FIND_STREAM_DATA; - var FindStreamContext: PVOID + FindStreamData: PWIN32_FIND_STREAM_DATA; + FindStreamContext: PVOID ): BOOL; stdcall; _DOKAN_ACCESS_STATE = record @@ -176,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 ( @@ -248,101 +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 MountPoint: LPCWSTR; - 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; + var 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 FindStreamContext : PVOID; - var DokanFileInfo: DOKAN_FILE_INFO + FindStreamContext : PVOID; + DokanFileInfo: PDOKAN_FILE_INFO ): NTSTATUS; stdcall; _DOKAN_OPERATIONS = record @@ -382,7 +382,6 @@ _DOKAN_MOUNT_POINT_INFO = record 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; @@ -417,8 +416,8 @@ _DOKAN_MOUNT_POINT_INFO = record 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; + 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, @@ -439,8 +438,8 @@ procedure DokanFree(); procedure DokanInit; stdcall; procedure DokanShutdown; stdcall; -function DokanMain(var Options: DOKAN_OPTIONS; var Operations: DOKAN_OPERATIONS): Integer; stdcall; -function DokanCreateFileSystem(var DokanOptions : DOKAN_OPTIONS; var DokanOperations : DOKAN_OPERATIONS; var DokanInstance : DOKAN_HANDLE) : Integer; 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; @@ -449,8 +448,8 @@ 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 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, diff --git a/Samples/Mirror/Mirror.dpr b/Samples/Mirror/Mirror.dpr index 1fa5039..991156f 100644 --- a/Samples/Mirror/Mirror.dpr +++ b/Samples/Mirror/Mirror.dpr @@ -150,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 @@ -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; @@ -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; var 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,13 +1465,13 @@ 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; @@ -1481,10 +1480,10 @@ begin 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; @@ -1492,16 +1491,16 @@ begin fsFlags := 0; lstrcpynW(VolumeNameBuffer, gVolumeName, VolumeNameSize); - if (@VolumeSerialNumber <> nil) then - VolumeSerialNumber := $19831116; - if (@MaximumComponentLength <> nil) then - MaximumComponentLength := 255; - if (@FileSystemFlags <> nil) then + 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] := gRootDirectory[0]; @@ -1509,25 +1508,25 @@ begin 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 @@ -1545,13 +1544,13 @@ begin end; 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; @@ -1583,7 +1582,7 @@ NTSYSCALLAPI NTSTATUS NTAPI NtQueryInformationFile( *) function MirrorFindStreams(FileName: LPCWSTR; FillFindStreamData: TDokanFillFindStreamData; - var FindStreamContext: PVOID;var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; + FindStreamContext: PVOID;DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var filePath: WCHAR_PATH; hFind: THandle; @@ -1606,12 +1605,12 @@ begin Result := DokanNtStatusFromWin32(error); Exit; end; - bufferFull := FillFindStreamData(findData, FindStreamContext); + bufferFull := FillFindStreamData(@findData, FindStreamContext); if bufferFull then begin Inc(count); while (FindNextStreamW(hFind, @findData) <> False) do begin - bufferFull := FillFindStreamData(findData, FindStreamContext); + bufferFull := FillFindStreamData(@findData, FindStreamContext); if not bufferFull then break; Inc(count); @@ -1640,13 +1639,13 @@ begin Result := STATUS_SUCCESS; Exit; end; -function MirrorMounted(var MountPoint: LPCWSTR; var DokanFileInfo: DOKAN_FILE_INFO): NTSTATUS; stdcall; +function MirrorMounted(MountPoint: LPCWSTR; DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; begin 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; @@ -1703,23 +1702,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; @@ -1727,18 +1714,18 @@ begin g_UseStdErr := False; g_CaseSensitive := False; - 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 + 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 @@ -1751,10 +1738,10 @@ begin 'L': begin Inc(command); lstrcpynW(gMountPoint, PWideChar(WideString(argv[command])), DOKAN_MAX_PATH); - dokanOptions^.MountPoint := gMountPoint; + dokanOptions.MountPoint := gMountPoint; end; 'T': begin - dokanOptions^.SingleThread := true; + dokanOptions.SingleThread := true; end; 'D': begin g_DebugMode := True; @@ -1763,35 +1750,35 @@ begin g_UseStdErr := True; 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; + 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; + 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; 'N': begin Inc(command); - dokanOptions^.Options := dokanOptions^.Options or DOKAN_OPTION_NETWORK; + dokanOptions.Options := dokanOptions.Options or DOKAN_OPTION_NETWORK; lstrcpynW(gUNCName, PWideChar(WideString(argv[command])), DOKAN_MAX_PATH); - dokanOptions^.UNCName := gUNCName; + dokanOptions.UNCName := gUNCName; DbgPrint('UNC Name: %s\n', [gUNCName]); end; 'V': begin @@ -1804,54 +1791,46 @@ begin 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]); + 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 (gUNCName <> '') and - (dokanOptions^.Options and DOKAN_OPTION_NETWORK = 0) then begin + (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 + 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; @@ -1879,43 +1858,43 @@ 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 := MirrorDokanGetDiskFreeSpace; - dokanOperations^.GetVolumeInformation := MirrorGetVolumeInformation; - dokanOperations^.Unmounted := MirrorUnmounted; - dokanOperations^.FindStreams := MirrorFindStreams; - dokanOperations^.Mounted := MirrorMounted; + 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^); + status := DokanMain(@dokanOptions, @dokanOperations); DokanShutdown; case (status) of DOKAN_SUCCESS: @@ -1938,8 +1917,6 @@ begin Writeln(ErrOutput, 'Unknown error: ', status); end; - Dispose(dokanOptions); - Dispose(dokanOperations); Readln; Result := EXIT_SUCCESS; Exit; end; diff --git a/Samples/Mirror/Mirror.dproj b/Samples/Mirror/Mirror.dproj index 08851ef..81a8247 100644 --- a/Samples/Mirror/Mirror.dproj +++ b/Samples/Mirror/Mirror.dproj @@ -115,7 +115,7 @@ 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 + /R d:\test /L k:\ /D /S /O From fd4f3dc9d520ba0156b08b771f535d719f923526 Mon Sep 17 00:00:00 2001 From: Sven Harazim Date: Tue, 4 Apr 2023 14:24:24 +0200 Subject: [PATCH 6/6] MirrorSetFileSecurity fixed --- Dokan.pas | 4 ++-- DokanWin.pas | 2 +- Samples/Mirror/Mirror.dpr | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Dokan.pas b/Dokan.pas index a6dd203..2558613 100644 --- a/Dokan.pas +++ b/Dokan.pas @@ -1,7 +1,7 @@ (* 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 - 2022 Sven Harazim + Copyright (C) 2019 - 2023 Sven Harazim Dokan : user-mode file system library for Windows @@ -332,7 +332,7 @@ _DOKAN_IO_SECURITY_CONTEXT = record TDokanSetFileSecurity = function ( FileName: LPCWSTR; - var SecurityInformation: PSECURITY_INFORMATION; + SecurityInformation: PSECURITY_INFORMATION; SecurityDescriptor: PSECURITY_DESCRIPTOR; BufferLength: ULONG; DokanFileInfo: PDOKAN_FILE_INFO diff --git a/DokanWin.pas b/DokanWin.pas index c8194d7..a35e94e 100644 --- a/DokanWin.pas +++ b/DokanWin.pas @@ -1,7 +1,7 @@ (* 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 - 2022 Sven Harazim + Copyright (C) 2019 - 2023 Sven Harazim Dokan : user-mode file system library for Windows diff --git a/Samples/Mirror/Mirror.dpr b/Samples/Mirror/Mirror.dpr index 991156f..9854cda 100644 --- a/Samples/Mirror/Mirror.dpr +++ b/Samples/Mirror/Mirror.dpr @@ -1,7 +1,7 @@ (* 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 - 2022 Sven Harazim + Copyright (C) 2019 - 2023 Sven Harazim Dokan : user-mode file system library for Windows @@ -1453,7 +1453,7 @@ begin end; function MirrorSetFileSecurity( - FileName: LPCWSTR; var SecurityInformation: PSECURITY_INFORMATION; + FileName: LPCWSTR; SecurityInformation: PSECURITY_INFORMATION; SecurityDescriptor: PSECURITY_DESCRIPTOR; SecurityDescriptorLength: ULONG; DokanFileInfo: PDOKAN_FILE_INFO): NTSTATUS; stdcall; var @@ -1476,6 +1476,7 @@ begin DbgPrint(' SetUserObjectSecurity error: %d\n', [error]); Result := DokanNtStatusFromWin32(error); Exit; end; + Result := STATUS_SUCCESS; Exit; end; @@ -1917,7 +1918,6 @@ begin Writeln(ErrOutput, 'Unknown error: ', status); end; - Readln; Result := EXIT_SUCCESS; Exit; end;