issue352: disallow '\n' and '\r' in filenames (dirstate and manifest)
authorBenoit Boissinot <benoit.boissinot@ens-lyon.org>
Wed, 01 Nov 2006 17:56:55 +0100
changeset 3607 f4c9bb4ad7b1
parent 3606 f8589028a7fa
child 3608 802da51cab5b
issue352: disallow '\n' and '\r' in filenames (dirstate and manifest)
mercurial/dirstate.py
mercurial/manifest.py
tests/test-issue352
tests/test-issue352.out
--- a/mercurial/dirstate.py	Tue Oct 31 18:10:23 2006 -0800
+++ b/mercurial/dirstate.py	Wed Nov 01 17:56:55 2006 +0100
@@ -211,7 +211,7 @@
                 self.dirs.setdefault(pc, 0)
                 self.dirs[pc] += delta
 
-    def checkshadows(self, files):
+    def checkinterfering(self, files):
         def prefixes(f):
             for c in strutil.rfindall(f, '/'):
                 yield f[:c]
@@ -219,6 +219,7 @@
         self.initdirs()
         seendirs = {}
         for f in files:
+            # shadows
             if self.dirs.get(f):
                 raise util.Abort(_('directory named %r already in dirstate') %
                                  f)
@@ -229,6 +230,9 @@
                     raise util.Abort(_('file named %r already in dirstate') %
                                      d)
                 seendirs[d] = True
+            # disallowed
+            if '\r' in f or '\n' in f:
+                raise util.Abort(_("'\\n' and '\\r' disallowed in filenames"))
 
     def update(self, files, state, **kw):
         ''' current states:
@@ -242,7 +246,7 @@
         self.markdirty()
         if state == "a":
             self.initdirs()
-            self.checkshadows(files)
+            self.checkinterfering(files)
         for f in files:
             if state == "r":
                 self.map[f] = ('r', 0, 0, 0)
--- a/mercurial/manifest.py	Tue Oct 31 18:10:23 2006 -0800
+++ b/mercurial/manifest.py	Wed Nov 01 17:56:55 2006 +0100
@@ -138,6 +138,10 @@
             return "".join([struct.pack(">lll", d[0], d[1], len(d[2])) + d[2] \
                             for d in x ])
 
+        def checkforbidden(f):
+            if '\n' in f or '\r' in f:
+                raise RevlogError(_("'\\n' and '\\r' disallowed in filenames"))
+
         # if we're using the listcache, make sure it is valid and
         # parented by the same node we're diffing against
         if not changed or not self.listcache or not p1 or \
@@ -145,6 +149,9 @@
             files = map.keys()
             files.sort()
 
+            for f in files:
+                checkforbidden(f)
+
             # if this is changed to support newlines in filenames,
             # be sure to check the templates/ dir again (especially *-raw.tmpl)
             text = ["%s\000%s%s\n" % (f, hex(map[f]), map.flags(f)) for f in files]
@@ -153,6 +160,8 @@
         else:
             addlist = self.listcache
 
+            for f in changed[0]:
+                checkforbidden(f)
             # combine the changed lists into one list for sorting
             work = [[x, 0] for x in changed[0]]
             work[len(work):] = [[x, 1] for x in changed[1]]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-issue352	Wed Nov 01 17:56:55 2006 +0100
@@ -0,0 +1,21 @@
+#!/bin/bash
+# http://www.selenic.com/mercurial/bts/issue352
+
+hg init foo
+cd foo
+
+A=`echo -e -n 'he\rllo'`
+
+echo foo > "hell
+o"
+echo foo > "$A"
+hg add
+hg ci -A -m m
+rm "$A"
+ls
+hg add
+# BUG ? we don't walk on filenames with '\n' (regexp related) ?
+hg debugwalk
+hg ci -A -m m
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-issue352.out	Wed Nov 01 17:56:55 2006 +0100
@@ -0,0 +1,7 @@
+adding he
llo
+abort: '\n' and '\r' disallowed in filenames
+adding he
llo
+abort: '\n' and '\r' disallowed in filenames
+hell
+o
+nothing changed