changeset 3607:f4c9bb4ad7b1

issue352: disallow '\n' and '\r' in filenames (dirstate and manifest)
author Benoit Boissinot <benoit.boissinot@ens-lyon.org>
date Wed, 01 Nov 2006 17:56:55 +0100
parents f8589028a7fa
children 802da51cab5b
files mercurial/dirstate.py mercurial/manifest.py tests/test-issue352 tests/test-issue352.out
diffstat 4 files changed, 43 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -211,7 +211,7 @@ class dirstate(object):
                 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 @@ class dirstate(object):
         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 @@ class dirstate(object):
                     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 @@ class dirstate(object):
         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
+++ b/mercurial/manifest.py
@@ -138,6 +138,10 @@ class manifest(revlog):
             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 @@ class manifest(revlog):
             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 @@ class manifest(revlog):
         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]]
new file mode 100755
--- /dev/null
+++ b/tests/test-issue352
@@ -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
new file mode 100644
--- /dev/null
+++ b/tests/test-issue352.out
@@ -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