This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-io.git
The following commit(s) were added to refs/heads/master by this push: new bd22d7517 Use NIO to simplify and cleanup path processing bd22d7517 is described below commit bd22d7517a3dc71389f7d12dad341c6534e5563a Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Mon Mar 18 16:13:25 2024 -0400 Use NIO to simplify and cleanup path processing --- .../org/apache/commons/io/FileSystemUtils.java | 219 ++++++++++----------- .../org/apache/commons/io/FileSystemUtilsTest.java | 21 +- 2 files changed, 120 insertions(+), 120 deletions(-) diff --git a/src/main/java/org/apache/commons/io/FileSystemUtils.java b/src/main/java/org/apache/commons/io/FileSystemUtils.java index 1284285d2..ec8a4ea50 100644 --- a/src/main/java/org/apache/commons/io/FileSystemUtils.java +++ b/src/main/java/org/apache/commons/io/FileSystemUtils.java @@ -22,6 +22,8 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.nio.charset.Charset; +import java.nio.file.Path; +import java.nio.file.Paths; import java.time.Duration; import java.util.Arrays; import java.util.List; @@ -33,8 +35,7 @@ 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 via the JDK {@link java.io.File File} class. * <p> * The current functions provided are: * <ul> @@ -42,10 +43,8 @@ import java.util.stream.Collectors; * </ul> * * @since 1.1 - * @deprecated As of 2.6 deprecated without replacement. Use equivalent - * methods in {@link java.nio.file.FileStore} instead, e.g. - * {@code Files.getFileStore(Paths.get("/home")).getUsableSpace()} - * or iterate over {@code FileSystems.getDefault().getFileStores()} + * @deprecated As of 2.6 deprecated without replacement. Use equivalent methods in {@link java.nio.file.FileStore} instead, e.g. + * {@code Files.getFileStore(Paths.get("/home")).getUsableSpace()} or iterate over {@code FileSystems.getDefault().getFileStores()} */ @Deprecated public class FileSystemUtils { @@ -82,22 +81,13 @@ public class FileSystemUtils { // 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")) { + } 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")) { + } 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")) { + } else if (osName.contains("hp-ux") || osName.contains("aix")) { os = POSIX_UNIX; } @@ -109,30 +99,26 @@ public class FileSystemUtils { } /** - * 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. + * 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. * <p> - * Note that some OS's are NOT currently supported, including OS/390, - * OpenVMS. + * Note that some OS's are NOT currently supported, including OS/390, OpenVMS. + * * <pre> - * FileSystemUtils.freeSpace("C:"); // Windows - * FileSystemUtils.freeSpace("/volume"); // *nix + * 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 + * 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 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 + * @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 Use freeSpaceKb(String) Deprecated from 1.3, may be removed in 2.0 */ @Deprecated public static long freeSpace(final String path) throws IOException { @@ -140,16 +126,17 @@ public class FileSystemUtils { } /** - * Returns the free space for the working directory - * in kibibytes (1024 bytes) by invoking the command line. + * Returns the free space for the working directory in kibibytes (1024 bytes) by invoking the command line. * <p> * Identical to: + * * <pre> * freeSpaceKb(FileUtils.current().getAbsolutePath()) * </pre> + * * @return the amount of free drive space on the drive or volume in kilobytes * @throws IllegalStateException if an error occurred in initialization - * @throws IOException if an error occurs when finding the free space + * @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()}. */ @@ -159,18 +146,18 @@ public class FileSystemUtils { } /** - * Returns the free space for the working directory - * in kibibytes (1024 bytes) by invoking the command line. + * Returns the free space for the working directory in kibibytes (1024 bytes) by invoking the command line. * <p> * Identical to: + * * <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 The timeout amount in milliseconds or no timeout if the value is zero or less * @return the amount of free drive space on the drive or volume in kilobytes * @throws IllegalStateException if an error occurred in initialization - * @throws IOException if an error occurs when finding the free space + * @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()}. */ @@ -178,28 +165,26 @@ public class FileSystemUtils { public static long freeSpaceKb(final long timeout) throws IOException { return freeSpaceKb(FileUtils.current().getAbsolutePath(), timeout); } + /** - * Returns the free space on a drive or volume in kibibytes (1024 bytes) - * by invoking the command line. + * Returns the free space on a drive or volume in kibibytes (1024 bytes) by invoking the command line. + * * <pre> - * FileSystemUtils.freeSpaceKb("C:"); // Windows - * FileSystemUtils.freeSpaceKb("/volume"); // *nix + * 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. + * + * 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. + * In order to work, you must be running Windows, or have an implementation of Unix df that supports GNU format when passed -k (or -kP). If you are going to + * rely on this code, please check that it works on your OS by running some simple tests to compare the command line with the output from this class. If + * your operating system isn't supported, please raise a JIRA call detailing the exact result from df -k and as much other detail as possible, thanks. * - * @param path the path to get free space for, not null, not empty on Unix + * @param path the path to get free space for, not null, not empty on Unix * @return the amount of free drive space on the drive or volume in kilobytes * @throws IllegalArgumentException if the path is invalid - * @throws IllegalStateException if an error occurred in initialization - * @throws IOException if an error occurs when finding the free space + * @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()}. */ @@ -209,29 +194,25 @@ public class FileSystemUtils { } /** - * Returns the free space on a drive or volume in kibibytes (1024 bytes) - * by invoking the command line. + * Returns the free space on a drive or volume in kibibytes (1024 bytes) by invoking the command line. + * * <pre> - * FileSystemUtils.freeSpaceKb("C:"); // Windows - * FileSystemUtils.freeSpaceKb("/volume"); // *nix + * 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. + * + * 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. + * 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 path the path to get free space for, not null, not empty on Unix + * @param timeout The timeout amount in milliseconds or no timeout if the value is zero or less * @return the amount of free drive space on the drive or volume in kilobytes * @throws IllegalArgumentException if the path is invalid - * @throws IllegalStateException if an error occurred in initialization - * @throws IOException if an error occurs when finding the free space + * @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()}. */ @@ -251,24 +232,23 @@ public class FileSystemUtils { } /** - * 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. + * 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 + * 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 - * @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 + * The free space is calculated via the command line. It uses 'dir /-c' on Windows and 'df' on *nix. + * + * @param path the path to get free space for, not null, not empty on Unix + * @param 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 + * @throws IllegalStateException if an error occurred in initialization + * @throws IOException if an error occurs when finding the free space */ long freeSpaceOS(final String path, final int os, final boolean kb, final Duration timeout) throws IOException { Objects.requireNonNull(path, "path"); @@ -289,16 +269,14 @@ public class FileSystemUtils { /** * Find 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 + * @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 { + long freeSpaceUnix(final String path, final boolean kb, final boolean posix, final Duration timeout) throws IOException { if (path.isEmpty()) { throw new IllegalArgumentException("Path must not be empty"); } @@ -342,23 +320,29 @@ public class FileSystemUtils { /** * Find free space on the Windows platform using the 'dir' command. * - * @param path 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 + * @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 path, final Duration timeout) throws IOException { - String normPath = FilenameUtils.normalize(path, false); - if (normPath == null) { - throw new IllegalArgumentException(path); - } - if (!normPath.isEmpty() && normPath.charAt(0) != '"') { - normPath = "\"" + normPath + "\""; + long freeSpaceWindows(final String pathStr, final Duration timeout) throws IOException { + Objects.requireNonNull(pathStr, "path"); + final String trimPathStr = pathStr.trim(); + final Path normPath; + if (!trimPathStr.isEmpty()) { + if (trimPathStr.charAt(0) != '"') { + // Paths.get throws IAE if the path is bad before we pass it to a shell. + normPath = Paths.get(trimPathStr).normalize(); + } else { + // Paths.get throws IAE if the path is bad before we pass it to a shell. + normPath = Paths.get(trimPathStr.substring(1, trimPathStr.length() - 1)).normalize(); + } + } else { + normPath = Paths.get(trimPathStr).normalize(); } // build and run the 'dir' command - final String[] cmdAttribs = { "cmd.exe", "/C", "dir /a /-c " + normPath }; + final String[] cmdAttribs = { "cmd.exe", "/C", "dir /a /-c \"" + normPath + "\""}; // read in the output of the command to an ArrayList final List<String> lines = performCommand(cmdAttribs, Integer.MAX_VALUE, timeout); @@ -370,17 +354,17 @@ public class FileSystemUtils { for (int i = lines.size() - 1; i >= 0; i--) { final String line = lines.get(i); if (!line.isEmpty()) { - return parseDir(line, normPath); + return parseDir(line, trimPathStr); } } // all lines are blank - throw new IOException("Command line 'dir /-c' did not return any info for path '" + normPath + "'"); + throw new IOException("Command line 'dir /-c' did not return any info for path '" + trimPathStr + "'"); } /** * Opens the process to the operating system. * - * @param cmdAttribs the command line parameters + * @param cmdAttribs the command line parameters * @return the process * @throws IOException If an I/O error occurs */ @@ -391,8 +375,8 @@ public class FileSystemUtils { /** * Parses the bytes from a string. * - * @param freeSpace the free space string - * @param path the path + * @param freeSpace the free space string + * @param path the path * @return the number of bytes * @throws IOException If an I/O error occurs */ @@ -412,8 +396,8 @@ public class FileSystemUtils { /** * Parses the Windows dir response last line * - * @param line the line to parse - * @param path the path that was sent + * @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 */ @@ -462,10 +446,9 @@ public class FileSystemUtils { /** * Performs an OS command. * - * @param cmdAttribs 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 + * @param cmdAttribs 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 */ diff --git a/src/test/java/org/apache/commons/io/FileSystemUtilsTest.java b/src/test/java/org/apache/commons/io/FileSystemUtilsTest.java index 617f03c0d..b6af69ae9 100644 --- a/src/test/java/org/apache/commons/io/FileSystemUtilsTest.java +++ b/src/test/java/org/apache/commons/io/FileSystemUtilsTest.java @@ -31,6 +31,8 @@ import java.time.Duration; import java.util.Locale; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Tests {@link FileSystemUtils}. @@ -93,6 +95,10 @@ public class FileSystemUtilsTest { 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 @@ -332,6 +338,17 @@ public class FileSystemUtilsTest { assertEquals(189416L, fsu.freeSpaceUnix("/", false, false, NEG_1_TIMEOUT)); } + @ParameterizedTest + @MethodSource("getIllegalFileNameChars") + public void testGetFreeSpaceWindows_IllegalFileName(final char illegalFileNameChar) throws Exception { + assertThrows(IllegalArgumentException.class, () -> new FileSystemUtils().freeSpaceWindows("\\ \"" + illegalFileNameChar, NEG_1_TIMEOUT)); + } + + @Test + public void testGetFreeSpaceWindows_IllegalFileNames() throws Exception { + assertThrows(IllegalArgumentException.class, () -> new FileSystemUtils().freeSpaceWindows("\\ \"", NEG_1_TIMEOUT)); + } + @Test public void testGetFreeSpaceWindows_String_EmptyMultiLineResponse() { final String lines = "\n\n"; @@ -353,7 +370,7 @@ public class FileSystemUtilsTest { "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 "); + final FileSystemUtils fsu = new MockFileSystemUtils(0, lines, "dir /a /-c \"\""); assertEquals(41411551232L, fsu.freeSpaceWindows("", NEG_1_TIMEOUT)); } @@ -370,7 +387,6 @@ public class FileSystemUtilsTest { 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 = @@ -388,6 +404,7 @@ public class FileSystemUtilsTest { final FileSystemUtils fsu = new MockFileSystemUtils(0, lines, "dir /a /-c \"C:\""); assertEquals(41411551232L, fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT)); } + @Test public void testGetFreeSpaceWindows_String_NoSuchDirectoryResponse() { final String lines =