Reject special Windows device names in ObjectChecker

If Windows rejection is enabled reject special device names like
NUL and PRN, including NUL.txt. This prevents a tree that might
be used on a Windows client from referencing a confusing name.

Change-Id: Ic700ea8fa68724509e0357d4b758a41178c4d70c
This commit is contained in:
Shawn Pearce 2014-03-11 22:49:36 -07:00
parent 5019471ccb
commit ba0f89b421
2 changed files with 90 additions and 4 deletions

View File

@ -1039,6 +1039,7 @@ public void testValidPosixTree() throws CorruptObjectException {
checkOneName("a<b>c:d|e");
checkOneName("test ");
checkOneName("test.");
checkOneName("NUL");
}
@Test
@ -1456,6 +1457,29 @@ public void testRejectDotAtEndOnWindows() {
}
}
@Test
public void testRejectDevicesOnWindows() {
checker.setSafeForWindows(true);
String[] bad = { "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3",
"COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2",
"LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" };
for (String b : bad) {
try {
checkOneName(b);
fail("incorrectly accepted " + b);
} catch (CorruptObjectException e) {
assertEquals("invalid name '" + b + "'", e.getMessage());
}
try {
checkOneName(b + ".txt");
fail("incorrectly accepted " + b + ".txt");
} catch (CorruptObjectException e) {
assertEquals("invalid name '" + b + "'", e.getMessage());
}
}
}
@Test
public void testRejectInvalidWindowsCharacters() {
checker.setSafeForWindows(true);

View File

@ -410,10 +410,68 @@ private void checkPathSegment(byte[] raw, int ptr, int end)
}
}
// Windows ignores space and dot at end of file name.
if (windows && (raw[end - 1] == ' ' || raw[end - 1] == '.'))
throw new CorruptObjectException("invalid name ends with '"
+ ((char) raw[end - 1]) + "'");
if (windows) {
// Windows ignores space and dot at end of file name.
if (raw[end - 1] == ' ' || raw[end - 1] == '.')
throw new CorruptObjectException("invalid name ends with '"
+ ((char) raw[end - 1]) + "'");
if (end - ptr >= 3)
checkNotWindowsDevice(raw, ptr, end);
}
}
private static void checkNotWindowsDevice(byte[] raw, int ptr, int end)
throws CorruptObjectException {
switch (toLower(raw[ptr])) {
case 'a': // AUX
if (end - ptr >= 3
&& toLower(raw[ptr + 1]) == 'u'
&& toLower(raw[ptr + 2]) == 'x'
&& (end - ptr == 3 || raw[ptr + 3] == '.'))
throw new CorruptObjectException("invalid name 'AUX'");
break;
case 'c': // CON, COM[1-9]
if (end - ptr >= 3
&& toLower(raw[ptr + 2]) == 'n'
&& toLower(raw[ptr + 1]) == 'o'
&& (end - ptr == 3 || raw[ptr + 3] == '.'))
throw new CorruptObjectException("invalid name 'CON'");
if (end - ptr >= 4
&& toLower(raw[ptr + 2]) == 'm'
&& toLower(raw[ptr + 1]) == 'o'
&& isPositiveDigit(raw[ptr + 3])
&& (end - ptr == 4 || raw[ptr + 4] == '.'))
throw new CorruptObjectException("invalid name 'COM"
+ ((char) raw[ptr + 3]) + "'");
break;
case 'l': // LPT[1-9]
if (end - ptr >= 4
&& toLower(raw[ptr + 1]) == 'p'
&& toLower(raw[ptr + 2]) == 't'
&& isPositiveDigit(raw[ptr + 3])
&& (end - ptr == 4 || raw[ptr + 4] == '.'))
throw new CorruptObjectException("invalid name 'LPT"
+ ((char) raw[ptr + 3]) + "'");
break;
case 'n': // NUL
if (end - ptr >= 3
&& toLower(raw[ptr + 1]) == 'u'
&& toLower(raw[ptr + 2]) == 'l'
&& (end - ptr == 3 || raw[ptr + 3] == '.'))
throw new CorruptObjectException("invalid name 'NUL'");
break;
case 'p': // PRN
if (end - ptr >= 3
&& toLower(raw[ptr + 1]) == 'r'
&& toLower(raw[ptr + 2]) == 'n'
&& (end - ptr == 3 || raw[ptr + 3] == '.'))
throw new CorruptObjectException("invalid name 'PRN'");
break;
}
}
private static boolean isInvalidOnWindows(byte c) {
@ -446,6 +504,10 @@ private static char toLower(byte b) {
return (char) b;
}
private static boolean isPositiveDigit(byte b) {
return '1' <= b && b <= '9';
}
/**
* Check a blob for errors.
*