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);
     }
 
 }