Skip to content

Commit

Permalink
Merge pull request #481 from lgoldstein/volume-mgmt-funcs
Browse files Browse the repository at this point in the history
Added volume management functions
  • Loading branch information
dblock committed Aug 5, 2015
2 parents a82a6ca + ca95bfb commit ab7eea6
Show file tree
Hide file tree
Showing 10 changed files with 714 additions and 69 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Features
* [#434](https://github.com/twall/jna/pull/434): Added GetEnvironmentStrings to 'com.sun.jna.platform.win32.Kernel32' - [@lgoldstein](https://github.com/lgoldstein).
* Loosen OSGI OS name matching to accommodate Windows 8 family - Niels Bertram.
* [#436] (https://github.com/twall/jna/pull/469): Added basic Pdh API implementation to 'com.sun.jna.platform.win32' - [@lgoldstein](https://github.com/lgoldstein).
* [#481] (https://github.com/twall/jna/pull/481): Added volume management functions to 'com.sun.jna.platform.win32' - [@lgoldstein](https://github.com/lgoldstein).

Bug Fixes
---------
Expand Down
269 changes: 267 additions & 2 deletions contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java

Large diffs are not rendered by default.

96 changes: 78 additions & 18 deletions contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
Expand Down Expand Up @@ -136,33 +135,22 @@ public static void deleteFile(String filename) {
/**
* Returns valid drives in the system.
*
* @return An array of valid drives.
* @return A {@link List} of valid drives.
*/
public static String[] getLogicalDriveStrings() {
DWORD dwSize = Kernel32.INSTANCE.GetLogicalDriveStrings(new DWORD(0),
null);
public static List<String> getLogicalDriveStrings() {
DWORD dwSize = Kernel32.INSTANCE.GetLogicalDriveStrings(new DWORD(0), null);
if (dwSize.intValue() <= 0) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}

char buf[] = new char[dwSize.intValue()];
dwSize = Kernel32.INSTANCE.GetLogicalDriveStrings(dwSize, buf);
if (dwSize.intValue() <= 0) {
int bufSize = dwSize.intValue();
if (bufSize <= 0) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}

List<String> drives = new ArrayList<String>();
String drive = "";
// the buffer is double-null-terminated
for (int i = 0; i < buf.length - 1; i++) {
if (buf[i] == 0) {
drives.add(drive);
drive = "";
} else {
drive += buf[i];
}
}
return drives.toArray(new String[0]);
return Native.toStringList(buf, 0, bufSize);
}

/**
Expand Down Expand Up @@ -609,4 +597,76 @@ public static final void writePrivateProfileSection(final String appName, final
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
}

/**
* Invokes the {@link Kernel32#QueryDosDevice(String, char[], int)} method
* and parses the result
* @param lpszDeviceName The device name
* @param maxTargetSize The work buffer size to use for the query
* @return The parsed result
*/
public static final List<String> queryDosDevice(String lpszDeviceName, int maxTargetSize) {
char[] lpTargetPath = new char[maxTargetSize];
int dwSize = Kernel32.INSTANCE.QueryDosDevice(lpszDeviceName, lpTargetPath, lpTargetPath.length);
if (dwSize == 0) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}

return Native.toStringList(lpTargetPath, 0, dwSize);
}

/**
* Invokes and parses the result of {@link Kernel32#GetVolumePathNamesForVolumeName(String, char[], int, IntByReference)}
* @param lpszVolumeName The volume name
* @return The parsed result
* @throws Win32Exception If failed to retrieve the required information
*/
public static final List<String> getVolumePathNamesForVolumeName(String lpszVolumeName) {
char[] lpszVolumePathNames = new char[WinDef.MAX_PATH + 1];
IntByReference lpcchReturnLength = new IntByReference();

if (!Kernel32.INSTANCE.GetVolumePathNamesForVolumeName(lpszVolumeName, lpszVolumePathNames, lpszVolumePathNames.length, lpcchReturnLength)) {
int hr = Kernel32.INSTANCE.GetLastError();
if (hr != WinError.ERROR_MORE_DATA) {
throw new Win32Exception(hr);
}

int required = lpcchReturnLength.getValue();
lpszVolumePathNames = new char[required];
// this time we MUST succeed
if (!Kernel32.INSTANCE.GetVolumePathNamesForVolumeName(lpszVolumeName, lpszVolumePathNames, lpszVolumePathNames.length, lpcchReturnLength)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
}

int bufSize = lpcchReturnLength.getValue();
return Native.toStringList(lpszVolumePathNames, 0, bufSize);
}

// prefix and suffix of a volume GUID path
public static final String VOLUME_GUID_PATH_PREFIX = "\\\\?\\Volume{";
public static final String VOLUME_GUID_PATH_SUFFIX = "}\\";

/**
* Parses and returns the pure GUID value of a volume name obtained
* from {@link Kernel32#FindFirstVolume(char[], int)} or
* {@link Kernel32#FindNextVolume(HANDLE, char[], int)} calls
*
* @param volumeName
* The volume name as returned by on of the above mentioned calls
* @return The pure GUID value after stripping the &quot;\\?\&quot; prefix and
* removing the trailing backslash.
* @throws IllegalArgumentException if bad format encountered
* @see <A HREF="https://msdn.microsoft.com/en-us/library/windows/desktop/aa365248(v=vs.85).aspx">Naming a Volume</A>
*/
public static final String extractVolumeGUID(String volumeGUIDPath) {
if ((volumeGUIDPath == null)
|| (volumeGUIDPath.length() <= (VOLUME_GUID_PATH_PREFIX.length() + VOLUME_GUID_PATH_SUFFIX.length()))
|| (!volumeGUIDPath.startsWith(VOLUME_GUID_PATH_PREFIX))
|| (!volumeGUIDPath.endsWith(VOLUME_GUID_PATH_SUFFIX))) {
throw new IllegalArgumentException("Bad volume GUID path format: " + volumeGUIDPath);
}

return volumeGUIDPath.substring(VOLUME_GUID_PATH_PREFIX.length(), volumeGUIDPath.length() - VOLUME_GUID_PATH_SUFFIX.length());
}
}
13 changes: 13 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/WinNT.java
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,19 @@ public abstract class SID_NAME_USE {
int FILE_READ_ONLY_VOLUME = 0x00080000;
int FILE_SEQUENTIAL_WRITE_ONCE = 0x00100000;
int FILE_SUPPORTS_TRANSACTIONS = 0x00200000;
// NOTE: These values are not supported until Windows Server 2008 R2 and Windows 7
int FILE_SUPPORTS_HARD_LINKS = 0x00400000;
int FILE_SUPPORTS_EXTENDED_ATTRIBUTES = 0x00800000;
int FILE_SUPPORTS_OPEN_BY_FILE_ID = 0x01000000;
int FILE_SUPPORTS_USN_JOURNAL = 0x02000000;


// The controllable aspects of the DefineDosDevice function.
// see https://msdn.microsoft.com/en-us/library/windows/desktop/aa363904(v=vs.85).aspx
int DDD_RAW_TARGET_PATH = 0x00000001;
int DDD_REMOVE_DEFINITION = 0x00000002;
int DDD_EXACT_MATCH_ON_REMOVE = 0x00000004;
int DDD_NO_BROADCAST_SYSTEM = 0x00000008;

/**
* The FILE_NOTIFY_INFORMATION structure describes the changes found by the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package com.sun.jna.platform.win32;

import com.sun.jna.platform.AbstractPlatformTestSupport;
import com.sun.jna.platform.win32.WinNT.HANDLE;

/**
* @author lgoldstein
Expand All @@ -35,11 +36,11 @@ public static final void assertCallSucceeded(String message, boolean result) {
return;
}

int hr=Kernel32.INSTANCE.GetLastError();
int hr = Kernel32.INSTANCE.GetLastError();
if (hr == WinError.ERROR_SUCCESS) {
fail(message + " failed with unknown reason code");
} else {
fail(message + " failed: hr=0x" + Integer.toHexString(hr));
fail(message + " failed: hr=" + hr + " - 0x" + Integer.toHexString(hr));
}
}

Expand All @@ -58,4 +59,26 @@ public static final void assertErrorSuccess(String message, int statusCode, bool
assertEquals(message, WinError.ERROR_SUCCESS, statusCode);
}
}

/**
* Makes sure that the handle argument is not {@code null} or {@link WinBase#INVALID_HANDLE_VALUE}.
* If invalid handle detected, then it invokes {@link Kernel32#GetLastError()}
* in order to display the error code
* @param message Message to display if bad handle
* @param handle The {@link HANDLE} to test
* @return The same as the input handle if good handle - otherwise does
* not return and throws an assertion error
*/
public static final HANDLE assertValidHandle(String message, HANDLE handle) {
if ((handle == null) || WinBase.INVALID_HANDLE_VALUE.equals(handle)) {
int hr = Kernel32.INSTANCE.GetLastError();
if (hr == WinError.ERROR_SUCCESS) {
fail(message + " failed with unknown reason code");
} else {
fail(message + " failed: hr=" + hr + " - 0x" + Integer.toHexString(hr));
}
}

return handle;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -399,13 +399,6 @@ public void testGlobalMemoryStatusEx() {
assertEquals(0, lpBuffer.ullAvailExtendedVirtual.intValue());
}

public void testGetLogicalDriveStrings() {
DWORD dwSize = Kernel32.INSTANCE.GetLogicalDriveStrings(new DWORD(0), null);
assertTrue(dwSize.intValue() > 0);
char buf[] = new char[dwSize.intValue()];
assertTrue(Kernel32.INSTANCE.GetLogicalDriveStrings(dwSize, buf).intValue() > 0);
}

public void testGetDiskFreeSpaceEx() {
LARGE_INTEGER.ByReference lpFreeBytesAvailable = new LARGE_INTEGER.ByReference();
LARGE_INTEGER.ByReference lpTotalNumberOfBytes = new LARGE_INTEGER.ByReference();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import junit.framework.TestCase;
import java.util.Collection;

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

import junit.framework.TestCase;

/**
* @author dblock[at]dblock[dot]org
* @author markus[at]headcrashing[dot]eu
Expand All @@ -35,7 +36,7 @@ public static void main(String[] args) throws Exception {
System.out.println("Temp path: " + Kernel32Util.getTempPath());
// logical drives
System.out.println("Logical drives: ");
String[] logicalDrives = Kernel32Util.getLogicalDriveStrings();
Collection<String> logicalDrives = Kernel32Util.getLogicalDriveStrings();
for(String logicalDrive : logicalDrives) {
// drive type
System.out.println(" " + logicalDrive + " ("
Expand Down Expand Up @@ -105,10 +106,10 @@ public void testGetTempPath() {
}

public void testGetLogicalDriveStrings() {
String[] logicalDrives = Kernel32Util.getLogicalDriveStrings();
assertTrue(logicalDrives.length > 0);
Collection<String> logicalDrives = Kernel32Util.getLogicalDriveStrings();
assertTrue("No logical drives found", logicalDrives.size() > 0);
for(String logicalDrive : logicalDrives) {
assertTrue(logicalDrive.length() > 0);
assertTrue("Empty logical drive name in list", logicalDrive.length() > 0);
}
}

Expand Down
Loading

0 comments on commit ab7eea6

Please sign in to comment.