Skip to content

Added volume management functions #481

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 5, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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