##// END OF EJS Templates
move path_auditor from util to scmutil
Adrian Buehlmann -
r13972:d1f4e7fd default
parent child Browse files
Show More
@@ -286,7 +286,7 b' def addremove(repo, pats=[], opts={}, dr'
286 286 similarity = float(opts.get('similarity') or 0)
287 287 # we'd use status here, except handling of symlinks and ignore is tricky
288 288 added, unknown, deleted, removed = [], [], [], []
289 audit_path = util.path_auditor(repo.root)
289 audit_path = scmutil.path_auditor(repo.root)
290 290 m = match(repo, pats, opts)
291 291 for abs in repo.walk(m):
292 292 target = repo.wjoin(abs)
@@ -3554,7 +3554,7 b' def revert(ui, repo, *pats, **opts):'
3554 3554 fc = ctx[f]
3555 3555 repo.wwrite(f, fc.data(), fc.flags())
3556 3556
3557 audit_path = util.path_auditor(repo.root)
3557 audit_path = scmutil.path_auditor(repo.root)
3558 3558 for f in remove[0]:
3559 3559 if repo.dirstate[f] == 'a':
3560 3560 repo.dirstate.forget(f)
@@ -31,7 +31,7 b' class localrepository(repo.repository):'
31 31 self.root = os.path.realpath(util.expandpath(path))
32 32 self.path = os.path.join(self.root, ".hg")
33 33 self.origroot = path
34 self.auditor = util.path_auditor(self.root, self._checknested)
34 self.auditor = scmutil.path_auditor(self.root, self._checknested)
35 35 self.opener = scmutil.opener(self.path)
36 36 self.wopener = scmutil.opener(self.root)
37 37 self.baseui = baseui
@@ -7,7 +7,7 b''
7 7
8 8 from node import nullid, nullrev, hex, bin
9 9 from i18n import _
10 import util, filemerge, copies, subrepo
10 import scmutil, util, filemerge, copies, subrepo
11 11 import errno, os, shutil
12 12
13 13 class mergestate(object):
@@ -303,7 +303,7 b' def applyupdates(repo, action, wctx, mct'
303 303 repo.ui.debug("removing %s\n" % f)
304 304 os.unlink(repo.wjoin(f))
305 305
306 audit_path = util.path_auditor(repo.root)
306 audit_path = scmutil.path_auditor(repo.root)
307 307
308 308 numupdates = len(action)
309 309 for i, a in enumerate(action):
@@ -7,7 +7,7 b''
7 7
8 8 from i18n import _
9 9 import util, error
10 import os, errno
10 import os, errno, stat
11 11
12 12 def checkportable(ui, f):
13 13 '''Check if filename f is portable and warn or abort depending on config'''
@@ -26,6 +26,81 b' def checkportable(ui, f):'
26 26 raise error.ConfigError(
27 27 _("ui.portablefilenames value is invalid ('%s')") % val)
28 28
29 class path_auditor(object):
30 '''ensure that a filesystem path contains no banned components.
31 the following properties of a path are checked:
32
33 - ends with a directory separator
34 - under top-level .hg
35 - starts at the root of a windows drive
36 - contains ".."
37 - traverses a symlink (e.g. a/symlink_here/b)
38 - inside a nested repository (a callback can be used to approve
39 some nested repositories, e.g., subrepositories)
40 '''
41
42 def __init__(self, root, callback=None):
43 self.audited = set()
44 self.auditeddir = set()
45 self.root = root
46 self.callback = callback
47
48 def __call__(self, path):
49 '''Check the relative path.
50 path may contain a pattern (e.g. foodir/**.txt)'''
51
52 if path in self.audited:
53 return
54 # AIX ignores "/" at end of path, others raise EISDIR.
55 if util.endswithsep(path):
56 raise util.Abort(_("path ends in directory separator: %s") % path)
57 normpath = os.path.normcase(path)
58 parts = util.splitpath(normpath)
59 if (os.path.splitdrive(path)[0]
60 or parts[0].lower() in ('.hg', '.hg.', '')
61 or os.pardir in parts):
62 raise util.Abort(_("path contains illegal component: %s") % path)
63 if '.hg' in path.lower():
64 lparts = [p.lower() for p in parts]
65 for p in '.hg', '.hg.':
66 if p in lparts[1:]:
67 pos = lparts.index(p)
68 base = os.path.join(*parts[:pos])
69 raise util.Abort(_('path %r is inside nested repo %r')
70 % (path, base))
71
72 parts.pop()
73 prefixes = []
74 while parts:
75 prefix = os.sep.join(parts)
76 if prefix in self.auditeddir:
77 break
78 curpath = os.path.join(self.root, prefix)
79 try:
80 st = os.lstat(curpath)
81 except OSError, err:
82 # EINVAL can be raised as invalid path syntax under win32.
83 # They must be ignored for patterns can be checked too.
84 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
85 raise
86 else:
87 if stat.S_ISLNK(st.st_mode):
88 raise util.Abort(
89 _('path %r traverses symbolic link %r')
90 % (path, prefix))
91 elif (stat.S_ISDIR(st.st_mode) and
92 os.path.isdir(os.path.join(curpath, '.hg'))):
93 if not self.callback or not self.callback(curpath):
94 raise util.Abort(_('path %r is inside nested repo %r') %
95 (path, prefix))
96 prefixes.append(prefix)
97 parts.pop()
98
99 self.audited.add(path)
100 # only add prefixes to the cache after checking everything: we don't
101 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
102 self.auditeddir.update(prefixes)
103
29 104 class opener(object):
30 105 '''Open files relative to a base directory
31 106
@@ -35,7 +110,7 b' class opener(object):'
35 110 def __init__(self, base, audit=True):
36 111 self.base = base
37 112 if audit:
38 self.auditor = util.path_auditor(base)
113 self.auditor = path_auditor(base)
39 114 else:
40 115 self.auditor = util.always
41 116 self.createmode = None
@@ -132,7 +207,7 b' def canonpath(root, cwd, myname, auditor'
132 207 name = os.path.join(root, cwd, name)
133 208 name = os.path.normpath(name)
134 209 if auditor is None:
135 auditor = util.path_auditor(root)
210 auditor = path_auditor(root)
136 211 if name != rootsep and name.startswith(rootsep):
137 212 name = name[len(rootsep):]
138 213 auditor(name)
@@ -8,7 +8,7 b''
8 8 import errno, os, re, xml.dom.minidom, shutil, posixpath
9 9 import stat, subprocess, tarfile
10 10 from i18n import _
11 import config, util, node, error, cmdutil, url, bookmarks
11 import config, scmutil, util, node, error, cmdutil, url, bookmarks
12 12 hg = None
13 13
14 14 nullstate = ('', '', 'empty')
@@ -234,7 +234,7 b' def subrepo(ctx, path):'
234 234 import hg as h
235 235 hg = h
236 236
237 util.path_auditor(ctx._repo.root)(path)
237 scmutil.path_auditor(ctx._repo.root)(path)
238 238 state = ctx.substate.get(path, nullstate)
239 239 if state[2] not in types:
240 240 raise util.Abort(_('unknown subrepo type %s') % state[2])
@@ -16,7 +16,7 b' hide platform-specific details from the '
16 16 from i18n import _
17 17 import error, osutil, encoding
18 18 import errno, re, shutil, sys, tempfile, traceback
19 import os, stat, time, calendar, textwrap, unicodedata, signal
19 import os, time, calendar, textwrap, unicodedata, signal
20 20 import imp, socket
21 21
22 22 # Python compatibility
@@ -492,80 +492,6 b' def checkwinfilename(path):'
492 492 return _("filename ends with '%s', which is not allowed "
493 493 "on Windows") % t
494 494
495 class path_auditor(object):
496 '''ensure that a filesystem path contains no banned components.
497 the following properties of a path are checked:
498
499 - ends with a directory separator
500 - under top-level .hg
501 - starts at the root of a windows drive
502 - contains ".."
503 - traverses a symlink (e.g. a/symlink_here/b)
504 - inside a nested repository (a callback can be used to approve
505 some nested repositories, e.g., subrepositories)
506 '''
507
508 def __init__(self, root, callback=None):
509 self.audited = set()
510 self.auditeddir = set()
511 self.root = root
512 self.callback = callback
513
514 def __call__(self, path):
515 '''Check the relative path.
516 path may contain a pattern (e.g. foodir/**.txt)'''
517
518 if path in self.audited:
519 return
520 # AIX ignores "/" at end of path, others raise EISDIR.
521 if endswithsep(path):
522 raise Abort(_("path ends in directory separator: %s") % path)
523 normpath = os.path.normcase(path)
524 parts = splitpath(normpath)
525 if (os.path.splitdrive(path)[0]
526 or parts[0].lower() in ('.hg', '.hg.', '')
527 or os.pardir in parts):
528 raise Abort(_("path contains illegal component: %s") % path)
529 if '.hg' in path.lower():
530 lparts = [p.lower() for p in parts]
531 for p in '.hg', '.hg.':
532 if p in lparts[1:]:
533 pos = lparts.index(p)
534 base = os.path.join(*parts[:pos])
535 raise Abort(_('path %r is inside nested repo %r')
536 % (path, base))
537
538 parts.pop()
539 prefixes = []
540 while parts:
541 prefix = os.sep.join(parts)
542 if prefix in self.auditeddir:
543 break
544 curpath = os.path.join(self.root, prefix)
545 try:
546 st = os.lstat(curpath)
547 except OSError, err:
548 # EINVAL can be raised as invalid path syntax under win32.
549 # They must be ignored for patterns can be checked too.
550 if err.errno not in (errno.ENOENT, errno.ENOTDIR, errno.EINVAL):
551 raise
552 else:
553 if stat.S_ISLNK(st.st_mode):
554 raise Abort(_('path %r traverses symbolic link %r') %
555 (path, prefix))
556 elif (stat.S_ISDIR(st.st_mode) and
557 os.path.isdir(os.path.join(curpath, '.hg'))):
558 if not self.callback or not self.callback(curpath):
559 raise Abort(_('path %r is inside nested repo %r') %
560 (path, prefix))
561 prefixes.append(prefix)
562 parts.pop()
563
564 self.audited.add(path)
565 # only add prefixes to the cache after checking everything: we don't
566 # want to add "foo/bar/baz" before checking if there's a "foo/.hg"
567 self.auditeddir.update(prefixes)
568
569 495 def lookup_reg(key, name=None, scope=None):
570 496 return None
571 497
General Comments 0
You need to be logged in to leave comments. Login now