# HG changeset patch # User Benoit Boissinot # Date 2006-11-01 16:56:55 # Node ID f4c9bb4ad7b1a4b40d885d5ff46d75f76d1e3439 # Parent f8589028a7fa6f807866a76515b1146be9187e7a issue352: disallow '\n' and '\r' in filenames (dirstate and manifest) diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py --- 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) diff --git a/mercurial/manifest.py b/mercurial/manifest.py --- 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]] diff --git a/tests/test-issue352 b/tests/test-issue352 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 diff --git a/tests/test-issue352.out b/tests/test-issue352.out 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