Reimplement FileSystemUtils using NIO
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index b72a82b..de99df4 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -46,6 +46,9 @@
<title>Apache Commons IO Release Notes</title>
</properties>
<body>
+ <release version="2.16.1" date="YYYY-MM-DD" description="Java 8 is required.">
+ <action dev="ggregory" type="fix" due-to="Gary Gregory">Reimplement FileSystemUtils using NIO.</action>
+ </release>
<release version="2.16.0" date="2024-03-25" description="Java 8 is required.">
<!-- Fix -->
<action dev="ggregory" type="fix" due-to="Elliotte Rusty Harold">Fix and re-enable testSkip_RequiredCharsets #518.</action>
diff --git a/src/main/java/org/apache/commons/io/FileSystemUtils.java b/src/main/java/org/apache/commons/io/FileSystemUtils.java
index 431f964..091b333 100644
--- a/src/main/java/org/apache/commons/io/FileSystemUtils.java
+++ b/src/main/java/org/apache/commons/io/FileSystemUtils.java
@@ -16,148 +16,68 @@
*/
package org.apache.commons.io;
-import java.io.BufferedReader;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.nio.charset.Charset;
-import java.nio.file.InvalidPathException;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.time.Duration;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
import java.util.Objects;
-import java.util.StringTokenizer;
-import java.util.stream.Collectors;
/**
* General File System utilities.
* <p>
- * This class provides static utility methods for general file system functions not provided via the JDK {@link java.io.File File} class.
+ * This class provides static utility methods for general file system functions not provided before Java 6's {@link java.io.File File} class.
+ * </p>
* <p>
* The current functions provided are:
+ * </p>
* <ul>
- * <li>Get the free space on a drive
+ * <li>Get the free space on a drive</li>
* </ul>
*
* @since 1.1
- * @deprecated As of 2.6 deprecated without replacement. Use equivalent methods in {@link java.nio.file.FileStore} instead, e.g.
+ * @deprecated As of 2.6 deprecated without replacement. Use equivalent methods in {@link java.nio.file.FileStore} instead,
* {@code Files.getFileStore(Paths.get("/home")).getUsableSpace()} or iterate over {@code FileSystems.getDefault().getFileStores()}
*/
@Deprecated
public class FileSystemUtils {
/**
- * Singleton instance, used mainly for testing.
- */
- private static final FileSystemUtils INSTANCE = new FileSystemUtils();
-
- /**
- * Operating system state flag for error.
- */
- private static final int INIT_PROBLEM = -1;
-
- /**
- * Operating system state flag for neither UNIX nor Windows.
- */
- private static final int OTHER = 0;
-
- /**
- * Operating system state flag for Windows.
- */
- private static final int WINDOWS = 1;
-
- /**
- * Operating system state flag for Unix.
- */
- private static final int UNIX = 2;
-
- /**
- * Operating system state flag for POSIX flavor Unix.
- */
- private static final int POSIX_UNIX = 3;
-
- /**
- * The operating system flag.
- */
- private static final int OS;
-
- /**
- * The path to {@code df}.
- */
- private static final String DF;
-
- static {
- int os = OTHER;
- String dfPath = "df";
- try {
- String osName = System.getProperty("os.name");
- if (osName == null) {
- throw new IOException("os.name not found");
- }
- osName = osName.toLowerCase(Locale.ENGLISH);
- // match
- if (osName.contains("windows")) {
- os = WINDOWS;
- } else if (osName.contains("linux") || osName.contains("mpe/ix") || osName.contains("freebsd") || osName.contains("openbsd")
- || osName.contains("irix") || osName.contains("digital unix") || osName.contains("unix") || osName.contains("mac os x")) {
- os = UNIX;
- } else if (osName.contains("sun os") || osName.contains("sunos") || osName.contains("solaris")) {
- os = POSIX_UNIX;
- dfPath = "/usr/xpg4/bin/df";
- } else if (osName.contains("hp-ux") || osName.contains("aix")) {
- os = POSIX_UNIX;
- }
-
- } catch (final Exception ex) {
- os = INIT_PROBLEM;
- }
- OS = os;
- DF = dfPath;
- }
-
- /**
- * Returns the free space on a drive or volume by invoking the command line. This method does not normalize the result, and typically returns bytes on
- * Windows, 512 byte units on OS X and kilobytes on Unix. As this is not very useful, this method is deprecated in favor of {@link #freeSpaceKb(String)}
- * which returns a result in kilobytes.
+ * Gets the number of kibibytes (1024 bytes) available to this Java virtual machine on the given file store.
* <p>
* Note that some OS's are NOT currently supported, including OS/390, OpenVMS.
+ * </p>
*
* <pre>
* FileSystemUtils.freeSpace("C:"); // Windows
* FileSystemUtils.freeSpace("/volume"); // *nix
* </pre>
*
- * 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
* @return the amount of free drive space on the drive or volume
+ * @throws IOException if an I/O error occurs.
* @throws IllegalArgumentException if the path is invalid
* @throws IllegalStateException if an error occurred in initialization
- * @throws IOException if an error occurs when finding the free space
* @since 1.1, enhanced OS support in 1.2 and 1.3
* @deprecated Use freeSpaceKb(String) Deprecated from 1.3, may be removed in 2.0
*/
@Deprecated
public static long freeSpace(final String path) throws IOException {
- return INSTANCE.freeSpaceOS(path, OS, false, Duration.ofMillis(-1));
+ return getFreeSpace(path);
}
/**
- * Returns the free space for the working directory in kibibytes (1024 bytes) by invoking the command line.
+ * Gets the number of kibibytes (1024 bytes) available to this Java virtual machine on the current file store.
* <p>
* Identical to:
+ * </p>
*
* <pre>
* freeSpaceKb(FileUtils.current().getAbsolutePath())
* </pre>
*
* @return the amount of free drive space on the drive or volume in kilobytes
+ * @throws IOException if an I/O error occurs.
* @throws IllegalStateException if an error occurred in initialization
- * @throws IOException if an error occurs when finding the free space
* @since 2.0
* @deprecated As of 2.6 deprecated without replacement. Please use {@link java.nio.file.FileStore#getUsableSpace()}.
*/
@@ -167,18 +87,19 @@
}
/**
- * Returns the free space for the working directory in kibibytes (1024 bytes) by invoking the command line.
+ * Gets the number of kibibytes (1024 bytes) available to this Java virtual machine on the current file store.
* <p>
* Identical to:
+ * </p>
*
* <pre>
* freeSpaceKb(FileUtils.current().getAbsolutePath())
* </pre>
*
- * @param timeout The timeout amount in milliseconds or no timeout if the value is zero or less
+ * @param timeout ignored.
* @return the amount of free drive space on the drive or volume in kilobytes
+ * @throws IOException if an I/O error occurs.
* @throws IllegalStateException if an error occurred in initialization
- * @throws IOException if an error occurs when finding the free space
* @since 2.0
* @deprecated As of 2.6 deprecated without replacement. Please use {@link java.nio.file.FileStore#getUsableSpace()}.
*/
@@ -188,24 +109,18 @@
}
/**
- * Returns the free space on a drive or volume in kibibytes (1024 bytes) by invoking the command line.
+ * Gets the number of kibibytes (1024 bytes) available to this Java virtual machine on the given file store.
*
* <pre>
* FileSystemUtils.freeSpaceKb("C:"); // Windows
* FileSystemUtils.freeSpaceKb("/volume"); // *nix
* </pre>
*
- * 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
- * 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
* @return the amount of free drive space on the drive or volume in kilobytes
+ * @throws IOException if an I/O error occurs.
* @throws IllegalArgumentException if the path is invalid
* @throws IllegalStateException if an error occurred in initialization
- * @throws IOException if an error occurs when finding the free space
* @since 1.2, enhanced OS support in 1.3
* @deprecated As of 2.6 deprecated without replacement. Please use {@link java.nio.file.FileStore#getUsableSpace()}.
*/
@@ -215,31 +130,49 @@
}
/**
- * Returns the free space on a drive or volume in kibibytes (1024 bytes) by invoking the command line.
+ * Gets the number of kibibytes (1024 bytes) available to this Java virtual machine on the given file store.
*
* <pre>
* FileSystemUtils.freeSpaceKb("C:"); // Windows
* FileSystemUtils.freeSpaceKb("/volume"); // *nix
* </pre>
*
- * 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
- * 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 timeout The timeout amount in milliseconds or no timeout if the value is zero or less
+ * @param timeout ignored.
* @return the amount of free drive space on the drive or volume in kilobytes
+ * @throws IOException if an I/O error occurs.
* @throws IllegalArgumentException if the path is invalid
* @throws IllegalStateException if an error occurred in initialization
- * @throws IOException if an error occurs when finding the free space
* @since 2.0
* @deprecated As of 2.6 deprecated without replacement. Please use {@link java.nio.file.FileStore#getUsableSpace()}.
*/
@Deprecated
public static long freeSpaceKb(final String path, final long timeout) throws IOException {
- return INSTANCE.freeSpaceOS(path, OS, true, Duration.ofMillis(timeout));
+ return getFreeSpace(path) / FileUtils.ONE_KB;
+ }
+
+ /**
+ * Gets the number of bytes available to this Java virtual machine on the given file store.
+ *
+ * <pre>
+ * FileSystemUtils.freeSpace("C:"); // Windows
+ * FileSystemUtils.freeSpace("/volume"); // *nix
+ * </pre>
+ *
+ * @param pathStr 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 IOException if an I/O error occurs.
+ * @throws IllegalArgumentException if the path is invalid
+ * @throws IllegalStateException if an error occurred in initialization
+ */
+ static long getFreeSpace(final String pathStr) throws IOException {
+ final Path path = Paths.get(Objects.requireNonNull(pathStr, "pathStr"));
+ if (Files.exists(path)) {
+ // Need an absolute path for input like "" to work
+ return Files.getFileStore(path.toAbsolutePath()).getUsableSpace();
+ // return path.toAbsolutePath().toFile().getUsableSpace();
+ }
+ throw new IllegalArgumentException(path.toString());
}
/**
@@ -252,275 +185,4 @@
// empty
}
- /**
- * 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>
- * FileSystemUtils.freeSpace("C:"); // Windows
- * FileSystemUtils.freeSpace("/volume"); // *nix
- * </pre>
- *
- * The free space is calculated via the command line. It uses 'dir /-c' on Windows and 'df' on *nix.
- *
- * @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
- * @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
- * @throws IOException if an error occurs when finding the free space
- */
- 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(pathStr, timeout) / FileUtils.ONE_KB : freeSpaceWindows(pathStr, timeout);
- case UNIX:
- return freeSpaceUnix(pathStr, kb, false, timeout);
- case POSIX_UNIX:
- return freeSpaceUnix(pathStr, kb, true, timeout);
- case OTHER:
- throw new IllegalStateException("Unsupported operating system");
- default:
- throw new IllegalStateException("Exception caught when determining operating system");
- }
- }
-
- /**
- * 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
- * @param posix whether to use the POSIX standard format flag
- * @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 volume
- * @throws IOException If an I/O error occurs
- */
- long freeSpaceUnix(final String path, final boolean kb, final boolean posix, final Duration timeout) throws IOException {
- final String pathStr = checkPath(path, false).toString();
- // build and run the 'dir' command
- String flags = "-";
- if (kb) {
- flags += "k";
- }
- if (posix) {
- flags += "P";
- }
- 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 '" + pathStr + "'- response was " + lines);
- }
- final String line2 = lines.get(1); // the line we're interested in
-
- // Now, we tokenize the string. The fourth element is what we want.
- StringTokenizer tok = new StringTokenizer(line2, " ");
- 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 '" + pathStr + "'- check path is valid");
- }
- final String line3 = lines.get(2); // the line may be interested in
- tok = new StringTokenizer(line3, " ");
- } else {
- tok.nextToken(); // Ignore Filesystem
- }
- tok.nextToken(); // Ignore 1K-blocks
- tok.nextToken(); // Ignore Used
- final String freeSpace = tok.nextToken();
- return parseBytes(freeSpace, path);
- }
-
- /**
- * 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
- * @return the amount of free drive space on the drive
- * @throws IOException If an I/O error occurs
- */
- long freeSpaceWindows(final String pathStr, final Duration timeout) throws IOException {
- final Path path = checkPath(pathStr, true);
- // build and run the 'dir' command
- // read in the output of the command to an ArrayList
- 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
- // of the ArrayList anyway, but this will ensure it works even if it's
- // not, still assuming it is on the last non-blank line)
- for (int i = lines.size() - 1; i >= 0; i--) {
- final String line = lines.get(i);
- if (!line.isEmpty()) {
- return parseDir(line, pathStr);
- }
- }
- // all lines are blank
- throw new IOException("Command 'dir' did not return any info for path '" + path + "'");
- }
-
- /**
- * Opens the process to the operating system.
- * <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[] cmdArray) throws IOException {
- return Runtime.getRuntime().exec(cmdArray);
- }
-
- /**
- * Parses the bytes from a string.
- *
- * @param freeSpace the free space string
- * @param path the path
- * @return the number of bytes
- * @throws IOException If an I/O error occurs
- */
- private long parseBytes(final String freeSpace, final String path) throws IOException {
- try {
- final long bytes = Long.parseLong(freeSpace);
- if (bytes < 0) {
- throw new IOException("Command line '" + DF + "' did not find free space in response for path '" + path + "'- check path is valid");
- }
- return bytes;
-
- } catch (final NumberFormatException ex) {
- throw new IOException("Command line '" + DF + "' did not return numeric data as expected for path '" + path + "'- check path is valid", ex);
- }
- }
-
- /**
- * 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
- */
- 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
- // numeric character inclusive is our free space bytes count
- int bytesStart = 0;
- int bytesEnd = 0;
- int j = line.length() - 1;
- innerLoop1: while (j >= 0) {
- final char c = line.charAt(j);
- if (Character.isDigit(c)) {
- // found the last numeric character, this is the end of
- // the free space bytes count
- bytesEnd = j + 1;
- break innerLoop1;
- }
- j--;
- }
- innerLoop2: while (j >= 0) {
- final char c = line.charAt(j);
- if (!Character.isDigit(c) && c != ',' && c != '.') {
- // found the next non-numeric character, this is the
- // beginning of the free space bytes count
- bytesStart = j + 1;
- break innerLoop2;
- }
- j--;
- }
- if (j < 0) {
- throw new IOException("Command line 'dir /-c' did not return valid info for path '" + path + "'");
- }
-
- // remove commas and dots in the bytes count
- final StringBuilder buf = new StringBuilder(line.substring(bytesStart, bytesEnd));
- for (int k = 0; k < buf.length(); k++) {
- if (buf.charAt(k) == ',' || buf.charAt(k) == '.') {
- buf.deleteCharAt(k--);
- }
- }
- return parseBytes(buf.toString(), path);
- }
-
- /**
- * Performs an OS command.
- *
- * @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
- */
- 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:
- // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4784692
- // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4801027
- // 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(cmdArray);
- final Thread monitor = ThreadMonitor.start(timeout);
- try (InputStream in = proc.getInputStream();
- OutputStream out = proc.getOutputStream();
- // default Charset is most likely appropriate here
- InputStream err = proc.getErrorStream();
- // If in is null here, InputStreamReader throws NullPointerException
- BufferedReader inr = new BufferedReader(new InputStreamReader(in, Charset.defaultCharset()))) {
-
- final List<String> lines = inr.lines().limit(max).map(line -> line.toLowerCase(Locale.getDefault()).trim()).collect(Collectors.toList());
- proc.waitFor();
- ThreadMonitor.stop(monitor);
-
- if (proc.exitValue() != 0) {
- // Command problem, throw exception
- 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(cmdArray));
- }
-
- return lines;
-
- } catch (final InterruptedException 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 4525ca3..fff75e4 100644
--- a/src/test/java/org/apache/commons/io/FileSystemUtilsTest.java
+++ b/src/test/java/org/apache/commons/io/FileSystemUtilsTest.java
@@ -16,23 +16,10 @@
*/
package org.apache.commons.io;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.time.Duration;
-import java.util.Locale;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.EnabledOnOs;
-import org.junit.jupiter.api.condition.OS;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@@ -42,479 +29,62 @@
@SuppressWarnings("deprecation") // testing deprecated class
public class FileSystemUtilsTest {
- static class MockFileSystemUtils extends FileSystemUtils {
- private final int exitCode;
- private final byte[] bytes;
- private final String cmd;
-
- public MockFileSystemUtils(final int exitCode, final String lines) {
- this(exitCode, lines, null);
- }
-
- public MockFileSystemUtils(final int exitCode, final String lines, final String cmd) {
- this.exitCode = exitCode;
- this.bytes = lines.getBytes();
- this.cmd = cmd;
- }
-
- @Override
- Process openProcess(final String[] cmdArray) {
- if (cmd != null) {
- assertEquals(cmd, cmdArray[cmdArray.length - 1]);
- }
- return new Process() {
-
- @Override
- public void destroy() {
- // nnop
- }
-
- @Override
- public int exitValue() {
- return exitCode;
- }
-
- @Override
- public InputStream getErrorStream() {
- return null;
- }
-
- @Override
- public InputStream getInputStream() {
- return new ByteArrayInputStream(bytes);
- }
-
- @Override
- public OutputStream getOutputStream() {
- return null;
- }
-
- @Override
- public int waitFor() throws InterruptedException {
- return exitCode;
- }
- };
- }
- }
-
- private static final Duration NEG_1_TIMEOUT = Duration.ofMillis(-1);
-
static char[] getIllegalFileNameChars() {
return FileSystem.getCurrent().getIllegalFileNameChars();
}
- @Test
- public void testGetFreeSpace_String() throws Exception {
- // test coverage, as we can't check value
- if (File.separatorChar == '/') {
- // have to figure out UNIX block size
- final String[] cmd;
- String osName = System.getProperty("os.name");
- osName = osName.toLowerCase(Locale.ENGLISH);
-
- if (osName.contains("hp-ux") || osName.contains("aix")) {
- cmd = new String[]{"df", "-P", "/"};
- } else if (osName.contains("sunos") || osName.contains("sun os")
- || osName.contains("solaris")) {
- cmd = new String[]{"/usr/xpg4/bin/df", "-P", "/"};
- } else {
- cmd = new String[]{"df", "/"};
- }
- final Process proc = Runtime.getRuntime().exec(cmd);
- boolean kilobyteBlock = true;
- try (BufferedReader r = new BufferedReader(new InputStreamReader(proc.getInputStream()))){
- final String line = r.readLine();
- assertNotNull(line, "Unexpected null line");
- if (line.contains("512")) {
- kilobyteBlock = false;
- }
- }
-
- // now perform the test
- final long free = FileSystemUtils.freeSpace("/");
- final long kb = FileSystemUtils.freeSpaceKb("/");
- // Assume disk space does not fluctuate
- // more than 1% between the above two calls;
- // this is also small enough to verify freeSpaceKb uses
- // kibibytes (1024) instead of SI kilobytes (1000)
- final double acceptableDelta = kb * 0.01d;
- if (kilobyteBlock) {
- assertEquals(free, kb, acceptableDelta);
- } else {
- assertEquals(free / 2d, kb, acceptableDelta);
- }
- } else {
- final long bytes = FileSystemUtils.freeSpace("");
- final long kb = FileSystemUtils.freeSpaceKb("");
- // Assume disk space does not fluctuate more than 1%
- final double acceptableDelta = kb * 0.01d;
- assertEquals((double) bytes / 1024, kb, acceptableDelta);
- }
- }
-
- @Test
- public void testGetFreeSpaceOS_String_InitError() throws Exception {
- final FileSystemUtils fsu = new FileSystemUtils();
- assertThrows(IllegalStateException.class, () -> fsu.freeSpaceOS("", -1, false, NEG_1_TIMEOUT));
- assertThrows(IllegalStateException.class, () -> fsu.freeSpaceOS("", -1, true, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceOS_String_NullPath() throws Exception {
- final FileSystemUtils fsu = new FileSystemUtils();
- assertThrows(NullPointerException.class, () -> fsu.freeSpaceOS(null, 1, false, NEG_1_TIMEOUT));
- assertThrows(NullPointerException.class, () -> fsu.freeSpaceOS(null, 1, true, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceOS_String_Other() throws Exception {
- final FileSystemUtils fsu = new FileSystemUtils();
- assertThrows(IllegalStateException.class, () -> fsu.freeSpaceOS("", 0, false, NEG_1_TIMEOUT));
- assertThrows(NullPointerException.class, () -> fsu.freeSpaceOS(null, 1, true, NEG_1_TIMEOUT));
- assertThrows(IllegalStateException.class, () -> fsu.freeSpaceOS("", 0, true, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceOS_String_Unix() throws Exception {
- final FileSystemUtils fsu = new FileSystemUtils() {
- @Override
- protected long freeSpaceUnix(final String path, final boolean kb, final boolean posix, final Duration timeout) throws IOException {
- return kb ? 12345L : 54321;
- }
- };
- assertEquals(54321L, fsu.freeSpaceOS("", 2, false, NEG_1_TIMEOUT));
- assertEquals(12345L, fsu.freeSpaceOS("", 2, true, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceOS_String_Windows() throws Exception {
- final FileSystemUtils fsu = new FileSystemUtils() {
- @Override
- protected long freeSpaceWindows(final String path, final Duration timeout) throws IOException {
- return 12345L;
- }
- };
- assertEquals(12345L, fsu.freeSpaceOS("", 1, false, NEG_1_TIMEOUT));
- assertEquals(12345L / 1024, fsu.freeSpaceOS("", 1, true, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceUnix_String_EmptyPath() throws Exception {
- final String lines =
- "Filesystem 1K-blocks Used Available Use% Mounted on\n" +
- "xxx:/home/users/s 14428928 12956424 1472504 90% /home/users/s";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertThrows(IllegalArgumentException.class, () -> fsu.freeSpaceUnix("", false, false, NEG_1_TIMEOUT));
- assertThrows(IllegalArgumentException.class, () -> fsu.freeSpaceUnix("", true, false, NEG_1_TIMEOUT));
- assertThrows(IllegalArgumentException.class, () -> fsu.freeSpaceUnix("", true, true, NEG_1_TIMEOUT));
- assertThrows(IllegalArgumentException.class, () -> fsu.freeSpaceUnix("", false, true, NEG_1_TIMEOUT));
- }
-
- @Test
-
- public void testGetFreeSpaceUnix_String_EmptyResponse() {
- final String lines = "";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceUnix_String_InvalidResponse1() {
- final String lines =
- "Filesystem 1K-blocks Used Available Use% Mounted on\n" +
- " 14428928 12956424 100";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceUnix_String_InvalidResponse2() {
- final String lines =
- "Filesystem 1K-blocks Used Available Use% Mounted on\n" +
- "xxx:/home/users/s 14428928 12956424 nnnnnnn 90% /home/users/s";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceUnix_String_InvalidResponse3() {
- final String lines =
- "Filesystem 1K-blocks Used Available Use% Mounted on\n" +
- "xxx:/home/users/s 14428928 12956424 -1 90% /home/users/s";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceUnix_String_InvalidResponse4() {
- final String lines =
- "Filesystem 1K-blocks Used Available Use% Mounted on\n" +
- "xxx-yyyyyyy-zzz:/home/users/s";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT));
- assertThrows(IOException.class, () -> fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceUnix_String_LongResponse() throws Exception {
- final String lines =
- "Filesystem 1K-blocks Used Available Use% Mounted on\n" +
- "xxx-yyyyyyy-zzz:/home/users/s\n" +
- " 14428928 12956424 1472504 90% /home/users/s";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertEquals(1472504L, fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceUnix_String_LongResponseKb() throws Exception {
- final String lines =
- "Filesystem 1K-blocks Used Available Use% Mounted on\n" +
- "xxx-yyyyyyy-zzz:/home/users/s\n" +
- " 14428928 12956424 1472504 90% /home/users/s";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertEquals(1472504L, fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceUnix_String_NormalResponseFreeBSD() throws Exception {
- // from Apache 'FreeBSD 6.1-RELEASE (SMP-turbo)'
- final String lines =
- "Filesystem 1K-blocks Used Avail Capacity Mounted on\n" +
- "/dev/xxxxxx 128990 102902 15770 87% /";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertEquals(15770L, fsu.freeSpaceUnix("/", false, false, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceUnix_String_NormalResponseKbFreeBSD() throws Exception {
- // from Apache 'FreeBSD 6.1-RELEASE (SMP-turbo)'
- // df and df -k are identical, but df -kP uses 512 blocks (not relevant as not used)
- final String lines =
- "Filesystem 1K-blocks Used Avail Capacity Mounted on\n" +
- "/dev/xxxxxx 128990 102902 15770 87% /";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertEquals(15770L, fsu.freeSpaceUnix("/", true, false, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceUnix_String_NormalResponseKbLinux() throws Exception {
- // from Sourceforge 'GNU bash, version 2.05b.0(1)-release (i386-redhat-linux-gnu)'
- // df, df -k and df -kP are all identical
- final String lines =
- "Filesystem 1K-blocks Used Available Use% Mounted on\n" +
- "/dev/xxx 497944 308528 189416 62% /";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertEquals(189416L, fsu.freeSpaceUnix("/", true, false, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceUnix_String_NormalResponseKbSolaris() throws Exception {
- // from IO-91 - ' SunOS et 5.10 Generic_118822-25 sun4u sparc SUNW,Ultra-4'
- // non-kb response does not contain free space - see IO-91
- final String lines =
- "Filesystem kbytes used avail capacity Mounted on\n" +
- "/dev/dsk/x0x0x0x0 1350955 815754 481163 63%";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertEquals(481163L, fsu.freeSpaceUnix("/dev/dsk/x0x0x0x0", true, false, NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceUnix_String_NormalResponseLinux() throws Exception {
- // from Sourceforge 'GNU bash, version 2.05b.0(1)-release (i386-redhat-linux-gnu)'
- final String lines =
- "Filesystem 1K-blocks Used Available Use% Mounted on\n" +
- "/dev/xxx 497944 308528 189416 62% /";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertEquals(189416L, fsu.freeSpaceUnix("/", false, false, NEG_1_TIMEOUT));
- }
-
- @EnabledOnOs(value = OS.WINDOWS)
@ParameterizedTest
@MethodSource("getIllegalFileNameChars")
- public void testGetFreeSpaceWindows_IllegalFileName(final char illegalFileNameChar) throws Exception {
- assertThrows(IllegalArgumentException.class, () -> new FileSystemUtils().freeSpaceWindows("\\ \"" + illegalFileNameChar, NEG_1_TIMEOUT));
- }
-
- @EnabledOnOs(value = OS.WINDOWS)
- @Test
- public void testGetFreeSpaceWindows_IllegalFileNames() throws Exception {
- assertThrows(IllegalArgumentException.class, () -> new FileSystemUtils().freeSpaceWindows("\\ \"", NEG_1_TIMEOUT));
+ public void testGetFreeSpace_IllegalFileName(final char illegalFileNameChar) throws Exception {
+ assertThrows(IllegalArgumentException.class, () -> FileSystemUtils.freeSpace("\\ \"" + illegalFileNameChar));
}
@Test
- public void testGetFreeSpaceWindows_String_EmptyMultiLineResponse() {
- final String lines = "\n\n";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertThrows(IOException.class, () -> fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT));
+ public void testGetFreeSpace_IllegalFileNames() throws Exception {
+ assertThrows(IllegalArgumentException.class, () -> FileSystemUtils.freeSpace("\\ \""));
}
@Test
- public void testGetFreeSpaceWindows_String_EmptyPath() throws Exception {
- final String lines =
- " Volume in drive C is HDD\n" +
- " Volume Serial Number is XXXX-YYYY\n" +
- "\n" +
- " Directory of C:\\Documents and Settings\\Xxxx\n" +
- "\n" +
- "19/08/2005 22:43 <DIR> .\n" +
- "19/08/2005 22:43 <DIR> ..\n" +
- "11/08/2005 01:07 81 build.properties\n" +
- "17/08/2005 21:44 <DIR> Desktop\n" +
- " 7 File(s) 180260 bytes\n" +
- " 10 Dir(s) 41411551232 bytes free";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines, "dir /a /-c \"\"");
- assertEquals(41411551232L, fsu.freeSpaceWindows("", NEG_1_TIMEOUT));
+ public void testGetFreeSpace_String() throws Exception {
+ assertThrows(NullPointerException.class, () -> FileSystemUtils.freeSpace(null));
+ assertThrows(IllegalArgumentException.class, () -> FileSystemUtils.freeSpace("this directory does not exist, at all."));
+ // "" means current dir.
+ assertTrue(FileSystemUtils.freeSpace("") > 0);
+ assertTrue(FileSystemUtils.freeSpace("target") > 0);
+ // files worked as well in previous versions.
+ assertTrue(FileSystemUtils.freeSpace("pom.xml") > 0);
}
@Test
- public void testGetFreeSpaceWindows_String_EmptyResponse() {
- final String lines = "";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertThrows(IOException.class, () -> fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT));
+ public void testGetFreeSpaceKb() throws Exception {
+ assertTrue(FileSystemUtils.freeSpaceKb() > 0);
}
@Test
- public void testGetFreeSpaceWindows_String_InvalidTextResponse() {
- final String lines = "BlueScreenOfDeath";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertThrows(IOException.class, () -> fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT));
- }
- @Test
- public void testGetFreeSpaceWindows_String_NormalResponse() throws Exception {
- final String lines =
- " Volume in drive C is HDD\n" +
- " Volume Serial Number is XXXX-YYYY\n" +
- "\n" +
- " Directory of C:\\Documents and Settings\\Xxxx\n" +
- "\n" +
- "19/08/2005 22:43 <DIR> .\n" +
- "19/08/2005 22:43 <DIR> ..\n" +
- "11/08/2005 01:07 81 build.properties\n" +
- "17/08/2005 21:44 <DIR> Desktop\n" +
- " 7 File(s) 180260 bytes\n" +
- " 10 Dir(s) 41411551232 bytes free";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines, "dir /a /-c \"C:\"");
- assertEquals(41411551232L, fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT));
+ public void testGetFreeSpaceKb_long() throws Exception {
+ assertTrue(FileSystemUtils.freeSpaceKb(0) > 0);
}
@Test
- public void testGetFreeSpaceWindows_String_NoSuchDirectoryResponse() {
- final String lines =
- " Volume in drive C is HDD\n" +
- " Volume Serial Number is XXXX-YYYY\n" +
- "\n" +
- " Directory of C:\\Documents and Settings\\empty" +
- "\n";
- final FileSystemUtils fsu = new MockFileSystemUtils(1, lines);
- assertThrows(IOException.class, () -> fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT));
+ public void testGetFreeSpaceKb_String() throws Exception {
+ assertThrows(NullPointerException.class, () -> FileSystemUtils.freeSpaceKb(null));
+ assertThrows(IllegalArgumentException.class, () -> FileSystemUtils.freeSpaceKb("this directory does not exist, at all."));
+ // "" means current dir.
+ assertTrue(FileSystemUtils.freeSpaceKb("") > 0);
+ assertTrue(FileSystemUtils.freeSpaceKb("target") > 0);
+ // files worked as well in previous versions.
+ assertTrue(FileSystemUtils.freeSpaceKb("pom.xml") > 0);
}
@Test
- public void testGetFreeSpaceWindows_String_ParseCommaFormatBytes() throws Exception {
- // this is the format of response when calling dir /c
- // we have now switched to dir /-c, so we should never get this
- final String lines =
- " Volume in drive C is HDD\n" +
- " Volume Serial Number is XXXX-YYYY\n" +
- "\n" +
- " Directory of C:\\Documents and Settings\\Xxxx\n" +
- "\n" +
- "19/08/2005 22:43 <DIR> .\n" +
- "19/08/2005 22:43 <DIR> ..\n" +
- "11/08/2005 01:07 81 build.properties\n" +
- "17/08/2005 21:44 <DIR> Desktop\n" +
- " 7 File(s) 180,260 bytes\n" +
- " 10 Dir(s) 41,411,551,232 bytes free";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertEquals(41411551232L, fsu.freeSpaceWindows("", NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceWindows_String_ParseCommaFormatBytes_Big() throws Exception {
- // test with very large free space
- final String lines =
- " Volume in drive C is HDD\n" +
- " Volume Serial Number is XXXX-YYYY\n" +
- "\n" +
- " Directory of C:\\Documents and Settings\\Xxxx\n" +
- "\n" +
- "19/08/2005 22:43 <DIR> .\n" +
- "19/08/2005 22:43 <DIR> ..\n" +
- "11/08/2005 01:07 81 build.properties\n" +
- "17/08/2005 21:44 <DIR> Desktop\n" +
- " 7 File(s) 180,260 bytes\n" +
- " 10 Dir(s) 141,411,551,232 bytes free";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertEquals(141411551232L, fsu.freeSpaceWindows("", NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceWindows_String_ParseCommaFormatBytes_Small() throws Exception {
- // test with very large free space
- final String lines =
- " Volume in drive C is HDD\n" +
- " Volume Serial Number is XXXX-YYYY\n" +
- "\n" +
- " Directory of C:\\Documents and Settings\\Xxxx\n" +
- "\n" +
- "19/08/2005 22:43 <DIR> .\n" +
- "19/08/2005 22:43 <DIR> ..\n" +
- "11/08/2005 01:07 81 build.properties\n" +
- "17/08/2005 21:44 <DIR> Desktop\n" +
- " 7 File(s) 180,260 bytes\n" +
- " 10 Dir(s) 1,232 bytes free";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
- assertEquals(1232L, fsu.freeSpaceWindows("", NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceWindows_String_quoted() throws Exception {
- final String lines =
- " Volume in drive C is HDD\n" +
- " Volume Serial Number is XXXX-YYYY\n" +
- "\n" +
- " Directory of C:\\Documents and Settings\\Xxxx\n" +
- "\n" +
- "19/08/2005 22:43 <DIR> .\n" +
- "19/08/2005 22:43 <DIR> ..\n" +
- "11/08/2005 01:07 81 build.properties\n" +
- "17/08/2005 21:44 <DIR> Desktop\n" +
- " 7 File(s) 180260 bytes\n" +
- " 10 Dir(s) 41411551232 bytes free";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines, "dir /a /-c \"C:\\somedir\"");
- assertEquals(41411551232L, fsu.freeSpaceWindows("\"C:\\somedir\"", NEG_1_TIMEOUT));
- }
-
- @Test
- public void testGetFreeSpaceWindows_String_StripDrive() throws Exception {
- final String lines =
- " Volume in drive C is HDD\n" +
- " Volume Serial Number is XXXX-YYYY\n" +
- "\n" +
- " Directory of C:\\Documents and Settings\\Xxxx\n" +
- "\n" +
- "19/08/2005 22:43 <DIR> .\n" +
- "19/08/2005 22:43 <DIR> ..\n" +
- "11/08/2005 01:07 81 build.properties\n" +
- "17/08/2005 21:44 <DIR> Desktop\n" +
- " 7 File(s) 180260 bytes\n" +
- " 10 Dir(s) 41411551232 bytes free";
- final FileSystemUtils fsu = new MockFileSystemUtils(0, lines, "dir /a /-c \"C:\\somedir\"");
- assertEquals(41411551232L, fsu.freeSpaceWindows("C:\\somedir", NEG_1_TIMEOUT));
+ public void testGetFreeSpaceKb_String_long() throws Exception {
+ assertThrows(NullPointerException.class, () -> FileSystemUtils.freeSpaceKb(null, 0));
+ assertThrows(IllegalArgumentException.class, () -> FileSystemUtils.freeSpaceKb("this directory does not exist, at all.", 0));
+ // "" means current dir.
+ assertTrue(FileSystemUtils.freeSpaceKb("", 0) > 0);
+ assertTrue(FileSystemUtils.freeSpaceKb("target", 0) > 0);
+ // files worked as well in previous versions.
+ assertTrue(FileSystemUtils.freeSpaceKb("pom.xml", 0) > 0);
}
}