diff --git a/CHANGES.md b/CHANGES.md
index 3fa61de086..42c4b8ae4a 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -63,6 +63,10 @@ Features
* [#689](https://github.com/java-native-access/jna/pull/689): Add `GetProcAddress(HMODULE, int)` to `com.sun.jna.platform.win32.Kernel32` - [@matthiasblaesing](https://github.com/matthiasblaesing).
* [#723](https://github.com/java-native-access/jna/pull/723): Added `com.sun.jna.platform.win32.Wevtapi` and `com.sun.jna.platform.win32.Winevt` - [@sakamotodesu](https://github.com/sakamotodesu).
* [#720](https://github.com/java-native-access/jna/issues/720): Added `SetThreadExecutionState` to `com.sun.jna.platform.win32.Kernel32` - [@matthiasblaesing](https://github.com/matthiasblaesing).
+* [#732](https://github.com/java-native-access/jna/pull/732): Added `com.sun.jna.platform.win32.WinioctlUtil` for help in determining FSCTL_* codes - [@amarcionek](https://github.com/amarcionek).
+* [#732](https://github.com/java-native-access/jna/pull/732): Added `com.sun.jna.platform.win32.Ntifs` with Reparse Point structures and defines - [@amarcionek](https://github.com/amarcionek).
+* [#732](https://github.com/java-native-access/jna/pull/732): Added initialization of FILETIME from LARGE_INTEGER - [@amarcionek](https://github.com/amarcionek).
+* [#732](https://github.com/java-native-access/jna/pull/732): Added `GetFileInformationByHandleEx` and `SetFileInformationByHandle` to `com.sun.jna.platform.win32.Kernel32` - [@amarcionek](https://github.com/amarcionek).
Bug Fixes
---------
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java
index 7715451120..ecb23c5120 100755
--- a/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java
@@ -41,6 +41,7 @@
import static com.sun.jna.platform.win32.WinNT.SE_DACL_PROTECTED;
import static com.sun.jna.platform.win32.WinNT.SE_SACL_PROTECTED;
import static com.sun.jna.platform.win32.WinNT.STANDARD_RIGHTS_READ;
+import static com.sun.jna.platform.win32.WinNT.TOKEN_ADJUST_PRIVILEGES;
import static com.sun.jna.platform.win32.WinNT.TOKEN_DUPLICATE;
import static com.sun.jna.platform.win32.WinNT.TOKEN_IMPERSONATE;
import static com.sun.jna.platform.win32.WinNT.TOKEN_QUERY;
@@ -48,6 +49,7 @@
import static com.sun.jna.platform.win32.WinNT.UNPROTECTED_SACL_SECURITY_INFORMATION;
import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -81,6 +83,7 @@
import com.sun.jna.platform.win32.WinNT.SECURITY_IMPERSONATION_LEVEL;
import com.sun.jna.platform.win32.WinNT.SID_AND_ATTRIBUTES;
import com.sun.jna.platform.win32.WinNT.SID_NAME_USE;
+import com.sun.jna.platform.win32.WinNT.TOKEN_TYPE;
import com.sun.jna.platform.win32.WinReg.HKEY;
import com.sun.jna.platform.win32.WinReg.HKEYByReference;
import com.sun.jna.ptr.IntByReference;
@@ -2636,4 +2639,207 @@ public DWORD callback(Pointer pbData, Pointer pvCallbackContext,
// close
Advapi32.INSTANCE.CloseEncryptedFileRaw(pvContext.getValue());
}
+
+ /**
+ * Convenience class to enable certain Windows process privileges
+ */
+ public static class Privilege implements Closeable {
+ /**
+ * If true, the thread is currently impersonating
+ */
+ private boolean currentlyImpersonating = false;
+
+ /**
+ * If true, the privileges have been enabled
+ */
+ private boolean privilegesEnabled = false;
+
+ /**
+ * LUID form of the privileges
+ */
+ private final WinNT.LUID[] pLuids;
+
+ /**
+ * Construct and enable a set of privileges
+ * @param privileges the names of the privileges in the form of SE_* from Advapi32.java
+ * @throws IllegalArgumentException
+ */
+ public Privilege(String... privileges) throws IllegalArgumentException, Win32Exception {
+ pLuids = new WinNT.LUID[privileges.length];
+ int i = 0;
+ for (String p : privileges) {
+ pLuids[i] = new WinNT.LUID();
+ if (!Advapi32.INSTANCE.LookupPrivilegeValue(null, p, pLuids[i])) {
+ throw new IllegalArgumentException("Failed to find privilege \"" + privileges[i] + "\" - " + Kernel32.INSTANCE.GetLastError());
+ }
+ i++;
+ }
+ }
+
+ /**
+ * Calls disable() to remove the privileges
+ * @see java.io.Closeable#close()
+ */
+ @Override
+ public void close() {
+ this.disable();
+ }
+
+ /**
+ * Enables the given privileges. If required, it will duplicate the process token. No resources are left open when this completes. That is, it is
+ * NOT required to drop the privileges, although it is considered a best practice if you do not need it. This class is state full. It keeps track
+ * of whether it has enabled the privileges. Multiple calls to enable() without a drop() in between have no affect.
+ * @return pointer to self (Privilege) as a convenience for try with resources statements
+ * @throws Win32Exception
+ */
+ public Privilege enable() throws Win32Exception {
+ // Ignore if already enabled.
+ if (privilegesEnabled)
+ return this;
+
+ // Get thread token
+ final HANDLEByReference phThreadToken = new HANDLEByReference();
+
+ try {
+ phThreadToken.setValue(getThreadToken());
+ WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(pLuids.length);
+ for (int i = 0; i < pLuids.length; i++) {
+ tp.Privileges[i] = new WinNT.LUID_AND_ATTRIBUTES(pLuids[i], new DWORD(WinNT.SE_PRIVILEGE_ENABLED));
+ }
+ if (!Advapi32.INSTANCE.AdjustTokenPrivileges(phThreadToken.getValue(), false, tp, 0, null, null)) {
+ throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
+ }
+ privilegesEnabled = true;
+ }
+ catch (Win32Exception ex) {
+ // If fails, clean up
+ if (currentlyImpersonating) {
+ Advapi32.INSTANCE.SetThreadToken(null, null);
+ currentlyImpersonating = false;
+ }
+ else {
+ if (privilegesEnabled) {
+ WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(pLuids.length);
+ for (int i = 0; i < pLuids.length; i++) {
+ tp.Privileges[i] = new WinNT.LUID_AND_ATTRIBUTES(pLuids[i], new DWORD(0));
+ }
+ Advapi32.INSTANCE.AdjustTokenPrivileges(phThreadToken.getValue(), false, tp, 0, null, null);
+ privilegesEnabled = false;
+ }
+ }
+ throw ex;
+ }
+ finally {
+ // Always close the thread token
+ if ((phThreadToken.getValue() != WinBase.INVALID_HANDLE_VALUE)
+ && (phThreadToken.getValue() != null)) {
+ Kernel32.INSTANCE.CloseHandle(phThreadToken.getValue());
+ phThreadToken.setValue(null);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Disabled the prior enabled privilege
+ * @throws Win32Exception
+ */
+ public void disable() throws Win32Exception {
+ // Get thread token
+ final HANDLEByReference phThreadToken = new HANDLEByReference();
+
+ try {
+ phThreadToken.setValue(getThreadToken());
+ if (currentlyImpersonating) {
+ Advapi32.INSTANCE.SetThreadToken(null, null);
+ }
+ else
+ {
+ if (privilegesEnabled) {
+ WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(pLuids.length);
+ for (int i = 0; i < pLuids.length; i++) {
+ tp.Privileges[i] = new WinNT.LUID_AND_ATTRIBUTES(pLuids[i], new DWORD(0));
+ }
+ Advapi32.INSTANCE.AdjustTokenPrivileges(phThreadToken.getValue(), false, tp, 0, null, null);
+ privilegesEnabled = false;
+ }
+ }
+ }
+ finally {
+ // Close the thread token
+ if ((phThreadToken.getValue() != WinBase.INVALID_HANDLE_VALUE)
+ && (phThreadToken.getValue() != null)) {
+ Kernel32.INSTANCE.CloseHandle(phThreadToken.getValue());
+ phThreadToken.setValue(null);
+ }
+ }
+ }
+
+ /**
+ * Get a handle to the thread token. May duplicate the process token
+ * and set as the thread token if ther thread has no token.
+ * @return HANDLE to the thread token
+ * @throws Win32Exception
+ */
+ private HANDLE getThreadToken() throws Win32Exception {
+ // we need to create a new token here for the duplicate
+ final HANDLEByReference phThreadToken = new HANDLEByReference();
+ final HANDLEByReference phProcessToken = new HANDLEByReference();
+
+ try {
+ // open thread token
+ if (!Advapi32.INSTANCE.OpenThreadToken(Kernel32.INSTANCE.GetCurrentThread(),
+ TOKEN_ADJUST_PRIVILEGES,
+ false,
+ phThreadToken)) {
+ // OpenThreadToken may fail with W32Errors.ERROR_NO_TOKEN if current thread is anonymous. Check for that condition here. If not, throw an error.
+ int lastError = Kernel32.INSTANCE.GetLastError();
+ if (W32Errors.ERROR_NO_TOKEN != lastError) {
+ throw new Win32Exception(lastError);
+ }
+
+ // Due to ERROR_NO_TOKEN, we need to open the process token to duplicate it, then set our thread token.
+ if (!Advapi32.INSTANCE.OpenProcessToken(Kernel32.INSTANCE.GetCurrentProcess(), TOKEN_DUPLICATE, phProcessToken)) {
+ throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
+ }
+
+ // Process token opened, now duplicate
+ if (!Advapi32.INSTANCE.DuplicateTokenEx(phProcessToken.getValue(),
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_IMPERSONATE,
+ null,
+ SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
+ TOKEN_TYPE.TokenImpersonation,
+ phThreadToken)) {
+ throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
+ }
+
+ // And set thread token.
+ if (!Advapi32.INSTANCE.SetThreadToken(null, phThreadToken.getValue())) {
+ throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
+ }
+ currentlyImpersonating = true;
+ }
+ }
+ catch (Win32Exception ex) {
+ // Close the thread token
+ if ((phThreadToken.getValue() != WinBase.INVALID_HANDLE_VALUE)
+ && (phThreadToken.getValue() != null)) {
+ Kernel32.INSTANCE.CloseHandle(phThreadToken.getValue());
+ phThreadToken.setValue(null);
+ }
+ throw ex;
+ }
+ finally
+ {
+ // Always close the process token
+ if ((phProcessToken.getValue() != WinBase.INVALID_HANDLE_VALUE)
+ && (phProcessToken.getValue() != null)) {
+ Kernel32.INSTANCE.CloseHandle(phProcessToken.getValue());
+ phProcessToken.setValue(null);
+ }
+ }
+
+ return phThreadToken.getValue();
+ }
+ }
}
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java
index fcca23ec1a..f66595f050 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java
@@ -1443,6 +1443,48 @@ boolean GetLogicalProcessorInformation(Pointer buffer,
*/
boolean GlobalMemoryStatusEx(MEMORYSTATUSEX lpBuffer);
+ /**
+ * Retrieves file information for the specified file.
+ * To set file information using a file handle, see SetFileInformationByHandle.
+ * @param hFile
+ * A handle to the file that contains the information to be retrieved.
+ * @param FileInformationClass
+ * A FILE_INFO_BY_HANDLE_CLASS enumeration value that specifies the type of
+ * information to be retrieved.
+ * @param lpFileInformation
+ * A pointer to the buffer that receives the requested file information.
+ * The structure that is returned corresponds to the class that is specified
+ * by FileInformationClass.
+ * @param dwBufferSize
+ * The size of the lpFileInformation buffer, in bytes.
+ * @return If the function succeeds, the return value is nonzero and file information
+ * data is contained in the buffer pointed to by the lpFileInformation parameter.
+ * If the function fails, the return value is zero. To get extended error
+ * information, call GetLastError.
+ */
+ boolean GetFileInformationByHandleEx(HANDLE hFile, int FileInformationClass, Pointer lpFileInformation, DWORD dwBufferSize);
+
+ /**
+ * Sets the file information for the specified file. To retrieve file information using a
+ * file handle, see GetFileInformationByHandleEx.
+ * @param hFile
+ * A handle to the file for which to change information.
+ * This handle must be opened with the appropriate permissions for the
+ * requested change. This handle should not be a pipe handle.
+ * @param FileInformationClass
+ * A FILE_INFO_BY_HANDLE_CLASS enumeration value that specifies the type of information to be changed.
+ * Valid values are FILE_BASIC_INFO, FILE_RENAME_INFO, FILE_DISPOSITION_INFO, FILE_ALLOCATION_INFO,
+ * FILE_END_OF_FILE_INFO, and FILE_IO_PRIORITY_HINT_INFO
+ * @param lpFileInformation
+ * A pointer to the buffer that contains the information to change for the specified file
+ * information class. The structure that this parameter points to corresponds to the class
+ * that is specified by FileInformationClass.
+ * @param dwBufferSize
+ * The size of the lpFileInformation buffer, in bytes.
+ * @return Returns nonzero if successful or zero otherwise. To get extended error information, call GetLastError.
+ */
+ boolean SetFileInformationByHandle(HANDLE hFile, int FileInformationClass, Pointer lpFileInformation, DWORD dwBufferSize);
+
/**
* Retrieves the date and time that a file or directory was created, last
* accessed, and last modified.
@@ -2494,6 +2536,18 @@ boolean SystemTimeToTzSpecificLocalTime(TIME_ZONE_INFORMATION lpTimeZone,
*/
boolean SystemTimeToFileTime(SYSTEMTIME lpSystemTime, FILETIME lpFileTime);
+ /**
+ * Converts a file time to system time format. System time is based on Coordinated Universal Time (UTC).
+ * @param lpFileTime
+ * [in] A pointer to a FILETIME structure containing the file time to be converted to system (UTC) date and time format.
+ This value must be less than 0x8000000000000000. Otherwise, the function fails.
+ * @param lpSystemTime
+ * A pointer to a SYSTEMTIME structure to receive the converted file time.
+ * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero.
+ * To get extended error information, call GetLastError.
+ */
+ boolean FileTimeToSystemTime(FILETIME lpFileTime, SYSTEMTIME lpSystemTime);
+
/**
* Creates a thread that runs in the virtual address space of another process.
*
@@ -2627,6 +2681,100 @@ boolean SystemTimeToTzSpecificLocalTime(TIME_ZONE_INFORMATION lpTimeZone,
*/
int QueryDosDevice(String lpDeviceName, char[] lpTargetPath, int ucchMax);
+ /**
+ * Searches a directory for a file or subdirectory with a name that matches a specific name (or partial name if wildcards are used).
+ * To specify additional attributes to use in a search, use the FindFirstFileEx function.
+ * @param lpFileName
+ * The directory or path, and the file name. The file name can include wildcard characters,
+ * for example, an asterisk (*) or a question mark (?).
+ * This parameter should not be NULL, an invalid string (for example, an empty string or a string that is
+ * missing the terminating null character), or end in a trailing backslash (\).
+ * If the string ends with a wildcard, period, or directory name, the user must have access to the root
+ * and all subdirectories on the path.
+ * In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this
+ * limit to approximately 32,000 wide characters, call the Unicode version of the function (FindFirstFileExW),
+ * and prepend "\\?\" to the path. For more information, see Naming a File.
+ * Tip Starting in Windows 10, version 1607, for the unicode version of this function (FindFirstFileExW),
+ * you can opt-in to remove the MAX_PATH character limitation without prepending "\\?\".
+ * See the "Maximum Path Limitation" section of Naming Files, Paths, and Namespaces for details.
+ * @param lpFindFileData
+ * A pointer to the buffer that receives the file data. The pointer type is determined by the level of
+ * information that is specified in the fInfoLevelId parameter.
+ * @return If the function succeeds, the return value is a search handle used in a subsequent call to FindNextFile or FindClose,
+ * and the lpFindFileData parameter contains information about the first file or directory found.
+ * If the function fails or fails to locate files from the search string in the lpFileName parameter, the return
+ * value is INVALID_HANDLE_VALUE and the contents of lpFindFileData are indeterminate.
+ * To get extended error information, call the GetLastError function.
+ * If the function fails because no matching files can be found, the GetLastError function returns ERROR_FILE_NOT_FOUND.
+ */
+ HANDLE FindFirstFile(String lpFileName, Pointer lpFindFileData);
+
+ /**
+ * Searches a directory for a file or subdirectory with a name and attributes that match those specified. For the most basic
+ * version of this function, see FindFirstFile.
+ * @param lpFileName
+ * The directory or path, and the file name. The file name can include wildcard characters,
+ * for example, an asterisk (*) or a question mark (?).
+ * This parameter should not be NULL, an invalid string (for example, an empty string or a string that is
+ * missing the terminating null character), or end in a trailing backslash (\).
+ * If the string ends with a wildcard, period, or directory name, the user must have access to the root
+ * and all subdirectories on the path.
+ * In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this
+ * limit to approximately 32,000 wide characters, call the Unicode version of the function (FindFirstFileExW),
+ * and prepend "\\?\" to the path. For more information, see Naming a File.
+ * Tip Starting in Windows 10, version 1607, for the unicode version of this function (FindFirstFileExW),
+ * you can opt-in to remove the MAX_PATH character limitation without prepending "\\?\".
+ * See the "Maximum Path Limitation" section of Naming Files, Paths, and Namespaces for details.
+ * @param fInfoLevelId
+ * The information level of the returned data. This parameter is one of the FINDEX_INFO_LEVELS enumeration values.
+ * @param lpFindFileData
+ * A pointer to the buffer that receives the file data. The pointer type is determined by the level of
+ * information that is specified in the fInfoLevelId parameter.
+ * @param fSearchOp
+ * The type of filtering to perform that is different from wildcard matching. This parameter is one of
+ * the FINDEX_SEARCH_OPS enumeration values.
+ * @param lpSearchFilter
+ * A pointer to the search criteria if the specified fSearchOp needs structured search information.
+ * At this time, none of the supported fSearchOp values require extended search information. Therefore,
+ * this pointer must be NULL.
+ * @param dwAdditionalFlags
+ * Specifies additional flags that control the search.
+ * FIND_FIRST_EX_CASE_SENSITIVE (0x01) - Searches are case-sensitive.
+ * FIND_FIRST_EX_LARGE_FETCH (0x02) - Uses a larger buffer for directory queries, which can increase performance
+ * of the find operation. Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This value
+ * is not supported until Windows Server 2008 R2 and Windows 7.
+ * @return If the function succeeds, the return value is a search handle used in a subsequent call to FindNextFile or FindClose,
+ * and the lpFindFileData parameter contains information about the first file or directory found.
+ * If the function fails or fails to locate files from the search string in the lpFileName parameter, the return
+ * value is INVALID_HANDLE_VALUE and the contents of lpFindFileData are indeterminate.
+ * To get extended error information, call the GetLastError function.
+ * If the function fails because no matching files can be found, the GetLastError function returns ERROR_FILE_NOT_FOUND.
+ */
+ HANDLE FindFirstFileEx(String lpFileName, int fInfoLevelId, Pointer lpFindFileData, int fSearchOp, Pointer lpSearchFilter, DWORD dwAdditionalFlags);
+
+ /**
+ * Continues a file search from a previous call to the FindFirstFile, FindFirstFileEx, or FindFirstFileTransacted functions.
+ * @param hFindFile
+ * The search handle returned by a previous call to the FindFirstFile or FindFirstFileEx function.
+ * @param lpFindFileData
+ * A pointer to the WIN32_FIND_DATA structure that receives information about the found file or subdirectory.
+ * @return If the function succeeds, the return value is nonzero and the lpFindFileData parameter contains
+ * information about the next file or directory found. If the function fails, the return value is zero and the
+ * contents of lpFindFileData are indeterminate. To get extended error information, call the GetLastError function.
+ * If the function fails because no more matching files can be found, the GetLastError function returns ERROR_NO_MORE_FILES.
+ */
+ boolean FindNextFile(HANDLE hFindFile, Pointer lpFindFileData);
+
+ /**
+ * Closes a file search handle opened by the FindFirstFile, FindFirstFileEx, FindFirstFileNameW, FindFirstFileNameTransactedW,
+ * FindFirstFileTransacted, FindFirstStreamTransactedW, or FindFirstStreamW functions.
+ * @param hFindFile
+ * The file search handle.
+ * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero.
+ * To get extended error information, call GetLastError.
+ */
+ boolean FindClose(HANDLE hFindFile);
+
/**
* Retrieves the name of a mounted folder on the specified volume - used
* to begin scanning the mounted folders on a volume
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Ntifs.java b/contrib/platform/src/com/sun/jna/platform/win32/Ntifs.java
new file mode 100644
index 0000000000..bb868b28c7
--- /dev/null
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Ntifs.java
@@ -0,0 +1,402 @@
+/* Copyright (c) 2016 Adam Marcionek, All Rights Reserved
+ *
+ * The contents of this file is dual-licensed under 2
+ * alternative Open Source/Free licenses: LGPL 2.1 or later and
+ * Apache License 2.0. (starting with JNA version 4.0.0).
+ *
+ * You can freely decide which license you want to apply to
+ * the project.
+ *
+ * You may obtain a copy of the LGPL License at:
+ *
+ * http://www.gnu.org/licenses/licenses.html
+ *
+ * A copy is also included in the downloadable source code package
+ * containing JNA, in file "LGPL2.1".
+ *
+ * You may obtain a copy of the Apache License at:
+ *
+ * http://www.apache.org/licenses/
+ *
+ * A copy is also included in the downloadable source code package
+ * containing JNA, in file "AL2.0".
+ */
+package com.sun.jna.platform.win32;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.sun.jna.Native;
+import com.sun.jna.Pointer;
+import com.sun.jna.Structure;
+import com.sun.jna.Union;
+import com.sun.jna.win32.W32APITypeMapper;
+
+/**
+ * Ported from Ntifs.h
+ * Microsoft Windows WDK 10
+ * @author amarcionek[at]gmail.com
+ */
+public interface Ntifs extends WinDef, BaseTSD {
+
+ // Defined in winnt.h
+ public int MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024;
+
+ // 1 long and 2 shorts aligned on longlong
+ public int REPARSE_BUFFER_HEADER_SIZE = 8;
+
+ public int SYMLINK_FLAG_RELATIVE = 1;
+
+ public static class SymbolicLinkReparseBuffer extends Structure {
+
+ public static class ByReference extends SymbolicLinkReparseBuffer implements Structure.ByReference {
+ public ByReference() {
+ }
+
+ public ByReference(Pointer memory) {
+ super(memory);
+ }
+ }
+
+ /**
+ * Offset, in bytes, of the substitute name string in the PathBuffer array.
+ * Note that this offset must be divided by sizeof(WCHAR) to get the array index.
+ */
+ public short SubstituteNameOffset = 0;
+
+ /**
+ * Length, in bytes, of the substitute name string. If this string is NULL-terminated,
+ * SubstituteNameLength does not include space for the UNICODE_NULL character.
+ */
+ public short SubstituteNameLength = 0;
+
+ /**
+ * Offset, in bytes, of the print name string in the PathBuffer array.
+ * Note that this offset must be divided by sizeof(WCHAR) to get the array index.
+ */
+ public short PrintNameOffset = 0;
+
+ /**
+ * Length, in bytes, of the print name string. If this string is NULL-terminated,
+ * PrintNameLength does not include space for the UNICODE_NULL character.
+ */
+ public short PrintNameLength = 0;
+
+ /**
+ * Used to indicate if the given symbolic link is an absolute or relative symbolic link.
+ * If Flags contains SYMLINK_FLAG_RELATIVE, the symbolic link contained in the PathBuffer
+ * array (at offset SubstitueNameOffset) is processed as a relative symbolic link; otherwise,
+ * it is processed as an absolute symbolic link.
+ */
+ public int Flags = 0;
+
+ /**
+ * First character of the path string. This is followed in memory by the remainder of the string.
+ * The path string contains the substitute name string and print name string. The substitute name
+ * and print name strings can appear in any order in the PathBuffer. (To locate the substitute
+ * name and print name strings in the PathBuffer, use the SubstituteNameOffset, SubstituteNameLength,
+ * PrintNameOffset, and PrintNameLength members.)
+ * NOTE: MAXIMUM_REPARSE_DATA_BUFFER_SIZE is chosen here based on documentation. Because chars are two
+ * bytes, the actual array size needs to be divided by 2
+ */
+ public char[] PathBuffer = new char[MAXIMUM_REPARSE_DATA_BUFFER_SIZE / 2];
+
+ public static int sizeOf() {
+ return Native.getNativeSize(MountPointReparseBuffer.class, null);
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList(new String[] { "SubstituteNameOffset", "SubstituteNameLength", "PrintNameOffset", "PrintNameLength", "Flags", "PathBuffer" });
+ }
+
+ public SymbolicLinkReparseBuffer() {
+ super(W32APITypeMapper.UNICODE);
+ }
+
+ public SymbolicLinkReparseBuffer(Pointer memory) {
+ super(memory, Structure.ALIGN_DEFAULT, W32APITypeMapper.UNICODE);
+ read();
+ }
+
+ public SymbolicLinkReparseBuffer(String substituteName, String printName, int Flags) {
+ super();
+ String bothNames = substituteName + printName;
+ PathBuffer = bothNames.toCharArray();
+ this.SubstituteNameOffset = 0;
+ this.SubstituteNameLength = (short) (substituteName.length() * 2);
+ this.PrintNameOffset = (short) (substituteName.length() * 2);
+ this.PrintNameLength = (short) (printName.length() * 2);
+ this.Flags = Flags;
+ write();
+ }
+
+ public SymbolicLinkReparseBuffer(short SubstituteNameOffset, short SubstituteNameLength, short PrintNameOffset, short PrintNameLength, int Flags, String PathBuffer) {
+ super();
+ this.SubstituteNameOffset = SubstituteNameOffset;
+ this.SubstituteNameLength = SubstituteNameLength;
+ this.PrintNameOffset = PrintNameOffset;
+ this.PrintNameLength = PrintNameLength;
+ this.Flags = Flags;
+ this.PathBuffer = PathBuffer.toCharArray();
+ write();
+ }
+
+ /**
+ * @return the print name in a String
+ */
+ public String getPrintName() {
+ return String.copyValueOf(PathBuffer, PrintNameOffset / 2, PrintNameLength / 2);
+ }
+
+ /**
+ * @return the substitute name in a String
+ */
+ public String getSubstituteName() {
+ return String.copyValueOf(PathBuffer, SubstituteNameOffset / 2, SubstituteNameLength / 2);
+ }
+ }
+
+ public static class MountPointReparseBuffer extends Structure {
+
+ public static class ByReference extends MountPointReparseBuffer implements Structure.ByReference {
+ public ByReference() {
+ }
+
+ public ByReference(Pointer memory) {
+ super(memory);
+ }
+ }
+
+ /**
+ * Offset, in bytes, of the substitute name string in the PathBuffer array.
+ * Note that this offset must be divided by sizeof(WCHAR) to get the array index.
+ */
+ public short SubstituteNameOffset = 0;
+
+ /**
+ * Length, in bytes, of the substitute name string. If this string is NULL-terminated,
+ * SubstituteNameLength does not include space for the UNICODE_NULL character.
+ */
+ public short SubstituteNameLength = 0;
+
+ /**
+ * Offset, in bytes, of the print name string in the PathBuffer array.
+ * Note that this offset must be divided by sizeof(WCHAR) to get the array index.
+ */
+ public short PrintNameOffset = 0;
+
+ /**
+ * Length, in bytes, of the print name string. If this string is NULL-terminated,
+ * PrintNameLength does not include space for the UNICODE_NULL character.
+ */
+ public short PrintNameLength = 0;
+
+ /**
+ * First character of the path string. This is followed in memory by the remainder of the string.
+ * The path string contains the substitute name string and print name string. The substitute name
+ * and print name strings can appear in any order in the PathBuffer. (To locate the substitute
+ * name and print name strings in the PathBuffer, use the SubstituteNameOffset, SubstituteNameLength,
+ * PrintNameOffset, and PrintNameLength members.)
+ * NOTE: MAXIMUM_REPARSE_DATA_BUFFER_SIZE is chosen here based on documentation. Because chars are two
+ * bytes, the actual array size needs to be divided by 2
+ */
+ public char[] PathBuffer = new char[MAXIMUM_REPARSE_DATA_BUFFER_SIZE / 2];
+
+ public static int sizeOf() {
+ return Native.getNativeSize(MountPointReparseBuffer.class, null);
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList(new String[] { "SubstituteNameOffset", "SubstituteNameLength", "PrintNameOffset", "PrintNameLength", "PathBuffer" });
+ }
+
+ public MountPointReparseBuffer() {
+ super(W32APITypeMapper.UNICODE);
+ }
+
+ public MountPointReparseBuffer(Pointer memory) {
+ super(memory, Structure.ALIGN_DEFAULT, W32APITypeMapper.UNICODE);
+ read();
+ }
+
+ public MountPointReparseBuffer(String substituteName, String printName) {
+ super();
+ String bothNames = substituteName + printName;
+ PathBuffer = bothNames.toCharArray();
+ this.SubstituteNameOffset = 0;
+ this.SubstituteNameLength = (short) substituteName.length();
+ this.PrintNameOffset = (short) (substituteName.length() * 2);
+ this.PrintNameLength = (short) (printName.length() * 2);
+ write();
+ }
+
+ public MountPointReparseBuffer(short SubstituteNameOffset, short SubstituteNameLength, short PrintNameOffset, short PrintNameLength, String PathBuffer) {
+ super();
+ this.SubstituteNameOffset = SubstituteNameOffset;
+ this.SubstituteNameLength = SubstituteNameLength;
+ this.PrintNameOffset = PrintNameOffset;
+ this.PrintNameLength = PrintNameLength;
+ this.PathBuffer = PathBuffer.toCharArray();
+ write();
+ }
+ }
+
+ public static class GenericReparseBuffer extends Structure {
+
+ public static class ByReference extends GenericReparseBuffer implements Structure.ByReference {
+ public ByReference() {
+ }
+
+ public ByReference(Pointer memory) {
+ super(memory);
+ }
+ }
+
+ /**
+ * Microsoft-defined data for the reparse point.
+ * NOTE: MAXIMUM_REPARSE_DATA_BUFFER_SIZE is chosen based on documentation
+ */
+ public byte[] DataBuffer = new byte[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+
+ public static int sizeOf() {
+ return Native.getNativeSize(GenericReparseBuffer.class, null);
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList(new String[] { "DataBuffer" });
+ }
+
+ public GenericReparseBuffer() {
+ super();
+ }
+
+ public GenericReparseBuffer(Pointer memory) {
+ super(memory);
+ read();
+ }
+
+ public GenericReparseBuffer(String DataBuffer) {
+ super();
+ this.DataBuffer = DataBuffer.getBytes();
+ write();
+ }
+ }
+
+ /**
+ * The REPARSE_DATA_BUFFER structure contains reparse point data for a Microsoft reparse point.
+ * (Third-party reparse point owners must use the REPARSE_GUID_DATA_BUFFER structure instead.)
+ */
+ public static class REPARSE_DATA_BUFFER extends Structure {
+
+ public static class ByReference extends REPARSE_DATA_BUFFER implements Structure.ByReference {
+ public ByReference() {
+ }
+
+ public ByReference(Pointer memory) {
+ super(memory);
+ }
+ }
+
+ /**
+ * Reparse point tag. Must be a Microsoft reparse point tag.
+ */
+ public int ReparseTag = 0;
+
+ /**
+ * Size, in bytes, of the reparse data in the DataBuffer member.
+ */
+ public short ReparseDataLength = 0;
+
+ /**
+ * Length, in bytes, of the unparsed portion of the file name pointed to by the FileName member of the associated file object.
+ * For more information about the FileName member, see FILE_OBJECT. This member is only valid for create operations when the
+ * I/O fails with STATUS_REPARSE. For all other purposes, such as setting or querying a reparse point for the reparse data,
+ * this member is treated as reserved.
+ */
+ public short Reserved = 0;
+
+ public static class REPARSE_UNION extends Union {
+ public static class ByReference extends REPARSE_UNION implements Structure.ByReference {
+
+ }
+
+ public REPARSE_UNION() {
+ super();
+ }
+
+ public REPARSE_UNION(Pointer memory) {
+ super(memory);
+ }
+
+ public SymbolicLinkReparseBuffer symLinkReparseBuffer;
+ public MountPointReparseBuffer mountPointReparseBuffer;
+ public GenericReparseBuffer genericReparseBuffer;
+ }
+
+ public REPARSE_UNION u;
+
+ public static int sizeOf() {
+ return Native.getNativeSize(REPARSE_DATA_BUFFER.class, null);
+ }
+
+ /**
+ * @return size of the structure considering the ReparseDataLength size
+ */
+ public int getSize() {
+ return REPARSE_BUFFER_HEADER_SIZE + ReparseDataLength;
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList(new String[] { "ReparseTag", "ReparseDataLength", "Reserved", "u" });
+ }
+
+ public REPARSE_DATA_BUFFER() {
+ super();
+ }
+
+ public REPARSE_DATA_BUFFER(int ReparseTag, short Reserved) {
+ super();
+ this.ReparseTag = ReparseTag;
+ this.Reserved = Reserved;
+ this.ReparseDataLength = 0;
+ write();
+ }
+
+ public REPARSE_DATA_BUFFER(int ReparseTag, short Reserved, SymbolicLinkReparseBuffer symLinkReparseBuffer) {
+ super();
+ this.ReparseTag = ReparseTag;
+ this.Reserved = Reserved;
+ this.ReparseDataLength = (short) symLinkReparseBuffer.size();
+ this.u.setType(SymbolicLinkReparseBuffer.class);
+ this.u.symLinkReparseBuffer = symLinkReparseBuffer;
+ write();
+ }
+
+ public REPARSE_DATA_BUFFER(Pointer memory) {
+ super(memory);
+ read();
+ }
+
+ @Override
+ public void read() {
+ super.read();
+ // Set structure value based on ReparseTag and then re-read the union.
+ switch(ReparseTag) {
+ default:
+ u.setType(GenericReparseBuffer.class);
+ break;
+ case WinNT.IO_REPARSE_TAG_MOUNT_POINT:
+ u.setType(MountPointReparseBuffer.class);
+ break;
+ case WinNT.IO_REPARSE_TAG_SYMLINK:
+ u.setType(SymbolicLinkReparseBuffer.class);
+ break;
+ }
+ u.read();
+ }
+ }
+}
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinBase.java b/contrib/platform/src/com/sun/jna/platform/win32/WinBase.java
index fb483014a7..79f5bd031e 100755
--- a/contrib/platform/src/com/sun/jna/platform/win32/WinBase.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/WinBase.java
@@ -30,11 +30,13 @@
import java.util.List;
import com.sun.jna.Callback;
+import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.Union;
import com.sun.jna.platform.win32.WinNT.HANDLE;
+import com.sun.jna.platform.win32.WinNT.LARGE_INTEGER;
import com.sun.jna.ptr.ByteByReference;
import com.sun.jna.win32.StdCallLibrary.StdCallCallback;
import com.sun.jna.win32.W32APITypeMapper;
@@ -194,6 +196,640 @@ public interface WinBase extends WinDef, BaseTSD {
*/
int STILL_ACTIVE = WinNT.STATUS_PENDING;
+ // Codes for FILE_INFO_BY_HANDLE_CLASS taken from Winbase.h
+ int FileBasicInfo = 0;
+ int FileStandardInfo = 1;
+ int FileNameInfo = 2;
+ int FileRenameInfo = 3;
+ int FileDispositionInfo = 4;
+ int FileAllocationInfo = 5;
+ int FileEndOfFileInfo = 6;
+ int FileStreamInfo = 7;
+ int FileCompressionInfo = 8;
+ int FileAttributeTagInfo = 9;
+ int FileIdBothDirectoryInfo = 10; // 0xA
+ int FileIdBothDirectoryRestartInfo = 11; // 0xB
+ int FileIoPriorityHintInfo = 12; // 0xC
+ int FileRemoteProtocolInfo = 13; // 0xD
+ int FileFullDirectoryInfo = 14; // 0xE
+ int FileFullDirectoryRestartInfo = 15; // 0xF
+ int FileStorageInfo = 16; // 0x10
+ int FileAlignmentInfo = 17; // 0x11
+ int FileIdInfo = 18; // 0x12
+ int FileIdExtdDirectoryInfo = 19; // 0x13
+ int FileIdExtdDirectoryRestartInfo = 20; // 0x14
+
+ /**
+ * Contains the basic information for a file. Used for file handles.
+ */
+ public static class FILE_BASIC_INFO extends Structure {
+
+ public static class ByReference extends FILE_BASIC_INFO implements Structure.ByReference {
+ public ByReference() {
+ }
+
+ public ByReference(Pointer memory) {
+ super(memory);
+ }
+ }
+
+ /**
+ * The time the file was created in FILETIME format, which is a 64-bit value
+ * representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).
+ */
+ public LARGE_INTEGER CreationTime;
+
+ /**
+ * The time the file was last accessed in FILETIME format.
+ */
+ public LARGE_INTEGER LastAccessTime;
+
+ /**
+ * The time the file was last written to in FILETIME format.
+ */
+ public LARGE_INTEGER LastWriteTime;
+
+ /**
+ * The time the file was changed in FILETIME format.
+ */
+ public LARGE_INTEGER ChangeTime;
+
+ /**
+ * The file attributes. For a list of attributes, see File Attribute Constants.
+ * If this is set to 0 in a FILE_BASIC_INFO structure passed to SetFileInformationByHandle
+ * then none of the attributes are changed.
+ */
+ public int FileAttributes;
+
+ public static int sizeOf()
+ {
+ return Native.getNativeSize(FILE_BASIC_INFO.class, null);
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList(new String[] { "CreationTime", "LastAccessTime", "LastWriteTime", "ChangeTime", "FileAttributes" });
+ }
+
+ public FILE_BASIC_INFO() {
+ super();
+ }
+
+ public FILE_BASIC_INFO(Pointer memory) {
+ super(memory);
+ read();
+ // This is admittedly odd, but the read() doesn't properly initialize the LARGE_INTEGERs via contructors, so do so here.
+ this.CreationTime = new LARGE_INTEGER(this.CreationTime.getValue());
+ this.LastAccessTime = new LARGE_INTEGER(this.LastAccessTime.getValue());
+ this.LastWriteTime = new LARGE_INTEGER(this.LastWriteTime.getValue());
+ this.ChangeTime = new LARGE_INTEGER(this.ChangeTime.getValue());
+ }
+
+ public FILE_BASIC_INFO(FILETIME CreationTime,
+ FILETIME LastAccessTime,
+ FILETIME LastWriteTime,
+ FILETIME ChangeTime,
+ int FileAttributes) {
+ this.CreationTime = new LARGE_INTEGER(CreationTime.toTime());
+ this.LastAccessTime = new LARGE_INTEGER(LastAccessTime.toTime());
+ this.LastWriteTime = new LARGE_INTEGER(LastWriteTime.toTime());
+ this.ChangeTime = new LARGE_INTEGER(ChangeTime.toTime());
+ this.FileAttributes = FileAttributes;
+ write();
+ }
+
+ public FILE_BASIC_INFO(LARGE_INTEGER CreationTime,
+ LARGE_INTEGER LastAccessTime,
+ LARGE_INTEGER LastWriteTime,
+ LARGE_INTEGER ChangeTime,
+ int FileAttributes) {
+ this.CreationTime = CreationTime;
+ this.LastAccessTime = LastAccessTime;
+ this.LastWriteTime = LastWriteTime;
+ this.ChangeTime = ChangeTime;
+ this.FileAttributes = FileAttributes;
+ write();
+ }
+ }
+
+ /**
+ * Receives extended information for the file. Used for file handles. Use only when calling GetFileInformationByHandleEx.
+ */
+ public static class FILE_STANDARD_INFO extends Structure {
+
+ public static class ByReference extends FILE_STANDARD_INFO implements Structure.ByReference {
+ public ByReference() {
+ }
+
+ public ByReference(Pointer memory) {
+ super(memory);
+ }
+ }
+
+ /**
+ * The amount of space that is allocated for the file.
+ */
+ public LARGE_INTEGER AllocationSize;
+
+ /**
+ * The end of the file.
+ */
+ public LARGE_INTEGER EndOfFile;
+
+ /**
+ * The number of links to the file.
+ */
+ public int NumberOfLinks;
+
+ /**
+ * TRUE if the file in the delete queue; otherwise, false.
+ */
+ public boolean DeletePending;
+
+ /**
+ * TRUE if the file is a directory; otherwise, false.
+ */
+ public boolean Directory;
+
+ public static int sizeOf()
+ {
+ return Native.getNativeSize(FILE_STANDARD_INFO.class, null);
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList(new String[] { "AllocationSize", "EndOfFile", "NumberOfLinks", "DeletePending", "Directory" });
+ }
+
+ public FILE_STANDARD_INFO() {
+ super();
+ }
+
+ public FILE_STANDARD_INFO(Pointer memory) {
+ super(memory);
+ read();
+ }
+
+ public FILE_STANDARD_INFO(LARGE_INTEGER AllocationSize,
+ LARGE_INTEGER EndOfFile,
+ int NumberOfLinks,
+ boolean DeletePending,
+ boolean Directory) {
+ this.AllocationSize = AllocationSize;
+ this.EndOfFile = EndOfFile;
+ this.NumberOfLinks = NumberOfLinks;
+ this.DeletePending = DeletePending;
+ this.Directory = Directory;
+ write();
+ }
+ }
+
+ /**
+ * Indicates whether a file should be deleted. Used for any handles. Use only when calling SetFileInformationByHandle.
+ */
+ public static class FILE_DISPOSITION_INFO extends Structure {
+
+ public static class ByReference extends FILE_DISPOSITION_INFO implements Structure.ByReference {
+ public ByReference() {
+ }
+
+ public ByReference(Pointer memory) {
+ super(memory);
+ }
+ }
+
+ /**
+ * Indicates whether the file should be deleted. Set to TRUE to delete the file. This member
+ * has no effect if the handle was opened with FILE_FLAG_DELETE_ON_CLOSE.
+ */
+ public boolean DeleteFile;
+
+ public static int sizeOf()
+ {
+ return Native.getNativeSize(FILE_DISPOSITION_INFO.class, null);
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList(new String[] { "DeleteFile" });
+ }
+
+ public FILE_DISPOSITION_INFO () {
+ super();
+ }
+
+ public FILE_DISPOSITION_INFO (Pointer memory) {
+ super(memory);
+ read();
+ }
+
+ public FILE_DISPOSITION_INFO (boolean DeleteFile) {
+ this.DeleteFile = DeleteFile;
+ write();
+ }
+ }
+
+ /**
+ * Receives extended information for the file. Used for file handles. Use only when calling GetFileInformationByHandleEx.
+ */
+ public static class FILE_COMPRESSION_INFO extends Structure {
+
+ public static class ByReference extends FILE_COMPRESSION_INFO implements Structure.ByReference {
+ public ByReference() {
+ }
+
+ public ByReference(Pointer memory) {
+ super(memory);
+ }
+ }
+
+ /**
+ * The file size of the compressed file.
+ */
+ public LARGE_INTEGER CompressedFileSize;
+
+ /**
+ * The compression format that is used to compress the file.
+ */
+ public short CompressionFormat;
+
+ /**
+ * The factor that the compression uses.
+ */
+ public byte CompressionUnitShift;
+
+ /**
+ * The number of chunks that are shifted by compression.
+ */
+ public byte ChunkShift;
+
+ /**
+ * The number of clusters that are shifted by compression.
+ */
+ public byte ClusterShift;
+
+ /**
+ * Reserved
+ */
+ public byte[] Reserved = new byte[3];
+
+ public static int sizeOf()
+ {
+ return Native.getNativeSize(FILE_COMPRESSION_INFO.class, null);
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList(new String[] { "CompressedFileSize", "CompressionFormat", "CompressionUnitShift", "ChunkShift", "ClusterShift", "Reserved" });
+ }
+
+ public FILE_COMPRESSION_INFO() {
+ super(W32APITypeMapper.DEFAULT);
+ }
+
+ public FILE_COMPRESSION_INFO(Pointer memory) {
+ super(memory, Structure.ALIGN_DEFAULT, W32APITypeMapper.DEFAULT);
+ read();
+ }
+
+ public FILE_COMPRESSION_INFO(LARGE_INTEGER CompressedFileSize,
+ short CompressionFormat,
+ byte CompressionUnitShift,
+ byte ChunkShift,
+ byte ClusterShift) {
+ this.CompressedFileSize = CompressedFileSize;
+ this.CompressionFormat = CompressionFormat;
+ this.CompressionUnitShift = CompressionUnitShift;
+ this.ChunkShift = ChunkShift;
+ this.ClusterShift = ClusterShift;
+ this.Reserved = new byte[3];
+ write();
+ }
+ }
+
+ /**
+ * Receives the requested file attribute information. Used for any handles. Use only when calling GetFileInformationByHandleEx.
+ */
+ public static class FILE_ATTRIBUTE_TAG_INFO extends Structure {
+
+ public static class ByReference extends FILE_ATTRIBUTE_TAG_INFO implements Structure.ByReference {
+ public ByReference() {
+ }
+
+ public ByReference(Pointer memory) {
+ super(memory);
+ }
+ }
+
+ /**
+ * The file attribute information.
+ */
+ public int FileAttributes;
+
+ /**
+ * The reparse tag.
+ */
+ public int ReparseTag;
+
+ public static int sizeOf()
+ {
+ return Native.getNativeSize(FILE_ATTRIBUTE_TAG_INFO.class, null);
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList(new String[] { "FileAttributes", "ReparseTag" });
+ }
+
+ public FILE_ATTRIBUTE_TAG_INFO() {
+ super();
+ }
+
+ public FILE_ATTRIBUTE_TAG_INFO(Pointer memory) {
+ super(memory);
+ read();
+ }
+
+ public FILE_ATTRIBUTE_TAG_INFO(int FileAttributes,
+ int ReparseTag) {
+ this.FileAttributes = FileAttributes;
+ this.ReparseTag = ReparseTag;
+ write();
+ }
+ }
+
+ /**
+ * Contains identification information for a file. This structure is returned from the
+ * GetFileInformationByHandleEx function when FileIdInfo is passed in the
+ * FileInformationClass parameter.
+ */
+ public static class FILE_ID_INFO extends Structure {
+
+ public static class ByReference extends FILE_ID_INFO implements Structure.ByReference {
+ public ByReference() {
+ }
+
+ public ByReference(Pointer memory) {
+ super(memory);
+ }
+ }
+
+ public static class FILE_ID_128 extends Structure {
+ public BYTE[] Identifier = new BYTE[16];
+
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList(new String[] { "Identifier" });
+ }
+
+ public FILE_ID_128() {
+ super();
+ }
+
+ public FILE_ID_128(Pointer memory) {
+ super(memory);
+ read();
+ }
+
+ public FILE_ID_128(BYTE[] Identifier) {
+ this.Identifier = Identifier;
+ write();
+ }
+ }
+
+ /**
+ * The serial number of the volume that contains a file.
+ */
+ public long VolumeSerialNumber;
+
+ /**
+ * The end of the file.
+ */
+ public FILE_ID_128 FileId;
+
+ public static int sizeOf()
+ {
+ return Native.getNativeSize(FILE_ID_INFO.class, null);
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList(new String[] { "VolumeSerialNumber", "FileId" });
+ }
+
+ public FILE_ID_INFO() {
+ super();
+ }
+
+ public FILE_ID_INFO(Pointer memory) {
+ super(memory);
+ read();
+ }
+
+ public FILE_ID_INFO(long VolumeSerialNumber,
+ FILE_ID_128 FileId) {
+ this.VolumeSerialNumber = VolumeSerialNumber;
+ this.FileId = FileId;
+ write();
+ }
+ }
+
+ // FINDEX_INFO_LEVELS values defines values that are used with the FindFirstFileEx function to specify the information level of the returned data.
+
+ /**
+ * The FindFirstFileEx function retrieves a standard set of attribute information. The data is returned
+ * in a WIN32_FIND_DATA structure.
+ */
+ int FindExInfoStandard = 0;
+
+ /**
+ * The FindFirstFileEx function does not query the short file name, improving overall enumeration speed. The data is
+ * returned in a WIN32_FIND_DATA structure, and the cAlternateFileName member is always a NULL string.
+ */
+ int FindExInfoBasic = 1;
+ /**
+ * This value is used for validation. Supported values are less than this value.
+ */
+ int FindExInfoMaxInfoLevel = 2;
+
+ // FINDEX_SEARCH_OPS values defines values that are used with the FindFirstFileEx function to specify the type of filtering to perform.
+ /**
+ * The search for a file that matches a specified file name. The lpSearchFilter parameter of FindFirstFileEx
+ * must be NULL when this search operation is used.
+ */
+ int FindExSearchNameMatch = 0;
+
+ /**
+ * This is an advisory flag. If the file system supports directory filtering, the function searches for a file that
+ * matches the specified name and is also a directory. If the file system does not support directory filtering,
+ * this flag is silently ignored.
+ * The lpSearchFilter parameter of the FindFirstFileEx function must be NULL when this search value is used.
+ * If directory filtering is desired, this flag can be used on all file systems, but because it is an advisory
+ * flag and only affects file systems that support it, the application must examine the file attribute data stored
+ * in the lpFindFileData parameter of the FindFirstFileEx function to determine whether the function has returned
+ * a handle to a directory.
+ */
+ int FindExSearchLimitToDirectories = 1;
+
+ /**
+ * This filtering type is not available. For more information, see Device Interface Classes.
+ */
+ int FindExSearchLimitToDevices = 2;
+
+ /**
+ * Contains information about the file that is found by the FindFirstFile, FindFirstFileEx, or FindNextFile function.
+ */
+ public static class WIN32_FIND_DATA extends Structure {
+
+ public static class ByReference extends WIN32_FIND_DATA implements Structure.ByReference {
+ public ByReference() {
+ }
+
+ public ByReference(Pointer memory) {
+ super(memory);
+ }
+ }
+
+ /**
+ * The file attributes of a file. For possible values and their descriptions,
+ * see File Attribute Constants. The FILE_ATTRIBUTE_SPARSE_FILE attribute on
+ * the file is set if any of the streams of the file have ever been sparse.
+ */
+ public int dwFileAttributes;
+
+ /**
+ * A FILETIME structure that specifies when a file or directory was created. If
+ * the underlying file system does not support creation time, this member is zero.
+ */
+ public FILETIME ftCreationTime;
+
+ /**
+ * A FILETIME structure. For a file, the structure specifies when the file was last
+ * read from, written to, or for executable files, run. For a directory, the structure
+ * specifies when the directory is created. If the underlying file system does not
+ * support last access time, this member is zero. On the FAT file system, the
+ * specified date for both files and directories is correct, but the time of day is
+ * always set to midnight.
+ */
+ public FILETIME ftLastAccessTime;
+
+ /**
+ * A FILETIME structure. For a file, the structure specifies when the file was last
+ * written to, truncated, or overwritten, for example, when WriteFile or SetEndOfFile
+ * are used. The date and time are not updated when file attributes or security descriptors
+ * are changed. For a directory, the structure specifies when the directory is created.
+ * If the underlying file system does not support last write time, this member is zero.
+ */
+ public FILETIME ftLastWriteTime;
+
+ /**
+ * The high-order DWORD value of the file size, in bytes. This value is zero unless the
+ * file size is greater than MAXDWORD.
+ * The size of the file is equal to (nFileSizeHigh * (MAXDWORD+1)) + nFileSizeLow.
+ */
+ public int nFileSizeHigh;
+
+ /**
+ * The low-order DWORD value of the file size, in bytes.
+ */
+ public int nFileSizeLow;
+
+ /**
+ * If the dwFileAttributes member includes the FILE_ATTRIBUTE_REPARSE_POINT attribute, this member
+ * specifies the reparse point tag. Otherwise, this value is undefined and should not be used.
+ * For more information see Reparse Point Tags.
+ *
+ * IO_REPARSE_TAG_CSV (0x80000009)
+ * IO_REPARSE_TAG_DEDUP (0x80000013)
+ * IO_REPARSE_TAG_DFS (0x8000000A)
+ * IO_REPARSE_TAG_DFSR (0x80000012)
+ * IO_REPARSE_TAG_HSM (0xC0000004)
+ * IO_REPARSE_TAG_HSM2 (0x80000006)
+ * IO_REPARSE_TAG_MOUNT_POINT (0xA0000003)
+ * IO_REPARSE_TAG_NFS (0x80000014)
+ * IO_REPARSE_TAG_SIS (0x80000007)
+ * IO_REPARSE_TAG_SYMLINK (0xA000000C)
+ * IO_REPARSE_TAG_WIM (0x80000008)
+ */
+ public int dwReserved0;
+
+ /**
+ * Reserved for future use.
+ */
+ public int dwReserved1;
+
+ /**
+ * The name of the file. NOTE: When written from Native memory, this will be a null terminated string.
+ * Any characters after the null terminator are random memory. Use function getFileName to
+ * get a String with the name.
+ */
+ public char[] cFileName = new char[MAX_PATH];
+
+ /**
+ * An alternative name for the file. This name is in the classic 8.3 file name format.
+ * NOTE: When written from Native memory, this will be a null terminated string.
+ * Any characters after the null terminator are random memory. Use function getAlternateFileName to
+ * get a String with the alternate name.
+ */
+ public char[] cAlternateFileName = new char[14];
+
+ public static int sizeOf() {
+ return Native.getNativeSize(WIN32_FIND_DATA.class, null);
+ }
+
+ @Override
+ protected List getFieldOrder() {
+ return Arrays.asList(new String[] { "dwFileAttributes", "ftCreationTime", "ftLastAccessTime", "ftLastWriteTime", "nFileSizeHigh", "nFileSizeLow", "dwReserved0", "dwReserved1", "cFileName", "cAlternateFileName" });
+ }
+
+ public WIN32_FIND_DATA() {
+ super(W32APITypeMapper.DEFAULT);
+ }
+
+ public WIN32_FIND_DATA(Pointer memory) {
+ super(memory, Structure.ALIGN_DEFAULT, W32APITypeMapper.DEFAULT);
+ read();
+ }
+
+ public WIN32_FIND_DATA(int dwFileAttributes,
+ FILETIME ftCreationTime,
+ FILETIME ftLastAccessTime,
+ FILETIME ftLastWriteTime,
+ int nFileSizeHigh,
+ int nFileSizeLow,
+ int dwReserved0,
+ int dwReserved1,
+ char[] cFileName,
+ char[] cAlternateFileName) {
+ this.dwFileAttributes = dwFileAttributes;
+ this.ftCreationTime = ftCreationTime;
+ this.ftLastAccessTime = ftLastAccessTime;
+ this.ftLastWriteTime = ftLastWriteTime;
+ this.nFileSizeHigh = nFileSizeHigh;
+ this.nFileSizeLow = nFileSizeLow;
+ this.dwReserved0 = dwReserved0;
+ this.cFileName = cFileName;
+ this.cAlternateFileName = cAlternateFileName;
+ write();
+ }
+
+ /**
+ * @return String containing the file name
+ */
+ public String getFileName() {
+ String actualFileName = new String(cFileName);
+ return actualFileName.substring(0, actualFileName.indexOf('\0'));
+ }
+
+ /**
+ * @return String containing the alternate file name
+ */
+ public String getAlternateFileName() {
+ String actualAlternateFileName = new String(cAlternateFileName);
+ return actualAlternateFileName.substring(0, actualAlternateFileName.indexOf('\0'));
+ }
+ }
+
/**
* The FILETIME structure is a 64-bit value representing the number of
* 100-nanosecond intervals since January 1, 1601 (UTC).
@@ -224,6 +860,15 @@ public FILETIME(Date date) {
dwLowDateTime = (int)(rawValue & 0xffffffffL);
}
+ /**
+ * Construct FILETIME from LARGE_INTEGER
+ * @param ft
+ */
+ public FILETIME(LARGE_INTEGER ft) {
+ dwHighDateTime = ft.getHigh().intValue();
+ dwLowDateTime = ft.getLow().intValue();
+ }
+
public FILETIME() {
}
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java b/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java
index 8290369cac..5dcf09bf07 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java
@@ -839,6 +839,16 @@ public abstract class SID_NAME_USE {
int FILE_SUPPORTS_OPEN_BY_FILE_ID = 0x01000000;
int FILE_SUPPORTS_USN_JOURNAL = 0x02000000;
+ // Reparse point tags
+ int IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003;
+ int IO_REPARSE_TAG_HSM = 0xC0000004;
+ int IO_REPARSE_TAG_HSM2 = 0x80000006;
+ int IO_REPARSE_TAG_SIS = 0x80000007;
+ int IO_REPARSE_TAG_WIM = 0x80000008;
+ int IO_REPARSE_TAG_CSV = 0x80000009;
+ int IO_REPARSE_TAG_DFS = 0x8000000A;
+ int IO_REPARSE_TAG_SYMLINK = 0xA000000C;
+ int IO_REPARSE_TAG_DFSR = 0x80000012;
// The controllable aspects of the DefineDosDevice function.
// see https://msdn.microsoft.com/en-us/library/windows/desktop/aa363904(v=vs.85).aspx
@@ -847,6 +857,15 @@ public abstract class SID_NAME_USE {
int DDD_EXACT_MATCH_ON_REMOVE = 0x00000004;
int DDD_NO_BROADCAST_SYSTEM = 0x00000008;
+ int COMPRESSION_FORMAT_NONE = 0x0000;
+ int COMPRESSION_FORMAT_DEFAULT = 0x0001;
+ int COMPRESSION_FORMAT_LZNT1 = 0x0002;
+ int COMPRESSION_FORMAT_XPRESS = 0x0003;
+ int COMPRESSION_FORMAT_XPRESS_HUFF = 0x0004;
+ int COMPRESSION_ENGINE_STANDARD = 0x0000;
+ int COMPRESSION_ENGINE_MAXIMUM = 0x0100;
+ int COMPRESSION_ENGINE_HIBER = 0x0200;
+
/**
* The FILE_NOTIFY_INFORMATION structure describes the changes found by the
* ReadDirectoryChangesW function.
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Winioctl.java b/contrib/platform/src/com/sun/jna/platform/win32/Winioctl.java
index 6fae3894b5..95700d26a9 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/Winioctl.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Winioctl.java
@@ -31,6 +31,103 @@
*/
public interface Winioctl {
+ // Devices
+ public int FILE_DEVICE_BEEP = 0x00000001;
+ public int FILE_DEVICE_CD_ROM = 0x00000002;
+ public int FILE_DEVICE_CD_ROM_FILE_SYSTEM = 0x00000003;
+ public int FILE_DEVICE_CONTROLLER = 0x00000004;
+ public int FILE_DEVICE_DATALINK = 0x00000005;
+ public int FILE_DEVICE_DFS = 0x00000006;
+ public int FILE_DEVICE_DISK = 0x00000007;
+ public int FILE_DEVICE_DISK_FILE_SYSTEM = 0x00000008;
+ public int FILE_DEVICE_FILE_SYSTEM = 0x00000009;
+ public int FILE_DEVICE_INPORT_PORT = 0x0000000a;
+ public int FILE_DEVICE_KEYBOARD = 0x0000000b;
+ public int FILE_DEVICE_MAILSLOT = 0x0000000c;
+ public int FILE_DEVICE_MIDI_IN = 0x0000000d;
+ public int FILE_DEVICE_MIDI_OUT = 0x0000000e;
+ public int FILE_DEVICE_MOUSE = 0x0000000f;
+ public int FILE_DEVICE_MULTI_UNC_PROVIDER = 0x00000010;
+ public int FILE_DEVICE_NAMED_PIPE = 0x00000011;
+ public int FILE_DEVICE_NETWORK = 0x00000012;
+ public int FILE_DEVICE_NETWORK_BROWSER = 0x00000013;
+ public int FILE_DEVICE_NETWORK_FILE_SYSTEM = 0x00000014;
+ public int FILE_DEVICE_NULL = 0x00000015;
+ public int FILE_DEVICE_PARALLEL_PORT = 0x00000016;
+ public int FILE_DEVICE_PHYSICAL_NETCARD = 0x00000017;
+ public int FILE_DEVICE_PRINTER = 0x00000018;
+ public int FILE_DEVICE_SCANNER = 0x00000019;
+ public int FILE_DEVICE_SERIAL_MOUSE_PORT = 0x0000001a;
+ public int FILE_DEVICE_SERIAL_PORT = 0x0000001b;
+ public int FILE_DEVICE_SCREEN = 0x0000001c;
+ public int FILE_DEVICE_SOUND = 0x0000001d;
+ public int FILE_DEVICE_STREAMS = 0x0000001e;
+ public int FILE_DEVICE_TAPE = 0x0000001f;
+ public int FILE_DEVICE_TAPE_FILE_SYSTEM = 0x00000020;
+ public int FILE_DEVICE_TRANSPORT = 0x00000021;
+ public int FILE_DEVICE_UNKNOWN = 0x00000022;
+ public int FILE_DEVICE_VIDEO = 0x00000023;
+ public int FILE_DEVICE_VIRTUAL_DISK = 0x00000024;
+ public int FILE_DEVICE_WAVE_IN = 0x00000025;
+ public int FILE_DEVICE_WAVE_OUT = 0x00000026;
+ public int FILE_DEVICE_8042_PORT = 0x00000027;
+ public int FILE_DEVICE_NETWORK_REDIRECTOR = 0x00000028;
+ public int FILE_DEVICE_BATTERY = 0x00000029;
+ public int FILE_DEVICE_BUS_EXTENDER = 0x0000002a;
+ public int FILE_DEVICE_MODEM = 0x0000002b;
+ public int FILE_DEVICE_VDM = 0x0000002c;
+ public int FILE_DEVICE_MASS_STORAGE = 0x0000002d;
+ public int FILE_DEVICE_SMB = 0x0000002e;
+ public int FILE_DEVICE_KS = 0x0000002f;
+ public int FILE_DEVICE_CHANGER = 0x00000030;
+ public int FILE_DEVICE_SMARTCARD = 0x00000031;
+ public int FILE_DEVICE_ACPI = 0x00000032;
+ public int FILE_DEVICE_DVD = 0x00000033;
+ public int FILE_DEVICE_FULLSCREEN_VIDEO = 0x00000034;
+ public int FILE_DEVICE_DFS_FILE_SYSTEM = 0x00000035;
+ public int FILE_DEVICE_DFS_VOLUME = 0x00000036;
+ public int FILE_DEVICE_SERENUM = 0x00000037;
+ public int FILE_DEVICE_TERMSRV = 0x00000038;
+ public int FILE_DEVICE_KSEC = 0x00000039;
+ public int FILE_DEVICE_FIPS = 0x0000003A;
+ public int FILE_DEVICE_INFINIBAND = 0x0000003B;
+ public int FILE_DEVICE_VMBUS = 0x0000003E;
+ public int FILE_DEVICE_CRYPT_PROVIDER = 0x0000003F;
+ public int FILE_DEVICE_WPD = 0x00000040;
+ public int FILE_DEVICE_BLUETOOTH = 0x00000041;
+ public int FILE_DEVICE_MT_COMPOSITE = 0x00000042;
+ public int FILE_DEVICE_MT_TRANSPORT = 0x00000043;
+ public int FILE_DEVICE_BIOMETRIC = 0x00000044;
+ public int FILE_DEVICE_PMI = 0x00000045;
+ public int FILE_DEVICE_EHSTOR = 0x00000046;
+ public int FILE_DEVICE_DEVAPI = 0x00000047;
+ public int FILE_DEVICE_GPIO = 0x00000048;
+ public int FILE_DEVICE_USBEX = 0x00000049;
+ public int FILE_DEVICE_CONSOLE = 0x00000050;
+ public int FILE_DEVICE_NFP = 0x00000051;
+ public int FILE_DEVICE_SYSENV = 0x00000052;
+ public int FILE_DEVICE_VIRTUAL_BLOCK = 0x00000053;
+ public int FILE_DEVICE_POINT_OF_SERVICE = 0x00000054;
+
+ // Functions
+ public int FSCTL_GET_COMPRESSION = 15;
+ public int FSCTL_SET_COMPRESSION = 16;
+ public int FSCTL_SET_REPARSE_POINT = 41;
+ public int FSCTL_GET_REPARSE_POINT = 42;
+ public int FSCTL_DELETE_REPARSE_POINT = 43;
+
+ // Methods
+ public int METHOD_BUFFERED = 0;
+ public int METHOD_IN_DIRECT = 1;
+ public int METHOD_OUT_DIRECT = 2;
+ public int METHOD_NEITHER = 3;
+
+ // Access
+ public int FILE_ANY_ACCESS = 0;
+ public int FILE_SPECIAL_ACCESS = FILE_ANY_ACCESS;
+ public int FILE_READ_ACCESS = 0x0001; // file & pipe
+ public int FILE_WRITE_ACCESS = 0x0002; // file & pipe
+
/**
* Retrieves the device type, device number, and, for a partitionable device, the partition number of a device.
*/
diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinioctlUtil.java b/contrib/platform/src/com/sun/jna/platform/win32/WinioctlUtil.java
new file mode 100644
index 0000000000..5475dde622
--- /dev/null
+++ b/contrib/platform/src/com/sun/jna/platform/win32/WinioctlUtil.java
@@ -0,0 +1,85 @@
+/* Copyright (c) 2016 Adam Marcionek, All Rights Reserved
+ *
+ * The contents of this file is dual-licensed under 2
+ * alternative Open Source/Free licenses: LGPL 2.1 or later and
+ * Apache License 2.0. (starting with JNA version 4.0.0).
+ *
+ * You can freely decide which license you want to apply to
+ * the project.
+ *
+ * You may obtain a copy of the LGPL License at:
+ *
+ * http://www.gnu.org/licenses/licenses.html
+ *
+ * A copy is also included in the downloadable source code package
+ * containing JNA, in file "LGPL2.1".
+ *
+ * You may obtain a copy of the Apache License at:
+ *
+ * http://www.apache.org/licenses/
+ *
+ * A copy is also included in the downloadable source code package
+ * containing JNA, in file "AL2.0".
+ */
+package com.sun.jna.platform.win32;
+
+/**
+ * Winioctl Utility API. Use WinioctlFunction to construct the full control codes for the
+ * FSCTL_* functions defined in Winioctl.h
+ *
+ * @author amarcionek[at]gmail.com
+ */
+public abstract class WinioctlUtil {
+
+ /**
+ * Simulates the macro CTL_CODE from Winioctl.h
+ * @param DeviceType the device type
+ * @param Function the function
+ * @param Method the method
+ * @param Access the access
+ * @return int with the resulting control code
+ */
+ public static int CTL_CODE(int DeviceType, int Function, int Method, int Access) {
+ return ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method);
+ }
+
+ /**
+ * Base interface for a Winiotcl function used to construct the control code
+ */
+ public interface WinioctlFunction {
+ /**
+ * @return the control code given the IOTCL's parameters
+ */
+ public abstract int getControlCode();
+ }
+
+ public static class FSCTL_GET_COMPRESSION implements WinioctlFunction {
+ public int getControlCode() {
+ return WinioctlUtil.CTL_CODE(Winioctl.FILE_DEVICE_FILE_SYSTEM, Winioctl.FSCTL_GET_COMPRESSION, Winioctl.METHOD_BUFFERED, Winioctl.FILE_ANY_ACCESS);
+ }
+ }
+
+ public static class FSCTL_SET_COMPRESSION implements WinioctlFunction {
+ public int getControlCode() {
+ return WinioctlUtil.CTL_CODE(Winioctl.FILE_DEVICE_FILE_SYSTEM, Winioctl.FSCTL_SET_COMPRESSION, Winioctl.METHOD_BUFFERED, WinNT.FILE_READ_DATA | WinNT.FILE_WRITE_DATA);
+ }
+ }
+
+ public static class FSCTL_SET_REPARSE_POINT implements WinioctlFunction {
+ public int getControlCode() {
+ return WinioctlUtil.CTL_CODE(Winioctl.FILE_DEVICE_FILE_SYSTEM, Winioctl.FSCTL_SET_REPARSE_POINT, Winioctl.METHOD_BUFFERED, Winioctl.FILE_SPECIAL_ACCESS);
+ }
+ }
+
+ public static class FSCTL_GET_REPARSE_POINT implements WinioctlFunction {
+ public int getControlCode() {
+ return WinioctlUtil.CTL_CODE(Winioctl.FILE_DEVICE_FILE_SYSTEM, Winioctl.FSCTL_GET_REPARSE_POINT, Winioctl.METHOD_BUFFERED, Winioctl.FILE_ANY_ACCESS);
+ }
+ }
+
+ public static class FSCTL_DELETE_REPARSE_POINT implements WinioctlFunction {
+ public int getControlCode() {
+ return WinioctlUtil.CTL_CODE(Winioctl.FILE_DEVICE_FILE_SYSTEM, Winioctl.FSCTL_DELETE_REPARSE_POINT, Winioctl.METHOD_BUFFERED, Winioctl.FILE_SPECIAL_ACCESS);
+ }
+ }
+}
\ No newline at end of file
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Advapi32UtilTest.java b/contrib/platform/test/com/sun/jna/platform/win32/Advapi32UtilTest.java
index 21b40f18f2..6a60cdeb4c 100755
--- a/contrib/platform/test/com/sun/jna/platform/win32/Advapi32UtilTest.java
+++ b/contrib/platform/test/com/sun/jna/platform/win32/Advapi32UtilTest.java
@@ -24,6 +24,7 @@
import com.sun.jna.platform.win32.Advapi32Util.Account;
import com.sun.jna.platform.win32.Advapi32Util.EventLogIterator;
import com.sun.jna.platform.win32.Advapi32Util.EventLogRecord;
+import com.sun.jna.platform.win32.Advapi32Util.Privilege;
import com.sun.jna.platform.win32.LMAccess.USER_INFO_1;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinNT.HANDLEByReference;
@@ -599,6 +600,35 @@ public void testBackupEncryptedFile() throws Exception {
dest.delete();
}
+ /**
+ * Test Privilege class
+ */
+ public void testPrivilege() {
+ // Test multiple known privileges
+ Privilege privilege = new Privilege(WinNT.SE_ASSIGNPRIMARYTOKEN_NAME, WinNT.SE_BACKUP_NAME);
+ try {
+ privilege.enable();
+ // Will throw if it fails p.enable() fails
+ }
+ finally {
+ privilege.close();
+ }
+
+ // Test unknown privilege
+ try {
+ privilege = new Privilege("NOT_A_PRIVILEGE");
+ }
+ catch (IllegalArgumentException ex) {
+ // Exception is expected
+ }
+ catch (Exception ex) {
+ fail("Encountered unknown exception - " + ex.getMessage());
+ }
+ finally {
+ privilege.close();
+ }
+ }
+
private File createTempFile() throws Exception{
String filePath = System.getProperty("java.io.tmpdir") + System.nanoTime()
+ ".text";
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java
index e993bbd404..b0ca34cf51 100644
--- a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java
+++ b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java
@@ -12,7 +12,6 @@
*/
package com.sun.jna.platform.win32;
-import com.sun.jna.Function;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
@@ -21,6 +20,10 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
@@ -29,6 +32,7 @@
import java.util.List;
import java.util.TimeZone;
+import com.sun.jna.Function;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
@@ -36,18 +40,34 @@
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
+import com.sun.jna.platform.win32.Ntifs.REPARSE_DATA_BUFFER;
+import com.sun.jna.platform.win32.Ntifs.SymbolicLinkReparseBuffer;
import com.sun.jna.platform.win32.WinBase.FILETIME;
+import com.sun.jna.platform.win32.WinBase.FILE_ATTRIBUTE_TAG_INFO;
+import com.sun.jna.platform.win32.WinBase.FILE_BASIC_INFO;
+import com.sun.jna.platform.win32.WinBase.FILE_COMPRESSION_INFO;
+import com.sun.jna.platform.win32.WinBase.FILE_DISPOSITION_INFO;
+import com.sun.jna.platform.win32.WinBase.FILE_ID_INFO;
+import com.sun.jna.platform.win32.WinBase.FILE_STANDARD_INFO;
import com.sun.jna.platform.win32.WinBase.MEMORYSTATUSEX;
+import com.sun.jna.platform.win32.WinBase.SYSTEMTIME;
import com.sun.jna.platform.win32.WinBase.SYSTEM_INFO;
+import com.sun.jna.platform.win32.WinBase.WIN32_FIND_DATA;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.HMODULE;
import com.sun.jna.platform.win32.WinDef.HWND;
+import com.sun.jna.platform.win32.WinDef.USHORT;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinNT.HANDLEByReference;
import com.sun.jna.platform.win32.WinNT.MEMORY_BASIC_INFORMATION;
import com.sun.jna.platform.win32.WinNT.OSVERSIONINFO;
import com.sun.jna.platform.win32.WinNT.OSVERSIONINFOEX;
+import com.sun.jna.platform.win32.WinioctlUtil.FSCTL_GET_COMPRESSION;
+import com.sun.jna.platform.win32.WinioctlUtil.FSCTL_GET_REPARSE_POINT;
+import com.sun.jna.platform.win32.WinioctlUtil.FSCTL_SET_COMPRESSION;
+import com.sun.jna.platform.win32.WinioctlUtil.FSCTL_SET_REPARSE_POINT;
import com.sun.jna.ptr.IntByReference;
+import com.sun.jna.ptr.ShortByReference;
import junit.framework.TestCase;
@@ -554,6 +574,131 @@ public void testGetFileAttributes() {
assertTrue(WinBase.INVALID_FILE_ATTRIBUTES != Kernel32.INSTANCE.GetFileAttributes("."));
}
+ public void testDeviceIoControlFsctlCompression() throws IOException {
+ File tmp = File.createTempFile("testDeviceIoControlFsctlCompression", "jna");
+ tmp.deleteOnExit();
+
+ HANDLE hFile = Kernel32.INSTANCE.CreateFile(tmp.getAbsolutePath(), WinNT.GENERIC_ALL, WinNT.FILE_SHARE_READ,
+ new WinBase.SECURITY_ATTRIBUTES(), WinNT.OPEN_EXISTING, WinNT.FILE_ATTRIBUTE_NORMAL, null);
+ assertFalse(WinBase.INVALID_HANDLE_VALUE.equals(hFile));
+
+ try {
+ ShortByReference lpBuffer = new ShortByReference();
+ IntByReference lpBytes = new IntByReference();
+
+ if (false == Kernel32.INSTANCE.DeviceIoControl(hFile,
+ new FSCTL_GET_COMPRESSION().getControlCode(),
+ null,
+ 0,
+ lpBuffer.getPointer(),
+ USHORT.SIZE,
+ lpBytes,
+ null)) {
+ fail("DeviceIoControl failed with " + Kernel32.INSTANCE.GetLastError());
+ }
+ assertEquals(WinNT.COMPRESSION_FORMAT_NONE, lpBuffer.getValue());
+ assertEquals(USHORT.SIZE, lpBytes.getValue());
+
+ lpBuffer = new ShortByReference((short)WinNT.COMPRESSION_FORMAT_LZNT1);
+
+ if (false == Kernel32.INSTANCE.DeviceIoControl(hFile,
+ new FSCTL_SET_COMPRESSION().getControlCode(),
+ lpBuffer.getPointer(),
+ USHORT.SIZE,
+ null,
+ 0,
+ lpBytes,
+ null)) {
+ fail("DeviceIoControl failed with " + Kernel32.INSTANCE.GetLastError());
+ }
+
+ if (false == Kernel32.INSTANCE.DeviceIoControl(hFile,
+ new FSCTL_GET_COMPRESSION().getControlCode(),
+ null,
+ 0,
+ lpBuffer.getPointer(),
+ USHORT.SIZE,
+ lpBytes,
+ null)) {
+ fail("DeviceIoControl failed with " + Kernel32.INSTANCE.GetLastError());
+ }
+ assertEquals(WinNT.COMPRESSION_FORMAT_LZNT1, lpBuffer.getValue());
+ assertEquals(USHORT.SIZE, lpBytes.getValue());
+
+ } finally {
+ Kernel32Util.closeHandle(hFile);
+ }
+ }
+
+ /**
+ * NOTE: Due to process elevation, this test must be run as administrator
+ * @throws IOException
+ */
+ public void testDeviceIoControlFsctlReparse() throws IOException {
+ Path folder = Files.createTempDirectory("testDeviceIoControlFsctlReparse_FOLDER");
+ Path link = Files.createTempDirectory("testDeviceIoControlFsctlReparse_LINK");
+ File delFolder = folder.toFile();
+ delFolder.deleteOnExit();
+ File delLink = link.toFile();
+ delLink.deleteOnExit();
+
+ // Required for FSCTL_SET_REPARSE_POINT
+ Advapi32Util.Privilege restore = new Advapi32Util.Privilege(WinNT.SE_RESTORE_NAME);
+ try {
+ restore.enable();
+ HANDLE hFile = Kernel32.INSTANCE.CreateFile(link.toAbsolutePath().toString(),
+ WinNT.GENERIC_READ | WinNT.FILE_WRITE_ATTRIBUTES | WinNT.FILE_WRITE_EA,
+ WinNT.FILE_SHARE_READ | WinNT.FILE_SHARE_WRITE | WinNT.FILE_SHARE_DELETE,
+ new WinBase.SECURITY_ATTRIBUTES(),
+ WinNT.OPEN_EXISTING,
+ WinNT.FILE_ATTRIBUTE_DIRECTORY | WinNT.FILE_FLAG_BACKUP_SEMANTICS | WinNT.FILE_FLAG_OPEN_REPARSE_POINT,
+ null);
+
+ if (WinBase.INVALID_HANDLE_VALUE.equals(hFile)) {
+ fail("CreateFile failed with " + Kernel32.INSTANCE.GetLastError());
+ }
+
+ try {
+ SymbolicLinkReparseBuffer symLinkReparseBuffer = new SymbolicLinkReparseBuffer(folder.getFileName().toString(),
+ folder.getFileName().toString(),
+ Ntifs.SYMLINK_FLAG_RELATIVE);
+
+ REPARSE_DATA_BUFFER lpBuffer = new REPARSE_DATA_BUFFER(WinNT.IO_REPARSE_TAG_SYMLINK, (short) 0, symLinkReparseBuffer);
+
+ assertTrue(Kernel32.INSTANCE.DeviceIoControl(hFile,
+ new FSCTL_SET_REPARSE_POINT().getControlCode(),
+ lpBuffer.getPointer(),
+ lpBuffer.getSize(),
+ null,
+ 0,
+ null,
+ null));
+
+ Memory p = new Memory(REPARSE_DATA_BUFFER.sizeOf());
+ IntByReference lpBytes = new IntByReference();
+ assertTrue(Kernel32.INSTANCE.DeviceIoControl(hFile,
+ new FSCTL_GET_REPARSE_POINT().getControlCode(),
+ null,
+ 0,
+ p,
+ (int) p.size(),
+ lpBytes,
+ null));
+ // Is a reparse point
+ lpBuffer = new REPARSE_DATA_BUFFER(p);
+ assertTrue(lpBytes.getValue() > 0);
+ assertTrue(lpBuffer.ReparseTag == WinNT.IO_REPARSE_TAG_SYMLINK);
+ assertEquals(folder.getFileName().toString(), lpBuffer.u.symLinkReparseBuffer.getPrintName());
+ assertEquals(folder.getFileName().toString(), lpBuffer.u.symLinkReparseBuffer.getSubstituteName());
+ } finally {
+ Kernel32Util.closeHandle(hFile);
+ }
+ }
+ finally {
+ restore.close();
+ }
+ }
+
public void testCopyFile() throws IOException {
File source = File.createTempFile("testCopyFile", "jna");
source.deleteOnExit();
@@ -606,6 +751,239 @@ public void testCreateProcess() {
assertTrue(processInformation.dwProcessId.longValue() > 0);
}
+ public void testFindFirstFile() throws IOException {
+ Path tmpDir = Files.createTempDirectory("testFindFirstFile");
+ File tmpFile = new File(Files.createTempFile(tmpDir, "testFindFirstFile", ".jna").toString());
+
+ Memory p = new Memory(WIN32_FIND_DATA.sizeOf());
+ HANDLE hFile = Kernel32.INSTANCE.FindFirstFile(tmpDir.toAbsolutePath().toString() + "\\*", p);
+ assertFalse(WinBase.INVALID_HANDLE_VALUE.equals(hFile));
+
+ try {
+
+ // Get data and confirm the 1st name is . for the directory itself.
+ WIN32_FIND_DATA fd = new WIN32_FIND_DATA(p);
+ String actualFileName = new String(fd.getFileName());
+ assertTrue(actualFileName.contentEquals("."));
+
+ // Get data and confirm the 2nd name is .. for the directory's parent
+ assertTrue(Kernel32.INSTANCE.FindNextFile(hFile, p));
+ fd = new WIN32_FIND_DATA(p);
+ actualFileName = new String(fd.getFileName());
+ assertTrue(actualFileName.contentEquals(".."));
+
+ // Get data and confirm the 3rd name is the tmp file name
+ assertTrue(Kernel32.INSTANCE.FindNextFile(hFile, p));
+ fd = new WIN32_FIND_DATA(p);
+ actualFileName = new String(fd.getFileName());
+ assertTrue(actualFileName.contentEquals(tmpFile.getName()));
+
+ // No more files in directory
+ assertFalse(Kernel32.INSTANCE.FindNextFile(hFile, p));
+ assertEquals(WinNT.ERROR_NO_MORE_FILES, Kernel32.INSTANCE.GetLastError());
+ }
+ finally {
+ Kernel32.INSTANCE.FindClose(hFile);
+ tmpFile.delete();
+ Files.delete(tmpDir);
+ }
+ }
+
+ public void testFindFirstFileExFindExInfoStandard() throws IOException {
+ Path tmpDir = Files.createTempDirectory("testFindFirstFileExFindExInfoStandard");
+ File tmpFile = new File(Files.createTempFile(tmpDir, "testFindFirstFileExFindExInfoStandard", ".jna").toString());
+
+ Memory p = new Memory(WIN32_FIND_DATA.sizeOf());
+ HANDLE hFile = Kernel32.INSTANCE.FindFirstFileEx(tmpDir.toAbsolutePath().toString() + "\\*",
+ WinBase.FindExInfoStandard,
+ p,
+ WinBase.FindExSearchNameMatch,
+ null,
+ new DWORD(0));
+ assertFalse(WinBase.INVALID_HANDLE_VALUE.equals(hFile));
+
+ try {
+
+ // Get data and confirm the 1st name is . for the directory itself.
+ WIN32_FIND_DATA fd = new WIN32_FIND_DATA(p);
+ String actualFileName = new String(fd.getFileName());
+ assertTrue(actualFileName.contentEquals("."));
+
+ // Get data and confirm the 2nd name is .. for the directory's parent
+ assertTrue(Kernel32.INSTANCE.FindNextFile(hFile, p));
+ fd = new WIN32_FIND_DATA(p);
+ actualFileName = new String(fd.getFileName());
+ assertTrue(actualFileName.contentEquals(".."));
+
+ // Get data and confirm the 3rd name is the tmp file name
+ assertTrue(Kernel32.INSTANCE.FindNextFile(hFile, p));
+ fd = new WIN32_FIND_DATA(p);
+ actualFileName = new String(fd.getFileName());
+ assertTrue(actualFileName.contentEquals(tmpFile.getName()));
+
+ // No more files in directory
+ assertFalse(Kernel32.INSTANCE.FindNextFile(hFile, p));
+ assertEquals(WinNT.ERROR_NO_MORE_FILES, Kernel32.INSTANCE.GetLastError());
+ }
+ finally {
+ Kernel32.INSTANCE.FindClose(hFile);
+ tmpFile.delete();
+ Files.delete(tmpDir);
+ }
+ }
+
+ public void testFindFirstFileExFindExInfoBasic() throws IOException {
+ Path tmpDir = Files.createTempDirectory("testFindFirstFileExFindExInfoBasic");
+ File tmpFile = new File(Files.createTempFile(tmpDir, "testFindFirstFileExFindExInfoBasic", ".jna").toString());
+
+ Memory p = new Memory(WIN32_FIND_DATA.sizeOf());
+ // Add the file name to the search to get just that one entry
+ HANDLE hFile = Kernel32.INSTANCE.FindFirstFileEx(tmpDir.toAbsolutePath().toString() + "\\" + tmpFile.getName(),
+ WinBase.FindExInfoBasic,
+ p,
+ WinBase.FindExSearchNameMatch,
+ null,
+ new DWORD(0));
+ assertFalse(WinBase.INVALID_HANDLE_VALUE.equals(hFile));
+
+ try {
+ // Get data and confirm the 1st name is for the file itself
+ WIN32_FIND_DATA fd = new WIN32_FIND_DATA(p);
+ String actualFileName = new String(fd.getFileName());
+ actualFileName = new String(fd.getFileName());
+ assertTrue(actualFileName.contentEquals(tmpFile.getName()));
+
+ // FindExInfoBasic does not return the short name, so confirm that its empty
+ String alternateFileName = fd.getAlternateFileName();
+ assertTrue(alternateFileName.isEmpty());
+
+ // No more files in directory
+ assertFalse(Kernel32.INSTANCE.FindNextFile(hFile, p));
+ assertEquals(WinNT.ERROR_NO_MORE_FILES, Kernel32.INSTANCE.GetLastError());
+ }
+ finally {
+ Kernel32.INSTANCE.FindClose(hFile);
+ tmpFile.delete();
+ Files.delete(tmpDir);
+ }
+ }
+
+ public void testGetFileInformationByHandleEx() throws IOException {
+ File tmp = File.createTempFile("testGetFileInformationByHandleEx", "jna");
+ tmp.deleteOnExit();
+
+ HANDLE hFile = Kernel32.INSTANCE.CreateFile(tmp.getAbsolutePath(), WinNT.GENERIC_WRITE, WinNT.FILE_SHARE_WRITE,
+ new WinBase.SECURITY_ATTRIBUTES(), WinNT.OPEN_EXISTING, WinNT.FILE_ATTRIBUTE_NORMAL, null);
+ assertFalse(WinBase.INVALID_HANDLE_VALUE.equals(hFile));
+
+ try {
+
+ Memory p = new Memory(FILE_BASIC_INFO.sizeOf());
+ if (false == Kernel32.INSTANCE.GetFileInformationByHandleEx(hFile, WinBase.FileBasicInfo, p, new DWORD(p.size()))) {
+ fail("GetFileInformationByHandleEx failed with " + Kernel32.INSTANCE.GetLastError());
+ }
+ FILE_BASIC_INFO fbi = new FILE_BASIC_INFO(p);
+ // New file has non-zero creation time
+ assertTrue(0 != fbi.CreationTime.getValue());
+
+ p = new Memory(FILE_STANDARD_INFO.sizeOf());
+ if (false == Kernel32.INSTANCE.GetFileInformationByHandleEx(hFile, WinBase.FileStandardInfo, p, new DWORD(p.size()))) {
+ fail("GetFileInformationByHandleEx failed with " + Kernel32.INSTANCE.GetLastError());
+ }
+ FILE_STANDARD_INFO fsi = new FILE_STANDARD_INFO(p);
+ // New file has 1 link
+ assertEquals(1, fsi.NumberOfLinks);
+
+ p = new Memory(FILE_COMPRESSION_INFO.sizeOf());
+ if (false == Kernel32.INSTANCE.GetFileInformationByHandleEx(hFile, WinBase.FileCompressionInfo, p, new DWORD(p.size()))) {
+ fail("GetFileInformationByHandleEx failed with " + Kernel32.INSTANCE.GetLastError());
+ }
+ FILE_COMPRESSION_INFO fci = new FILE_COMPRESSION_INFO(p);
+ // Uncompressed file should be zero
+ assertEquals(0, fci.CompressionFormat);
+
+ p = new Memory(FILE_ATTRIBUTE_TAG_INFO.sizeOf());
+ if (false == Kernel32.INSTANCE.GetFileInformationByHandleEx(hFile, WinBase.FileAttributeTagInfo, p, new DWORD(p.size()))) {
+ fail("GetFileInformationByHandleEx failed with " + Kernel32.INSTANCE.GetLastError());
+ }
+ FILE_ATTRIBUTE_TAG_INFO fati = new FILE_ATTRIBUTE_TAG_INFO(p);
+ // New files have the archive bit
+ assertEquals(WinNT.FILE_ATTRIBUTE_ARCHIVE, fati.FileAttributes);
+
+ p = new Memory(FILE_ID_INFO.sizeOf());
+ if (false == Kernel32.INSTANCE.GetFileInformationByHandleEx(hFile, WinBase.FileIdInfo, p, new DWORD(p.size()))) {
+ fail("GetFileInformationByHandleEx failed with " + Kernel32.INSTANCE.GetLastError());
+ }
+ FILE_ID_INFO fii = new FILE_ID_INFO(p);
+ // Volume serial number should be non-zero
+ assertFalse(fii.VolumeSerialNumber == 0);
+ } finally {
+ Kernel32.INSTANCE.CloseHandle(hFile);
+ }
+ }
+
+ public void testSetFileInformationByHandleFileBasicInfo() throws IOException, InterruptedException {
+ File tmp = File.createTempFile("testSetFileInformationByHandleFileBasicInfo", "jna");
+ tmp.deleteOnExit();
+
+ HANDLE hFile = Kernel32.INSTANCE.CreateFile(tmp.getAbsolutePath(),
+ WinNT.GENERIC_READ | WinNT.GENERIC_WRITE,
+ WinNT.FILE_SHARE_READ | WinNT.FILE_SHARE_WRITE,
+ new WinBase.SECURITY_ATTRIBUTES(),
+ WinNT.OPEN_EXISTING,
+ WinNT.FILE_ATTRIBUTE_NORMAL,
+ null);
+
+ assertFalse(WinBase.INVALID_HANDLE_VALUE.equals(hFile));
+
+ try {
+ Memory p = new Memory(FILE_BASIC_INFO.sizeOf());
+ if (false == Kernel32.INSTANCE.GetFileInformationByHandleEx(hFile, WinBase.FileBasicInfo, p, new DWORD(p.size())))
+ fail("GetFileInformationByHandleEx failed with " + Kernel32.INSTANCE.GetLastError());
+
+ FILE_BASIC_INFO fbi = new FILE_BASIC_INFO(p);
+ // Add TEMP attribute
+ fbi.FileAttributes = fbi.FileAttributes | WinNT.FILE_ATTRIBUTE_TEMPORARY;
+ fbi.ChangeTime = new WinNT.LARGE_INTEGER(0);
+ fbi.CreationTime = new WinNT.LARGE_INTEGER(0);
+ fbi.LastAccessTime = new WinNT.LARGE_INTEGER(0);
+ fbi.LastWriteTime = new WinNT.LARGE_INTEGER(0);
+ fbi.write();
+
+ if (false == Kernel32.INSTANCE.SetFileInformationByHandle(hFile, WinBase.FileBasicInfo, fbi.getPointer(), new DWORD(FILE_BASIC_INFO.sizeOf())))
+ fail("GetFileInformationByHandleEx failed with " + Kernel32.INSTANCE.GetLastError());
+
+ if (false == Kernel32.INSTANCE.GetFileInformationByHandleEx(hFile, WinBase.FileBasicInfo, p, new DWORD(p.size())))
+ fail("GetFileInformationByHandleEx failed with " + Kernel32.INSTANCE.GetLastError());
+
+ fbi = new FILE_BASIC_INFO(p);
+ assertTrue((fbi.FileAttributes & WinNT.FILE_ATTRIBUTE_TEMPORARY) != 0);
+ }
+ finally {
+ Kernel32.INSTANCE.CloseHandle(hFile);
+ }
+ }
+
+ public void testSetFileInformationByHandleFileDispositionInfo() throws IOException, InterruptedException {
+ File tmp = File.createTempFile("testSetFileInformationByHandleFileDispositionInfo", "jna");
+
+ HANDLE hFile = Kernel32.INSTANCE.CreateFile(tmp.getAbsolutePath(), WinNT.GENERIC_WRITE | WinNT.DELETE, WinNT.FILE_SHARE_WRITE,
+ new WinBase.SECURITY_ATTRIBUTES(), WinNT.OPEN_EXISTING, WinNT.FILE_ATTRIBUTE_NORMAL, null);
+
+ assertFalse(WinBase.INVALID_HANDLE_VALUE.equals(hFile));
+
+ try {
+ FILE_DISPOSITION_INFO fdi = new FILE_DISPOSITION_INFO(true);
+ if (false == Kernel32.INSTANCE.SetFileInformationByHandle(hFile, WinBase.FileDispositionInfo, fdi.getPointer(), new DWORD(FILE_DISPOSITION_INFO.sizeOf())))
+ fail("SetFileInformationByHandle failed with " + Kernel32.INSTANCE.GetLastError());
+
+ } finally {
+ Kernel32.INSTANCE.CloseHandle(hFile);
+ }
+
+ assertFalse(Files.exists(Paths.get(tmp.getAbsolutePath())));
+ }
+
public void testGetSetFileTime() throws IOException {
File tmp = File.createTempFile("testGetSetFileTime", "jna");
tmp.deleteOnExit();
@@ -774,6 +1152,72 @@ public final void testWritePrivateProfileSection() throws IOException {
reader.close();
}
+ /**
+ * Test both SystemTimeToFileTime and FileTimeToSystemTime
+ * @throws IOException
+ */
+ public final void testSystemTimeToFileTimeAndFileTimeToSystemTime() throws IOException {
+
+ WinBase.SYSTEMTIME systemTime = new WinBase.SYSTEMTIME();
+ Kernel32.INSTANCE.GetSystemTime(systemTime);
+ WinBase.FILETIME fileTime = new WinBase.FILETIME();
+
+ if (false == Kernel32.INSTANCE.SystemTimeToFileTime(systemTime, fileTime)) {
+ fail("SystemTimeToFileTime failed with " + Kernel32.INSTANCE.GetLastError());
+ }
+
+ WinBase.SYSTEMTIME newSystemTime = new WinBase.SYSTEMTIME();
+ if (false == Kernel32.INSTANCE.FileTimeToSystemTime(fileTime, newSystemTime)) {
+ fail("FileTimeToSystemTime failed with " + Kernel32.INSTANCE.GetLastError());
+ }
+
+ assertEquals(systemTime.wYear, newSystemTime.wYear);
+ assertEquals(systemTime.wDay, newSystemTime.wDay);
+ assertEquals(systemTime.wMonth, newSystemTime.wMonth);
+ assertEquals(systemTime.wHour, newSystemTime.wHour);
+ assertEquals(systemTime.wMinute, newSystemTime.wMinute);
+ assertEquals(systemTime.wSecond, newSystemTime.wSecond);
+ assertEquals(systemTime.wMilliseconds, newSystemTime.wMilliseconds);
+ }
+
+ /**
+ * Test FILETIME's LARGE_INTEGER constructor
+ * @throws IOException
+ */
+ public final void testFileTimeFromLargeInteger() throws IOException {
+
+ File tmp = File.createTempFile("testGetFileInformationByHandleEx", "jna");
+ tmp.deleteOnExit();
+
+ HANDLE hFile = Kernel32.INSTANCE.CreateFile(tmp.getAbsolutePath(), WinNT.GENERIC_WRITE, WinNT.FILE_SHARE_WRITE,
+ new WinBase.SECURITY_ATTRIBUTES(), WinNT.OPEN_EXISTING, WinNT.FILE_ATTRIBUTE_NORMAL, null);
+ assertFalse(WinBase.INVALID_HANDLE_VALUE.equals(hFile));
+
+ try {
+
+ Memory p = new Memory(FILE_BASIC_INFO.sizeOf());
+ if (false == Kernel32.INSTANCE.GetFileInformationByHandleEx(hFile, WinBase.FileBasicInfo, p, new DWORD(p.size()))) {
+ fail("GetFileInformationByHandleEx failed with " + Kernel32.INSTANCE.GetLastError());
+ }
+ FILE_BASIC_INFO fbi = new FILE_BASIC_INFO(p);
+ FILETIME ft = new FILETIME(fbi.LastWriteTime);
+ SYSTEMTIME stUTC = new SYSTEMTIME();
+ SYSTEMTIME stLocal = new SYSTEMTIME();
+ Kernel32.INSTANCE.FileTimeToSystemTime(ft, stUTC);
+ // Covert to local
+ Kernel32.INSTANCE.SystemTimeToTzSpecificLocalTime(null, stUTC, stLocal);
+ FileTime calculatedCreateTime = FileTime.fromMillis(stLocal.toCalendar().getTimeInMillis());
+
+ // Actual file's createTime
+ FileTime createTime = Files.getLastModifiedTime(Paths.get(tmp.getAbsolutePath()));
+
+ assertEquals(createTime.toMillis(), calculatedCreateTime.toMillis());
+ }
+ finally {
+ Kernel32.INSTANCE.CloseHandle(hFile);
+ }
+ }
+
public final void testCreateRemoteThread() throws IOException {
HANDLE hThrd = Kernel32.INSTANCE.CreateRemoteThread(null, null, 0, null, null, null, null);
assertNull(hThrd);