Mercurial > hg-stable
comparison mercurial/util.py @ 13972:d1f4e7fd970a
move path_auditor from util to scmutil
author | Adrian Buehlmann <adrian@cadifra.com> |
---|---|
date | Wed, 20 Apr 2011 22:43:31 +0200 |
parents | bfeaa88b875d |
children | 23f2736abce3 |
comparison
equal
deleted
inserted
replaced
13971:bfeaa88b875d | 13972:d1f4e7fd970a |
---|---|
14 """ | 14 """ |
15 | 15 |
16 from i18n import _ | 16 from i18n import _ |
17 import error, osutil, encoding | 17 import error, osutil, encoding |
18 import errno, re, shutil, sys, tempfile, traceback | 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 import imp, socket | 20 import imp, socket |
21 | 21 |
22 # Python compatibility | 22 # Python compatibility |
23 | 23 |
24 def sha1(s): | 24 def sha1(s): |
490 t = n[-1] | 490 t = n[-1] |
491 if t in '. ': | 491 if t in '. ': |
492 return _("filename ends with '%s', which is not allowed " | 492 return _("filename ends with '%s', which is not allowed " |
493 "on Windows") % t | 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 def lookup_reg(key, name=None, scope=None): | 495 def lookup_reg(key, name=None, scope=None): |
570 return None | 496 return None |
571 | 497 |
572 def hidewindow(): | 498 def hidewindow(): |
573 """Hide current shell window. | 499 """Hide current shell window. |