From ca83dc3795df3a3e152a8e1da8320a96c0f58d6b Mon Sep 17 00:00:00 2001 From: Adam Marcionek Date: Mon, 21 Nov 2016 15:53:29 -0500 Subject: [PATCH 1/4] Added WinioctlUtil, Ntifs and modified Kernel32 * Added `com.sun.jna.platform.win32.WinioctlUtil` for help in determining FSCTL_* codes * Added `com.sun.jna.platform.win32.Ntifs` with Reparse Point structures and defines * Added initialization of FILETIME from LARGE_INTEGER * Added `GetFileInformationByHandleEx` and `SetFileInformationByHandle` to `com.sun.jna.platform.win32.Kernel32` --- CHANGES.md | 4 + .../sun/jna/platform/win32/Advapi32Util.java | 189 +++++ .../com/sun/jna/platform/win32/Kernel32.java | 149 ++++ .../src/com/sun/jna/platform/win32/Ntifs.java | 390 +++++++++++ .../com/sun/jna/platform/win32/WinBase.java | 648 ++++++++++++++++++ .../src/com/sun/jna/platform/win32/WinNT.java | 19 + .../com/sun/jna/platform/win32/Winioctl.java | 97 +++ .../sun/jna/platform/win32/WinioctlUtil.java | 74 ++ .../jna/platform/win32/Advapi32UtilTest.java | 13 + .../sun/jna/platform/win32/Kernel32Test.java | 446 +++++++++++- 10 files changed, 2028 insertions(+), 1 deletion(-) create mode 100644 contrib/platform/src/com/sun/jna/platform/win32/Ntifs.java create mode 100644 contrib/platform/src/com/sun/jna/platform/win32/WinioctlUtil.java diff --git a/CHANGES.md b/CHANGES.md index 6d17247de1..b682c9645d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,10 @@ Release 4.3 (Next release) Features -------- +* [#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). * [#526](https://github.com/java-native-access/jna/pull/526): Added initialization and conversion between Windows SYSTEMTIME and Java Calendar - [@lgoldstein](https://github.com/lgoldstein). * [#532](https://github.com/java-native-access/jna/pull/529): Added `com.sun.jna.platform.win32.Mpr`, `com.sun.jna.platform.win32.LmShare`, and `com.sun.jna.platform.win32.Winnetwk` - [@amarcionek](https://github.com/amarcionek). * [#532](https://github.com/java-native-access/jna/pull/529): Added `ACCESS_*` definitions to `com.sun.jna.platform.win32.LmAccess` - [@amarcionek](https://github.com/amarcionek). 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 be7f370b54..4e5f6af24e 100755 --- a/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java @@ -30,6 +30,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; @@ -70,6 +71,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; @@ -2625,4 +2627,191 @@ public DWORD callback(Pointer pbData, Pointer pvCallbackContext, // close Advapi32.INSTANCE.CloseEncryptedFileRaw(pvContext.getValue()); } + + /** + * Convenience class to enables a certain Windows process privilege + */ + public static class Privilege { + /** + * If true, the thread is currently impersonating + */ + private boolean currentlyImpersonating = false; + + /** + * If true, the Privilege has been enabled + */ + private boolean privilegeEnabled = false; + + /** + * LUID form of the privilege + */ + private final WinNT.LUID pLuid = new WinNT.LUID(); + + /** + * String form of the privilege + */ + private final String privilege; + + /** + * Construct a Privilege + * @param privilege the name of the privilege in the form of SE_* from Advapi32.java + * @throws IllegalArgumentException + */ + public Privilege(String privilege) throws IllegalArgumentException { + this.privilege = privilege; + if (!Advapi32.INSTANCE.LookupPrivilegeValue(null, this.privilege, pLuid)) { + throw new IllegalArgumentException("Failed to find privilege \"" + privilege + "\" - " + Kernel32.INSTANCE.GetLastError()); + } + } + + /** + * Enables the given privilege. 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 privilege, 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 a privilege. Multiple calls to enable() without a drop() in between have no affect. + * @throws Win32Exception + */ + public void enable() throws Win32Exception { + // Ignore if already enabled. + if (privilegeEnabled) + return; + + // Get thread token + final HANDLEByReference phThreadToken = new HANDLEByReference(); + + try { + phThreadToken.setValue(getThreadToken()); + WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(1); + tp.Privileges[0] = new WinNT.LUID_AND_ATTRIBUTES(pLuid, new DWORD(WinNT.SE_PRIVILEGE_ENABLED)); + if (!Advapi32.INSTANCE.AdjustTokenPrivileges(phThreadToken.getValue(), false, tp, 0, null, null)) { + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + privilegeEnabled = true; + } + catch (Win32Exception ex) { + // If fails, clean up + if (currentlyImpersonating) { + Advapi32.INSTANCE.SetThreadToken(null, null); + currentlyImpersonating = false; + } + else { + if (privilegeEnabled) { + WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(1); + tp.Privileges[0] = new WinNT.LUID_AND_ATTRIBUTES(pLuid, new DWORD(0)); + Advapi32.INSTANCE.AdjustTokenPrivileges(phThreadToken.getValue(), false, tp, 0, null, null); + privilegeEnabled = 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); + } + } + } + + /** + * 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 (privilegeEnabled) { + WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(1); + tp.Privileges[0] = new WinNT.LUID_AND_ATTRIBUTES(pLuid, new DWORD(0)); + Advapi32.INSTANCE.AdjustTokenPrivileges(phThreadToken.getValue(), false, tp, 0, null, null); + privilegeEnabled = 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 c68111618a..96ac08f9d8 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java @@ -15,6 +15,7 @@ import com.sun.jna.LastErrorException; import com.sun.jna.Native; import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.WTypes.LPWSTR; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.PointerByReference; import com.sun.jna.win32.StdCallLibrary; @@ -1432,6 +1433,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. @@ -2483,6 +2526,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. * @@ -2616,6 +2671,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(LPWSTR 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(LPWSTR 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..a1da16da07 --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/win32/Ntifs.java @@ -0,0 +1,390 @@ +/* Copyright (c) 2016 Adam Marcionek All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +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; + +/** + * 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 USHORT SubstituteNameOffset = new USHORT(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 USHORT SubstituteNameLength = new USHORT(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 USHORT PrintNameOffset = new USHORT(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 USHORT PrintNameLength = new USHORT(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 ULONG Flags = new ULONG(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(); + } + + public SymbolicLinkReparseBuffer(Pointer memory) { + super(memory); + read(); + } + + public SymbolicLinkReparseBuffer(String substituteName, String printName, int Flags) { + super(); + String bothNames = substituteName + printName; + PathBuffer = bothNames.toCharArray(); + this.SubstituteNameOffset = new USHORT(0); + this.SubstituteNameLength = new USHORT(substituteName.length() * 2); + this.PrintNameOffset = new USHORT((substituteName.length()) * 2); + this.PrintNameLength = new USHORT(printName.length() * 2); + this.Flags = new ULONG(Flags); + write(); + } + + public SymbolicLinkReparseBuffer(USHORT SubstituteNameOffset, USHORT SubstituteNameLength, USHORT PrintNameOffset, USHORT PrintNameLength, ULONG 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, this.PrintNameOffset.intValue() / 2, this.PrintNameLength.intValue() / 2); + } + + /** + * @return the substitute name in a String + */ + public String getSubstituteName() { + return String.copyValueOf(PathBuffer, this.SubstituteNameOffset.intValue() / 2, this.SubstituteNameLength.intValue() / 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 USHORT SubstituteNameOffset; + + /** + * 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 USHORT SubstituteNameLength; + + /** + * 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 USHORT PrintNameOffset; + + /** + * 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 USHORT PrintNameLength; + + /** + * 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(); + } + + public MountPointReparseBuffer(Pointer memory) { + super(memory); + read(); + } + + public MountPointReparseBuffer(String substituteName, String printName) { + super(); + String bothNames = substituteName + printName; + PathBuffer = bothNames.toCharArray(); + this.SubstituteNameOffset = new USHORT(0); + this.SubstituteNameLength = new USHORT(substituteName.length()); + this.PrintNameOffset = new USHORT((substituteName.length()) * 2); + this.PrintNameLength = new USHORT(printName.length() * 2); + write(); + } + + public MountPointReparseBuffer(USHORT SubstituteNameOffset, USHORT SubstituteNameLength, USHORT PrintNameOffset, USHORT 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 ULONG ReparseTag; + + /** + * Size, in bytes, of the reparse data in the DataBuffer member. + */ + public USHORT ReparseDataLength = new USHORT(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 USHORT Reserved; + + 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 + this.ReparseDataLength.intValue(); + } + + @Override + protected List getFieldOrder() { + return Arrays.asList(new String[] { "ReparseTag", "ReparseDataLength", "Reserved", "u" }); + } + + public REPARSE_DATA_BUFFER() { + super(); + } + + public REPARSE_DATA_BUFFER(int ReparseTag, int Reserved) { + super(); + this.ReparseTag = new ULONG(ReparseTag); + this.Reserved = new USHORT(Reserved); + this.ReparseDataLength = new USHORT(0); + write(); + } + + public REPARSE_DATA_BUFFER(int ReparseTag, int Reserved, SymbolicLinkReparseBuffer symLinkReparseBuffer) { + super(); + this.ReparseTag = new ULONG(ReparseTag); + this.Reserved = new USHORT(Reserved); + this.ReparseDataLength = new USHORT(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.intValue()) { + 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 51a800916c..5249f4458f 100755 --- a/contrib/platform/src/com/sun/jna/platform/win32/WinBase.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/WinBase.java @@ -19,11 +19,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; @@ -183,6 +185,643 @@ 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 DWORD 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, + DWORD 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, + DWORD 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 DWORD 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, + DWORD 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 WORD CompressionFormat; + + /** + * The factor that the compression uses. + */ + public UCHAR CompressionUnitShift; + + /** + * The number of chunks that are shifted by compression. + */ + public UCHAR ChunkShift; + + /** + * The number of clusters that are shifted by compression. + */ + public UCHAR ClusterShift; + + /** + * Reserved + */ + public UCHAR[] Reserved = new UCHAR[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(); + } + + public FILE_COMPRESSION_INFO(Pointer memory) { + super(memory); + read(); + } + + public FILE_COMPRESSION_INFO(LARGE_INTEGER CompressedFileSize, + WORD CompressionFormat, + UCHAR CompressionUnitShift, + UCHAR ChunkShift, + UCHAR ClusterShift) { + this.CompressedFileSize = CompressedFileSize; + this.CompressionFormat = CompressionFormat; + this.CompressionUnitShift = CompressionUnitShift; + this.ChunkShift = ChunkShift; + this.ClusterShift = ClusterShift; + this.Reserved = new UCHAR[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 DWORD FileAttributes; + + /** + * The reparse tag. + */ + public DWORD 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(DWORD FileAttributes, + DWORD 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 ULONGLONG 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(ULONGLONG VolumeSerialNumber, + FILE_ID_128 FileId, + DWORD NumberOfLinks, + boolean DeletePending, + boolean Directory) { + 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 DWORD 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 DWORD nFileSizeHigh; + + /** + * The low-order DWORD value of the file size, in bytes. + */ + public DWORD 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 DWORD dwReserved0; + + /** + * Reserved for future use. + */ + public DWORD 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(); + } + + public WIN32_FIND_DATA(Pointer memory) { + super(memory); + read(); + } + + public WIN32_FIND_DATA(DWORD dwFileAttributes, + FILETIME ftCreationTime, + FILETIME ftLastAccessTime, + FILETIME ftLastWriteTime, + DWORD nFileSizeHigh, + DWORD nFileSizeLow, + DWORD dwReserved0, + DWORD 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). @@ -213,6 +852,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 455abfe72a..65ae06bfb0 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java @@ -828,6 +828,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 @@ -836,6 +846,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 b6abeeb18d..f2863e4db4 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Winioctl.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Winioctl.java @@ -20,6 +20,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..dc43f727a3 --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/win32/WinioctlUtil.java @@ -0,0 +1,74 @@ +/* Copyright (c) 2016 Adam Marcionek, All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +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..808019437f 100755 --- a/contrib/platform/test/com/sun/jna/platform/win32/Advapi32UtilTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Advapi32UtilTest.java @@ -599,6 +599,19 @@ public void testBackupEncryptedFile() throws Exception { dest.delete(); } + /** + * Test Privilege class + */ + public void testPrivilege() { + Advapi32Util.Privilege p = new Advapi32Util.Privilege(WinNT.SE_ASSIGNPRIMARYTOKEN_NAME); + try { + p.enable(); // Will throw if it fails + } + finally { + p.disable(); + } + } + 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 f3a9ade920..1856c2cfaf 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,37 @@ 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.WTypes.LPWSTR; 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.ULONGLONG; +import com.sun.jna.platform.win32.WinDef.USHORT; +import com.sun.jna.platform.win32.WinDef.WORD; 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 +577,128 @@ 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); + 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, 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.intValue() == 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); + restore.disable(); + } + } + 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(new LPWSTR(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(new LPWSTR(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(new LPWSTR(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(new DWORD(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(new WORD(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(new DWORD(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 == new ULONGLONG(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 = new DWORD(fbi.FileAttributes.intValue() | 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.intValue() & 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); From 2cea7182931b6f5c314d9d26afa8d1f73a0fd400 Mon Sep 17 00:00:00 2001 From: Adam Marcionek Date: Mon, 28 Nov 2016 15:54:13 -0500 Subject: [PATCH 2/4] Changes based on feedback --- CHANGES.md | 8 +- .../com/sun/jna/platform/win32/Kernel32.java | 5 +- .../src/com/sun/jna/platform/win32/Ntifs.java | 108 ++++++++++-------- .../com/sun/jna/platform/win32/WinBase.java | 75 ++++++------ .../sun/jna/platform/win32/WinioctlUtil.java | 31 +++-- .../sun/jna/platform/win32/Kernel32Test.java | 25 ++-- 6 files changed, 134 insertions(+), 118 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index fa592e826f..42c4b8ae4a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,10 +7,6 @@ Release 4.3 (Next release) Features -------- -* [#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). * [#526](https://github.com/java-native-access/jna/pull/526): Added initialization and conversion between Windows SYSTEMTIME and Java Calendar - [@lgoldstein](https://github.com/lgoldstein). * [#532](https://github.com/java-native-access/jna/pull/529): Added `com.sun.jna.platform.win32.Mpr`, `com.sun.jna.platform.win32.LmShare`, and `com.sun.jna.platform.win32.Winnetwk` - [@amarcionek](https://github.com/amarcionek). * [#532](https://github.com/java-native-access/jna/pull/529): Added `ACCESS_*` definitions to `com.sun.jna.platform.win32.LmAccess` - [@amarcionek](https://github.com/amarcionek). @@ -67,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/Kernel32.java b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java index 9b95d1a682..f66595f050 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java @@ -26,7 +26,6 @@ import com.sun.jna.LastErrorException; import com.sun.jna.Native; import com.sun.jna.Pointer; -import com.sun.jna.platform.win32.WTypes.LPWSTR; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.PointerByReference; import com.sun.jna.win32.StdCallLibrary; @@ -2708,7 +2707,7 @@ boolean SystemTimeToTzSpecificLocalTime(TIME_ZONE_INFORMATION lpTimeZone, * 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(LPWSTR lpFileName, Pointer lpFindFileData); + 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 @@ -2751,7 +2750,7 @@ boolean SystemTimeToTzSpecificLocalTime(TIME_ZONE_INFORMATION lpTimeZone, * 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(LPWSTR lpFileName, int fInfoLevelId, Pointer lpFindFileData, int fSearchOp, Pointer lpSearchFilter, DWORD dwAdditionalFlags); + 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. diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Ntifs.java b/contrib/platform/src/com/sun/jna/platform/win32/Ntifs.java index a1da16da07..bb868b28c7 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Ntifs.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Ntifs.java @@ -1,14 +1,25 @@ -/* Copyright (c) 2016 Adam Marcionek All Rights Reserved +/* Copyright (c) 2016 Adam Marcionek, All Rights Reserved * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. + * 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). * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. + * 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; @@ -19,6 +30,7 @@ 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 @@ -50,25 +62,25 @@ public ByReference(Pointer 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 USHORT SubstituteNameOffset = new USHORT(0); + 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 USHORT SubstituteNameLength = new USHORT(0); + 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 USHORT PrintNameOffset = new USHORT(0); + 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 USHORT PrintNameLength = new USHORT(0); + public short PrintNameLength = 0; /** * Used to indicate if the given symbolic link is an absolute or relative symbolic link. @@ -76,7 +88,7 @@ public ByReference(Pointer memory) { * array (at offset SubstitueNameOffset) is processed as a relative symbolic link; otherwise, * it is processed as an absolute symbolic link. */ - public ULONG Flags = new ULONG(0); + public int Flags = 0; /** * First character of the path string. This is followed in memory by the remainder of the string. @@ -99,11 +111,11 @@ protected List getFieldOrder() { } public SymbolicLinkReparseBuffer() { - super(); + super(W32APITypeMapper.UNICODE); } public SymbolicLinkReparseBuffer(Pointer memory) { - super(memory); + super(memory, Structure.ALIGN_DEFAULT, W32APITypeMapper.UNICODE); read(); } @@ -111,15 +123,15 @@ public SymbolicLinkReparseBuffer(String substituteName, String printName, int Fl super(); String bothNames = substituteName + printName; PathBuffer = bothNames.toCharArray(); - this.SubstituteNameOffset = new USHORT(0); - this.SubstituteNameLength = new USHORT(substituteName.length() * 2); - this.PrintNameOffset = new USHORT((substituteName.length()) * 2); - this.PrintNameLength = new USHORT(printName.length() * 2); - this.Flags = new ULONG(Flags); + 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(USHORT SubstituteNameOffset, USHORT SubstituteNameLength, USHORT PrintNameOffset, USHORT PrintNameLength, ULONG Flags, String PathBuffer) { + public SymbolicLinkReparseBuffer(short SubstituteNameOffset, short SubstituteNameLength, short PrintNameOffset, short PrintNameLength, int Flags, String PathBuffer) { super(); this.SubstituteNameOffset = SubstituteNameOffset; this.SubstituteNameLength = SubstituteNameLength; @@ -134,14 +146,14 @@ public SymbolicLinkReparseBuffer(USHORT SubstituteNameOffset, USHORT SubstituteN * @return the print name in a String */ public String getPrintName() { - return String.copyValueOf(PathBuffer, this.PrintNameOffset.intValue() / 2, this.PrintNameLength.intValue() / 2); + return String.copyValueOf(PathBuffer, PrintNameOffset / 2, PrintNameLength / 2); } /** * @return the substitute name in a String */ public String getSubstituteName() { - return String.copyValueOf(PathBuffer, this.SubstituteNameOffset.intValue() / 2, this.SubstituteNameLength.intValue() / 2); + return String.copyValueOf(PathBuffer, SubstituteNameOffset / 2, SubstituteNameLength / 2); } } @@ -160,25 +172,25 @@ public ByReference(Pointer 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 USHORT SubstituteNameOffset; + 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 USHORT SubstituteNameLength; + 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 USHORT PrintNameOffset; + 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 USHORT PrintNameLength; + public short PrintNameLength = 0; /** * First character of the path string. This is followed in memory by the remainder of the string. @@ -201,11 +213,11 @@ protected List getFieldOrder() { } public MountPointReparseBuffer() { - super(); + super(W32APITypeMapper.UNICODE); } public MountPointReparseBuffer(Pointer memory) { - super(memory); + super(memory, Structure.ALIGN_DEFAULT, W32APITypeMapper.UNICODE); read(); } @@ -213,14 +225,14 @@ public MountPointReparseBuffer(String substituteName, String printName) { super(); String bothNames = substituteName + printName; PathBuffer = bothNames.toCharArray(); - this.SubstituteNameOffset = new USHORT(0); - this.SubstituteNameLength = new USHORT(substituteName.length()); - this.PrintNameOffset = new USHORT((substituteName.length()) * 2); - this.PrintNameLength = new USHORT(printName.length() * 2); + this.SubstituteNameOffset = 0; + this.SubstituteNameLength = (short) substituteName.length(); + this.PrintNameOffset = (short) (substituteName.length() * 2); + this.PrintNameLength = (short) (printName.length() * 2); write(); } - public MountPointReparseBuffer(USHORT SubstituteNameOffset, USHORT SubstituteNameLength, USHORT PrintNameOffset, USHORT PrintNameLength, String PathBuffer) { + public MountPointReparseBuffer(short SubstituteNameOffset, short SubstituteNameLength, short PrintNameOffset, short PrintNameLength, String PathBuffer) { super(); this.SubstituteNameOffset = SubstituteNameOffset; this.SubstituteNameLength = SubstituteNameLength; @@ -291,12 +303,12 @@ public ByReference(Pointer memory) { /** * Reparse point tag. Must be a Microsoft reparse point tag. */ - public ULONG ReparseTag; + public int ReparseTag = 0; /** * Size, in bytes, of the reparse data in the DataBuffer member. */ - public USHORT ReparseDataLength = new USHORT(0); + 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. @@ -304,7 +316,7 @@ public ByReference(Pointer memory) { * 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 USHORT Reserved; + public short Reserved = 0; public static class REPARSE_UNION extends Union { public static class ByReference extends REPARSE_UNION implements Structure.ByReference { @@ -334,7 +346,7 @@ public static int sizeOf() { * @return size of the structure considering the ReparseDataLength size */ public int getSize() { - return REPARSE_BUFFER_HEADER_SIZE + this.ReparseDataLength.intValue(); + return REPARSE_BUFFER_HEADER_SIZE + ReparseDataLength; } @Override @@ -346,19 +358,19 @@ public REPARSE_DATA_BUFFER() { super(); } - public REPARSE_DATA_BUFFER(int ReparseTag, int Reserved) { + public REPARSE_DATA_BUFFER(int ReparseTag, short Reserved) { super(); - this.ReparseTag = new ULONG(ReparseTag); - this.Reserved = new USHORT(Reserved); - this.ReparseDataLength = new USHORT(0); + this.ReparseTag = ReparseTag; + this.Reserved = Reserved; + this.ReparseDataLength = 0; write(); } - public REPARSE_DATA_BUFFER(int ReparseTag, int Reserved, SymbolicLinkReparseBuffer symLinkReparseBuffer) { + public REPARSE_DATA_BUFFER(int ReparseTag, short Reserved, SymbolicLinkReparseBuffer symLinkReparseBuffer) { super(); - this.ReparseTag = new ULONG(ReparseTag); - this.Reserved = new USHORT(Reserved); - this.ReparseDataLength = new USHORT(symLinkReparseBuffer.size()); + this.ReparseTag = ReparseTag; + this.Reserved = Reserved; + this.ReparseDataLength = (short) symLinkReparseBuffer.size(); this.u.setType(SymbolicLinkReparseBuffer.class); this.u.symLinkReparseBuffer = symLinkReparseBuffer; write(); @@ -373,7 +385,7 @@ public REPARSE_DATA_BUFFER(Pointer memory) { public void read() { super.read(); // Set structure value based on ReparseTag and then re-read the union. - switch(ReparseTag.intValue()) { + switch(ReparseTag) { default: u.setType(GenericReparseBuffer.class); break; 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 2d3117a105..397341af0d 100755 --- a/contrib/platform/src/com/sun/jna/platform/win32/WinBase.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/WinBase.java @@ -259,7 +259,7 @@ public ByReference(Pointer memory) { * If this is set to 0 in a FILE_BASIC_INFO structure passed to SetFileInformationByHandle * then none of the attributes are changed. */ - public DWORD FileAttributes; + public int FileAttributes; public static int sizeOf() { @@ -289,7 +289,7 @@ public FILE_BASIC_INFO(FILETIME CreationTime, FILETIME LastAccessTime, FILETIME LastWriteTime, FILETIME ChangeTime, - DWORD FileAttributes) { + int FileAttributes) { this.CreationTime = new LARGE_INTEGER(CreationTime.toTime()); this.LastAccessTime = new LARGE_INTEGER(LastAccessTime.toTime()); this.LastWriteTime = new LARGE_INTEGER(LastWriteTime.toTime()); @@ -302,7 +302,7 @@ public FILE_BASIC_INFO(LARGE_INTEGER CreationTime, LARGE_INTEGER LastAccessTime, LARGE_INTEGER LastWriteTime, LARGE_INTEGER ChangeTime, - DWORD FileAttributes) { + int FileAttributes) { this.CreationTime = CreationTime; this.LastAccessTime = LastAccessTime; this.LastWriteTime = LastWriteTime; @@ -339,7 +339,7 @@ public ByReference(Pointer memory) { /** * The number of links to the file. */ - public DWORD NumberOfLinks; + public int NumberOfLinks; /** * TRUE if the file in the delete queue; otherwise, false. @@ -372,7 +372,7 @@ public FILE_STANDARD_INFO(Pointer memory) { public FILE_STANDARD_INFO(LARGE_INTEGER AllocationSize, LARGE_INTEGER EndOfFile, - DWORD NumberOfLinks, + int NumberOfLinks, boolean DeletePending, boolean Directory) { this.AllocationSize = AllocationSize; @@ -451,27 +451,27 @@ public ByReference(Pointer memory) { /** * The compression format that is used to compress the file. */ - public WORD CompressionFormat; + public short CompressionFormat; /** * The factor that the compression uses. */ - public UCHAR CompressionUnitShift; + public char CompressionUnitShift; /** * The number of chunks that are shifted by compression. */ - public UCHAR ChunkShift; + public char ChunkShift; /** * The number of clusters that are shifted by compression. */ - public UCHAR ClusterShift; + public char ClusterShift; /** * Reserved */ - public UCHAR[] Reserved = new UCHAR[3]; + public char[] Reserved = new char[3]; public static int sizeOf() { @@ -484,25 +484,25 @@ protected List getFieldOrder() { } public FILE_COMPRESSION_INFO() { - super(); + super(W32APITypeMapper.DEFAULT); } public FILE_COMPRESSION_INFO(Pointer memory) { - super(memory); + super(memory, Structure.ALIGN_DEFAULT, W32APITypeMapper.DEFAULT); read(); } public FILE_COMPRESSION_INFO(LARGE_INTEGER CompressedFileSize, - WORD CompressionFormat, - UCHAR CompressionUnitShift, - UCHAR ChunkShift, - UCHAR ClusterShift) { + short CompressionFormat, + char CompressionUnitShift, + char ChunkShift, + char ClusterShift) { this.CompressedFileSize = CompressedFileSize; this.CompressionFormat = CompressionFormat; this.CompressionUnitShift = CompressionUnitShift; this.ChunkShift = ChunkShift; this.ClusterShift = ClusterShift; - this.Reserved = new UCHAR[3]; + this.Reserved = new char[3]; write(); } } @@ -524,12 +524,12 @@ public ByReference(Pointer memory) { /** * The file attribute information. */ - public DWORD FileAttributes; + public int FileAttributes; /** * The reparse tag. */ - public DWORD ReparseTag; + public int ReparseTag; public static int sizeOf() { @@ -550,8 +550,8 @@ public FILE_ATTRIBUTE_TAG_INFO(Pointer memory) { read(); } - public FILE_ATTRIBUTE_TAG_INFO(DWORD FileAttributes, - DWORD ReparseTag) { + public FILE_ATTRIBUTE_TAG_INFO(int FileAttributes, + int ReparseTag) { this.FileAttributes = FileAttributes; this.ReparseTag = ReparseTag; write(); @@ -600,7 +600,7 @@ public FILE_ID_128(BYTE[] Identifier) { /** * The serial number of the volume that contains a file. */ - public ULONGLONG VolumeSerialNumber; + public long VolumeSerialNumber; /** * The end of the file. @@ -626,11 +626,8 @@ public FILE_ID_INFO(Pointer memory) { read(); } - public FILE_ID_INFO(ULONGLONG VolumeSerialNumber, - FILE_ID_128 FileId, - DWORD NumberOfLinks, - boolean DeletePending, - boolean Directory) { + public FILE_ID_INFO(long VolumeSerialNumber, + FILE_ID_128 FileId) { this.VolumeSerialNumber = VolumeSerialNumber; this.FileId = FileId; write(); @@ -698,7 +695,7 @@ public ByReference(Pointer memory) { * 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 DWORD dwFileAttributes; + public int dwFileAttributes; /** * A FILETIME structure that specifies when a file or directory was created. If @@ -730,12 +727,12 @@ public ByReference(Pointer memory) { * file size is greater than MAXDWORD. * The size of the file is equal to (nFileSizeHigh * (MAXDWORD+1)) + nFileSizeLow. */ - public DWORD nFileSizeHigh; + public int nFileSizeHigh; /** * The low-order DWORD value of the file size, in bytes. */ - public DWORD nFileSizeLow; + public int nFileSizeLow; /** * If the dwFileAttributes member includes the FILE_ATTRIBUTE_REPARSE_POINT attribute, this member @@ -754,12 +751,12 @@ public ByReference(Pointer memory) { * IO_REPARSE_TAG_SYMLINK (0xA000000C) * IO_REPARSE_TAG_WIM (0x80000008) */ - public DWORD dwReserved0; + public int dwReserved0; /** * Reserved for future use. */ - public DWORD dwReserved1; + public int dwReserved1; /** * The name of the file. NOTE: When written from Native memory, this will be a null terminated string. @@ -786,22 +783,22 @@ protected List getFieldOrder() { } public WIN32_FIND_DATA() { - super(); + super(W32APITypeMapper.DEFAULT); } public WIN32_FIND_DATA(Pointer memory) { - super(memory); + super(memory, Structure.ALIGN_DEFAULT, W32APITypeMapper.DEFAULT); read(); } - public WIN32_FIND_DATA(DWORD dwFileAttributes, + public WIN32_FIND_DATA(int dwFileAttributes, FILETIME ftCreationTime, FILETIME ftLastAccessTime, FILETIME ftLastWriteTime, - DWORD nFileSizeHigh, - DWORD nFileSizeLow, - DWORD dwReserved0, - DWORD dwReserved1, + int nFileSizeHigh, + int nFileSizeLow, + int dwReserved0, + int dwReserved1, char[] cFileName, char[] cAlternateFileName) { this.dwFileAttributes = dwFileAttributes; diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinioctlUtil.java b/contrib/platform/src/com/sun/jna/platform/win32/WinioctlUtil.java index dc43f727a3..5475dde622 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/WinioctlUtil.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/WinioctlUtil.java @@ -1,14 +1,25 @@ /* Copyright (c) 2016 Adam Marcionek, All Rights Reserved - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. + * + * 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; 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 c08dfd54e6..07017fda6c 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java @@ -42,7 +42,6 @@ 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.WTypes.LPWSTR; 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; @@ -57,9 +56,7 @@ 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.ULONGLONG; import com.sun.jna.platform.win32.WinDef.USHORT; -import com.sun.jna.platform.win32.WinDef.WORD; 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; @@ -666,7 +663,7 @@ public void testDeviceIoControlFsctlReparse() throws IOException { folder.getFileName().toString(), Ntifs.SYMLINK_FLAG_RELATIVE); - REPARSE_DATA_BUFFER lpBuffer = new REPARSE_DATA_BUFFER(WinNT.IO_REPARSE_TAG_SYMLINK, 0, symLinkReparseBuffer); + 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(), @@ -690,7 +687,7 @@ public void testDeviceIoControlFsctlReparse() throws IOException { // Is a reparse point lpBuffer = new REPARSE_DATA_BUFFER(p); assertTrue(lpBytes.getValue() > 0); - assertTrue(lpBuffer.ReparseTag.intValue() == WinNT.IO_REPARSE_TAG_SYMLINK); + 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 { @@ -756,7 +753,7 @@ public void testFindFirstFile() throws IOException { File tmpFile = new File(Files.createTempFile(tmpDir, "testFindFirstFile", ".jna").toString()); Memory p = new Memory(WIN32_FIND_DATA.sizeOf()); - HANDLE hFile = Kernel32.INSTANCE.FindFirstFile(new LPWSTR(tmpDir.toAbsolutePath().toString() + "\\*"), p); + HANDLE hFile = Kernel32.INSTANCE.FindFirstFile(tmpDir.toAbsolutePath().toString() + "\\*", p); assertFalse(WinBase.INVALID_HANDLE_VALUE.equals(hFile)); try { @@ -794,7 +791,7 @@ public void testFindFirstFileExFindExInfoStandard() throws IOException { File tmpFile = new File(Files.createTempFile(tmpDir, "testFindFirstFileExFindExInfoStandard", ".jna").toString()); Memory p = new Memory(WIN32_FIND_DATA.sizeOf()); - HANDLE hFile = Kernel32.INSTANCE.FindFirstFileEx(new LPWSTR(tmpDir.toAbsolutePath().toString() + "\\*"), + HANDLE hFile = Kernel32.INSTANCE.FindFirstFileEx(tmpDir.toAbsolutePath().toString() + "\\*", WinBase.FindExInfoStandard, p, WinBase.FindExSearchNameMatch, @@ -838,7 +835,7 @@ public void testFindFirstFileExFindExInfoBasic() throws IOException { 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(new LPWSTR(tmpDir.toAbsolutePath().toString() + "\\" + tmpFile.getName()), + HANDLE hFile = Kernel32.INSTANCE.FindFirstFileEx(tmpDir.toAbsolutePath().toString() + "\\" + tmpFile.getName(), WinBase.FindExInfoBasic, p, WinBase.FindExSearchNameMatch, @@ -892,7 +889,7 @@ public void testGetFileInformationByHandleEx() throws IOException { } FILE_STANDARD_INFO fsi = new FILE_STANDARD_INFO(p); // New file has 1 link - assertEquals(new DWORD(1), fsi.NumberOfLinks); + assertEquals(1, fsi.NumberOfLinks); p = new Memory(FILE_COMPRESSION_INFO.sizeOf()); if (false == Kernel32.INSTANCE.GetFileInformationByHandleEx(hFile, WinBase.FileCompressionInfo, p, new DWORD(p.size()))) { @@ -900,7 +897,7 @@ public void testGetFileInformationByHandleEx() throws IOException { } FILE_COMPRESSION_INFO fci = new FILE_COMPRESSION_INFO(p); // Uncompressed file should be zero - assertEquals(new WORD(0), fci.CompressionFormat); + 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()))) { @@ -908,7 +905,7 @@ public void testGetFileInformationByHandleEx() throws IOException { } FILE_ATTRIBUTE_TAG_INFO fati = new FILE_ATTRIBUTE_TAG_INFO(p); // New files have the archive bit - assertEquals(new DWORD(WinNT.FILE_ATTRIBUTE_ARCHIVE), fati.FileAttributes); + 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()))) { @@ -916,7 +913,7 @@ public void testGetFileInformationByHandleEx() throws IOException { } FILE_ID_INFO fii = new FILE_ID_INFO(p); // Volume serial number should be non-zero - assertFalse(fii.VolumeSerialNumber == new ULONGLONG(0)); + assertFalse(fii.VolumeSerialNumber == 0); } finally { Kernel32.INSTANCE.CloseHandle(hFile); } @@ -943,7 +940,7 @@ public void testSetFileInformationByHandleFileBasicInfo() throws IOException, In FILE_BASIC_INFO fbi = new FILE_BASIC_INFO(p); // Add TEMP attribute - fbi.FileAttributes = new DWORD(fbi.FileAttributes.intValue() | WinNT.FILE_ATTRIBUTE_TEMPORARY); + 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); @@ -957,7 +954,7 @@ public void testSetFileInformationByHandleFileBasicInfo() throws IOException, In fail("GetFileInformationByHandleEx failed with " + Kernel32.INSTANCE.GetLastError()); fbi = new FILE_BASIC_INFO(p); - assertTrue((fbi.FileAttributes.intValue() & WinNT.FILE_ATTRIBUTE_TEMPORARY) != 0); + assertTrue((fbi.FileAttributes & WinNT.FILE_ATTRIBUTE_TEMPORARY) != 0); } finally { Kernel32.INSTANCE.CloseHandle(hFile); From d8a84389a7b31b73c8188cf0d0800f29f3c6b67f Mon Sep 17 00:00:00 2001 From: Adam Marcionek Date: Mon, 5 Dec 2016 11:51:31 -0500 Subject: [PATCH 3/4] More changes based on feedback * Converted char to byte for UCHAR * Made Privilege implement Closeable --- .../sun/jna/platform/win32/Advapi32Util.java | 85 +++++++++------- .../com/sun/jna/platform/win32/WinBase.java | 16 +-- .../jna/platform/win32/Advapi32UtilTest.java | 18 +++- .../sun/jna/platform/win32/Kernel32Test.java | 97 +++++++++---------- 4 files changed, 121 insertions(+), 95 deletions(-) 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 0c2a03e024..f6b30dc34c 100755 --- a/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java @@ -49,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; @@ -2640,50 +2641,63 @@ public DWORD callback(Pointer pbData, Pointer pvCallbackContext, } /** - * Convenience class to enables a certain Windows process privilege + * Convenience class to enable certain Windows process privileges */ - public static class Privilege { + public static class Privilege implements Closeable { /** * If true, the thread is currently impersonating */ private boolean currentlyImpersonating = false; /** - * If true, the Privilege has been enabled + * If true, the privileges have been enabled */ - private boolean privilegeEnabled = false; + private boolean privilegesEnabled = false; /** - * LUID form of the privilege + * LUID form of the privileges */ - private final WinNT.LUID pLuid = new WinNT.LUID(); + private final WinNT.LUID[] pLuids; /** - * String form of the privilege + * Construct and enable a set of privileges + * @param privileges the name of the privileges in the form of SE_* from Advapi32.java + * @enable if true, enable the privilege immediately. + * @throws IllegalArgumentException */ - private final String privilege; + public Privilege(String[] privileges, boolean enable) 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++; + } + if (enable) + this.enable(); + } /** - * Construct a Privilege - * @param privilege the name of the privilege in the form of SE_* from Advapi32.java - * @throws IllegalArgumentException + * Calls {@link#disable} to remove the privileges + * @see java.io.Closeable#close() */ - public Privilege(String privilege) throws IllegalArgumentException { - this.privilege = privilege; - if (!Advapi32.INSTANCE.LookupPrivilegeValue(null, this.privilege, pLuid)) { - throw new IllegalArgumentException("Failed to find privilege \"" + privilege + "\" - " + Kernel32.INSTANCE.GetLastError()); - } + @Override + public void close() { + this.disable(); } /** - * Enables the given privilege. 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 privilege, 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 a privilege. Multiple calls to enable() without a drop() in between have no affect. + * 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 void enable() throws Win32Exception { // Ignore if already enabled. - if (privilegeEnabled) + if (privilegesEnabled) return; // Get thread token @@ -2691,12 +2705,14 @@ public void enable() throws Win32Exception { try { phThreadToken.setValue(getThreadToken()); - WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(1); - tp.Privileges[0] = new WinNT.LUID_AND_ATTRIBUTES(pLuid, new DWORD(WinNT.SE_PRIVILEGE_ENABLED)); + 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()); } - privilegeEnabled = true; + privilegesEnabled = true; } catch (Win32Exception ex) { // If fails, clean up @@ -2705,11 +2721,13 @@ public void enable() throws Win32Exception { currentlyImpersonating = false; } else { - if (privilegeEnabled) { - WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(1); - tp.Privileges[0] = new WinNT.LUID_AND_ATTRIBUTES(pLuid, new DWORD(0)); + 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); - privilegeEnabled = false; + privilegesEnabled = false; } } throw ex; @@ -2728,8 +2746,7 @@ public void enable() throws Win32Exception { * Disabled the prior enabled privilege * @throws Win32Exception */ - public void disable() throws Win32Exception - { + public void disable() throws Win32Exception { // Get thread token final HANDLEByReference phThreadToken = new HANDLEByReference(); @@ -2740,11 +2757,13 @@ public void disable() throws Win32Exception } else { - if (privilegeEnabled) { - WinNT.TOKEN_PRIVILEGES tp = new WinNT.TOKEN_PRIVILEGES(1); - tp.Privileges[0] = new WinNT.LUID_AND_ATTRIBUTES(pLuid, new DWORD(0)); + 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); - privilegeEnabled = false; + privilegesEnabled = false; } } } 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 397341af0d..79f5bd031e 100755 --- a/contrib/platform/src/com/sun/jna/platform/win32/WinBase.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/WinBase.java @@ -456,22 +456,22 @@ public ByReference(Pointer memory) { /** * The factor that the compression uses. */ - public char CompressionUnitShift; + public byte CompressionUnitShift; /** * The number of chunks that are shifted by compression. */ - public char ChunkShift; + public byte ChunkShift; /** * The number of clusters that are shifted by compression. */ - public char ClusterShift; + public byte ClusterShift; /** * Reserved */ - public char[] Reserved = new char[3]; + public byte[] Reserved = new byte[3]; public static int sizeOf() { @@ -494,15 +494,15 @@ public FILE_COMPRESSION_INFO(Pointer memory) { public FILE_COMPRESSION_INFO(LARGE_INTEGER CompressedFileSize, short CompressionFormat, - char CompressionUnitShift, - char ChunkShift, - char ClusterShift) { + byte CompressionUnitShift, + byte ChunkShift, + byte ClusterShift) { this.CompressedFileSize = CompressedFileSize; this.CompressionFormat = CompressionFormat; this.CompressionUnitShift = CompressionUnitShift; this.ChunkShift = ChunkShift; this.ClusterShift = ClusterShift; - this.Reserved = new char[3]; + this.Reserved = new byte[3]; write(); } } 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 808019437f..693e51958f 100755 --- a/contrib/platform/test/com/sun/jna/platform/win32/Advapi32UtilTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Advapi32UtilTest.java @@ -603,12 +603,20 @@ public void testBackupEncryptedFile() throws Exception { * Test Privilege class */ public void testPrivilege() { - Advapi32Util.Privilege p = new Advapi32Util.Privilege(WinNT.SE_ASSIGNPRIMARYTOKEN_NAME); - try { - p.enable(); // Will throw if it fails + // Test multiple known privileges + try(Advapi32Util.Privilege p = new Advapi32Util.Privilege(new String[] { WinNT.SE_ASSIGNPRIMARYTOKEN_NAME, WinNT.SE_BACKUP_NAME }, true);) { + // Will throw if it fails p.enable() fails + } + + // Test unknown privilege + try(Advapi32Util.Privilege p = new Advapi32Util.Privilege(new String[] { "NOT_A_PRIVILEGE"}, true);) { + // Will throw if it fails p.enable() fails + } + catch (IllegalArgumentException ex) { + // Exception is expected } - finally { - p.disable(); + catch (Exception ex) { + fail("Encountered unknown exception - " + ex.getMessage()); } } 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 07017fda6c..18f9f8ecbc 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java @@ -643,56 +643,55 @@ public void testDeviceIoControlFsctlReparse() throws IOException { delLink.deleteOnExit(); // Required for FSCTL_SET_REPARSE_POINT - Advapi32Util.Privilege restore = new Advapi32Util.Privilege(WinNT.SE_RESTORE_NAME); - 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)); + try(Advapi32Util.Privilege restore = new Advapi32Util.Privilege(new String[] { WinNT.SE_RESTORE_NAME }, true)) { + + 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()); + } - 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); - restore.disable(); + 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); + } } } From bfd9087797db1a1ae9e2b376d0642838631c96c2 Mon Sep 17 00:00:00 2001 From: Adam Marcionek Date: Tue, 6 Dec 2016 09:54:01 -0500 Subject: [PATCH 4/4] Final changes based on feedback * Changed Privilege constructor * Changed enable interface to return this * Removed try with resources * Fixed javadoc --- .../com/sun/jna/platform/win32/Advapi32Util.java | 14 ++++++-------- .../sun/jna/platform/win32/Advapi32UtilTest.java | 15 ++++++++++++--- .../com/sun/jna/platform/win32/Kernel32Test.java | 8 ++++++-- 3 files changed, 24 insertions(+), 13 deletions(-) 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 f6b30dc34c..ecb23c5120 100755 --- a/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Advapi32Util.java @@ -2661,11 +2661,10 @@ public static class Privilege implements Closeable { /** * Construct and enable a set of privileges - * @param privileges the name of the privileges in the form of SE_* from Advapi32.java - * @enable if true, enable the privilege immediately. + * @param privileges the names of the privileges in the form of SE_* from Advapi32.java * @throws IllegalArgumentException */ - public Privilege(String[] privileges, boolean enable) throws IllegalArgumentException, Win32Exception { + public Privilege(String... privileges) throws IllegalArgumentException, Win32Exception { pLuids = new WinNT.LUID[privileges.length]; int i = 0; for (String p : privileges) { @@ -2675,12 +2674,10 @@ public Privilege(String[] privileges, boolean enable) throws IllegalArgumentExce } i++; } - if (enable) - this.enable(); } /** - * Calls {@link#disable} to remove the privileges + * Calls disable() to remove the privileges * @see java.io.Closeable#close() */ @Override @@ -2695,10 +2692,10 @@ public void close() { * @return pointer to self (Privilege) as a convenience for try with resources statements * @throws Win32Exception */ - public void enable() throws Win32Exception { + public Privilege enable() throws Win32Exception { // Ignore if already enabled. if (privilegesEnabled) - return; + return this; // Get thread token final HANDLEByReference phThreadToken = new HANDLEByReference(); @@ -2740,6 +2737,7 @@ public void enable() throws Win32Exception { phThreadToken.setValue(null); } } + return this; } /** 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 693e51958f..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; @@ -604,13 +605,18 @@ public void testBackupEncryptedFile() throws Exception { */ public void testPrivilege() { // Test multiple known privileges - try(Advapi32Util.Privilege p = new Advapi32Util.Privilege(new String[] { WinNT.SE_ASSIGNPRIMARYTOKEN_NAME, WinNT.SE_BACKUP_NAME }, true);) { + 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(Advapi32Util.Privilege p = new Advapi32Util.Privilege(new String[] { "NOT_A_PRIVILEGE"}, true);) { - // Will throw if it fails p.enable() fails + try { + privilege = new Privilege("NOT_A_PRIVILEGE"); } catch (IllegalArgumentException ex) { // Exception is expected @@ -618,6 +624,9 @@ public void testPrivilege() { catch (Exception ex) { fail("Encountered unknown exception - " + ex.getMessage()); } + finally { + privilege.close(); + } } private File createTempFile() throws Exception{ 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 18f9f8ecbc..b0ca34cf51 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java @@ -643,8 +643,9 @@ public void testDeviceIoControlFsctlReparse() throws IOException { delLink.deleteOnExit(); // Required for FSCTL_SET_REPARSE_POINT - try(Advapi32Util.Privilege restore = new Advapi32Util.Privilege(new String[] { WinNT.SE_RESTORE_NAME }, true)) { - + 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, @@ -693,6 +694,9 @@ public void testDeviceIoControlFsctlReparse() throws IOException { Kernel32Util.closeHandle(hFile); } } + finally { + restore.close(); + } } public void testCopyFile() throws IOException {