Internal refactoring
diff --git a/src/main/java/org/apache/commons/io/FileSystemUtils.java b/src/main/java/org/apache/commons/io/FileSystemUtils.java
index ec8a4ea..431f964 100644
--- a/src/main/java/org/apache/commons/io/FileSystemUtils.java
+++ b/src/main/java/org/apache/commons/io/FileSystemUtils.java
@@ -22,6 +22,7 @@
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.Charset;
+import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
@@ -49,24 +50,44 @@
@Deprecated
public class FileSystemUtils {
- /** Singleton instance, used mainly for testing. */
+ /**
+ * Singleton instance, used mainly for testing.
+ */
private static final FileSystemUtils INSTANCE = new FileSystemUtils();
- /** Operating system state flag for error. */
+ /**
+ * Operating system state flag for error.
+ */
private static final int INIT_PROBLEM = -1;
- /** Operating system state flag for neither Unix nor Windows. */
+
+ /**
+ * Operating system state flag for neither UNIX nor Windows.
+ */
private static final int OTHER = 0;
- /** Operating system state flag for Windows. */
+
+ /**
+ * Operating system state flag for Windows.
+ */
private static final int WINDOWS = 1;
- /** Operating system state flag for Unix. */
+
+ /**
+ * Operating system state flag for Unix.
+ */
private static final int UNIX = 2;
- /** Operating system state flag for Posix flavor Unix. */
+
+ /**
+ * Operating system state flag for POSIX flavor Unix.
+ */
private static final int POSIX_UNIX = 3;
- /** The operating system flag. */
+ /**
+ * The operating system flag.
+ */
private static final int OS;
- /** The path to df */
+ /**
+ * The path to {@code df}.
+ */
private static final String DF;
static {
@@ -112,7 +133,7 @@
*
* The free space is calculated via the command line. It uses 'dir /-c' on Windows and 'df' on *nix.
*
- * @param path the path to get free space for, not null, not empty on Unix
+ * @param path the path to get free space for, not null, not empty on UNIX
* @return the amount of free drive space on the drive or volume
* @throws IllegalArgumentException if the path is invalid
* @throws IllegalStateException if an error occurred in initialization
@@ -176,11 +197,11 @@
*
* The free space is calculated via the command line. It uses 'dir /-c' on Windows, 'df -kP' on AIX/HP-UX and 'df -k' on other Unix.
* <p>
- * In order to work, you must be running Windows, or have an implementation of Unix df that supports GNU format when passed -k (or -kP). If you are going to
+ * In order to work, you must be running Windows, or have an implementation of UNIX df that supports GNU format when passed -k (or -kP). If you are going to
* rely on this code, please check that it works on your OS by running some simple tests to compare the command line with the output from this class. If
* your operating system isn't supported, please raise a JIRA call detailing the exact result from df -k and as much other detail as possible, thanks.
*
- * @param path the path to get free space for, not null, not empty on Unix
+ * @param path the path to get free space for, not null, not empty on UNIX
* @return the amount of free drive space on the drive or volume in kilobytes
* @throws IllegalArgumentException if the path is invalid
* @throws IllegalStateException if an error occurred in initialization
@@ -203,11 +224,11 @@
*
* The free space is calculated via the command line. It uses 'dir /-c' on Windows, 'df -kP' on AIX/HP-UX and 'df -k' on other Unix.
* <p>
- * In order to work, you must be running Windows, or have an implementation of Unix df that supports GNU format when passed -k (or -kP). If you are going to
+ * In order to work, you must be running Windows, or have an implementation of UNIX df that supports GNU format when passed -k (or -kP). If you are going to
* rely on this code, please check that it works on your OS by running some simple tests to compare the command line with the output from this class. If
* your operating system isn't supported, please raise a JIRA call detailing the exact result from df -k and as much other detail as possible, thanks.
*
- * @param path the path to get free space for, not null, not empty on Unix
+ * @param path the path to get free space for, not null, not empty on UNIX
* @param timeout The timeout amount in milliseconds or no timeout if the value is zero or less
* @return the amount of free drive space on the drive or volume in kilobytes
* @throws IllegalArgumentException if the path is invalid
@@ -232,6 +253,31 @@
}
/**
+ * Checks that a path string is valid through NIO's {@link Paths#get(String, String...)}.
+ *
+ * @param pathStr string.
+ * @param allowEmpty allows empty paths.
+ * @return A checked normalized Path.
+ * @throws InvalidPathException if the path string cannot be converted to a {@code Path}
+ */
+ private Path checkPath(final String pathStr, final boolean allowEmpty) {
+ Objects.requireNonNull(pathStr, "pathStr");
+ if (!allowEmpty && pathStr.isEmpty()) {
+ throw new IllegalArgumentException("Path must not be empty");
+ }
+ final Path normPath;
+ final String trimPathStr = pathStr.trim();
+ if (trimPathStr.isEmpty() || trimPathStr.charAt(0) != '"') {
+ // Paths.get throws InvalidPathException if the path is bad before we pass it to a shell.
+ normPath = Paths.get(trimPathStr).normalize();
+ } else {
+ // Paths.get throws InvalidPathException if the path is bad before we pass it to a shell.
+ normPath = Paths.get(trimPathStr.substring(1, trimPathStr.length() - 1)).normalize();
+ }
+ return normPath;
+ }
+
+ /**
* Returns the free space on a drive or volume in a cross-platform manner. Note that some OS's are NOT currently supported, including OS/390.
*
* <pre>
@@ -241,7 +287,7 @@
*
* The free space is calculated via the command line. It uses 'dir /-c' on Windows and 'df' on *nix.
*
- * @param path the path to get free space for, not null, not empty on Unix
+ * @param pathStr the path to get free space for, not null, not empty on UNIX
* @param os the operating system code
* @param kb whether to normalize to kilobytes
* @param timeout The timeout amount in milliseconds or no timeout if the value is zero or less
@@ -250,15 +296,15 @@
* @throws IllegalStateException if an error occurred in initialization
* @throws IOException if an error occurs when finding the free space
*/
- long freeSpaceOS(final String path, final int os, final boolean kb, final Duration timeout) throws IOException {
- Objects.requireNonNull(path, "path");
+ long freeSpaceOS(final String pathStr, final int os, final boolean kb, final Duration timeout) throws IOException {
+ Objects.requireNonNull(pathStr, "path");
switch (os) {
case WINDOWS:
- return kb ? freeSpaceWindows(path, timeout) / FileUtils.ONE_KB : freeSpaceWindows(path, timeout);
+ return kb ? freeSpaceWindows(pathStr, timeout) / FileUtils.ONE_KB : freeSpaceWindows(pathStr, timeout);
case UNIX:
- return freeSpaceUnix(path, kb, false, timeout);
+ return freeSpaceUnix(pathStr, kb, false, timeout);
case POSIX_UNIX:
- return freeSpaceUnix(path, kb, true, timeout);
+ return freeSpaceUnix(pathStr, kb, true, timeout);
case OTHER:
throw new IllegalStateException("Unsupported operating system");
default:
@@ -267,7 +313,7 @@
}
/**
- * Find free space on the *nix platform using the 'df' command.
+ * Finds free space on the *nix platform using the 'df' command.
*
* @param path the path to get free space for
* @param kb whether to normalize to kilobytes
@@ -277,10 +323,7 @@
* @throws IOException If an I/O error occurs
*/
long freeSpaceUnix(final String path, final boolean kb, final boolean posix, final Duration timeout) throws IOException {
- if (path.isEmpty()) {
- throw new IllegalArgumentException("Path must not be empty");
- }
-
+ final String pathStr = checkPath(path, false).toString();
// build and run the 'dir' command
String flags = "-";
if (kb) {
@@ -289,13 +332,13 @@
if (posix) {
flags += "P";
}
- final String[] cmdAttribs = flags.length() > 1 ? new String[] { DF, flags, path } : new String[] { DF, path };
+ final String[] cmdAttribs = flags.length() > 1 ? new String[] { DF, flags, pathStr } : new String[] { DF, pathStr };
// perform the command, asking for up to 3 lines (header, interesting, overflow)
final List<String> lines = performCommand(cmdAttribs, 3, timeout);
if (lines.size() < 2) {
// unknown problem, throw exception
- throw new IOException("Command line '" + DF + "' did not return info as expected for path '" + path + "'- response was " + lines);
+ throw new IOException("Command line '" + DF + "' did not return info as expected for path '" + pathStr + "'- response was " + lines);
}
final String line2 = lines.get(1); // the line we're interested in
@@ -304,7 +347,7 @@
if (tok.countTokens() < 4) {
// could be long Filesystem, thus data on third line
if (tok.countTokens() != 1 || lines.size() < 3) {
- throw new IOException("Command line '" + DF + "' did not return data as expected for path '" + path + "'- check path is valid");
+ throw new IOException("Command line '" + DF + "' did not return data as expected for path '" + pathStr + "'- check path is valid");
}
final String line3 = lines.get(2); // the line may be interested in
tok = new StringTokenizer(line3, " ");
@@ -318,7 +361,7 @@
}
/**
- * Find free space on the Windows platform using the 'dir' command.
+ * Finds free space on the Windows platform using the 'dir' command.
*
* @param pathStr the path to get free space for, including the colon
* @param timeout The timeout amount in milliseconds or no timeout if the value is zero or less
@@ -326,26 +369,10 @@
* @throws IOException If an I/O error occurs
*/
long freeSpaceWindows(final String pathStr, final Duration timeout) throws IOException {
- Objects.requireNonNull(pathStr, "path");
- final String trimPathStr = pathStr.trim();
- final Path normPath;
- if (!trimPathStr.isEmpty()) {
- if (trimPathStr.charAt(0) != '"') {
- // Paths.get throws IAE if the path is bad before we pass it to a shell.
- normPath = Paths.get(trimPathStr).normalize();
- } else {
- // Paths.get throws IAE if the path is bad before we pass it to a shell.
- normPath = Paths.get(trimPathStr.substring(1, trimPathStr.length() - 1)).normalize();
- }
- } else {
- normPath = Paths.get(trimPathStr).normalize();
- }
-
+ final Path path = checkPath(pathStr, true);
// build and run the 'dir' command
- final String[] cmdAttribs = { "cmd.exe", "/C", "dir /a /-c \"" + normPath + "\""};
-
// read in the output of the command to an ArrayList
- final List<String> lines = performCommand(cmdAttribs, Integer.MAX_VALUE, timeout);
+ final List<String> lines = performCommand(new String[] { "cmd.exe", "/C", "dir /a /-c \"" + path + "\"" }, Integer.MAX_VALUE, timeout);
// now iterate over the lines we just read and find the LAST
// non-empty line (the free space bytes should be in the last element
@@ -354,22 +381,24 @@
for (int i = lines.size() - 1; i >= 0; i--) {
final String line = lines.get(i);
if (!line.isEmpty()) {
- return parseDir(line, trimPathStr);
+ return parseDir(line, pathStr);
}
}
// all lines are blank
- throw new IOException("Command line 'dir /-c' did not return any info for path '" + trimPathStr + "'");
+ throw new IOException("Command 'dir' did not return any info for path '" + path + "'");
}
/**
* Opens the process to the operating system.
- *
- * @param cmdAttribs the command line parameters
+ * <p>
+ * Package-private for tests.
+ * </p>
+ * @param cmdArray the command line parameters
* @return the process
* @throws IOException If an I/O error occurs
*/
- Process openProcess(final String[] cmdAttribs) throws IOException {
- return Runtime.getRuntime().exec(cmdAttribs);
+ Process openProcess(final String[] cmdArray) throws IOException {
+ return Runtime.getRuntime().exec(cmdArray);
}
/**
@@ -380,7 +409,7 @@
* @return the number of bytes
* @throws IOException If an I/O error occurs
*/
- long parseBytes(final String freeSpace, final String path) throws IOException {
+ private long parseBytes(final String freeSpace, final String path) throws IOException {
try {
final long bytes = Long.parseLong(freeSpace);
if (bytes < 0) {
@@ -394,14 +423,14 @@
}
/**
- * Parses the Windows dir response last line
+ * Parses the Windows dir response last line.
*
* @param line the line to parse
* @param path the path that was sent
* @return the number of bytes
* @throws IOException If an I/O error occurs
*/
- long parseDir(final String line, final String path) throws IOException {
+ private long parseDir(final String line, final String path) throws IOException {
// read from the end of the line to find the last numeric
// character on the line, then continue until we find the first
// non-numeric character, and everything between that and the last
@@ -446,13 +475,13 @@
/**
* Performs an OS command.
*
- * @param cmdAttribs the command line parameters
+ * @param cmdArray the command line parameters
* @param max The maximum limit for the lines returned
* @param timeout The timeout amount in milliseconds or no timeout if the value is zero or less
* @return the lines returned by the command, converted to lower-case
* @throws IOException if an error occurs
*/
- List<String> performCommand(final String[] cmdAttribs, final int max, final Duration timeout) throws IOException {
+ private List<String> performCommand(final String[] cmdArray, final int max, final Duration timeout) throws IOException {
//
// This method does what it can to avoid the 'Too many open files' error
// based on trial and error and these links:
@@ -461,7 +490,7 @@
// However, it's still not perfect as the JDK support is so poor.
// (See commons-exec or Ant for a better multithreaded multi-OS solution.)
//
- final Process proc = openProcess(cmdAttribs);
+ final Process proc = openProcess(cmdArray);
final Thread monitor = ThreadMonitor.start(timeout);
try (InputStream in = proc.getInputStream();
OutputStream out = proc.getOutputStream();
@@ -476,17 +505,17 @@
if (proc.exitValue() != 0) {
// Command problem, throw exception
- throw new IOException("Command line returned OS error code '" + proc.exitValue() + "' for command " + Arrays.asList(cmdAttribs));
+ throw new IOException("Command line returned OS error code '" + proc.exitValue() + "' for command " + Arrays.asList(cmdArray));
}
if (lines.isEmpty()) {
// Unknown problem, throw exception
- throw new IOException("Command line did not return any info for command " + Arrays.asList(cmdAttribs));
+ throw new IOException("Command line did not return any info for command " + Arrays.asList(cmdArray));
}
return lines;
} catch (final InterruptedException ex) {
- throw new IOException("Command line threw an InterruptedException for command " + Arrays.asList(cmdAttribs) + " timeout=" + timeout, ex);
+ throw new IOException("Command line threw an InterruptedException for command " + Arrays.asList(cmdArray) + " timeout=" + timeout, ex);
} finally {
if (proc != null) {
proc.destroy();
diff --git a/src/test/java/org/apache/commons/io/FileSystemUtilsTest.java b/src/test/java/org/apache/commons/io/FileSystemUtilsTest.java
index 141bd69..4525ca3 100644
--- a/src/test/java/org/apache/commons/io/FileSystemUtilsTest.java
+++ b/src/test/java/org/apache/commons/io/FileSystemUtilsTest.java
@@ -58,11 +58,12 @@
}
@Override
- Process openProcess(final String[] params) {
+ Process openProcess(final String[] cmdArray) {
if (cmd != null) {
- assertEquals(cmd, params[params.length - 1]);
+ assertEquals(cmd, cmdArray[cmdArray.length - 1]);
}
return new Process() {
+
@Override
public void destroy() {
// nnop