Show More
@@ -98,3 +98,4 b' 7f8d16af8cae246fa5a48e723d48d58b015aed94' | |||||
98 | ced632394371a36953ce4d394f86278ae51a2aae 0 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 |
@@ -111,3 +111,4 b' 7f8d16af8cae246fa5a48e723d48d58b015aed94' | |||||
111 | ced632394371a36953ce4d394f86278ae51a2aae 3.2 |
|
111 | ced632394371a36953ce4d394f86278ae51a2aae 3.2 | |
112 | 643c58303fb0ec020907af28b9e486be299ba043 3.2.1 |
|
112 | 643c58303fb0ec020907af28b9e486be299ba043 3.2.1 | |
113 | 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2 |
|
113 | 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2 | |
|
114 | 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3 |
@@ -191,8 +191,15 b' def removelargefiles(ui, repo, isaddremo' | |||||
191 | # are removing the file. |
|
191 | # are removing the file. | |
192 | if isaddremove: |
|
192 | if isaddremove: | |
193 | ui.status(_('removing %s\n') % f) |
|
193 | ui.status(_('removing %s\n') % f) | |
|
194 | ||||
|
195 | if not opts.get('dry_run'): | |||
|
196 | if not after: | |||
194 | util.unlinkpath(repo.wjoin(f), ignoremissing=True) |
|
197 | util.unlinkpath(repo.wjoin(f), ignoremissing=True) | |
195 | lfdirstate.remove(f) |
|
198 | lfdirstate.remove(f) | |
|
199 | ||||
|
200 | if opts.get('dry_run'): | |||
|
201 | return result | |||
|
202 | ||||
196 | lfdirstate.write() |
|
203 | lfdirstate.write() | |
197 | remove = [lfutil.standin(f) for f in remove] |
|
204 | remove = [lfutil.standin(f) for f in remove] | |
198 | # If this is being called by addremove, let the original addremove |
|
205 | # If this is being called by addremove, let the original addremove |
@@ -17,6 +17,11 b' import revlog' | |||||
17 |
|
17 | |||
18 | propertycache = util.propertycache |
|
18 | propertycache = util.propertycache | |
19 |
|
19 | |||
|
20 | # Phony node value to stand-in for new files in some uses of | |||
|
21 | # manifests. Manifests support 21-byte hashes for nodes which are | |||
|
22 | # dirty in the working copy. | |||
|
23 | _newnode = '!' * 21 | |||
|
24 | ||||
20 | class basectx(object): |
|
25 | class basectx(object): | |
21 | """A basectx object represents the common logic for its children: |
|
26 | """A basectx object represents the common logic for its children: | |
22 | changectx: read-only context that is already present in the repo, |
|
27 | changectx: read-only context that is already present in the repo, | |
@@ -104,7 +109,7 b' class basectx(object):' | |||||
104 | if (fn not in deletedset and |
|
109 | if (fn not in deletedset and | |
105 | ((fn in withflags and mf1.flags(fn) != mf2.flags(fn)) or |
|
110 | ((fn in withflags and mf1.flags(fn) != mf2.flags(fn)) or | |
106 | (mf1[fn] != mf2node and |
|
111 | (mf1[fn] != mf2node and | |
107 | (mf2node or self[fn].cmp(other[fn]))))): |
|
112 | (mf2node != _newnode or self[fn].cmp(other[fn]))))): | |
108 | modified.append(fn) |
|
113 | modified.append(fn) | |
109 | elif listclean: |
|
114 | elif listclean: | |
110 | clean.append(fn) |
|
115 | clean.append(fn) | |
@@ -1382,7 +1387,7 b' class workingctx(committablectx):' | |||||
1382 | """ |
|
1387 | """ | |
1383 | mf = self._repo['.']._manifestmatches(match, s) |
|
1388 | mf = self._repo['.']._manifestmatches(match, s) | |
1384 | for f in s.modified + s.added: |
|
1389 | for f in s.modified + s.added: | |
1385 |
mf[f] = |
|
1390 | mf[f] = _newnode | |
1386 | mf.setflag(f, self.flags(f)) |
|
1391 | mf.setflag(f, self.flags(f)) | |
1387 | for f in s.removed: |
|
1392 | for f in s.removed: | |
1388 | if f in mf: |
|
1393 | if f in mf: |
@@ -8,6 +8,28 b'' | |||||
8 | import error |
|
8 | import error | |
9 | import unicodedata, locale, os |
|
9 | import unicodedata, locale, os | |
10 |
|
10 | |||
|
11 | # These unicode characters are ignored by HFS+ (Apple Technote 1150, | |||
|
12 | # "Unicode Subtleties"), so we need to ignore them in some places for | |||
|
13 | # sanity. | |||
|
14 | _ignore = [unichr(int(x, 16)).encode("utf-8") for x in | |||
|
15 | "200c 200d 200e 200f 202a 202b 202c 202d 202e " | |||
|
16 | "206a 206b 206c 206d 206e 206f feff".split()] | |||
|
17 | # verify the next function will work | |||
|
18 | assert set([i[0] for i in _ignore]) == set(["\xe2", "\xef"]) | |||
|
19 | ||||
|
20 | def hfsignoreclean(s): | |||
|
21 | """Remove codepoints ignored by HFS+ from s. | |||
|
22 | ||||
|
23 | >>> hfsignoreclean(u'.h\u200cg'.encode('utf-8')) | |||
|
24 | '.hg' | |||
|
25 | >>> hfsignoreclean(u'.h\ufeffg'.encode('utf-8')) | |||
|
26 | '.hg' | |||
|
27 | """ | |||
|
28 | if "\xe2" in s or "\xef" in s: | |||
|
29 | for c in _ignore: | |||
|
30 | s = s.replace(c, '') | |||
|
31 | return s | |||
|
32 | ||||
11 | def _getpreferredencoding(): |
|
33 | def _getpreferredencoding(): | |
12 | ''' |
|
34 | ''' | |
13 | On darwin, getpreferredencoding ignores the locale environment and |
|
35 | On darwin, getpreferredencoding ignores the locale environment and |
@@ -17,6 +17,9 b' class manifestdict(dict):' | |||||
17 | flags = {} |
|
17 | flags = {} | |
18 | dict.__init__(self, mapping) |
|
18 | dict.__init__(self, mapping) | |
19 | self._flags = flags |
|
19 | self._flags = flags | |
|
20 | def __setitem__(self, k, v): | |||
|
21 | assert v is not None | |||
|
22 | dict.__setitem__(self, k, v) | |||
20 | def flags(self, f): |
|
23 | def flags(self, f): | |
21 | return self._flags.get(f, "") |
|
24 | return self._flags.get(f, "") | |
22 | def withflags(self): |
|
25 | def withflags(self): |
@@ -1,8 +1,12 b'' | |||||
1 | import os, errno, stat |
|
1 | import os, errno, stat | |
2 |
|
2 | |||
|
3 | import encoding | |||
3 | import util |
|
4 | import util | |
4 | from i18n import _ |
|
5 | from i18n import _ | |
5 |
|
6 | |||
|
7 | def _lowerclean(s): | |||
|
8 | return encoding.hfsignoreclean(s.lower()) | |||
|
9 | ||||
6 | class pathauditor(object): |
|
10 | class pathauditor(object): | |
7 | '''ensure that a filesystem path contains no banned components. |
|
11 | '''ensure that a filesystem path contains no banned components. | |
8 | the following properties of a path are checked: |
|
12 | the following properties of a path are checked: | |
@@ -39,11 +43,18 b' class pathauditor(object):' | |||||
39 | raise util.Abort(_("path ends in directory separator: %s") % path) |
|
43 | raise util.Abort(_("path ends in directory separator: %s") % path) | |
40 | parts = util.splitpath(path) |
|
44 | parts = util.splitpath(path) | |
41 | if (os.path.splitdrive(path)[0] |
|
45 | if (os.path.splitdrive(path)[0] | |
42 |
or parts[0] |
|
46 | or _lowerclean(parts[0]) in ('.hg', '.hg.', '') | |
43 | or os.pardir in parts): |
|
47 | or os.pardir in parts): | |
44 | raise util.Abort(_("path contains illegal component: %s") % path) |
|
48 | raise util.Abort(_("path contains illegal component: %s") % path) | |
45 | if '.hg' in path.lower(): |
|
49 | # Windows shortname aliases | |
46 |
|
|
50 | for p in parts: | |
|
51 | if "~" in p: | |||
|
52 | first, last = p.split("~", 1) | |||
|
53 | if last.isdigit() and first.upper() in ["HG", "HG8B6C"]: | |||
|
54 | raise util.Abort(_("path contains illegal component: %s") | |||
|
55 | % path) | |||
|
56 | if '.hg' in _lowerclean(path): | |||
|
57 | lparts = [_lowerclean(p.lower()) for p in parts] | |||
47 | for p in '.hg', '.hg.': |
|
58 | for p in '.hg', '.hg.': | |
48 | if p in lparts[1:]: |
|
59 | if p in lparts[1:]: | |
49 | pos = lparts.index(p) |
|
60 | pos = lparts.index(p) |
@@ -208,6 +208,7 b" if sys.platform == 'darwin':" | |||||
208 | - escape-encode invalid characters |
|
208 | - escape-encode invalid characters | |
209 | - decompose to NFD |
|
209 | - decompose to NFD | |
210 | - lowercase |
|
210 | - lowercase | |
|
211 | - omit ignored characters [200c-200f, 202a-202e, 206a-206f,feff] | |||
211 |
|
212 | |||
212 | >>> normcase('UPPER') |
|
213 | >>> normcase('UPPER') | |
213 | 'upper' |
|
214 | 'upper' | |
@@ -265,7 +266,9 b" if sys.platform == 'darwin':" | |||||
265 | u = s.decode('utf-8') |
|
266 | u = s.decode('utf-8') | |
266 |
|
267 | |||
267 | # Decompose then lowercase (HFS+ technote specifies lower) |
|
268 | # Decompose then lowercase (HFS+ technote specifies lower) | |
268 |
|
|
269 | enc = unicodedata.normalize('NFD', u).lower().encode('utf-8') | |
|
270 | # drop HFS+ ignored characters | |||
|
271 | return encoding.hfsignoreclean(enc) | |||
269 |
|
272 | |||
270 | if sys.platform == 'cygwin': |
|
273 | if sys.platform == 'cygwin': | |
271 | # workaround for cygwin, in which mount point part of path is |
|
274 | # workaround for cygwin, in which mount point part of path is |
@@ -195,4 +195,16 b' case changes.' | |||||
195 | $ hg qrefresh a # issue 3271, qrefresh with file handled case wrong |
|
195 | $ hg qrefresh a # issue 3271, qrefresh with file handled case wrong | |
196 | $ hg status # empty status means the qrefresh worked |
|
196 | $ hg status # empty status means the qrefresh worked | |
197 |
|
197 | |||
|
198 | #if osx | |||
|
199 | ||||
|
200 | We assume anyone running the tests on a case-insensitive volume on OS | |||
|
201 | X will be using HFS+. If that's not true, this test will fail. | |||
|
202 | ||||
|
203 | $ rm A | |||
|
204 | >>> open(u'a\u200c'.encode('utf-8'), 'w').write('unicode is fun') | |||
|
205 | $ hg status | |||
|
206 | M A | |||
|
207 | ||||
|
208 | #endif | |||
|
209 | ||||
198 | $ cd .. |
|
210 | $ cd .. |
@@ -518,4 +518,55 b' commit copy' | |||||
518 | 0 0 6 ..... 0 26d3ca0dfd18 000000000000 000000000000 (re) |
|
518 | 0 0 6 ..... 0 26d3ca0dfd18 000000000000 000000000000 (re) | |
519 | 1 6 7 ..... 1 d267bddd54f7 26d3ca0dfd18 000000000000 (re) |
|
519 | 1 6 7 ..... 1 d267bddd54f7 26d3ca0dfd18 000000000000 (re) | |
520 |
|
520 | |||
521 | $ cd .. |
|
521 | verify pathauditor blocks evil filepaths | |
|
522 | $ cat > evil-commit.py <<EOF | |||
|
523 | > from mercurial import ui, hg, context, node | |||
|
524 | > notrc = u".h\u200cg".encode('utf-8') + '/hgrc' | |||
|
525 | > u = ui.ui() | |||
|
526 | > r = hg.repository(u, '.') | |||
|
527 | > def filectxfn(repo, memctx, path): | |||
|
528 | > return context.memfilectx(repo, path, '[hooks]\nupdate = echo owned') | |||
|
529 | > c = context.memctx(r, [r['tip'].node(), node.nullid], | |||
|
530 | > 'evil', [notrc], filectxfn, 0) | |||
|
531 | > r.commitctx(c) | |||
|
532 | > EOF | |||
|
533 | $ $PYTHON evil-commit.py | |||
|
534 | $ hg co --clean tip | |||
|
535 | abort: path contains illegal component: .h\xe2\x80\x8cg/hgrc (esc) | |||
|
536 | [255] | |||
|
537 | ||||
|
538 | $ hg rollback -f | |||
|
539 | repository tip rolled back to revision 1 (undo commit) | |||
|
540 | $ cat > evil-commit.py <<EOF | |||
|
541 | > from mercurial import ui, hg, context, node | |||
|
542 | > notrc = "HG~1/hgrc" | |||
|
543 | > u = ui.ui() | |||
|
544 | > r = hg.repository(u, '.') | |||
|
545 | > def filectxfn(repo, memctx, path): | |||
|
546 | > return context.memfilectx(repo, path, '[hooks]\nupdate = echo owned') | |||
|
547 | > c = context.memctx(r, [r['tip'].node(), node.nullid], | |||
|
548 | > 'evil', [notrc], filectxfn, 0) | |||
|
549 | > r.commitctx(c) | |||
|
550 | > EOF | |||
|
551 | $ $PYTHON evil-commit.py | |||
|
552 | $ hg co --clean tip | |||
|
553 | abort: path contains illegal component: HG~1/hgrc | |||
|
554 | [255] | |||
|
555 | ||||
|
556 | $ hg rollback -f | |||
|
557 | repository tip rolled back to revision 1 (undo commit) | |||
|
558 | $ cat > evil-commit.py <<EOF | |||
|
559 | > from mercurial import ui, hg, context, node | |||
|
560 | > notrc = "HG8B6C~2/hgrc" | |||
|
561 | > u = ui.ui() | |||
|
562 | > r = hg.repository(u, '.') | |||
|
563 | > def filectxfn(repo, memctx, path): | |||
|
564 | > return context.memfilectx(repo, path, '[hooks]\nupdate = echo owned') | |||
|
565 | > c = context.memctx(r, [r['tip'].node(), node.nullid], | |||
|
566 | > 'evil', [notrc], filectxfn, 0) | |||
|
567 | > r.commitctx(c) | |||
|
568 | > EOF | |||
|
569 | $ $PYTHON evil-commit.py | |||
|
570 | $ hg co --clean tip | |||
|
571 | abort: path contains illegal component: HG8B6C~2/hgrc | |||
|
572 | [255] |
@@ -255,6 +255,16 b' verify that large files in subrepos hand' | |||||
255 | Add a normal file to the subrepo, then test archiving |
|
255 | Add a normal file to the subrepo, then test archiving | |
256 |
|
256 | |||
257 | $ echo 'normal file' > subrepo/normal.txt |
|
257 | $ echo 'normal file' > subrepo/normal.txt | |
|
258 | $ mv subrepo/large.txt subrepo/renamed-large.txt | |||
|
259 | $ hg -R subrepo addremove --dry-run | |||
|
260 | removing large.txt | |||
|
261 | adding normal.txt | |||
|
262 | adding renamed-large.txt | |||
|
263 | $ hg status -S | |||
|
264 | ! subrepo/large.txt | |||
|
265 | ? subrepo/normal.txt | |||
|
266 | ? subrepo/renamed-large.txt | |||
|
267 | $ mv subrepo/renamed-large.txt subrepo/large.txt | |||
258 | $ hg -R subrepo add subrepo/normal.txt |
|
268 | $ hg -R subrepo add subrepo/normal.txt | |
259 |
|
269 | |||
260 | Lock in subrepo, otherwise the change isn't archived |
|
270 | Lock in subrepo, otherwise the change isn't archived |
General Comments 0
You need to be logged in to leave comments.
Login now