]> source.dussan.org Git - jgit.git/commitdiff
Reject special Windows device names in ObjectChecker 29/23229/3
authorShawn Pearce <spearce@spearce.org>
Wed, 12 Mar 2014 05:49:36 +0000 (22:49 -0700)
committerShawn Pearce <spearce@spearce.org>
Wed, 12 Mar 2014 22:53:30 +0000 (15:53 -0700)
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

org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java

index 3e9195eea3ec8bb19b369c9920eabca92b9460a3..d434c852e6931f171b1310bfa82079d0395cfb76 100644 (file)
@@ -1039,6 +1039,7 @@ public class ObjectCheckerTest {
                checkOneName("a<b>c:d|e");
                checkOneName("test ");
                checkOneName("test.");
+               checkOneName("NUL");
        }
 
        @Test
@@ -1456,6 +1457,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);
index 39f071c98edb1c11ca0eeb742399907c95ec6736..260a643e66daca9ea040e4e2e7323d5c44f3d77e 100644 (file)
@@ -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.
         *