From 325d14ebc606ec17aead66c68e41df1b5f2f1b68 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 27 May 2020 22:07:37 +0200 Subject: [PATCH 1/9] Create interface to specify the calling convention of callbacks into the dokan library and let the filesystem operations extend it. --- .../dev/dokan/dokan_java/DokanCallback.java | 9 +++ .../dev/dokan/dokan_java/DokanOperations.java | 55 ++++++++++--------- 2 files changed, 37 insertions(+), 27 deletions(-) create mode 100644 src/main/java/dev/dokan/dokan_java/DokanCallback.java diff --git a/src/main/java/dev/dokan/dokan_java/DokanCallback.java b/src/main/java/dev/dokan/dokan_java/DokanCallback.java new file mode 100644 index 0000000..bc628a4 --- /dev/null +++ b/src/main/java/dev/dokan/dokan_java/DokanCallback.java @@ -0,0 +1,9 @@ +package dev.dokan.dokan_java; + + +import com.sun.jna.win32.StdCallLibrary; + + +public interface DokanCallback extends StdCallLibrary.StdCallCallback { + +} diff --git a/src/main/java/dev/dokan/dokan_java/DokanOperations.java b/src/main/java/dev/dokan/dokan_java/DokanOperations.java index 933cec3..345bd52 100644 --- a/src/main/java/dev/dokan/dokan_java/DokanOperations.java +++ b/src/main/java/dev/dokan/dokan_java/DokanOperations.java @@ -3,6 +3,7 @@ import java.util.Arrays; import java.util.List; +import com.sun.jna.win32.StdCallLibrary; import dev.dokan.dokan_java.constants.dokany.MountOption; import dev.dokan.dokan_java.constants.microsoft.NtStatuses; import dev.dokan.dokan_java.constants.microsoft.FileSystemFlag; @@ -103,7 +104,7 @@ protected List getFieldOrder() { * @see MSDN for more information about the parameters of this callback. */ @FunctionalInterface - interface ZwCreateFile extends Callback { + interface ZwCreateFile extends DokanCallback { /** * @param rawPath Path requested by the Kernel on the File System. @@ -133,7 +134,7 @@ long callback( * Cleanup is requested before @{link {@link DokanOperations#CloseFile} is called. */ @FunctionalInterface - interface Cleanup extends Callback { + interface Cleanup extends DokanCallback { /** * @param rawPath @@ -151,7 +152,7 @@ void callback( * CloseFile is requested after {@link DokanOperations.Cleanup} is called. Anything remaining in {@link DokanFileInfo#Context} has to be cleared before return. */ @FunctionalInterface - interface CloseFile extends Callback { + interface CloseFile extends DokanCallback { /** * @param rawPath @@ -165,7 +166,7 @@ void callback( /** * ReadFile callback on the file previously opened in {@link DokanOperations.ZwCreateFile}. It can be called by different thread at the same time, therefore the read has to be thread safe. */ - interface ReadFile extends Callback { + interface ReadFile extends DokanCallback { /** * @param rawPath @@ -189,7 +190,7 @@ long callback( * WriteFile callback on the file previously opened in {@link DokanOperations.ZwCreateFile} It can be called by different thread at the same time, therefore the write/context has to be thread safe. */ @FunctionalInterface - interface WriteFile extends Callback { + interface WriteFile extends DokanCallback { /** * @param rawPath @@ -214,7 +215,7 @@ long callback( * Clears buffers for this context and causes any buffered data to be written to the file. */ @FunctionalInterface - interface FlushFileBuffers extends Callback { + interface FlushFileBuffers extends DokanCallback { /** * @param rawPath @@ -230,7 +231,7 @@ long callback( * Get specific informations on a file. */ @FunctionalInterface - interface GetFileInformation extends Callback { + interface GetFileInformation extends DokanCallback { /** * @param fileName @@ -248,7 +249,7 @@ long callback( * List all files in the path requested. */ @FunctionalInterface - interface FindFiles extends Callback { + interface FindFiles extends DokanCallback { /** * @param rawPath @@ -266,7 +267,7 @@ long callback( * Same as {@link DokanOperations.FindFiles} but with a search pattern to filter the result. */ @FunctionalInterface - interface FindFilesWithPattern extends Callback { + interface FindFilesWithPattern extends DokanCallback { /** * @param fileName @@ -286,7 +287,7 @@ long callback( * Set file attributes on a specific file. */ @FunctionalInterface - interface SetFileAttributes extends Callback { + interface SetFileAttributes extends DokanCallback { /** * @param rawPath @@ -304,7 +305,7 @@ long callback( * Set file times on a specific file. */ @FunctionalInterface - interface SetFileTime extends Callback { + interface SetFileTime extends DokanCallback { /** * @param rawPath path to file or directory @@ -336,7 +337,7 @@ long callback( * @see {@link DokanOperations.DeleteDirectory} */ @FunctionalInterface - interface DeleteFile extends Callback { + interface DeleteFile extends DokanCallback { /** * @param rawPath @@ -354,7 +355,7 @@ long callback( * @see {@link DokanOperations.DeleteFile} for more specifics. */ @FunctionalInterface - interface DeleteDirectory extends Callback { + interface DeleteDirectory extends DokanCallback { /** * @param rawPath @@ -370,7 +371,7 @@ long callback( * Move a file or directory to a new location. */ @FunctionalInterface - interface MoveFile extends Callback { + interface MoveFile extends DokanCallback { /** * @param rawPath @@ -390,7 +391,7 @@ long callback( * SetEndOfFile is used to truncate or extend a file (physical file size). */ @FunctionalInterface - interface SetEndOfFile extends Callback { + interface SetEndOfFile extends DokanCallback { /** * @param rawPath @@ -408,7 +409,7 @@ long callback( * SetAllocationSize is used to truncate or extend a file. */ @FunctionalInterface - interface SetAllocationSize extends Callback { + interface SetAllocationSize extends DokanCallback { /** * @param rawPath @@ -426,7 +427,7 @@ long callback( * Lock file at a specific offset and data length. This is only used if {@link MountOption#FILELOCK_USER_MODE} is enabled. */ @FunctionalInterface - interface LockFile extends Callback { + interface LockFile extends DokanCallback { /** * @param rawPath @@ -446,7 +447,7 @@ long callback( * Unlock file at a specific offset and data length. This is only used if {@link MountOption#FILELOCK_USER_MODE} is enabled. */ @FunctionalInterface - interface UnlockFile extends Callback { + interface UnlockFile extends DokanCallback { /** * @param rawPath @@ -470,7 +471,7 @@ long callback( * DokanOperations.CloseFile} and @{link DokanOperations.Cleanup}). */ @FunctionalInterface - interface GetDiskFreeSpace extends Callback { + interface GetDiskFreeSpace extends DokanCallback { /** * @param freeBytesAvailable @@ -504,7 +505,7 @@ long callback( * */ @FunctionalInterface - interface GetVolumeInformation extends Callback { + interface GetVolumeInformation extends DokanCallback { /** * @param rawVolumeNameBuffer @@ -532,7 +533,7 @@ long callback( * Is called when Dokan succeeded mounting the volume. */ @FunctionalInterface - interface Mounted extends Callback { + interface Mounted extends DokanCallback { long mounted( DokanFileInfo dokanFileInfo); @@ -542,7 +543,7 @@ long mounted( * Is called when Dokan succeeded unmounting the volume. */ @FunctionalInterface - interface Unmounted extends Callback { + interface Unmounted extends DokanCallback { long unmounted( final DokanFileInfo dokanFileInfo); @@ -554,7 +555,7 @@ long unmounted( * Supported since version 0.6.0. You must specify the version in {@link DokanOptions#Version}. */ @FunctionalInterface - interface GetFileSecurity extends Callback { + interface GetFileSecurity extends DokanCallback { /** * @param rawPath @@ -580,7 +581,7 @@ long callback( * Supported since version 0.6.0. You must specify the version in {@link DokanOptions#Version}. */ @FunctionalInterface - interface SetFileSecurity extends Callback { + interface SetFileSecurity extends DokanCallback { /** * @param rawPath @@ -599,7 +600,7 @@ long callback( } @FunctionalInterface - public interface FillWin32FindData extends Callback { + public interface FillWin32FindData extends StdCallLibrary.StdCallCallback { /** * @param rawFillFindData @@ -614,7 +615,7 @@ void fillWin32FindData( * Retrieve all NTFS Streams informations on the file. This is only called if {@link MountOption#ALT_STREAM} is enabled. */ @FunctionalInterface - interface FindStreams extends Callback { + interface FindStreams extends DokanCallback { /** * @param rawPath @@ -633,7 +634,7 @@ long callback( * */ @FunctionalInterface - public interface FillWin32FindStreamData extends Callback { + public interface FillWin32FindStreamData extends StdCallLibrary.StdCallCallback { /** * @param rawFillFindData From 532176b67c29164c0e8f82f46fe70b003903ae24 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 27 May 2020 22:08:35 +0200 Subject: [PATCH 2/9] fix method signature of callbacks related to findFiles/findStreams functions --- .../java/dev/dokan/dokan_java/DokanOperations.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/dev/dokan/dokan_java/DokanOperations.java b/src/main/java/dev/dokan/dokan_java/DokanOperations.java index 345bd52..f6fecc8 100644 --- a/src/main/java/dev/dokan/dokan_java/DokanOperations.java +++ b/src/main/java/dev/dokan/dokan_java/DokanOperations.java @@ -599,14 +599,18 @@ long callback( DokanFileInfo dokanFileInfo); } + /** + * Used to add an entry in FindFiles operation + */ @FunctionalInterface public interface FillWin32FindData extends StdCallLibrary.StdCallCallback { /** * @param rawFillFindData * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@code 1} if buffer is full, otherwise {@code 0} (currently it never returns 1) */ - void fillWin32FindData( + int fillWin32FindData( WIN32_FIND_DATA rawFillFindData, DokanFileInfo dokanFileInfo); } @@ -630,8 +634,7 @@ long callback( } /** - * - * + * TODO */ @FunctionalInterface public interface FillWin32FindStreamData extends StdCallLibrary.StdCallCallback { @@ -639,8 +642,9 @@ public interface FillWin32FindStreamData extends StdCallLibrary.StdCallCallback /** * @param rawFillFindData * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return */ - void callback( + int fillWin32FindStreamData( Win32FindStreamData rawFillFindData, DokanFileInfo dokanFileInfo); } From d5abad8ccc1e966bb61e4273f02faf9d948c5e98 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 27 May 2020 22:09:44 +0200 Subject: [PATCH 3/9] reformat DokanOperations --- .../dev/dokan/dokan_java/DokanOperations.java | 1431 +++++++++-------- 1 file changed, 716 insertions(+), 715 deletions(-) diff --git a/src/main/java/dev/dokan/dokan_java/DokanOperations.java b/src/main/java/dev/dokan/dokan_java/DokanOperations.java index f6fecc8..a412469 100644 --- a/src/main/java/dev/dokan/dokan_java/DokanOperations.java +++ b/src/main/java/dev/dokan/dokan_java/DokanOperations.java @@ -1,5 +1,6 @@ package dev.dokan.dokan_java; + import java.util.Arrays; import java.util.List; @@ -36,723 +37,723 @@ @SuppressWarnings("ALL") public class DokanOperations extends Structure { - public DokanOperations() { - } - - @Override - protected List getFieldOrder() { - return Arrays.asList( - "ZwCreateFile", - "Cleanup", - "CloseFile", - "ReadFile", - "WriteFile", - "FlushFileBuffers", - "GetFileInformation", - "FindFiles", - "FindFilesWithPattern", - "SetFileAttributes", - "SetFileTime", - "DeleteFile", - "DeleteDirectory", - "MoveFile", - "SetEndOfFile", - "SetAllocationSize", - "LockFile", - "UnlockFile", - "GetDiskFreeSpace", - "GetVolumeInformation", - "Mounted", - "Unmounted", - "GetFileSecurity", - "SetFileSecurity", - "FindStreams"); - } - - public ZwCreateFile ZwCreateFile = null; - public Cleanup Cleanup = null; - public CloseFile CloseFile = null; - public ReadFile ReadFile = null; - public WriteFile WriteFile = null; - public FlushFileBuffers FlushFileBuffers = null; - public GetFileInformation GetFileInformation = null; - public FindFiles FindFiles = null; - public FindFilesWithPattern FindFilesWithPattern = null; - public SetFileAttributes SetFileAttributes = null; - public SetFileTime SetFileTime = null; - public DeleteFile DeleteFile = null; - public DeleteDirectory DeleteDirectory = null; - public MoveFile MoveFile = null; - public SetEndOfFile SetEndOfFile = null; - public SetAllocationSize SetAllocationSize = null; - public LockFile LockFile = null; - public UnlockFile UnlockFile = null; - public GetDiskFreeSpace GetDiskFreeSpace = null; - public GetVolumeInformation GetVolumeInformation = null; - public Mounted Mounted = null; - public Unmounted Unmounted = null; - public GetFileSecurity GetFileSecurity = null; - public SetFileSecurity SetFileSecurity = null; - public FindStreams FindStreams = null; - - /** - * CreateFile is called each time a request is made on a file system object. - *

- * If the file is a directory, this method is also called. In this case, the method should return {@link NtStatuses#STATUS_SUCCESS} when that directory can be opened and {@link DokanFileInfo#IsDirectory} has to be set to - * true. {@link DokanFileInfo#Context} can be used to store data FileStream that can be retrieved in all other request related to the context. - * - * @see MSDN for more information about the parameters of this callback. - */ - @FunctionalInterface - interface ZwCreateFile extends DokanCallback { - - /** - * @param rawPath Path requested by the Kernel on the File System. - * @param securityContext ?? - * @param rawDesiredAccess ?? Permissions for file or directory. - * @param rawFileAttributes Provides attributes for files and directories. See MSDN - * @param rawShareAccess Type of share access to other threads. Device and intermediate drivers usually set ShareAccess to zero, which gives the caller exclusive access to the open file. - * @param rawCreateDisposition - * @param rawCreateOptions Represents advanced options for creating a File object. See MSDN - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - DokanIOSecurityContext securityContext, - int rawDesiredAccess, - int rawFileAttributes, - int rawShareAccess, - int rawCreateDisposition, - int rawCreateOptions, - DokanFileInfo dokanFileInfo); - } - - /** - * Receipt of this request indicates that the last handle for a file object that is associated with the target device object has been closed (but, due to outstanding I/O requests, might not have been released). - *

- * Cleanup is requested before @{link {@link DokanOperations#CloseFile} is called. - */ - @FunctionalInterface - interface Cleanup extends DokanCallback { - - /** - * @param rawPath - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - */ - void callback( - WString rawPath, - DokanFileInfo dokanFileInfo); - } - - /** - * CloseFile is called at the end of the life of the context. Receipt of this request indicates that the last handle of the file object that is associated with the target device object has been closed and released. - * All outstanding I/O requests have been completed or canceled. - *

- * CloseFile is requested after {@link DokanOperations.Cleanup} is called. Anything remaining in {@link DokanFileInfo#Context} has to be cleared before return. - */ - @FunctionalInterface - interface CloseFile extends DokanCallback { - - /** - * @param rawPath - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - */ - void callback( - WString rawPath, - DokanFileInfo dokanFileInfo); - } - - /** - * ReadFile callback on the file previously opened in {@link DokanOperations.ZwCreateFile}. It can be called by different thread at the same time, therefore the read has to be thread safe. - */ - interface ReadFile extends DokanCallback { - - /** - * @param rawPath - * @param rawBuffer - * @param rawBufferLength - * @param rawReadLength - * @param rawOffset - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - Pointer rawBuffer, - int rawBufferLength, - IntByReference rawReadLength, - long rawOffset, - DokanFileInfo dokanFileInfo); - } - - /** - * WriteFile callback on the file previously opened in {@link DokanOperations.ZwCreateFile} It can be called by different thread at the same time, therefore the write/context has to be thread safe. - */ - @FunctionalInterface - interface WriteFile extends DokanCallback { - - /** - * @param rawPath - * @param rawBuffer - * @param rawNumberOfBytesToWrite - * @param rawNumberOfBytesWritten - * @param rawOffset - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - Pointer rawBuffer, - int rawNumberOfBytesToWrite, - IntByReference rawNumberOfBytesWritten, - long rawOffset, - DokanFileInfo dokanFileInfo); - - } - - /** - * Clears buffers for this context and causes any buffered data to be written to the file. - */ - @FunctionalInterface - interface FlushFileBuffers extends DokanCallback { - - /** - * @param rawPath - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - DokanFileInfo dokanFileInfo); - } - - /** - * Get specific informations on a file. - */ - @FunctionalInterface - interface GetFileInformation extends DokanCallback { - - /** - * @param fileName - * @param handleFileInfo - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString fileName, - ByHandleFileInformation handleFileInfo, - DokanFileInfo dokanFileInfo); - } - - /** - * List all files in the path requested. - */ - @FunctionalInterface - interface FindFiles extends DokanCallback { - - /** - * @param rawPath - * @param rawFillFindData - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - FillWin32FindData rawFillFindData, - DokanFileInfo dokanFileInfo); - } - - /** - * Same as {@link DokanOperations.FindFiles} but with a search pattern to filter the result. - */ - @FunctionalInterface - interface FindFilesWithPattern extends DokanCallback { - - /** - * @param fileName - * @param searchPattern - * @param rawFillFindData - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString fileName, - WString searchPattern, - FillWin32FindData rawFillFindData, - DokanFileInfo dokanFileInfo); - } - - /** - * Set file attributes on a specific file. - */ - @FunctionalInterface - interface SetFileAttributes extends DokanCallback { - - /** - * @param rawPath - * @param rawAttributes - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - int rawAttributes, - DokanFileInfo dokanFileInfo); - } - - /** - * Set file times on a specific file. - */ - @FunctionalInterface - interface SetFileTime extends DokanCallback { - - /** - * @param rawPath path to file or directory - * @param rawCreationTime time of creation - * @param rawLastAccessTime time of last access - * @param rawLastWriteTime time of last modification - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - FILETIME rawCreationTime, - FILETIME rawLastAccessTime, - FILETIME rawLastWriteTime, - DokanFileInfo dokanFileInfo); - } - - /** - * Check if it is possible to delete a file. - *

- * You should NOT delete the file in this method, but instead you must only check whether you can delete the file or not, and return {@link NtStatuses#STATUS_SUCCESS} (when you can delete it) or appropriate error codes such - * as {@link NtStatuses#STATUS_ACCESS_DENIED}, {@link NtStatuses#STATUS_OBJECT_NO_LONGER_EXISTS}, {@link NtStatuses#STATUS_OBJECT_NAME_NOT_FOUND}. - *

- * {@link DokanOperations.DeleteFile} will also be called with {@link DokanFileInfo#DeleteOnClose} set to false to notify the driver when the file is no longer requested to be deleted. - *

- * When you return {@link NtStatuses#STATUS_SUCCESS}, you get a {@link DokanOperations.Cleanup}> call afterwards with {@link DokanFileInfo#DeleteOnClose} set to true and only then you have to actually delete the file - * being closed. - * - * @see {@link DokanOperations.DeleteDirectory} - */ - @FunctionalInterface - interface DeleteFile extends DokanCallback { - - /** - * @param rawPath - * @param dokanFileInfo {@link DokanFileInfo} with information about the file. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - DokanFileInfo dokanFileInfo); - } - - /** - * Check if it is possible to delete a directory. - * - * @see {@link DokanOperations.DeleteFile} for more specifics. - */ - @FunctionalInterface - interface DeleteDirectory extends DokanCallback { - - /** - * @param rawPath - * @param dokanFileInfo {@link DokanFileInfo} with information about the directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - DokanFileInfo dokanFileInfo); - } - - /** - * Move a file or directory to a new location. - */ - @FunctionalInterface - interface MoveFile extends DokanCallback { - - /** - * @param rawPath - * @param rawNewFileName - * @param rawReplaceIfExisting - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - WString rawNewFileName, - boolean rawReplaceIfExisting, - DokanFileInfo dokanFileInfo); - } - - /** - * SetEndOfFile is used to truncate or extend a file (physical file size). - */ - @FunctionalInterface - interface SetEndOfFile extends DokanCallback { - - /** - * @param rawPath - * @param rawByteOffset - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - long rawByteOffset, - DokanFileInfo dokanFileInfo); - } - - /** - * SetAllocationSize is used to truncate or extend a file. - */ - @FunctionalInterface - interface SetAllocationSize extends DokanCallback { - - /** - * @param rawPath - * @param rawLength - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - long rawLength, - DokanFileInfo dokanFileInfo); - } - - /** - * Lock file at a specific offset and data length. This is only used if {@link MountOption#FILELOCK_USER_MODE} is enabled. - */ - @FunctionalInterface - interface LockFile extends DokanCallback { - - /** - * @param rawPath - * @param rawByteOffset - * @param rawLength - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - long rawByteOffset, - long rawLength, - DokanFileInfo dokanFileInfo); - } - - /** - * Unlock file at a specific offset and data length. This is only used if {@link MountOption#FILELOCK_USER_MODE} is enabled. - */ - @FunctionalInterface - interface UnlockFile extends DokanCallback { - - /** - * @param rawPath - * @param rawByteOffset - * @param rawLength - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - long rawByteOffset, - long rawLength, - DokanFileInfo dokanFileInfo); - } - - /** - * Retrieves information about the amount of space that is available on a disk volume, which is the total amount of space, the total amount of free space, and the total amount of free space available to the user that - * is associated with the calling thread. - *

- * Neither this method nor {@link DokanOperations.GetVolumeInformation} save the {@link DokanFileInfo#Context}. Before these methods are called, {@link DokanOperations.ZwCreateFile} may not be called. (ditto @{link - * DokanOperations.CloseFile} and @{link DokanOperations.Cleanup}). - */ - @FunctionalInterface - interface GetDiskFreeSpace extends DokanCallback { - - /** - * @param freeBytesAvailable - * @param totalNumberOfBytes - * @param totalNumberOfFreeBytes - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - LongByReference freeBytesAvailable, - LongByReference totalNumberOfBytes, - LongByReference totalNumberOfFreeBytes, - DokanFileInfo dokanFileInfo); - } - - /** - * Retrieves information about the file system and volume associated with the specified root directory. - *

- * Neither this method nor {@link DokanOperations.GetVolumeInformation} save the {@link DokanFileInfo#Context}. Before these methods are called, {@link DokanOperations.ZwCreateFile} may not be called. (ditto @{link - * DokanOperations.CloseFile} and @{link DokanOperations.Cleanup}). - * - * @see {@link FileSystemFlag#READ_ONLY_VOLUME} is automatically added to the if was specified when the volume was mounted. - *

- * If {@link NtStatuses#STATUS_NOT_IMPLEMENTED} is returned, the Dokan kernel driver use following settings by default: - * - *

    - *
  • rawVolumeSerialNumber = 0x19831116
  • - *
  • rawMaximumComponentLength = 256
  • - *
  • rawFileSystemFlags = CaseSensitiveSearch, CasePreservedNames, SupportsRemoteStorage, UnicodeOnDisk
  • - *
  • rawFileSystemNameBuffer = NTFS
  • - *
- */ - @FunctionalInterface - interface GetVolumeInformation extends DokanCallback { - - /** - * @param rawVolumeNameBuffer - * @param rawVolumeNameSize - * @param rawVolumeSerialNumber - * @param rawMaximumComponentLength - * @param rawFileSystemFlags - * @param rawFileSystemNameBuffer - * @param rawFileSystemNameSize - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - Pointer rawVolumeNameBuffer, - int rawVolumeNameSize, - IntByReference rawVolumeSerialNumber, - IntByReference rawMaximumComponentLength, - IntByReference /* FileSystemFeatures */ rawFileSystemFlags, - Pointer rawFileSystemNameBuffer, - int rawFileSystemNameSize, - DokanFileInfo dokanFileInfo); - } - - /** - * Is called when Dokan succeeded mounting the volume. - */ - @FunctionalInterface - interface Mounted extends DokanCallback { - - long mounted( - DokanFileInfo dokanFileInfo); - } - - /** - * Is called when Dokan succeeded unmounting the volume. - */ - @FunctionalInterface - interface Unmounted extends DokanCallback { - - long unmounted( - final DokanFileInfo dokanFileInfo); - } - - /** - * Get specified information about the security of a file or directory. - *

- * Supported since version 0.6.0. You must specify the version in {@link DokanOptions#Version}. - */ - @FunctionalInterface - interface GetFileSecurity extends DokanCallback { - - /** - * @param rawPath - * @param rawSecurityInformation - * @param rawSecurityDescriptor - * @param rawSecurityDescriptorLength - * @param rawSecurityDescriptorLengthNeeded - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - int /* SecurityInformation */ rawSecurityInformation, - Pointer rawSecurityDescriptor, - int rawSecurityDescriptorLength, - IntByReference rawSecurityDescriptorLengthNeeded, - DokanFileInfo dokanFileInfo); - } - - /** - * Sets the security of a file or directory object. - *

- * Supported since version 0.6.0. You must specify the version in {@link DokanOptions#Version}. - */ - @FunctionalInterface - interface SetFileSecurity extends DokanCallback { - - /** - * @param rawPath - * @param rawSecurityInformation - * @param rawSecurityDescriptor - * @param rawSecurityDescriptorLength - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - int rawSecurityInformation, - Pointer rawSecurityDescriptor, - int rawSecurityDescriptorLength, - DokanFileInfo dokanFileInfo); - } - - /** - * Used to add an entry in FindFiles operation - */ - @FunctionalInterface - public interface FillWin32FindData extends StdCallLibrary.StdCallCallback { - - /** - * @param rawFillFindData - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + public DokanOperations() { + } + + @Override + protected List getFieldOrder() { + return Arrays.asList( + "ZwCreateFile", + "Cleanup", + "CloseFile", + "ReadFile", + "WriteFile", + "FlushFileBuffers", + "GetFileInformation", + "FindFiles", + "FindFilesWithPattern", + "SetFileAttributes", + "SetFileTime", + "DeleteFile", + "DeleteDirectory", + "MoveFile", + "SetEndOfFile", + "SetAllocationSize", + "LockFile", + "UnlockFile", + "GetDiskFreeSpace", + "GetVolumeInformation", + "Mounted", + "Unmounted", + "GetFileSecurity", + "SetFileSecurity", + "FindStreams"); + } + + public ZwCreateFile ZwCreateFile = null; + public Cleanup Cleanup = null; + public CloseFile CloseFile = null; + public ReadFile ReadFile = null; + public WriteFile WriteFile = null; + public FlushFileBuffers FlushFileBuffers = null; + public GetFileInformation GetFileInformation = null; + public FindFiles FindFiles = null; + public FindFilesWithPattern FindFilesWithPattern = null; + public SetFileAttributes SetFileAttributes = null; + public SetFileTime SetFileTime = null; + public DeleteFile DeleteFile = null; + public DeleteDirectory DeleteDirectory = null; + public MoveFile MoveFile = null; + public SetEndOfFile SetEndOfFile = null; + public SetAllocationSize SetAllocationSize = null; + public LockFile LockFile = null; + public UnlockFile UnlockFile = null; + public GetDiskFreeSpace GetDiskFreeSpace = null; + public GetVolumeInformation GetVolumeInformation = null; + public Mounted Mounted = null; + public Unmounted Unmounted = null; + public GetFileSecurity GetFileSecurity = null; + public SetFileSecurity SetFileSecurity = null; + public FindStreams FindStreams = null; + + /** + * CreateFile is called each time a request is made on a file system object. + *

+ * If the file is a directory, this method is also called. In this case, the method should return {@link NtStatuses#STATUS_SUCCESS} when that directory can be opened and {@link DokanFileInfo#IsDirectory} has to be set to + * true. {@link DokanFileInfo#Context} can be used to store data FileStream that can be retrieved in all other request related to the context. + * + * @see MSDN for more information about the parameters of this callback. + */ + @FunctionalInterface + interface ZwCreateFile extends DokanCallback { + + /** + * @param rawPath Path requested by the Kernel on the File System. + * @param securityContext ?? + * @param rawDesiredAccess ?? Permissions for file or directory. + * @param rawFileAttributes Provides attributes for files and directories. See MSDN + * @param rawShareAccess Type of share access to other threads. Device and intermediate drivers usually set ShareAccess to zero, which gives the caller exclusive access to the open file. + * @param rawCreateDisposition + * @param rawCreateOptions Represents advanced options for creating a File object. See MSDN + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + DokanIOSecurityContext securityContext, + int rawDesiredAccess, + int rawFileAttributes, + int rawShareAccess, + int rawCreateDisposition, + int rawCreateOptions, + DokanFileInfo dokanFileInfo); + } + + /** + * Receipt of this request indicates that the last handle for a file object that is associated with the target device object has been closed (but, due to outstanding I/O requests, might not have been released). + *

+ * Cleanup is requested before @{link {@link DokanOperations#CloseFile} is called. + */ + @FunctionalInterface + interface Cleanup extends DokanCallback { + + /** + * @param rawPath + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + */ + void callback( + WString rawPath, + DokanFileInfo dokanFileInfo); + } + + /** + * CloseFile is called at the end of the life of the context. Receipt of this request indicates that the last handle of the file object that is associated with the target device object has been closed and released. + * All outstanding I/O requests have been completed or canceled. + *

+ * CloseFile is requested after {@link DokanOperations.Cleanup} is called. Anything remaining in {@link DokanFileInfo#Context} has to be cleared before return. + */ + @FunctionalInterface + interface CloseFile extends DokanCallback { + + /** + * @param rawPath + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + */ + void callback( + WString rawPath, + DokanFileInfo dokanFileInfo); + } + + /** + * ReadFile callback on the file previously opened in {@link DokanOperations.ZwCreateFile}. It can be called by different thread at the same time, therefore the read has to be thread safe. + */ + interface ReadFile extends DokanCallback { + + /** + * @param rawPath + * @param rawBuffer + * @param rawBufferLength + * @param rawReadLength + * @param rawOffset + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + Pointer rawBuffer, + int rawBufferLength, + IntByReference rawReadLength, + long rawOffset, + DokanFileInfo dokanFileInfo); + } + + /** + * WriteFile callback on the file previously opened in {@link DokanOperations.ZwCreateFile} It can be called by different thread at the same time, therefore the write/context has to be thread safe. + */ + @FunctionalInterface + interface WriteFile extends DokanCallback { + + /** + * @param rawPath + * @param rawBuffer + * @param rawNumberOfBytesToWrite + * @param rawNumberOfBytesWritten + * @param rawOffset + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + Pointer rawBuffer, + int rawNumberOfBytesToWrite, + IntByReference rawNumberOfBytesWritten, + long rawOffset, + DokanFileInfo dokanFileInfo); + + } + + /** + * Clears buffers for this context and causes any buffered data to be written to the file. + */ + @FunctionalInterface + interface FlushFileBuffers extends DokanCallback { + + /** + * @param rawPath + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + DokanFileInfo dokanFileInfo); + } + + /** + * Get specific informations on a file. + */ + @FunctionalInterface + interface GetFileInformation extends DokanCallback { + + /** + * @param fileName + * @param handleFileInfo + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString fileName, + ByHandleFileInformation handleFileInfo, + DokanFileInfo dokanFileInfo); + } + + /** + * List all files in the path requested. + */ + @FunctionalInterface + interface FindFiles extends DokanCallback { + + /** + * @param rawPath + * @param rawFillFindData + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + FillWin32FindData rawFillFindData, + DokanFileInfo dokanFileInfo); + } + + /** + * Same as {@link DokanOperations.FindFiles} but with a search pattern to filter the result. + */ + @FunctionalInterface + interface FindFilesWithPattern extends DokanCallback { + + /** + * @param fileName + * @param searchPattern + * @param rawFillFindData + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString fileName, + WString searchPattern, + FillWin32FindData rawFillFindData, + DokanFileInfo dokanFileInfo); + } + + /** + * Set file attributes on a specific file. + */ + @FunctionalInterface + interface SetFileAttributes extends DokanCallback { + + /** + * @param rawPath + * @param rawAttributes + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + int rawAttributes, + DokanFileInfo dokanFileInfo); + } + + /** + * Set file times on a specific file. + */ + @FunctionalInterface + interface SetFileTime extends DokanCallback { + + /** + * @param rawPath path to file or directory + * @param rawCreationTime time of creation + * @param rawLastAccessTime time of last access + * @param rawLastWriteTime time of last modification + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + FILETIME rawCreationTime, + FILETIME rawLastAccessTime, + FILETIME rawLastWriteTime, + DokanFileInfo dokanFileInfo); + } + + /** + * Check if it is possible to delete a file. + *

+ * You should NOT delete the file in this method, but instead you must only check whether you can delete the file or not, and return {@link NtStatuses#STATUS_SUCCESS} (when you can delete it) or appropriate error codes such + * as {@link NtStatuses#STATUS_ACCESS_DENIED}, {@link NtStatuses#STATUS_OBJECT_NO_LONGER_EXISTS}, {@link NtStatuses#STATUS_OBJECT_NAME_NOT_FOUND}. + *

+ * {@link DokanOperations.DeleteFile} will also be called with {@link DokanFileInfo#DeleteOnClose} set to false to notify the driver when the file is no longer requested to be deleted. + *

+ * When you return {@link NtStatuses#STATUS_SUCCESS}, you get a {@link DokanOperations.Cleanup}> call afterwards with {@link DokanFileInfo#DeleteOnClose} set to true and only then you have to actually delete the file + * being closed. + * + * @see {@link DokanOperations.DeleteDirectory} + */ + @FunctionalInterface + interface DeleteFile extends DokanCallback { + + /** + * @param rawPath + * @param dokanFileInfo {@link DokanFileInfo} with information about the file. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + DokanFileInfo dokanFileInfo); + } + + /** + * Check if it is possible to delete a directory. + * + * @see {@link DokanOperations.DeleteFile} for more specifics. + */ + @FunctionalInterface + interface DeleteDirectory extends DokanCallback { + + /** + * @param rawPath + * @param dokanFileInfo {@link DokanFileInfo} with information about the directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + DokanFileInfo dokanFileInfo); + } + + /** + * Move a file or directory to a new location. + */ + @FunctionalInterface + interface MoveFile extends DokanCallback { + + /** + * @param rawPath + * @param rawNewFileName + * @param rawReplaceIfExisting + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + WString rawNewFileName, + boolean rawReplaceIfExisting, + DokanFileInfo dokanFileInfo); + } + + /** + * SetEndOfFile is used to truncate or extend a file (physical file size). + */ + @FunctionalInterface + interface SetEndOfFile extends DokanCallback { + + /** + * @param rawPath + * @param rawByteOffset + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + long rawByteOffset, + DokanFileInfo dokanFileInfo); + } + + /** + * SetAllocationSize is used to truncate or extend a file. + */ + @FunctionalInterface + interface SetAllocationSize extends DokanCallback { + + /** + * @param rawPath + * @param rawLength + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + long rawLength, + DokanFileInfo dokanFileInfo); + } + + /** + * Lock file at a specific offset and data length. This is only used if {@link MountOption#FILELOCK_USER_MODE} is enabled. + */ + @FunctionalInterface + interface LockFile extends DokanCallback { + + /** + * @param rawPath + * @param rawByteOffset + * @param rawLength + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + long rawByteOffset, + long rawLength, + DokanFileInfo dokanFileInfo); + } + + /** + * Unlock file at a specific offset and data length. This is only used if {@link MountOption#FILELOCK_USER_MODE} is enabled. + */ + @FunctionalInterface + interface UnlockFile extends DokanCallback { + + /** + * @param rawPath + * @param rawByteOffset + * @param rawLength + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + long rawByteOffset, + long rawLength, + DokanFileInfo dokanFileInfo); + } + + /** + * Retrieves information about the amount of space that is available on a disk volume, which is the total amount of space, the total amount of free space, and the total amount of free space available to the user that + * is associated with the calling thread. + *

+ * Neither this method nor {@link DokanOperations.GetVolumeInformation} save the {@link DokanFileInfo#Context}. Before these methods are called, {@link DokanOperations.ZwCreateFile} may not be called. (ditto @{link + * DokanOperations.CloseFile} and @{link DokanOperations.Cleanup}). + */ + @FunctionalInterface + interface GetDiskFreeSpace extends DokanCallback { + + /** + * @param freeBytesAvailable + * @param totalNumberOfBytes + * @param totalNumberOfFreeBytes + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + LongByReference freeBytesAvailable, + LongByReference totalNumberOfBytes, + LongByReference totalNumberOfFreeBytes, + DokanFileInfo dokanFileInfo); + } + + /** + * Retrieves information about the file system and volume associated with the specified root directory. + *

+ * Neither this method nor {@link DokanOperations.GetVolumeInformation} save the {@link DokanFileInfo#Context}. Before these methods are called, {@link DokanOperations.ZwCreateFile} may not be called. (ditto @{link + * DokanOperations.CloseFile} and @{link DokanOperations.Cleanup}). + * + * @see {@link FileSystemFlag#READ_ONLY_VOLUME} is automatically added to the if was specified when the volume was mounted. + *

+ * If {@link NtStatuses#STATUS_NOT_IMPLEMENTED} is returned, the Dokan kernel driver use following settings by default: + * + *

    + *
  • rawVolumeSerialNumber = 0x19831116
  • + *
  • rawMaximumComponentLength = 256
  • + *
  • rawFileSystemFlags = CaseSensitiveSearch, CasePreservedNames, SupportsRemoteStorage, UnicodeOnDisk
  • + *
  • rawFileSystemNameBuffer = NTFS
  • + *
+ */ + @FunctionalInterface + interface GetVolumeInformation extends DokanCallback { + + /** + * @param rawVolumeNameBuffer + * @param rawVolumeNameSize + * @param rawVolumeSerialNumber + * @param rawMaximumComponentLength + * @param rawFileSystemFlags + * @param rawFileSystemNameBuffer + * @param rawFileSystemNameSize + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + Pointer rawVolumeNameBuffer, + int rawVolumeNameSize, + IntByReference rawVolumeSerialNumber, + IntByReference rawMaximumComponentLength, + IntByReference /* FileSystemFeatures */ rawFileSystemFlags, + Pointer rawFileSystemNameBuffer, + int rawFileSystemNameSize, + DokanFileInfo dokanFileInfo); + } + + /** + * Is called when Dokan succeeded mounting the volume. + */ + @FunctionalInterface + interface Mounted extends DokanCallback { + + long mounted( + DokanFileInfo dokanFileInfo); + } + + /** + * Is called when Dokan succeeded unmounting the volume. + */ + @FunctionalInterface + interface Unmounted extends DokanCallback { + + long unmounted( + final DokanFileInfo dokanFileInfo); + } + + /** + * Get specified information about the security of a file or directory. + *

+ * Supported since version 0.6.0. You must specify the version in {@link DokanOptions#Version}. + */ + @FunctionalInterface + interface GetFileSecurity extends DokanCallback { + + /** + * @param rawPath + * @param rawSecurityInformation + * @param rawSecurityDescriptor + * @param rawSecurityDescriptorLength + * @param rawSecurityDescriptorLengthNeeded + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + int /* SecurityInformation */ rawSecurityInformation, + Pointer rawSecurityDescriptor, + int rawSecurityDescriptorLength, + IntByReference rawSecurityDescriptorLengthNeeded, + DokanFileInfo dokanFileInfo); + } + + /** + * Sets the security of a file or directory object. + *

+ * Supported since version 0.6.0. You must specify the version in {@link DokanOptions#Version}. + */ + @FunctionalInterface + interface SetFileSecurity extends DokanCallback { + + /** + * @param rawPath + * @param rawSecurityInformation + * @param rawSecurityDescriptor + * @param rawSecurityDescriptorLength + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + int rawSecurityInformation, + Pointer rawSecurityDescriptor, + int rawSecurityDescriptorLength, + DokanFileInfo dokanFileInfo); + } + + /** + * Used to add an entry in FindFiles operation + */ + @FunctionalInterface + public interface FillWin32FindData extends StdCallLibrary.StdCallCallback { + + /** + * @param rawFillFindData + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. * @return {@code 1} if buffer is full, otherwise {@code 0} (currently it never returns 1) - */ - int fillWin32FindData( - WIN32_FIND_DATA rawFillFindData, - DokanFileInfo dokanFileInfo); - } - - /** - * Retrieve all NTFS Streams informations on the file. This is only called if {@link MountOption#ALT_STREAM} is enabled. - */ - @FunctionalInterface - interface FindStreams extends DokanCallback { - - /** - * @param rawPath - * @param rawFillFindData - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return {@link NtStatuses} - */ - long callback( - WString rawPath, - FillWin32FindStreamData rawFillFindData, - DokanFileInfo dokanFileInfo); - } - - /** - * TODO - */ - @FunctionalInterface - public interface FillWin32FindStreamData extends StdCallLibrary.StdCallCallback { - - /** - * @param rawFillFindData - * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. - * @return - */ - int fillWin32FindStreamData( - Win32FindStreamData rawFillFindData, - DokanFileInfo dokanFileInfo); - } - - interface Win32FindStreamDataInterface { - - void length(long val); - - char[] cFileName(); - } - - public void setZwCreateFile(DokanOperations.ZwCreateFile zwCreateFile) { - ZwCreateFile = zwCreateFile; - } - - public void setCleanup(DokanOperations.Cleanup cleanup) { - Cleanup = cleanup; - } - - public void setCloseFile(DokanOperations.CloseFile closeFile) { - CloseFile = closeFile; - } - - public void setReadFile(DokanOperations.ReadFile readFile) { - ReadFile = readFile; - } - - public void setWriteFile(DokanOperations.WriteFile writeFile) { - WriteFile = writeFile; - } - - public void setFlushFileBuffers(DokanOperations.FlushFileBuffers flushFileBuffers) { - FlushFileBuffers = flushFileBuffers; - } - - public void setGetFileInformation(DokanOperations.GetFileInformation getFileInformation) { - GetFileInformation = getFileInformation; - } - - public void setFindFiles(DokanOperations.FindFiles findFiles) { - FindFiles = findFiles; - } - - public void setFindFilesWithPattern(DokanOperations.FindFilesWithPattern findFilesWithPattern) { - FindFilesWithPattern = findFilesWithPattern; - } - - public void setSetFileAttributes(DokanOperations.SetFileAttributes setFileAttributes) { - SetFileAttributes = setFileAttributes; - } - - public void setSetFileTime(DokanOperations.SetFileTime setFileTime) { - SetFileTime = setFileTime; - } - - public void setDeleteFile(DokanOperations.DeleteFile deleteFile) { - DeleteFile = deleteFile; - } - - public void setDeleteDirectory(DokanOperations.DeleteDirectory deleteDirectory) { - DeleteDirectory = deleteDirectory; - } - - public void setMoveFile(DokanOperations.MoveFile moveFile) { - MoveFile = moveFile; - } - - public void setSetEndOfFile(DokanOperations.SetEndOfFile setEndOfFile) { - SetEndOfFile = setEndOfFile; - } - - public void setSetAllocationSize(DokanOperations.SetAllocationSize setAllocationSize) { - SetAllocationSize = setAllocationSize; - } - - public void setLockFile(DokanOperations.LockFile lockFile) { - LockFile = lockFile; - } - - public void setUnlockFile(DokanOperations.UnlockFile unlockFile) { - UnlockFile = unlockFile; - } - - public void setGetDiskFreeSpace(DokanOperations.GetDiskFreeSpace getDiskFreeSpace) { - GetDiskFreeSpace = getDiskFreeSpace; - } - - public void setGetVolumeInformation(DokanOperations.GetVolumeInformation getVolumeInformation) { - GetVolumeInformation = getVolumeInformation; - } - - public void setMounted(DokanOperations.Mounted mounted) { - Mounted = mounted; - } - - public void setUnmounted(DokanOperations.Unmounted unmounted) { - Unmounted = unmounted; - } + */ + int fillWin32FindData( + WIN32_FIND_DATA rawFillFindData, + DokanFileInfo dokanFileInfo); + } + + /** + * Retrieve all NTFS Streams informations on the file. This is only called if {@link MountOption#ALT_STREAM} is enabled. + */ + @FunctionalInterface + interface FindStreams extends DokanCallback { + + /** + * @param rawPath + * @param rawFillFindData + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return {@link NtStatuses} + */ + long callback( + WString rawPath, + FillWin32FindStreamData rawFillFindData, + DokanFileInfo dokanFileInfo); + } + + /** + * TODO + */ + @FunctionalInterface + public interface FillWin32FindStreamData extends StdCallLibrary.StdCallCallback { + + /** + * @param rawFillFindData + * @param dokanFileInfo {@link DokanFileInfo} with information about the file or directory. + * @return + */ + int fillWin32FindStreamData( + Win32FindStreamData rawFillFindData, + DokanFileInfo dokanFileInfo); + } + + interface Win32FindStreamDataInterface { + + void length(long val); + + char[] cFileName(); + } + + public void setZwCreateFile(DokanOperations.ZwCreateFile zwCreateFile) { + ZwCreateFile = zwCreateFile; + } + + public void setCleanup(DokanOperations.Cleanup cleanup) { + Cleanup = cleanup; + } + + public void setCloseFile(DokanOperations.CloseFile closeFile) { + CloseFile = closeFile; + } + + public void setReadFile(DokanOperations.ReadFile readFile) { + ReadFile = readFile; + } + + public void setWriteFile(DokanOperations.WriteFile writeFile) { + WriteFile = writeFile; + } + + public void setFlushFileBuffers(DokanOperations.FlushFileBuffers flushFileBuffers) { + FlushFileBuffers = flushFileBuffers; + } + + public void setGetFileInformation(DokanOperations.GetFileInformation getFileInformation) { + GetFileInformation = getFileInformation; + } + + public void setFindFiles(DokanOperations.FindFiles findFiles) { + FindFiles = findFiles; + } + + public void setFindFilesWithPattern(DokanOperations.FindFilesWithPattern findFilesWithPattern) { + FindFilesWithPattern = findFilesWithPattern; + } + + public void setSetFileAttributes(DokanOperations.SetFileAttributes setFileAttributes) { + SetFileAttributes = setFileAttributes; + } + + public void setSetFileTime(DokanOperations.SetFileTime setFileTime) { + SetFileTime = setFileTime; + } + + public void setDeleteFile(DokanOperations.DeleteFile deleteFile) { + DeleteFile = deleteFile; + } + + public void setDeleteDirectory(DokanOperations.DeleteDirectory deleteDirectory) { + DeleteDirectory = deleteDirectory; + } + + public void setMoveFile(DokanOperations.MoveFile moveFile) { + MoveFile = moveFile; + } + + public void setSetEndOfFile(DokanOperations.SetEndOfFile setEndOfFile) { + SetEndOfFile = setEndOfFile; + } + + public void setSetAllocationSize(DokanOperations.SetAllocationSize setAllocationSize) { + SetAllocationSize = setAllocationSize; + } + + public void setLockFile(DokanOperations.LockFile lockFile) { + LockFile = lockFile; + } + + public void setUnlockFile(DokanOperations.UnlockFile unlockFile) { + UnlockFile = unlockFile; + } + + public void setGetDiskFreeSpace(DokanOperations.GetDiskFreeSpace getDiskFreeSpace) { + GetDiskFreeSpace = getDiskFreeSpace; + } + + public void setGetVolumeInformation(DokanOperations.GetVolumeInformation getVolumeInformation) { + GetVolumeInformation = getVolumeInformation; + } + + public void setMounted(DokanOperations.Mounted mounted) { + Mounted = mounted; + } + + public void setUnmounted(DokanOperations.Unmounted unmounted) { + Unmounted = unmounted; + } - public void setGetFileSecurity(DokanOperations.GetFileSecurity getFileSecurity) { - GetFileSecurity = getFileSecurity; - } + public void setGetFileSecurity(DokanOperations.GetFileSecurity getFileSecurity) { + GetFileSecurity = getFileSecurity; + } - public void setSetFileSecurity(DokanOperations.SetFileSecurity setFileSecurity) { - SetFileSecurity = setFileSecurity; - } + public void setSetFileSecurity(DokanOperations.SetFileSecurity setFileSecurity) { + SetFileSecurity = setFileSecurity; + } - public void setFindStreams(DokanOperations.FindStreams findStreams) { - FindStreams = findStreams; - } + public void setFindStreams(DokanOperations.FindStreams findStreams) { + FindStreams = findStreams; + } } From 244c640407b7effaccdc6bad751d4e4eea1fb5f1 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 27 May 2020 22:22:27 +0200 Subject: [PATCH 4/9] remove parameter to useKernelFlagsAndCodes --- .../dokan_java/AbstractDokanFileSystem.java | 247 ++++++------------ .../dokan/dokan_java/DokanFileSystemStub.java | 4 +- 2 files changed, 81 insertions(+), 170 deletions(-) diff --git a/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java b/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java index f0cf8cc..03d1d4e 100644 --- a/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java +++ b/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java @@ -29,7 +29,6 @@ public abstract class AbstractDokanFileSystem implements DokanFileSystem { protected final FileSystemInformation fileSystemInformation; protected final DokanOperations dokanOperations; - protected final boolean usesKernelFlagsAndCodes; protected Path mountPoint; protected String volumeName; protected int volumeSerialnumber; @@ -38,9 +37,8 @@ public abstract class AbstractDokanFileSystem implements DokanFileSystem { private final AtomicBoolean isMounted; private Set notImplementedMethods; - public AbstractDokanFileSystem(FileSystemInformation fileSystemInformation, boolean usesKernelFlagsAndCodes) { + public AbstractDokanFileSystem(FileSystemInformation fileSystemInformation) { this.fileSystemInformation = fileSystemInformation; - this.usesKernelFlagsAndCodes = usesKernelFlagsAndCodes; this.isMounted = new AtomicBoolean(false); this.dokanOperations = new DokanOperations(); init(dokanOperations); @@ -52,171 +50,84 @@ private void init(DokanOperations dokanOperations) { .map(Method::getName) .collect(Collectors.toSet()); - if (usesKernelFlagsAndCodes) { - if (isImplemented("zwCreateFile")) { - dokanOperations.setZwCreateFile(this::zwCreateFile); - } - if (isImplemented("cleanup")) { - dokanOperations.setCleanup(this::cleanup); - } - if (isImplemented("closeFile")) { - dokanOperations.setCloseFile(this::closeFile); - } - if (isImplemented("readFile")) { - dokanOperations.setReadFile(this::readFile); - } - if (isImplemented("writeFile")) { - dokanOperations.setWriteFile(this::writeFile); - } - if (isImplemented("flushFileBuffer")) { - dokanOperations.setFlushFileBuffers(this::flushFileBuffers); - } - if (isImplemented("getFileInformation")) { - dokanOperations.setGetFileInformation(this::getFileInformation); - } - if (isImplemented("findFiles")) { - dokanOperations.setFindFiles(this::findFiles); - } - if (isImplemented("findFilesWithPattern")) { - dokanOperations.setFindFilesWithPattern(this::findFilesWithPattern); - } - if (isImplemented("setFileAttributes")) { - dokanOperations.setSetFileAttributes(this::setFileAttributes); - } - if (isImplemented("setFileTime")) { - dokanOperations.setSetFileTime(this::setFileTime); - } - if (isImplemented("deleteFile")) { - dokanOperations.setDeleteFile(this::deleteFile); - } - if (isImplemented("deleteDirectory")) { - dokanOperations.setDeleteDirectory(this::deleteDirectory); - } - if (isImplemented("moveFile")) { - dokanOperations.setMoveFile(this::moveFile); - } - if (isImplemented("setEndOfFile")) { - dokanOperations.setSetEndOfFile(this::setEndOfFile); - } - if (isImplemented("setAllocationSize")) { - dokanOperations.setSetAllocationSize(this::setAllocationSize); - } - if (isImplemented("lockFile")) { - dokanOperations.setLockFile(this::lockFile); - } - if (isImplemented("unlockFile")) { - dokanOperations.setUnlockFile(this::unlockFile); - } - if (isImplemented("getDiskFreeSpace")) { - dokanOperations.setGetDiskFreeSpace(this::getDiskFreeSpace); - } - if (isImplemented("getVolumeInformation")) { - dokanOperations.setGetVolumeInformation(this::getVolumeInformation); - } - if (isImplemented("mounted")) { - dokanOperations.setMounted(this::mounted); - } - if (isImplemented("unmounted")) { - dokanOperations.setUnmounted(this::unmounted); - } - if (isImplemented("getFileSecurity")) { - dokanOperations.setGetFileSecurity(this::getFileSecurity); - } - if (isImplemented("setFileSecurity")) { - dokanOperations.setSetFileSecurity(this::setFileSecurity); - } - if (isImplemented("fillWin32FindData")) { - //TODO: write meaningful comment why there is no method binding - } - if (isImplemented("findStreams")) { - dokanOperations.setFindStreams(this::findStreams); - } - } else { - if (isImplemented("zwCreateFile")) { - dokanOperations.setZwCreateFile((rawPath, securityContext, rawDesiredAccess, rawFileAttributes, rawShareAccess, rawCreateDisposition, rawCreateOptions, dokanFileInfo) -> { - int creationDisposition = DokanUtils.convertCreateDispositionToCreationDispostion(rawCreateDisposition); - int desiredAccessGeneric = DokanUtils.mapFileGenericAccessToGenericAccess(rawDesiredAccess); - int fileAttributesAndFlags = DokanUtils.addFileFlagsToFileAttributes(rawFileAttributes, rawCreateOptions); - return DokanUtils.ntStatusFromWin32ErrorCode(this.zwCreateFile(rawPath, securityContext, desiredAccessGeneric, fileAttributesAndFlags, rawShareAccess, creationDisposition, rawCreateOptions, dokanFileInfo)); - }); - } - if (isImplemented("cleanup")) { - dokanOperations.setCleanup(this::cleanup); //cleanup returns void, so no further preprocessing is necessary - } - if (isImplemented("closeFile")) { - dokanOperations.setCloseFile(this::closeFile); - } - if (isImplemented("readFile")) { - dokanOperations.setReadFile((rawPath, rawBuffer, rawBufferLength, rawReadLength, rawOffset, dokanyFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.readFile(rawPath, rawBuffer, rawBufferLength, rawReadLength, rawOffset, dokanyFileInfo))); - } - if (isImplemented("writeFile")) { - dokanOperations.setWriteFile((rawPath, rawBuffer, rawNumberOfBytesToWrite, rawNumberOfWritesWritten, rawOffset, dokanyFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.writeFile(rawPath, rawBuffer, rawNumberOfBytesToWrite, rawNumberOfWritesWritten, rawOffset, dokanyFileInfo))); - } - if (isImplemented("flushFileBuffer")) { - dokanOperations.setFlushFileBuffers((rawPath, dokanyFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.flushFileBuffers(rawPath, dokanyFileInfo))); - } - if (isImplemented("getFileInformation")) { - dokanOperations.setGetFileInformation((rawPath, handleFileInfo, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.getFileInformation(rawPath, handleFileInfo, dokanFileInfo))); - } - if (isImplemented("findFiles")) { - dokanOperations.setFindFiles((rawPath, rawFillWin32FindData, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.findFiles(rawPath, rawFillWin32FindData, dokanFileInfo))); - } - if (isImplemented("findFilesWithPattern")) { - dokanOperations.setFindFilesWithPattern(((rawPath, rawFillWin32FindData, pattern, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.findFilesWithPattern(rawPath, rawFillWin32FindData, pattern, dokanFileInfo)))); - } - if (isImplemented("setFileAttributes")) { - dokanOperations.setSetFileAttributes((rawPath, rawAttributes, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.setFileAttributes(rawPath, rawAttributes, dokanFileInfo))); - } - if (isImplemented("setFileTime")) { - dokanOperations.setSetFileTime((rawPath, rawCreatonTime, rawLastAccessTime, rawLastWriteTime, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.setFileTime(rawPath, rawCreatonTime, rawLastAccessTime, rawLastWriteTime, dokanFileInfo))); - } - if (isImplemented("deleteFile")) { - dokanOperations.setDeleteFile((rawPath, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.deleteFile(rawPath, dokanFileInfo))); - } - if (isImplemented("deleteDirectory")) { - dokanOperations.setDeleteDirectory((rawPath, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.deleteDirectory(rawPath, dokanFileInfo))); - } - if (isImplemented("moveFile")) { - dokanOperations.setMoveFile((rawPath, rawNewFileName, rawReplaceIfExisting, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.moveFile(rawPath, rawNewFileName, rawReplaceIfExisting, dokanFileInfo))); - } - if (isImplemented("setEndOfFile")) { - dokanOperations.setSetEndOfFile((rawPath, rawByteOffset, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.setEndOfFile(rawPath, rawByteOffset, dokanFileInfo))); - } - if (isImplemented("setAllocationSize")) { - dokanOperations.setSetAllocationSize((rawPath, rawLength, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.setAllocationSize(rawPath, rawLength, dokanFileInfo))); - } - if (isImplemented("lockFile")) { - dokanOperations.setLockFile((rawPath, rawByteOffset, rawLength, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.lockFile(rawPath, rawByteOffset, rawLength, dokanFileInfo))); - } - if (isImplemented("unlockFile")) { - dokanOperations.setUnlockFile((rawPath, rawByteOffset, rawLength, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.unlockFile(rawPath, rawByteOffset, rawLength, dokanFileInfo))); - } - if (isImplemented("getDiskFreeSpace")) { - dokanOperations.setGetDiskFreeSpace((freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.getDiskFreeSpace(freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes, dokanFileInfo))); - } - if (isImplemented("getVolumeInformation")) { - dokanOperations.setGetVolumeInformation((rawVolumeNameBuffer, rawVolumeNameSize, rawVolumeSerialNumber, rawMaximumComponentLength, rawFileSystemFlags, rawFileSystemNameBuffer, rawFileSystemNameSize, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.getVolumeInformation(rawVolumeNameBuffer, rawVolumeNameSize, rawVolumeSerialNumber, rawMaximumComponentLength, rawFileSystemFlags, rawFileSystemNameBuffer, rawFileSystemNameSize, dokanFileInfo))); - } - if (isImplemented("mounted")) { - dokanOperations.setMounted((dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.mounted(dokanFileInfo))); - } - if (isImplemented("unmounted")) { - dokanOperations.setUnmounted((dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.unmounted(dokanFileInfo))); - } - if (isImplemented("getFileSecurity")) { - dokanOperations.setGetFileSecurity((rawPath, rawSecurityInformation, rawSecurityDescriptor, rawSecurityDescriptorLength, rawSecurityDescriptorLengthNeeded, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.getFileSecurity(rawPath, rawSecurityInformation, rawSecurityDescriptor, rawSecurityDescriptorLength, rawSecurityDescriptorLengthNeeded, dokanFileInfo))); - } - if (isImplemented("setFileSecurity")) { - dokanOperations.setSetFileSecurity((rawPath, rawSecurityInformation, rawSecurityDescriptor, rawSecurityDescriptorLength, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.setFileSecurity(rawPath, rawSecurityInformation, rawSecurityDescriptor, rawSecurityDescriptorLength, dokanFileInfo))); - } - if (isImplemented("fillWin32FindData")) { - //TODO: write meaningful comment why there is no method binding - } - if (isImplemented("findStreams")) { - dokanOperations.setFindStreams((rawPath, fillWin32FindStreamData, dokanFileInfo) -> DokanUtils.ntStatusFromWin32ErrorCode(this.findStreams(rawPath, fillWin32FindStreamData, dokanFileInfo))); - } - - } + if (isImplemented("zwCreateFile")) { + dokanOperations.setZwCreateFile(this::zwCreateFile); + } + if (isImplemented("cleanup")) { + dokanOperations.setCleanup(this::cleanup); + } + if (isImplemented("closeFile")) { + dokanOperations.setCloseFile(this::closeFile); + } + if (isImplemented("readFile")) { + dokanOperations.setReadFile(this::readFile); + } + if (isImplemented("writeFile")) { + dokanOperations.setWriteFile(this::writeFile); + } + if (isImplemented("flushFileBuffer")) { + dokanOperations.setFlushFileBuffers(this::flushFileBuffers); + } + if (isImplemented("getFileInformation")) { + dokanOperations.setGetFileInformation(this::getFileInformation); + } + if (isImplemented("findFiles")) { + dokanOperations.setFindFiles(this::findFiles); + } + if (isImplemented("findFilesWithPattern")) { + dokanOperations.setFindFilesWithPattern(this::findFilesWithPattern); + } + if (isImplemented("setFileAttributes")) { + dokanOperations.setSetFileAttributes(this::setFileAttributes); + } + if (isImplemented("setFileTime")) { + dokanOperations.setSetFileTime(this::setFileTime); + } + if (isImplemented("deleteFile")) { + dokanOperations.setDeleteFile(this::deleteFile); + } + if (isImplemented("deleteDirectory")) { + dokanOperations.setDeleteDirectory(this::deleteDirectory); + } + if (isImplemented("moveFile")) { + dokanOperations.setMoveFile(this::moveFile); + } + if (isImplemented("setEndOfFile")) { + dokanOperations.setSetEndOfFile(this::setEndOfFile); + } + if (isImplemented("setAllocationSize")) { + dokanOperations.setSetAllocationSize(this::setAllocationSize); + } + if (isImplemented("lockFile")) { + dokanOperations.setLockFile(this::lockFile); + } + if (isImplemented("unlockFile")) { + dokanOperations.setUnlockFile(this::unlockFile); + } + if (isImplemented("getDiskFreeSpace")) { + dokanOperations.setGetDiskFreeSpace(this::getDiskFreeSpace); + } + if (isImplemented("getVolumeInformation")) { + dokanOperations.setGetVolumeInformation(this::getVolumeInformation); + } + if (isImplemented("mounted")) { + dokanOperations.setMounted(this::mounted); + } + if (isImplemented("unmounted")) { + dokanOperations.setUnmounted(this::unmounted); + } + if (isImplemented("getFileSecurity")) { + dokanOperations.setGetFileSecurity(this::getFileSecurity); + } + if (isImplemented("setFileSecurity")) { + dokanOperations.setSetFileSecurity(this::setFileSecurity); + } + if (isImplemented("fillWin32FindData")) { + //TODO: write meaningful comment why there is no method binding + } + if (isImplemented("findStreams")) { + dokanOperations.setFindStreams(this::findStreams); + } } private boolean isImplemented(String funcName) { diff --git a/src/main/java/dev/dokan/dokan_java/DokanFileSystemStub.java b/src/main/java/dev/dokan/dokan_java/DokanFileSystemStub.java index 74510ec..fce0a5c 100644 --- a/src/main/java/dev/dokan/dokan_java/DokanFileSystemStub.java +++ b/src/main/java/dev/dokan/dokan_java/DokanFileSystemStub.java @@ -12,8 +12,8 @@ public class DokanFileSystemStub extends AbstractDokanFileSystem { - public DokanFileSystemStub(FileSystemInformation fileSystemInformation, boolean usesKernelFlagsAndCodes) { - super(fileSystemInformation, usesKernelFlagsAndCodes); + public DokanFileSystemStub(FileSystemInformation fileSystemInformation) { + super(fileSystemInformation); } /** From ad476abaf7ee4140ddf6cfaa6a7b175ed81a6dde Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 27 May 2020 22:58:32 +0200 Subject: [PATCH 5/9] change DirListingFileSystem to return NtStatus codes and handle kernel flags --- .../examples/DirListingFileSystem.java | 79 +++++++++---------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/src/main/java/dev/dokan/dokan_java/examples/DirListingFileSystem.java b/src/main/java/dev/dokan/dokan_java/examples/DirListingFileSystem.java index e725a63..4488741 100644 --- a/src/main/java/dev/dokan/dokan_java/examples/DirListingFileSystem.java +++ b/src/main/java/dev/dokan/dokan_java/examples/DirListingFileSystem.java @@ -1,8 +1,8 @@ package dev.dokan.dokan_java.examples; + import com.sun.jna.Pointer; import com.sun.jna.WString; -import com.sun.jna.platform.win32.WinBase; import com.sun.jna.platform.win32.WinNT; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.LongByReference; @@ -11,9 +11,10 @@ import dev.dokan.dokan_java.DokanUtils; import dev.dokan.dokan_java.FileSystemInformation; import dev.dokan.dokan_java.constants.EnumInteger; -import dev.dokan.dokan_java.constants.microsoft.CreateOptions; -import dev.dokan.dokan_java.constants.microsoft.CreationDisposition; +import dev.dokan.dokan_java.constants.microsoft.CreateDisposition; +import dev.dokan.dokan_java.constants.microsoft.CreateOption; import dev.dokan.dokan_java.constants.microsoft.FileAttribute; +import dev.dokan.dokan_java.constants.microsoft.NtStatuses; import dev.dokan.dokan_java.constants.microsoft.Win32ErrorCodes; import dev.dokan.dokan_java.structure.ByHandleFileInformation; import dev.dokan.dokan_java.structure.DokanFileInfo; @@ -39,7 +40,7 @@ public class DirListingFileSystem extends DokanFileSystemStub { private final Path root; public DirListingFileSystem(Path root, FileSystemInformation fileSystemInformation) { - super(fileSystemInformation, false); + super(fileSystemInformation); this.root = root; this.handleHandler = new AtomicLong(0); FileStore tmp = null; @@ -56,32 +57,33 @@ public int zwCreateFile(WString rawPath, DokanIOSecurityContext securityContext, Path p = getrootedPath(rawPath); //the files must exist and we are read only here - CreationDisposition openOption = EnumInteger.enumFromInt(rawCreateDisposition, CreationDisposition.values()); - if (!Files.exists(p)) { + CreateDisposition openOption = EnumInteger.enumFromInt(rawCreateDisposition, CreateDisposition.values()); + if (Files.exists(p)) { switch (openOption) { - case CREATE_NEW: - case OPEN_ALWAYS: - case CREATE_ALWAYS: - return Win32ErrorCodes.ERROR_ACCESS_DENIED; - case OPEN_EXISTING: - case TRUNCATE_EXISTING: - return Win32ErrorCodes.ERROR_FILE_NOT_FOUND; //this is maybe a lot, but definitly not atomical + case FILE_CREATE: + return NtStatuses.STATUS_OBJECT_NAME_COLLISION; + case FILE_OPEN: + case FILE_OPEN_IF: + break; + case FILE_OVERWRITE: + case FILE_OVERWRITE_IF: + case FILE_SUPERSEDE: + return NtStatuses.STATUS_ACCESS_DENIED; default: - return Win32ErrorCodes.ERROR_GEN_FAILURE; + return NtStatuses.STATUS_UNSUCCESSFUL; } } else { switch (openOption) { - case CREATE_NEW: - return Win32ErrorCodes.ERROR_ALREADY_EXISTS; - case TRUNCATE_EXISTING: - return Win32ErrorCodes.ERROR_ACCESS_DENIED; //this is maybe a lot, but definitly not atomical - case OPEN_ALWAYS: - case CREATE_ALWAYS: - case OPEN_EXISTING: - //NO-OP - break; + case FILE_CREATE: + case FILE_OPEN_IF: + case FILE_OVERWRITE_IF: + case FILE_SUPERSEDE: + return NtStatuses.STATUS_ACCESS_DENIED; + case FILE_OPEN: + case FILE_OVERWRITE: + return NtStatuses.STATUS_OBJECT_NAME_NOT_FOUND; default: - return Win32ErrorCodes.ERROR_GEN_FAILURE; + return NtStatuses.STATUS_UNSUCCESSFUL; } } @@ -94,14 +96,11 @@ public int zwCreateFile(WString rawPath, DokanIOSecurityContext securityContext, } if (Files.isDirectory(p)) { - if ((rawCreateOptions & CreateOptions.FILE_NON_DIRECTORY_FILE) != 0) { - return Win32ErrorCodes.ERROR_DIRECTORY; + if ( EnumIntegerSet.enumSetFromInt(rawCreateOptions, CreateOption.values()).contains(CreateOption.FILE_NON_DIRECTORY_FILE)) { + return NtStatuses.STATUS_FILE_IS_A_DIRECTORY; } else { dokanFileInfo.IsDirectory = 1; } - //TODO - } else { - } long val = this.handleHandler.incrementAndGet(); @@ -111,7 +110,7 @@ public int zwCreateFile(WString rawPath, DokanIOSecurityContext securityContext, dokanFileInfo.Context = val; - return Win32ErrorCodes.ERROR_SUCCESS; + return NtStatuses.STATUS_SUCCESS; } private int setFileAttributes(Path p, EnumIntegerSet fileAttrs) { @@ -159,13 +158,13 @@ public void closeFile(WString rawPath, DokanFileInfo dokanFileInfo) { public int getFileInformation(WString rawPath, ByHandleFileInformation handleFileInfo, DokanFileInfo dokanFileInfo) { Path p = getrootedPath(rawPath); if (dokanFileInfo.Context == 0) { - return Win32ErrorCodes.ERROR_INVALID_HANDLE; + return NtStatuses.STATUS_INVALID_HANDLE; } try { getFileInformation(p).copyTo(handleFileInfo); - return Win32ErrorCodes.ERROR_SUCCESS; + return NtStatuses.STATUS_SUCCESS; } catch (IOException e) { - return Win32ErrorCodes.ERROR_READ_FAULT; + return NtStatuses.STATUS_IO_DEVICE_ERROR; } } @@ -194,7 +193,7 @@ private ByHandleFileInformation getFileInformation(Path p) throws IOException { public int findFiles(WString rawPath, DokanOperations.FillWin32FindData rawFillFindData, DokanFileInfo dokanFileInfo) { Path path = getrootedPath(rawPath); if (dokanFileInfo.Context == 0) { - return Win32ErrorCodes.ERROR_INVALID_HANDLE; + return NtStatuses.STATUS_INVALID_HANDLE; } try (Stream stream = Files.list(path)) { stream.map(p -> { @@ -208,24 +207,24 @@ public int findFiles(WString rawPath, DokanOperations.FillWin32FindData rawFillF rawFillFindData.fillWin32FindData(file, dokanFileInfo); } }); - return Win32ErrorCodes.ERROR_SUCCESS; + return NtStatuses.STATUS_SUCCESS; } catch (IOException e) { - return Win32ErrorCodes.ERROR_READ_FAULT; + return NtStatuses.STATUS_IO_DEVICE_ERROR; } } @Override public int getDiskFreeSpace(LongByReference freeBytesAvailable, LongByReference totalNumberOfBytes, LongByReference totalNumberOfFreeBytes, DokanFileInfo dokanFileInfo) { if (this.fileStore == null) { - return Win32ErrorCodes.ERROR_GEN_FAILURE; + return NtStatuses.STATUS_UNSUCCESSFUL; } else { try { freeBytesAvailable.setValue(fileStore.getUsableSpace()); totalNumberOfBytes.setValue(fileStore.getTotalSpace()); totalNumberOfFreeBytes.setValue(fileStore.getUnallocatedSpace()); - return Win32ErrorCodes.ERROR_SUCCESS; + return NtStatuses.STATUS_SUCCESS; } catch (IOException e) { - return Win32ErrorCodes.ERROR_IO_DEVICE; + return NtStatuses.STATUS_IO_DEVICE_ERROR; } } } @@ -237,7 +236,7 @@ public int getVolumeInformation(Pointer rawVolumeNameBuffer, int rawVolumeNameSi rawMaximumComponentLength.setValue(this.fileSystemInformation.getMaxComponentLength()); rawFileSystemFlags.setValue(this.fileSystemInformation.getFileSystemFeatures().toInt()); rawFileSystemNameBuffer.setWideString(0L, DokanUtils.trimStrToSize(this.fileSystemInformation.getFileSystemName(), rawFileSystemNameSize)); - return Win32ErrorCodes.ERROR_SUCCESS; + return NtStatuses.STATUS_SUCCESS; } private Path getrootedPath(WString rawPath) { From b31bc009ad61b42edd3b96fceca42fc3c13b072a Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 27 May 2020 23:16:25 +0200 Subject: [PATCH 6/9] remove not-read-only code from dir listing example --- .../examples/DirListingFileSystem.java | 36 ------------------- 1 file changed, 36 deletions(-) diff --git a/src/main/java/dev/dokan/dokan_java/examples/DirListingFileSystem.java b/src/main/java/dev/dokan/dokan_java/examples/DirListingFileSystem.java index 4488741..dc79530 100644 --- a/src/main/java/dev/dokan/dokan_java/examples/DirListingFileSystem.java +++ b/src/main/java/dev/dokan/dokan_java/examples/DirListingFileSystem.java @@ -88,13 +88,6 @@ public int zwCreateFile(WString rawPath, DokanIOSecurityContext securityContext, } - //set attributes - EnumIntegerSet fileAttrs = EnumIntegerSet.enumSetFromInt(rawFileAttributes, FileAttribute.values()); - int status = setFileAttributes(p, fileAttrs); - if (status != Win32ErrorCodes.ERROR_SUCCESS) { - return status; - } - if (Files.isDirectory(p)) { if ( EnumIntegerSet.enumSetFromInt(rawCreateOptions, CreateOption.values()).contains(CreateOption.FILE_NON_DIRECTORY_FILE)) { return NtStatuses.STATUS_FILE_IS_A_DIRECTORY; @@ -113,35 +106,6 @@ public int zwCreateFile(WString rawPath, DokanIOSecurityContext securityContext, return NtStatuses.STATUS_SUCCESS; } - private int setFileAttributes(Path p, EnumIntegerSet fileAttrs) { - DosFileAttributeView attrView = Files.getFileAttributeView(p, DosFileAttributeView.class); - try { - for (FileAttribute attr : fileAttrs) { - switch (attr) { - case HIDDEN: - attrView.setHidden(true); - break; - case READONLY: - attrView.setReadOnly(true); - break; - case ARCHIVE: - attrView.setArchive(true); - break; - case SYSTEM: - attrView.setSystem(true); - break; - default: - //not supported - break; - } - } - return Win32ErrorCodes.ERROR_SUCCESS; - } catch (IOException e) { - return Win32ErrorCodes.ERROR_WRITE_FAULT; - - } - } - @Override public void cleanup(WString rawPath, DokanFileInfo dokanFileInfo) { Path p = getrootedPath(rawPath); From a6253479cd2cdf65721b9bf8f9bcaa26f6e5467d Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 27 May 2020 23:29:12 +0200 Subject: [PATCH 7/9] remove unnecessary statement --- .../java/dev/dokan/dokan_java/AbstractDokanFileSystem.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java b/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java index 03d1d4e..dffe800 100644 --- a/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java +++ b/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java @@ -122,9 +122,6 @@ private void init(DokanOperations dokanOperations) { if (isImplemented("setFileSecurity")) { dokanOperations.setSetFileSecurity(this::setFileSecurity); } - if (isImplemented("fillWin32FindData")) { - //TODO: write meaningful comment why there is no method binding - } if (isImplemented("findStreams")) { dokanOperations.setFindStreams(this::findStreams); } From ec00aefb10321206538e616a5bce006a16cdcf5e Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 27 May 2020 23:36:05 +0200 Subject: [PATCH 8/9] add a threadinitializer to the dokan callbacks, such that if a Dokan thread uses the callbacks and returns is not detached and remains as a deamon thread --- .../dokan_java/AbstractDokanFileSystem.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java b/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java index dffe800..1a2c1bc 100644 --- a/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java +++ b/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java @@ -1,5 +1,7 @@ package dev.dokan.dokan_java; +import com.sun.jna.CallbackThreadInitializer; +import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.WString; import com.sun.jna.ptr.LongByReference; @@ -26,6 +28,7 @@ public abstract class AbstractDokanFileSystem implements DokanFileSystem { private static final int TIMEOUT = 3000; + private static final CallbackThreadInitializer DEFAULT_CALLBACK_THREAD_INITIALIZER = new CallbackThreadInitializer(); protected final FileSystemInformation fileSystemInformation; protected final DokanOperations dokanOperations; @@ -52,78 +55,103 @@ private void init(DokanOperations dokanOperations) { if (isImplemented("zwCreateFile")) { dokanOperations.setZwCreateFile(this::zwCreateFile); + Native.setCallbackThreadInitializer(dokanOperations.ZwCreateFile, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("cleanup")) { dokanOperations.setCleanup(this::cleanup); + Native.setCallbackThreadInitializer(dokanOperations.Cleanup, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("closeFile")) { dokanOperations.setCloseFile(this::closeFile); + Native.setCallbackThreadInitializer(dokanOperations.CloseFile, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("readFile")) { dokanOperations.setReadFile(this::readFile); + Native.setCallbackThreadInitializer(dokanOperations.ReadFile, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("writeFile")) { dokanOperations.setWriteFile(this::writeFile); + Native.setCallbackThreadInitializer(dokanOperations.WriteFile, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("flushFileBuffer")) { dokanOperations.setFlushFileBuffers(this::flushFileBuffers); + Native.setCallbackThreadInitializer(dokanOperations.FlushFileBuffers, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("getFileInformation")) { dokanOperations.setGetFileInformation(this::getFileInformation); + Native.setCallbackThreadInitializer(dokanOperations.GetFileInformation, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("findFiles")) { dokanOperations.setFindFiles(this::findFiles); + Native.setCallbackThreadInitializer(dokanOperations.FindFiles, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("findFilesWithPattern")) { dokanOperations.setFindFilesWithPattern(this::findFilesWithPattern); + Native.setCallbackThreadInitializer(dokanOperations.FindFilesWithPattern, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("setFileAttributes")) { dokanOperations.setSetFileAttributes(this::setFileAttributes); + Native.setCallbackThreadInitializer(dokanOperations.SetFileAttributes, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("setFileTime")) { dokanOperations.setSetFileTime(this::setFileTime); + Native.setCallbackThreadInitializer(dokanOperations.SetFileTime, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("deleteFile")) { dokanOperations.setDeleteFile(this::deleteFile); + Native.setCallbackThreadInitializer(dokanOperations.DeleteFile, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("deleteDirectory")) { dokanOperations.setDeleteDirectory(this::deleteDirectory); + Native.setCallbackThreadInitializer(dokanOperations.DeleteDirectory, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("moveFile")) { dokanOperations.setMoveFile(this::moveFile); + Native.setCallbackThreadInitializer(dokanOperations.MoveFile, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("setEndOfFile")) { dokanOperations.setSetEndOfFile(this::setEndOfFile); + Native.setCallbackThreadInitializer(dokanOperations.SetEndOfFile, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("setAllocationSize")) { dokanOperations.setSetAllocationSize(this::setAllocationSize); + Native.setCallbackThreadInitializer(dokanOperations.SetAllocationSize, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("lockFile")) { dokanOperations.setLockFile(this::lockFile); + Native.setCallbackThreadInitializer(dokanOperations.LockFile, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("unlockFile")) { dokanOperations.setUnlockFile(this::unlockFile); + Native.setCallbackThreadInitializer(dokanOperations.UnlockFile, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("getDiskFreeSpace")) { dokanOperations.setGetDiskFreeSpace(this::getDiskFreeSpace); + Native.setCallbackThreadInitializer(dokanOperations.GetDiskFreeSpace, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("getVolumeInformation")) { dokanOperations.setGetVolumeInformation(this::getVolumeInformation); + Native.setCallbackThreadInitializer(dokanOperations.GetVolumeInformation, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("mounted")) { dokanOperations.setMounted(this::mounted); + Native.setCallbackThreadInitializer(dokanOperations.Mounted, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("unmounted")) { dokanOperations.setUnmounted(this::unmounted); + Native.setCallbackThreadInitializer(dokanOperations.Unmounted, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("getFileSecurity")) { dokanOperations.setGetFileSecurity(this::getFileSecurity); + Native.setCallbackThreadInitializer(dokanOperations.GetFileSecurity, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("setFileSecurity")) { dokanOperations.setSetFileSecurity(this::setFileSecurity); + Native.setCallbackThreadInitializer(dokanOperations.SetFileSecurity, DEFAULT_CALLBACK_THREAD_INITIALIZER); } if (isImplemented("findStreams")) { dokanOperations.setFindStreams(this::findStreams); + Native.setCallbackThreadInitializer(dokanOperations.FindStreams, DEFAULT_CALLBACK_THREAD_INITIALIZER); } } From e0cbff18549b35edf5edd2be55b38b8d0f0b0f3d Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 27 May 2020 23:37:03 +0200 Subject: [PATCH 9/9] reformat AbstractDokanFileSystem --- .../dokan_java/AbstractDokanFileSystem.java | 238 +++++++++--------- 1 file changed, 120 insertions(+), 118 deletions(-) diff --git a/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java b/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java index 1a2c1bc..3dd13df 100644 --- a/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java +++ b/src/main/java/dev/dokan/dokan_java/AbstractDokanFileSystem.java @@ -1,5 +1,6 @@ package dev.dokan.dokan_java; + import com.sun.jna.CallbackThreadInitializer; import com.sun.jna.Native; import com.sun.jna.Pointer; @@ -22,36 +23,37 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; + /** * TODO: Add Description to this class */ public abstract class AbstractDokanFileSystem implements DokanFileSystem { - private static final int TIMEOUT = 3000; - private static final CallbackThreadInitializer DEFAULT_CALLBACK_THREAD_INITIALIZER = new CallbackThreadInitializer(); + private static final int TIMEOUT = 3000; + private static final CallbackThreadInitializer DEFAULT_CALLBACK_THREAD_INITIALIZER = new CallbackThreadInitializer(); - protected final FileSystemInformation fileSystemInformation; - protected final DokanOperations dokanOperations; - protected Path mountPoint; - protected String volumeName; - protected int volumeSerialnumber; - protected DokanOptions dokanOptions; + protected final FileSystemInformation fileSystemInformation; + protected final DokanOperations dokanOperations; + protected Path mountPoint; + protected String volumeName; + protected int volumeSerialnumber; + protected DokanOptions dokanOptions; - private final AtomicBoolean isMounted; - private Set notImplementedMethods; + private final AtomicBoolean isMounted; + private Set notImplementedMethods; - public AbstractDokanFileSystem(FileSystemInformation fileSystemInformation) { - this.fileSystemInformation = fileSystemInformation; - this.isMounted = new AtomicBoolean(false); - this.dokanOperations = new DokanOperations(); - init(dokanOperations); - } + public AbstractDokanFileSystem(FileSystemInformation fileSystemInformation) { + this.fileSystemInformation = fileSystemInformation; + this.isMounted = new AtomicBoolean(false); + this.dokanOperations = new DokanOperations(); + init(dokanOperations); + } - private void init(DokanOperations dokanOperations) { - notImplementedMethods = Arrays.stream(getClass().getMethods()) - .filter(method -> method.getAnnotation(NotImplemented.class) != null) - .map(Method::getName) - .collect(Collectors.toSet()); + private void init(DokanOperations dokanOperations) { + notImplementedMethods = Arrays.stream(getClass().getMethods()) + .filter(method -> method.getAnnotation(NotImplemented.class) != null) + .map(Method::getName) + .collect(Collectors.toSet()); if (isImplemented("zwCreateFile")) { dokanOperations.setZwCreateFile(this::zwCreateFile); @@ -153,114 +155,114 @@ private void init(DokanOperations dokanOperations) { dokanOperations.setFindStreams(this::findStreams); Native.setCallbackThreadInitializer(dokanOperations.FindStreams, DEFAULT_CALLBACK_THREAD_INITIALIZER); } - } + } - private boolean isImplemented(String funcName) { - return !notImplementedMethods.contains(funcName); - } + private boolean isImplemented(String funcName) { + return !notImplementedMethods.contains(funcName); + } - /** - * The general mount method. If the underlying system supports shutdown hooks, one is installed in case the JVM is shutting down and the filesystem is still mounted. - * - * @param mountPoint path pointing to an empty directory or unused drive letter - * @param volumeName the displayed name of the volume (only important when a drive letter is used as a mount point) - * @param volumeSerialnumber the serial number of the volume (only important when a drive letter is used as a mount point) - * @param blocking if true the mount and further file system calls are foreground operations and thus will block this thread. To unmount the device you have to use the dokanctl.exe tool. - * @param timeout timeout after which a not processed file system call is canceled and the volume is unmounted - * @param allocationUnitSize the size of the smallest allocatable space in bytes - * @param sectorSize the sector size - * @param UNCName - * @param threadCount the number of threads spawned for processing filesystem calls - * @param options an {@link EnumIntegerSet} containing {@link MountOption}s - */ - @Override - public final synchronized void mount(Path mountPoint, String volumeName, int volumeSerialnumber, boolean blocking, long timeout, long allocationUnitSize, long sectorSize, String UNCName, short threadCount, EnumIntegerSet options) { - this.dokanOptions = new DokanOptions(mountPoint.toString(), threadCount, options, UNCName, timeout, allocationUnitSize, sectorSize); - this.mountPoint = mountPoint; - this.volumeName = volumeName; - this.volumeSerialnumber = volumeSerialnumber; + /** + * The general mount method. If the underlying system supports shutdown hooks, one is installed in case the JVM is shutting down and the filesystem is still mounted. + * + * @param mountPoint path pointing to an empty directory or unused drive letter + * @param volumeName the displayed name of the volume (only important when a drive letter is used as a mount point) + * @param volumeSerialnumber the serial number of the volume (only important when a drive letter is used as a mount point) + * @param blocking if true the mount and further file system calls are foreground operations and thus will block this thread. To unmount the device you have to use the dokanctl.exe tool. + * @param timeout timeout after which a not processed file system call is canceled and the volume is unmounted + * @param allocationUnitSize the size of the smallest allocatable space in bytes + * @param sectorSize the sector size + * @param UNCName + * @param threadCount the number of threads spawned for processing filesystem calls + * @param options an {@link EnumIntegerSet} containing {@link MountOption}s + */ + @Override + public final synchronized void mount(Path mountPoint, String volumeName, int volumeSerialnumber, boolean blocking, long timeout, long allocationUnitSize, long sectorSize, String UNCName, short threadCount, EnumIntegerSet options) { + this.dokanOptions = new DokanOptions(mountPoint.toString(), threadCount, options, UNCName, timeout, allocationUnitSize, sectorSize); + this.mountPoint = mountPoint; + this.volumeName = volumeName; + this.volumeSerialnumber = volumeSerialnumber; - try { - int mountStatus; + try { + int mountStatus; - if (DokanUtils.canHandleShutdownHooks()) { - Runtime.getRuntime().addShutdownHook(new Thread(this::unmount)); - } + if (DokanUtils.canHandleShutdownHooks()) { + Runtime.getRuntime().addShutdownHook(new Thread(this::unmount)); + } - if (blocking) { - mountStatus = execMount(dokanOptions); - } else { - try { - mountStatus = CompletableFuture - .supplyAsync(() -> execMount(dokanOptions)) - .get(TIMEOUT, TimeUnit.MILLISECONDS); - } catch (TimeoutException e) { - // ok - mountStatus = 0; - } - isMounted.set(true); - } - if (mountStatus < 0) { - throw new RuntimeException("Negative result of mount operation. Code" + mountStatus + " -- " + MountError.fromInt(mountStatus).getDescription()); - } - } catch (UnsatisfiedLinkError | Exception e) { - throw new MountFailedException("Unable to mount filesystem.", e); - } - } + if (blocking) { + mountStatus = execMount(dokanOptions); + } else { + try { + mountStatus = CompletableFuture + .supplyAsync(() -> execMount(dokanOptions)) + .get(TIMEOUT, TimeUnit.MILLISECONDS); + } catch (TimeoutException e) { + // ok + mountStatus = 0; + } + isMounted.set(true); + } + if (mountStatus < 0) { + throw new RuntimeException("Negative result of mount operation. Code" + mountStatus + " -- " + MountError.fromInt(mountStatus).getDescription()); + } + } catch (UnsatisfiedLinkError | Exception e) { + throw new MountFailedException("Unable to mount filesystem.", e); + } + } - /** - * Additional method for easy mounting with a lot of default values - * - * @param mountPoint - * @param mountOptions - */ - public void mount(Path mountPoint, EnumIntegerSet mountOptions) { - String uncName = null; - short threadCount = 5; - long timeout = 3000; - long allocationUnitSize = 4096; - long sectorsize = 512; - String volumeName = "DOKAN"; - int volumeSerialnumber = 30975; - mount(mountPoint, volumeName, volumeSerialnumber, false, timeout, allocationUnitSize, sectorsize, uncName, threadCount, mountOptions); - } + /** + * Additional method for easy mounting with a lot of default values + * + * @param mountPoint + * @param mountOptions + */ + public void mount(Path mountPoint, EnumIntegerSet mountOptions) { + String uncName = null; + short threadCount = 5; + long timeout = 3000; + long allocationUnitSize = 4096; + long sectorsize = 512; + String volumeName = "DOKAN"; + int volumeSerialnumber = 30975; + mount(mountPoint, volumeName, volumeSerialnumber, false, timeout, allocationUnitSize, sectorsize, uncName, threadCount, mountOptions); + } - private int execMount(DokanOptions dokanOptions) { - return DokanNativeMethods.DokanMain(dokanOptions, this.dokanOperations); - } + private int execMount(DokanOptions dokanOptions) { + return DokanNativeMethods.DokanMain(dokanOptions, this.dokanOperations); + } - @Override - public final synchronized void unmount() { - if (!volumeIsStillMounted()) { - isMounted.set(false); - } + @Override + public final synchronized void unmount() { + if (!volumeIsStillMounted()) { + isMounted.set(false); + } - if (isMounted.get()) { - if (DokanNativeMethods.DokanRemoveMountPoint(new WString(mountPoint.toAbsolutePath().toString()))) { - isMounted.set(false); - } else { - throw new UnmountFailedException("Unmount of " + volumeName + "(" + mountPoint + ") failed. Try again, shut down JVM or use `dokanctl.exe to unmount manually."); - } - } - } + if (isMounted.get()) { + if (DokanNativeMethods.DokanRemoveMountPoint(new WString(mountPoint.toAbsolutePath().toString()))) { + isMounted.set(false); + } else { + throw new UnmountFailedException("Unmount of " + volumeName + "(" + mountPoint + ") failed. Try again, shut down JVM or use `dokanctl.exe to unmount manually."); + } + } + } - private boolean volumeIsStillMounted() { - char[] mntPtCharArray = mountPoint.toAbsolutePath().toString().toCharArray(); - LongByReference length = new LongByReference(); - Pointer startOfList = DokanNativeMethods.DokanGetMountPointList(false, length); - List list = DokanControl.getDokanControlList(startOfList, length.getValue()); - // It is not enough that the entry.MountPoint contains the actual mount point. It also has to ends afterwards. - boolean mountPointInList = list.stream().anyMatch(entry -> - Arrays.equals(entry.MountPoint, 12, 12 + mntPtCharArray.length, mntPtCharArray, 0, mntPtCharArray.length) - && (entry.MountPoint.length == 12 + mntPtCharArray.length || entry.MountPoint[12 + mntPtCharArray.length] == '\0')); - DokanNativeMethods.DokanReleaseMountPointList(startOfList); - return mountPointInList; - } + private boolean volumeIsStillMounted() { + char[] mntPtCharArray = mountPoint.toAbsolutePath().toString().toCharArray(); + LongByReference length = new LongByReference(); + Pointer startOfList = DokanNativeMethods.DokanGetMountPointList(false, length); + List list = DokanControl.getDokanControlList(startOfList, length.getValue()); + // It is not enough that the entry.MountPoint contains the actual mount point. It also has to ends afterwards. + boolean mountPointInList = list.stream().anyMatch(entry -> + Arrays.equals(entry.MountPoint, 12, 12 + mntPtCharArray.length, mntPtCharArray, 0, mntPtCharArray.length) + && (entry.MountPoint.length == 12 + mntPtCharArray.length || entry.MountPoint[12 + mntPtCharArray.length] == '\0')); + DokanNativeMethods.DokanReleaseMountPointList(startOfList); + return mountPointInList; + } - @Override - public void close() { - unmount(); - } + @Override + public void close() { + unmount(); + } }