Skip to content

Commit 4f50c37

Browse files
committed
[IO-555] Add reserved file names. Impl for Windows only for now.
1 parent 2bacf63 commit 4f50c37

2 files changed

Lines changed: 59 additions & 23 deletions

File tree

src/main/java/org/apache/commons/io/FileSystem.java

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public enum FileSystem {
3939
0,
4040
'/'
4141
// @formatter:on
42-
}),
42+
}, new String[] {}),
4343

4444
MAC_OSX(255, 1024, new char[] {
4545
// KEEP THIS ARRAY SORTED!
@@ -49,9 +49,9 @@ public enum FileSystem {
4949
'/',
5050
':'
5151
// @formatter:on
52-
}),
52+
}, new String[] {}),
5353

54-
GENERIC(Integer.MAX_VALUE, Integer.MAX_VALUE, new char[] { 0 }),
54+
GENERIC(Integer.MAX_VALUE, Integer.MAX_VALUE, new char[] { 0 }, new String[] {}),
5555

5656
WINDOWS(255, 32000, new char[] {
5757
// KEEP THIS ARRAY SORTED!
@@ -63,7 +63,10 @@ public enum FileSystem {
6363
29, 30, 31,
6464
'"', '*', '/', ':', '<', '>', '?', '\\', '|'
6565
// @formatter:on
66-
});
66+
},
67+
// KEEP THIS ARRAY SORTED!
68+
new String[] { "AUX", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "CON", "LPT1",
69+
"LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9", "NUL", "PRN" });
6770

