Show More
@@ -0,0 +1,23 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | hg init | |||
|
4 | ||||
|
5 | echo % should fail | |||
|
6 | hg add .hg/00changelog.i | |||
|
7 | ||||
|
8 | mkdir a | |||
|
9 | echo a > a/a | |||
|
10 | hg ci -Ama | |||
|
11 | ln -s a b | |||
|
12 | echo b > a/b | |||
|
13 | ||||
|
14 | echo % should fail | |||
|
15 | hg add b/b | |||
|
16 | ||||
|
17 | echo % should succeed | |||
|
18 | hg add b | |||
|
19 | ||||
|
20 | echo % should still fail - maybe | |||
|
21 | hg add b/b | |||
|
22 | ||||
|
23 | exit 0 |
@@ -0,0 +1,8 b'' | |||||
|
1 | % should fail | |||
|
2 | abort: path contains illegal component: .hg/00changelog.i | |||
|
3 | adding a/a | |||
|
4 | % should fail | |||
|
5 | abort: path 'b/b' traverses symbolic link 'b' | |||
|
6 | % should succeed | |||
|
7 | % should still fail - maybe | |||
|
8 | abort: path 'b/b' traverses symbolic link 'b' |
@@ -69,7 +69,8 b' class localrepository(repo.repository):' | |||||
69 | self.encodefn = lambda x: x |
|
69 | self.encodefn = lambda x: x | |
70 | self.decodefn = lambda x: x |
|
70 | self.decodefn = lambda x: x | |
71 | self.spath = self.path |
|
71 | self.spath = self.path | |
72 |
self.sopener = util.encodedopener(util.opener(self.spath), |
|
72 | self.sopener = util.encodedopener(util.opener(self.spath), | |
|
73 | self.encodefn) | |||
73 |
|
74 | |||
74 | self.ui = ui.ui(parentui=parentui) |
|
75 | self.ui = ui.ui(parentui=parentui) | |
75 | try: |
|
76 | try: |
@@ -391,13 +391,15 b' def applyupdates(repo, action, wctx, mct' | |||||
391 | repo.ui.debug(_("copying %s to %s\n") % (f, fd)) |
|
391 | repo.ui.debug(_("copying %s to %s\n") % (f, fd)) | |
392 | repo.wwrite(fd, repo.wread(f), flags) |
|
392 | repo.wwrite(fd, repo.wread(f), flags) | |
393 |
|
393 | |||
|
394 | audit_path = util.path_auditor(repo.root) | |||
|
395 | ||||
394 | for a in action: |
|
396 | for a in action: | |
395 | f, m = a[:2] |
|
397 | f, m = a[:2] | |
396 | if f and f[0] == "/": |
|
398 | if f and f[0] == "/": | |
397 | continue |
|
399 | continue | |
398 | if m == "r": # remove |
|
400 | if m == "r": # remove | |
399 | repo.ui.note(_("removing %s\n") % f) |
|
401 | repo.ui.note(_("removing %s\n") % f) | |
400 |
|
|
402 | audit_path(f) | |
401 | try: |
|
403 | try: | |
402 | util.unlink(repo.wjoin(f)) |
|
404 | util.unlink(repo.wjoin(f)) | |
403 | except OSError, inst: |
|
405 | except OSError, inst: |
@@ -13,8 +13,8 b' platform-specific details from the core.' | |||||
13 | """ |
|
13 | """ | |
14 |
|
14 | |||
15 | from i18n import _ |
|
15 | from i18n import _ | |
16 | import cStringIO, errno, getpass, popen2, re, shutil, sys, tempfile |
|
16 | import cStringIO, errno, getpass, popen2, re, shutil, sys, tempfile, strutil | |
17 | import os, threading, time, calendar, ConfigParser, locale, glob |
|
17 | import os, stat, threading, time, calendar, ConfigParser, locale, glob | |
18 |
|
18 | |||
19 | try: |
|
19 | try: | |
20 | set = set |
|
20 | set = set | |
@@ -366,6 +366,7 b' def canonpath(root, cwd, myname):' | |||||
366 | if not os.path.isabs(name): |
|
366 | if not os.path.isabs(name): | |
367 | name = os.path.join(root, cwd, name) |
|
367 | name = os.path.join(root, cwd, name) | |
368 | name = os.path.normpath(name) |
|
368 | name = os.path.normpath(name) | |
|
369 | audit_path = path_auditor(root) | |||
369 | if name != rootsep and name.startswith(rootsep): |
|
370 | if name != rootsep and name.startswith(rootsep): | |
370 | name = name[len(rootsep):] |
|
371 | name = name[len(rootsep):] | |
371 | audit_path(name) |
|
372 | audit_path(name) | |
@@ -680,12 +681,45 b' def copyfiles(src, dst, hardlink=None):' | |||||
680 | else: |
|
681 | else: | |
681 | shutil.copy(src, dst) |
|
682 | shutil.copy(src, dst) | |
682 |
|
683 | |||
683 | def audit_path(path): |
|
684 | class path_auditor(object): | |
684 |
|
|
685 | '''ensure that a filesystem path contains no banned components. | |
685 | parts = os.path.normcase(path).split(os.sep) |
|
686 | the following properties of a path are checked: | |
686 | if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '') |
|
687 | ||
687 | or os.pardir in parts): |
|
688 | - under top-level .hg | |
688 | raise Abort(_("path contains illegal component: %s") % path) |
|
689 | - starts at the root of a windows drive | |
|
690 | - contains ".." | |||
|
691 | - traverses a symlink (e.g. a/symlink_here/b) | |||
|
692 | - inside a nested repository''' | |||
|
693 | ||||
|
694 | def __init__(self, root): | |||
|
695 | self.audited = {} | |||
|
696 | self.root = root | |||
|
697 | ||||
|
698 | def __call__(self, path): | |||
|
699 | if path in self.audited: | |||
|
700 | return | |||
|
701 | parts = os.path.normcase(path).split(os.sep) | |||
|
702 | if (os.path.splitdrive(path)[0] or parts[0] in ('.hg', '') | |||
|
703 | or os.pardir in parts): | |||
|
704 | raise Abort(_("path contains illegal component: %s") % path) | |||
|
705 | def check(prefix): | |||
|
706 | curpath = os.path.join(self.root, prefix) | |||
|
707 | try: | |||
|
708 | st = os.lstat(curpath) | |||
|
709 | except OSError, err: | |||
|
710 | if err.errno != errno.ENOENT: | |||
|
711 | raise | |||
|
712 | else: | |||
|
713 | if stat.S_ISLNK(st.st_mode): | |||
|
714 | raise Abort(_('path %r traverses symbolic link %r') % | |||
|
715 | (path, prefix)) | |||
|
716 | if os.path.exists(os.path.join(curpath, '.hg')): | |||
|
717 | raise Abort(_('path %r is inside repo %r') % | |||
|
718 | (path, prefix)) | |||
|
719 | self.audited[prefix] = True | |||
|
720 | for c in strutil.rfindall(path, os.sep): | |||
|
721 | check(path[:c]) | |||
|
722 | self.audited[path] = True | |||
689 |
|
723 | |||
690 | def _makelock_file(info, pathname): |
|
724 | def _makelock_file(info, pathname): | |
691 | ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL) |
|
725 | ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL) | |
@@ -1262,7 +1296,10 b' class opener(object):' | |||||
1262 | """ |
|
1296 | """ | |
1263 | def __init__(self, base, audit=True): |
|
1297 | def __init__(self, base, audit=True): | |
1264 | self.base = base |
|
1298 | self.base = base | |
1265 |
|
|
1299 | if audit: | |
|
1300 | self.audit_path = path_auditor(base) | |||
|
1301 | else: | |||
|
1302 | self.audit_path = always | |||
1266 |
|
1303 | |||
1267 | def __getattr__(self, name): |
|
1304 | def __getattr__(self, name): | |
1268 | if name == '_can_symlink': |
|
1305 | if name == '_can_symlink': | |
@@ -1271,8 +1308,7 b' class opener(object):' | |||||
1271 | raise AttributeError(name) |
|
1308 | raise AttributeError(name) | |
1272 |
|
1309 | |||
1273 | def __call__(self, path, mode="r", text=False, atomictemp=False): |
|
1310 | def __call__(self, path, mode="r", text=False, atomictemp=False): | |
1274 |
|
|
1311 | self.audit_path(path) | |
1275 | audit_path(path) |
|
|||
1276 | f = os.path.join(self.base, path) |
|
1312 | f = os.path.join(self.base, path) | |
1277 |
|
1313 | |||
1278 | if not text and "b" not in mode: |
|
1314 | if not text and "b" not in mode: | |
@@ -1293,8 +1329,7 b' class opener(object):' | |||||
1293 | return posixfile(f, mode) |
|
1329 | return posixfile(f, mode) | |
1294 |
|
1330 | |||
1295 | def symlink(self, src, dst): |
|
1331 | def symlink(self, src, dst): | |
1296 |
|
|
1332 | self.audit_path(dst) | |
1297 | audit_path(dst) |
|
|||
1298 | linkname = os.path.join(self.base, dst) |
|
1333 | linkname = os.path.join(self.base, dst) | |
1299 | try: |
|
1334 | try: | |
1300 | os.unlink(linkname) |
|
1335 | os.unlink(linkname) |
@@ -4,16 +4,21 b' hg init a' | |||||
4 | cd a |
|
4 | cd a | |
5 | hg init b |
|
5 | hg init b | |
6 | echo x > b/x |
|
6 | echo x > b/x | |
|
7 | ||||
7 | echo '# should print nothing' |
|
8 | echo '# should print nothing' | |
|
9 | hg add b | |||
8 | hg st |
|
10 | hg st | |
9 | echo '# should print ? b/x' |
|
11 | ||
|
12 | echo '# should fail' | |||
10 | hg st b/x |
|
13 | hg st b/x | |
11 |
|
||||
12 | hg add b/x |
|
14 | hg add b/x | |
13 |
|
15 | |||
14 |
echo '# should print |
|
16 | echo '# should arguably print nothing' | |
|
17 | hg st b | |||
|
18 | ||||
|
19 | echo a > a | |||
|
20 | hg ci -Ama a | |||
|
21 | ||||
|
22 | echo '# should fail' | |||
|
23 | hg mv a b | |||
15 | hg st |
|
24 | hg st | |
16 | echo '# should forget b/x' |
|
|||
17 | hg revert --all |
|
|||
18 | echo '# should print nothing' |
|
|||
19 | hg st b |
|
@@ -1,8 +1,7 b'' | |||||
1 | # should print nothing |
|
1 | # should print nothing | |
2 |
# should |
|
2 | # should fail | |
3 | ? b/x |
|
3 | abort: path 'b/x' is inside repo 'b' | |
4 | # should print A b/x |
|
4 | abort: path 'b/x' is inside repo 'b' | |
5 | A b/x |
|
5 | # should arguably print nothing | |
6 |
# should f |
|
6 | # should fail | |
7 | forgetting b/x |
|
7 | abort: path 'b/a' is inside repo 'b' | |
8 | # should print nothing |
|
General Comments 0
You need to be logged in to leave comments.
Login now