aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Pearce <spearce@spearce.org>2014-03-11 22:49:36 -0700
committerShawn Pearce <spearce@spearce.org>2014-03-12 15:53:30 -0700
commitba0f89b4211fd57fe52120ec9a7c3cbaadbadd3b (patch)
tree96405fd15d1f3fad088893d9ce397820b70acd65
parent5019471ccb5f6283c0bbde6f697631f928fea987 (diff)
downloadjgit-ba0f89b4211fd57fe52120ec9a7c3cbaadbadd3b.tar.gz
jgit-ba0f89b4211fd57fe52120ec9a7c3cbaadbadd3b.zip
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
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java24
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java70
2 files changed, 90 insertions, 4 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
index 3e9195eea3..d434c852e6 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
@@ -1039,6 +1039,7 @@ public class ObjectCheckerTest {
checkOneName("a<b>c:d|e");
checkOneName("test ");
checkOneName("test.");
+ checkOneName("NUL");
}
@Test
@@ -1457,6 +1458,29 @@ public class ObjectCheckerTest {
}
@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);
rejectName('<');
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
index 39f071c98e..260a643e66 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
@@ -410,10 +410,68 @@ public class ObjectChecker {
}
}
- // 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 @@ public class ObjectChecker {
return (char) b;
}
+ private static boolean isPositiveDigit(byte b) {
+ return '1' <= b && b <= '9';
+ }
+
/**
* Check a blob for errors.
*