Skip to content

Commit 0153b6f

Browse files
author
Lyor Goldstein
committed
Added volume management functions
1 parent a82a6ca commit 0153b6f

File tree

10 files changed

+686
-51
lines changed

10 files changed

+686
-51
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Features
4848
* [#434](https://github.com/twall/jna/pull/434): Added GetEnvironmentStrings to 'com.sun.jna.platform.win32.Kernel32' - [@lgoldstein](https://github.com/lgoldstein).
4949
* Loosen OSGI OS name matching to accommodate Windows 8 family - Niels Bertram.
5050
* [#436] (https://github.com/twall/jna/pull/469): Added basic Pdh API implementation to 'com.sun.jna.platform.win32' - [@lgoldstein](https://github.com/lgoldstein).
51+
* [#481] (https://github.com/twall/jna/pull/481): Added volume management functions to 'com.sun.jna.platform.win32' - [@lgoldstein](https://github.com/lgoldstein).
5152

5253
Bug Fixes
5354
---------

contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java

+267-2
Large diffs are not rendered by default.

contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java

+78-18
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import java.io.File;
1616
import java.io.FileNotFoundException;
1717
import java.nio.ByteOrder;
18-
import java.util.ArrayList;
1918
import java.util.List;
2019
import java.util.Map;
2120
import java.util.TreeMap;
@@ -136,33 +135,22 @@ public static void deleteFile(String filename) {
136135
/**
137136
* Returns valid drives in the system.
138137
*
139-
* @return An array of valid drives.
138+
* @return A {@link List} of valid drives.
140139
*/
141-
public static String[] getLogicalDriveStrings() {
142-
DWORD dwSize = Kernel32.INSTANCE.GetLogicalDriveStrings(new DWORD(0),
143-
null);
140+
public static List<String> getLogicalDriveStrings() {
141+
DWORD dwSize = Kernel32.INSTANCE.GetLogicalDriveStrings(new DWORD(0), null);
144142
if (dwSize.intValue() <= 0) {
145143
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
146144
}
147145

148146
char buf[] = new char[dwSize.intValue()];
149147
dwSize = Kernel32.INSTANCE.GetLogicalDriveStrings(dwSize, buf);
150-
if (dwSize.intValue() <= 0) {
148+
int bufSize = dwSize.intValue();
149+
if (bufSize <= 0) {
151150
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
152151
}
153152

154-
List<String> drives = new ArrayList<String>();
155-
String drive = "";
156-
// the buffer is double-null-terminated
157-
for (int i = 0; i < buf.length - 1; i++) {
158-
if (buf[i] == 0) {
159-
drives.add(drive);
160-
drive = "";
161-
} else {
162-
drive += buf[i];
163-
}
164-
}
165-
return drives.toArray(new String[0]);
153+
return Native.toStringList(buf, 0, bufSize);
166154
}
167155

168156
/**
@@ -609,4 +597,76 @@ public static final void writePrivateProfileSection(final String appName, final
609597
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
610598
}
611599
}
600+
601+
/**
602+
* Invokes the {@link Kernel32#QueryDosDevice(String, char[], int)} method
603+
* and parses the result
604+
* @param lpszDeviceName The device name
605+
* @param maxTargetSize The work buffer size to use for the query
606+
* @return The parsed result
607+
*/
608+
public static final List<String> queryDosDevice(String lpszDeviceName, int maxTargetSize) {
609+
char[] lpTargetPath = new char[maxTargetSize];
610+
int dwSize = Kernel32.INSTANCE.QueryDosDevice(lpszDeviceName, lpTargetPath, lpTargetPath.length);
611+
if (dwSize == 0) {
612+
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
613+
}
614+
615+
return Native.toStringList(lpTargetPath, 0, dwSize);
616+
}
617+
618+
/**
619+
* Invokes and parses the result of {@link Kernel32#GetVolumePathNamesForVolumeName(String, char[], int, IntByReference)}
620+
* @param lpszVolumeName The volume name
621+
* @return The parsed result
622+
* @throws Win32Exception If failed to retrieve the required information
623+
*/
624+
public static final List<String> getVolumePathNamesForVolumeName(String lpszVolumeName) {
625+
char[] lpszVolumePathNames = new char[WinDef.MAX_PATH + 1];
626+
IntByReference lpcchReturnLength = new IntByReference();
627+
628+
if (!Kernel32.INSTANCE.GetVolumePathNamesForVolumeName(lpszVolumeName, lpszVolumePathNames, lpszVolumePathNames.length, lpcchReturnLength)) {
629+
int hr = Kernel32.INSTANCE.GetLastError();
630+
if (hr != WinError.ERROR_MORE_DATA) {
631+
throw new Win32Exception(hr);
632+
}
633+
634+
int required = lpcchReturnLength.getValue();
635+
lpszVolumePathNames = new char[required];
636+
// this time we MUST succeed
637+
if (!Kernel32.INSTANCE.GetVolumePathNamesForVolumeName(lpszVolumeName, lpszVolumePathNames, lpszVolumePathNames.length, lpcchReturnLength)) {
638+
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
639+
}
640+
}
641+
642+
int bufSize = lpcchReturnLength.getValue();
643+
return Native.toStringList(lpszVolumePathNames, 0, bufSize);
644+
}
645+
646+
// prefix and suffix of a volume GUID path
647+
public static final String VOLUME_GUID_PATH_PREFIX = "\\\\?\\Volume{";
648+
public static final String VOLUME_GUID_PATH_SUFFIX = "}\\";
649+
650+
/**
651+
* Parses and returns the pure GUID value of a volume name obtained
652+
* from {@link Kernel32#FindFirstVolume(char[], int)} or
653+
* {@link Kernel32#FindNextVolume(HANDLE, char[], int)} calls
654+
*
655+
* @param volumeName
656+
* The volume name as returned by on of the above mentioned calls
657+
* @return The pure GUID value after stripping the &quot;\\?\&quot; prefix and
658+
* removing the trailing backslash.
659+
* @throws IllegalArgumentException if bad format encountered
660+
* @see <A HREF="https://msdn.microsoft.com/en-us/library/windows/desktop/aa365248(v=vs.85).aspx">Naming a Volume</A>
661+
*/
662+
public static final String extractVolumeGUID(String volumeGUIDPath) {
663+
if ((volumeGUIDPath == null)
664+
|| (volumeGUIDPath.length() <= (VOLUME_GUID_PATH_PREFIX.length() + VOLUME_GUID_PATH_SUFFIX.length()))
665+
|| (!volumeGUIDPath.startsWith(VOLUME_GUID_PATH_PREFIX))
666+
|| (!volumeGUIDPath.endsWith(VOLUME_GUID_PATH_SUFFIX))) {
667+
throw new IllegalArgumentException("Bad volume GUID path format: " + volumeGUIDPath);
668+
}
669+
670+
return volumeGUIDPath.substring(VOLUME_GUID_PATH_PREFIX.length(), volumeGUIDPath.length() - VOLUME_GUID_PATH_SUFFIX.length());
671+
}
612672
}

contrib/platform/src/com/sun/jna/platform/win32/WinNT.java

+13
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,19 @@ public abstract class SID_NAME_USE {
722722
int FILE_READ_ONLY_VOLUME = 0x00080000;
723723
int FILE_SEQUENTIAL_WRITE_ONCE = 0x00100000;
724724
int FILE_SUPPORTS_TRANSACTIONS = 0x00200000;
725+
// NOTE: These values are not supported until Windows Server 2008 R2 and Windows 7
726+
int FILE_SUPPORTS_HARD_LINKS = 0x00400000;
727+
int FILE_SUPPORTS_EXTENDED_ATTRIBUTES = 0x00800000;
728+
int FILE_SUPPORTS_OPEN_BY_FILE_ID = 0x01000000;
729+
int FILE_SUPPORTS_USN_JOURNAL = 0x02000000;
730+
731+
732+
// The controllable aspects of the DefineDosDevice function.
733+
// see https://msdn.microsoft.com/en-us/library/windows/desktop/aa363904(v=vs.85).aspx
734+
int DDD_RAW_TARGET_PATH = 0x00000001;
735+
int DDD_REMOVE_DEFINITION = 0x00000002;
736+
int DDD_EXACT_MATCH_ON_REMOVE = 0x00000004;
737+
int DDD_NO_BROADCAST_SYSTEM = 0x00000008;
725738

726739
/**
727740
* The FILE_NOTIFY_INFORMATION structure describes the changes found by the

contrib/platform/test/com/sun/jna/platform/win32/AbstractWin32TestSupport.java

+25-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package com.sun.jna.platform.win32;
1414

1515
import com.sun.jna.platform.AbstractPlatformTestSupport;
16+
import com.sun.jna.platform.win32.WinNT.HANDLE;
1617

1718
/**
1819
* @author lgoldstein
@@ -35,11 +36,11 @@ public static final void assertCallSucceeded(String message, boolean result) {
3536
return;
3637
}
3738

38-
int hr=Kernel32.INSTANCE.GetLastError();
39+
int hr = Kernel32.INSTANCE.GetLastError();
3940
if (hr == WinError.ERROR_SUCCESS) {
4041
fail(message + " failed with unknown reason code");
4142
} else {
42-
fail(message + " failed: hr=0x" + Integer.toHexString(hr));
43+
fail(message + " failed: hr=" + hr + " - 0x" + Integer.toHexString(hr));
4344
}
4445
}
4546

@@ -58,4 +59,26 @@ public static final void assertErrorSuccess(String message, int statusCode, bool
5859
assertEquals(message, WinError.ERROR_SUCCESS, statusCode);
5960
}
6061
}
62+
63+
/**
64+
* Makes sure that the handle argument is not {@code null} or {@link WinBase#INVALID_HANDLE_VALUE}.
65+
* If invalid handle detected, then it invokes {@link Kernel32#GetLastError()}
66+
* in order to display the error code
67+
* @param message Message to display if bad handle
68+
* @param handle The {@link HANDLE} to test
69+
* @return The same as the input handle if good handle - otherwise does
70+
* not return and throws an assertion error
71+
*/
72+
public static final HANDLE assertValidHandle(String message, HANDLE handle) {
73+
if ((handle == null) || WinBase.INVALID_HANDLE_VALUE.equals(handle)) {
74+
int hr = Kernel32.INSTANCE.GetLastError();
75+
if (hr == WinError.ERROR_SUCCESS) {
76+
fail(message + " failed with unknown reason code");
77+
} else {
78+
fail(message + " failed: hr=" + hr + " - 0x" + Integer.toHexString(hr));
79+
}
80+
}
81+
82+
return handle;
83+
}
6184
}

contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java

-7
Original file line numberDiff line numberDiff line change
@@ -399,13 +399,6 @@ public void testGlobalMemoryStatusEx() {
399399
assertEquals(0, lpBuffer.ullAvailExtendedVirtual.intValue());
400400
}
401401

402-
public void testGetLogicalDriveStrings() {
403-
DWORD dwSize = Kernel32.INSTANCE.GetLogicalDriveStrings(new DWORD(0), null);
404-
assertTrue(dwSize.intValue() > 0);
405-
char buf[] = new char[dwSize.intValue()];
406-
assertTrue(Kernel32.INSTANCE.GetLogicalDriveStrings(dwSize, buf).intValue() > 0);
407-
}
408-
409402
public void testGetDiskFreeSpaceEx() {
410403
LARGE_INTEGER.ByReference lpFreeBytesAvailable = new LARGE_INTEGER.ByReference();
411404
LARGE_INTEGER.ByReference lpTotalNumberOfBytes = new LARGE_INTEGER.ByReference();

contrib/platform/test/com/sun/jna/platform/win32/Kernel32UtilTest.java

+7-6
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@
1919
import java.io.FileWriter;
2020
import java.io.IOException;
2121
import java.io.PrintWriter;
22-
23-
import junit.framework.TestCase;
22+
import java.util.Collection;
2423

2524
import com.sun.jna.platform.win32.WinNT.LARGE_INTEGER;
2625

26+
import junit.framework.TestCase;
27+
2728
/**
2829
* @author dblock[at]dblock[dot]org
2930
* @author markus[at]headcrashing[dot]eu
@@ -35,7 +36,7 @@ public static void main(String[] args) throws Exception {
3536
System.out.println("Temp path: " + Kernel32Util.getTempPath());
3637
// logical drives
3738
System.out.println("Logical drives: ");
38-
String[] logicalDrives = Kernel32Util.getLogicalDriveStrings();
39+
Collection<String> logicalDrives = Kernel32Util.getLogicalDriveStrings();
3940
for(String logicalDrive : logicalDrives) {
4041
// drive type
4142
System.out.println(" " + logicalDrive + " ("
@@ -105,10 +106,10 @@ public void testGetTempPath() {
105106
}
106107

107108
public void testGetLogicalDriveStrings() {
108-
String[] logicalDrives = Kernel32Util.getLogicalDriveStrings();
109-
assertTrue(logicalDrives.length > 0);
109+
Collection<String> logicalDrives = Kernel32Util.getLogicalDriveStrings();
110+
assertTrue("No logical drives found", logicalDrives.size() > 0);
110111
for(String logicalDrive : logicalDrives) {
111-
assertTrue(logicalDrive.length() > 0);
112+
assertTrue("Empty logical drive name in list", logicalDrive.length() > 0);
112113
}
113114
}
114115

0 commit comments

Comments
 (0)