You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2022/06/14 18:38:23 UTC

[commons-io] branch master updated (af54b61e -> 7f351abd)

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/commons-io.git


    from af54b61e [IO-763]Javadoc] o.a.c.i.filefilter.FileFilterUtils doc does not match impl: missing some file filters
     new aa65025e Format tweak.
     new 7f351abd [IO-762] FileSystem.WINDOWS.isReservedFileName doesn't check for file extension

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/changes/changes.xml                            |   5 +-
 .../java/org/apache/commons/io/FileSystem.java     | 112 +++++++++++++++++----
 .../java/org/apache/commons/io/FileSystemTest.java |  35 +++++++
 3 files changed, 133 insertions(+), 19 deletions(-)


[commons-io] 01/02: Format tweak.

Posted by gg...@apache.org.
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

commit aa65025e251369f75acabf19dd42968a0e870e28
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Tue Jun 14 13:45:09 2022 -0400

    Format tweak.
---
 src/main/java/org/apache/commons/io/FileSystem.java | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/main/java/org/apache/commons/io/FileSystem.java b/src/main/java/org/apache/commons/io/FileSystem.java
index d940908d..760fd212 100644
--- a/src/main/java/org/apache/commons/io/FileSystem.java
+++ b/src/main/java/org/apache/commons/io/FileSystem.java
@@ -232,7 +232,6 @@ public enum FileSystem {
     private final String[] reservedFileNames;
     private final boolean supportsDriveLetter;
     private final char nameSeparator;
-
     private final char nameSeparatorOther;
 
     /**


[commons-io] 02/02: [IO-762] FileSystem.WINDOWS.isReservedFileName doesn't check for file extension

Posted by gg...@apache.org.
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

commit 7f351abd9aa51e7bdb104d14bf8533decd3ee170
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Tue Jun 14 14:38:12 2022 -0400

    [IO-762] FileSystem.WINDOWS.isReservedFileName doesn't check for file
    extension
---
 src/changes/changes.xml                            |   5 +-
 .../java/org/apache/commons/io/FileSystem.java     | 111 +++++++++++++++++----
 .../java/org/apache/commons/io/FileSystemTest.java |  35 +++++++
 3 files changed, 133 insertions(+), 18 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 206721fc..c9db4116 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -175,7 +175,10 @@ The <action> type attribute can be add,update,fix,remove.
         RegexFileFilter is no longer Serializable.
       </action>
       <action issue="IO-763" dev="ggregory" type="fix" due-to="Richard Adams, Gary Gregory">
-        [Javadoc] o.a.c.i.filefilter.FileFilterUtils doc does not match impl: missing some file filters
+        [Javadoc] FileFilterUtils doc does not match impl: missing some file filters.
+      </action>
+      <action issue="IO-762" dev="ggregory" type="fix" due-to="Leonidas Chiron, Gary Gregory">
+        FileSystem.WINDOWS.isReservedFileName doesn't check for file extension.
       </action>
       <!-- ADD -->
       <action type="add" dev="ggregory" due-to="Gary Gregory">
diff --git a/src/main/java/org/apache/commons/io/FileSystem.java b/src/main/java/org/apache/commons/io/FileSystem.java
index 760fd212..1a96bc9d 100644
--- a/src/main/java/org/apache/commons/io/FileSystem.java
+++ b/src/main/java/org/apache/commons/io/FileSystem.java
@@ -36,7 +36,7 @@ public enum FileSystem {
     /**
      * Generic file system.
      */
-    GENERIC(false, false, Integer.MAX_VALUE, Integer.MAX_VALUE, new char[] { 0 }, new String[] {}, false, '/'),
+    GENERIC(false, false, Integer.MAX_VALUE, Integer.MAX_VALUE, new char[] { 0 }, new String[] {}, false, false, '/'),
 
     /**
      * Linux file system.
@@ -48,7 +48,7 @@ public enum FileSystem {
             0,
              '/'
             // @formatter:on
-    }, new String[] {}, false, '/'),
+    }, new String[] {}, false, false, '/'),
 
     /**
      * MacOS file system.
@@ -61,7 +61,7 @@ public enum FileSystem {
             '/',
              ':'
             // @formatter:on
-    }, new String[] {}, false, '/'),
+    }, new String[] {}, false, false, '/'),
 
     /**
      * Windows file system.
@@ -89,7 +89,7 @@ public enum FileSystem {
                     // @formatter:on
             }, // KEEP THIS ARRAY SORTED!
             new String[] { "AUX", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "CON", "CONIN$", "CONOUT$",
-                    "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", "NUL", "PRN" }, true, '\\');
+                    "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", "NUL", "PRN" }, true, true, '\\');
 
     /**
      * <p>
@@ -230,6 +230,7 @@ public enum FileSystem {
     private final int maxFileNameLength;
     private final int maxPathLength;
     private final String[] reservedFileNames;
+    private final boolean reservedFileNamesExtensions;
     private final boolean supportsDriveLetter;
     private final char nameSeparator;
     private final char nameSeparatorOther;
@@ -243,16 +244,18 @@ public enum FileSystem {
      * @param maxPathLength The maximum length of the path to a file. This can include folders.
      * @param illegalFileNameChars Illegal characters for this file system.
      * @param reservedFileNames The reserved file names.
+     * @param reservedFileNamesExtensions TODO
      * @param supportsDriveLetter Whether this file system support driver letters.
      * @param nameSeparator The name separator, '\\' on Windows, '/' on Linux.
      */
     FileSystem(final boolean caseSensitive, final boolean casePreserving, final int maxFileLength,
         final int maxPathLength, final char[] illegalFileNameChars, final String[] reservedFileNames,
-        final boolean supportsDriveLetter, final char nameSeparator) {
+        final boolean reservedFileNamesExtensions, final boolean supportsDriveLetter, final char nameSeparator) {
         this.maxFileNameLength = maxFileLength;
         this.maxPathLength = maxPathLength;
         this.illegalFileNameChars = Objects.requireNonNull(illegalFileNameChars, "illegalFileNameChars");
         this.reservedFileNames = Objects.requireNonNull(reservedFileNames, "reservedFileNames");
+        this.reservedFileNamesExtensions = reservedFileNamesExtensions;
         this.caseSensitive = caseSensitive;
         this.casePreserving = casePreserving;
         this.supportsDriveLetter = supportsDriveLetter;
@@ -308,7 +311,7 @@ public enum FileSystem {
     }
 
     /**
-     * Whether this file system preserves case.
+     * Tests whether this file system preserves case.
      *
      * @return Whether this file system preserves case.
      */
@@ -317,7 +320,7 @@ public enum FileSystem {
     }
 
     /**
-     * Whether this file system is case-sensitive.
+     * Tests whether this file system is case-sensitive.
      *
      * @return Whether this file system is case-sensitive.
      */
@@ -326,7 +329,7 @@ public enum FileSystem {
     }
 
     /**
-     * Returns {@code true} if the given character is illegal in a file name, {@code false} otherwise.
+     * Tests if the given character is illegal in a file name, {@code false} otherwise.
      *
      * @param c
      *            the character to test
@@ -337,7 +340,7 @@ public enum FileSystem {
     }
 
     /**
-     * Checks if a candidate file name (without a path) such as {@code "filename.ext"} or {@code "filename"} is a
+     * Tests if a candidate file name (without a path) such as {@code "filename.ext"} or {@code "filename"} is a
      * potentially legal file name. If the file name length exceeds {@link #getMaxFileNameLength()}, or if it contains
      * an illegal character then the check fails.
      *
@@ -352,23 +355,19 @@ public enum FileSystem {
         if (isReservedFileName(candidate)) {
             return false;
         }
-        for (int i = 0; i < candidate.length(); i++) {
-            if (isIllegalFileNameChar(candidate.charAt(i))) {
-                return false;
-            }
-        }
-        return true;
+        return candidate.chars().anyMatch(i -> isIllegalFileNameChar((char) i));
     }
 
     /**
-     * Returns whether the given string is a reserved file name.
+     * Tests whether the given string is a reserved file name.
      *
      * @param candidate
      *            the string to test
      * @return {@code true} if the given string is a reserved file name.
      */
     public boolean isReservedFileName(final CharSequence candidate) {
-        return Arrays.binarySearch(reservedFileNames, candidate) >= 0;
+        final CharSequence test = reservedFileNamesExtensions ? trimExtension(candidate) : candidate;
+        return Arrays.binarySearch(reservedFileNames, test) >= 0;
     }
 
     /**
@@ -429,4 +428,82 @@ public enum FileSystem {
         }
         return changed ? String.valueOf(charArray) : truncated;
     }
+
+    /**
+     * Copied from Apache Commons Lang CharSequenceUtils.
+     *
+     * Returns the index within {@code cs} of the first occurrence of the
+     * specified character, starting the search at the specified index.
+     * <p>
+     * If a character with value {@code searchChar} occurs in the
+     * character sequence represented by the {@code cs}
+     * object at an index no smaller than {@code start}, then
+     * the index of the first such occurrence is returned. For values
+     * of {@code searchChar} in the range from 0 to 0xFFFF (inclusive),
+     * this is the smallest value <i>k</i> such that:
+     * </p>
+     * <blockquote><pre>
+     * (this.charAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= start)
+     * </pre></blockquote>
+     * is true. For other values of {@code searchChar}, it is the
+     * smallest value <i>k</i> such that:
+     * <blockquote><pre>
+     * (this.codePointAt(<i>k</i>) == searchChar) &amp;&amp; (<i>k</i> &gt;= start)
+     * </pre></blockquote>
+     * <p>
+     * is true. In either case, if no such character occurs inm {@code cs}
+     * at or after position {@code start}, then
+     * {@code -1} is returned.
+     * </p>
+     * <p>
+     * There is no restriction on the value of {@code start}. If it
+     * is negative, it has the same effect as if it were zero: the entire
+     * {@code CharSequence} may be searched. If it is greater than
+     * the length of {@code cs}, it has the same effect as if it were
+     * equal to the length of {@code cs}: {@code -1} is returned.
+     * </p>
+     * <p>All indices are specified in {@code char} values
+     * (Unicode code units).
+     * </p>
+     *
+     * @param cs  the {@code CharSequence} to be processed, not null
+     * @param searchChar  the char to be searched for
+     * @param start  the start index, negative starts at the string start
+     * @return the index where the search char was found, -1 if not found
+     * @since 3.6 updated to behave more like {@code String}
+     */
+    private static int indexOf(final CharSequence cs, final int searchChar, int start) {
+        if (cs instanceof String) {
+            return ((String) cs).indexOf(searchChar, start);
+        }
+        final int sz = cs.length();
+        if (start < 0) {
+            start = 0;
+        }
+        if (searchChar < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
+            for (int i = start; i < sz; i++) {
+                if (cs.charAt(i) == searchChar) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+        //supplementary characters (LANG1300)
+        if (searchChar <= Character.MAX_CODE_POINT) {
+            final char[] chars = Character.toChars(searchChar);
+            for (int i = start; i < sz - 1; i++) {
+                final char high = cs.charAt(i);
+                final char low = cs.charAt(i + 1);
+                if (high == chars[0] && low == chars[1]) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    CharSequence trimExtension(final CharSequence cs) {
+        final int index = indexOf(cs, '.', 0);
+        return index < 0 ? cs : cs.subSequence(0, index);
+    }
 }
\ No newline at end of file
diff --git a/src/test/java/org/apache/commons/io/FileSystemTest.java b/src/test/java/org/apache/commons/io/FileSystemTest.java
index 7cb294d7..a1e24331 100644
--- a/src/test/java/org/apache/commons/io/FileSystemTest.java
+++ b/src/test/java/org/apache/commons/io/FileSystemTest.java
@@ -21,9 +21,16 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import java.io.IOException;
+
 import org.apache.commons.lang3.SystemUtils;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledOnOs;
+import org.junit.jupiter.api.condition.OS;
 
+/**
+ * Tests {@link FileSystem}.
+ */
 public class FileSystemTest {
 
 
@@ -63,6 +70,34 @@ public class FileSystemTest {
         }
     }
 
+    @Test
+    @EnabledOnOs(OS.WINDOWS)
+    public void testIsReservedFileNameOnWindows() throws IOException {
+        final FileSystem fs = FileSystem.WINDOWS;
+        for (final String candidate : fs.getReservedFileNames()) {
+            // System.out.printf("Reserved %s exists: %s%n", candidate, Files.exists(Paths.get(candidate)));
+            assertTrue(fs.isReservedFileName(candidate));
+            assertTrue(fs.isReservedFileName(candidate + ".txt"), candidate);
+        }
+
+// This can hang when trying to create files for some reserved names, but it is interesting to keep
+//
+//        for (final String candidate : fs.getReservedFileNames()) {
+//            System.out.printf("Testing %s%n", candidate);
+//            assertTrue(fs.isReservedFileName(candidate));
+//            final Path path = Paths.get(candidate);
+//            final boolean exists = Files.exists(path);
+//            try {
+//                PathUtils.writeString(path, "Hello World!", StandardCharsets.UTF_8);
+//            } catch (IOException ignored) {
+//                // Asking to create a reserved file either:
+//                // - Throws an exception, for example "AUX"
+//                // - Is a NOOP, for example "COM3"
+//            }
+//            assertEquals(exists, Files.exists(path), path.toString());
+//        }
+    }
+
     @Test
     public void testReplacementWithNUL() {
         for (final FileSystem fs : FileSystem.values()) {