6871
/**
6972
* The prefix String for all Windows OS.
@@ -176,13 +179,16 @@ private static boolean isOsNameMatch(final String osName, final String osNamePre
176179

177180
private final char[] illegalFileNameChars;
178181
private final int maxFileNameLength;
179-
180182
private final int maxPathLength;
183+
private final String[] reservedFileNames;
181184

182-
private FileSystem(final int maxFileLength, final int maxPathLength, final char[] illegalFileNameChars) {
185+
private FileSystem(final int maxFileLength, final int maxPathLength, final char[] illegalFileNameChars,
186+
final String[] reservedFileNames) {
183187
this.maxFileNameLength = maxFileLength;
184188
this.maxPathLength = maxPathLength;
185189
this.illegalFileNameChars = Objects.requireNonNull(illegalFileNameChars, "illegalFileNameChars");
190+
this.reservedFileNames = Objects.requireNonNull(reservedFileNames, "reservedFileNames");
191+
;
186192
}
187193

188194
/**
@@ -216,10 +222,22 @@ private boolean isIllegalFileNameChar(final char c) {
216222
return Arrays.binarySearch(illegalFileNameChars, c) >= 0;
217223
}
218224

225+
/**
226+
* Returns whether the given string is a reserved file name.
227+
*
228+
* @param candidate
229+
* the string to test
230+
* @return {@code true} if the given string is a reserved file name.
231+
*/
232+
public boolean isReservedFileName(final CharSequence candidate) {
233+
return Arrays.binarySearch(reservedFileNames, candidate) >= 0;
234+
}
235+
219236
/**
220237
* Converts a candidate file name (without a path) like {@code "filename.ext"} or {@code "filename"} to a legal file
221238
* name. Illegal characters in the candidate name are replaced by the {@code replacement} character. If the file
222-
* name length exceeds {@link #getMaxFileNameLength()}, then the name is truncated to {@link #getMaxFileNameLength()}.
239+
* name length exceeds {@link #getMaxFileNameLength()}, then the name is truncated to
240+
* {@link #getMaxFileNameLength()}.
223241
*
224242
* @param candidate
225243
* a candidate file name (without a path) like {@code "filename.ext"} or {@code "filename"}
@@ -248,11 +266,9 @@ public String toLegalFileName(final String candidate, final char replacement) {
248266
}
249267

250268
/**
251-
* Checks if a candidate file name (without a path)
252-
* such as {@code "filename.ext"} or {@code "filename"}
253-
* is a potentially legal file name.
254-
* If the file name length exceeds {@link #getMaxFileNameLength()},
255-
* or if it contains an illegal character then the check fails.
269+
* Checks if a candidate file name (without a path) such as {@code "filename.ext"} or {@code "filename"} is a
270+
* potentially legal file name. If the file name length exceeds {@link #getMaxFileNameLength()}, or if it contains
271+
* an illegal character then the check fails.
256272
*
257273
* @param candidate
258274
* a candidate file name (without a path) like {@code "filename.ext"} or {@code "filename"}
@@ -262,11 +278,18 @@ public boolean isLegalFileName(final CharSequence candidate) {
262278
if (candidate == null || candidate.length() == 0 || candidate.length() > maxFileNameLength) {
263279
return false;
264280
}
281+
if (isReservedFileName(candidate)) {
282+
return false;
283+
}
265284
for (int i = 0; i < candidate.length(); i++) {
266285
if (isIllegalFileNameChar(candidate.charAt(i))) {
267286
return false;
268287
}
269288
}
270289
return true;
271290
}
291+
292+
public String[] getReservedFileNames() {
293+
return reservedFileNames;
294+
}
272295
}

src/test/java/org/apache/commons/io/FileSystemTestCase.java

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,22 @@ public class FileSystemTestCase {
2424

2525
@Test
2626
public void testSorted() {
27-
for (FileSystem fs : FileSystem.values()) {
28-
char[] chars=fs.getIllegalFileNameChars();
29-
for (int i=0; i < chars.length - 1; i++) {
30-
Assert.assertTrue(fs.name(), chars[i] < chars[i+1]);
27+
for (final FileSystem fs : FileSystem.values()) {
28+
final char[] chars = fs.getIllegalFileNameChars();
29+
for (int i = 0; i < chars.length - 1; i++) {
30+
Assert.assertTrue(fs.name(), chars[i] < chars[i + 1]);
3131
}
3232
}
33-
}
33+
}
3434

3535
@Test
3636
public void testToLegalFileNameWindows() {
37-
FileSystem fs = FileSystem.WINDOWS;
38-
char replacement = '-';
37+
final FileSystem fs = FileSystem.WINDOWS;
38+
final char replacement = '-';
3939
for (char i = 0; i < 32; i++) {
4040
Assert.assertEquals(replacement, fs.toLegalFileName(String.valueOf(i), replacement).charAt(0));
4141
}
42-
char[] illegal = new char[] { '<', '>', ':', '"', '/', '\\', '|', '?', '*' };
42+
final char[] illegal = new char[] { '<', '>', ':', '"', '/', '\\', '|', '?', '*' };
4343
for (char i = 0; i < illegal.length; i++) {
4444
Assert.assertEquals(replacement, fs.toLegalFileName(String.valueOf(i), replacement).charAt(0));
4545
}
@@ -56,20 +56,33 @@ public void testToLegalFileNameWindows() {
5656

5757
@Test
5858
public void testIsLegalName() {
59-
for (FileSystem fs : FileSystem.values()) {
59+
for (final FileSystem fs : FileSystem.values()) {
6060
Assert.assertFalse(fs.name(), fs.isLegalFileName("")); // Empty is always illegal
6161
Assert.assertFalse(fs.name(), fs.isLegalFileName(null)); // null is always illegal
6262
Assert.assertFalse(fs.name(), fs.isLegalFileName("\0")); // Assume NUL is always illegal
6363
Assert.assertTrue(fs.name(), fs.isLegalFileName("0")); // Assume simple name always legal
64+
for (final String candidate : fs.getReservedFileNames()) {
65+
// Reserved file names are not legal
66+
Assert.assertFalse(fs.isLegalFileName(candidate));
67+
}
68+
}
69+
}
70+
71+
@Test
72+
public void testIsReservedFileName() {
73+
for (final FileSystem fs : FileSystem.values()) {
74+
for (final String candidate : fs.getReservedFileNames()) {
75+
Assert.assertTrue(fs.isReservedFileName(candidate));
76+
}
6477
}
6578
}
6679

6780
@Test
6881
public void testReplacementWithNUL() {
69-
for (FileSystem fs : FileSystem.values()) {
82+
for (final FileSystem fs : FileSystem.values()) {
7083
try {
7184
fs.toLegalFileName("Test", '\0'); // Assume NUL is always illegal
72-
} catch (IllegalArgumentException iae) {
85+
} catch (final IllegalArgumentException iae) {
7386
Assert.assertTrue(iae.getMessage(), iae.getMessage().startsWith("The replacement character '\\0'"));
7487
}
7588
}

0 commit comments

Comments
 (0)