Mercurial > public > mercurial-scm > hg
comparison mercurial/util.py @ 13916:98ee3dd5bab4
path_auditor: check filenames for basic platform validity (issue2755)
Example (on Windows):
$ hg parents
$ hg manifest tip
con.xml
$ hg update
abort: filename contains 'con', which is reserved on Windows: con.xml
Before this patch, update produced (as explained in issue2755):
$ hg update
abort: No usable temporary filename found
I've added the new function checkwinfilename to util.py and not to windows.py,
so that we can later call it when running on posix platforms too, for when we
decide to implement a (configurable) warning message on 'hg add'.
As per this patch, checkwinfilename is currently only used when running
on Windwows.
path_auditor calls checkosfilename, which is a NOP on posix and an alias for
checkwinfilename on Windows.
author | Adrian Buehlmann <adrian@cadifra.com> |
---|---|
date | Wed, 06 Apr 2011 18:09:43 +0200 |
parents | 93452579df9e |
children | 61ba09d8d118 |
comparison
equal
deleted
inserted
replaced
13915:8f81d6f4047f | 13916:98ee3dd5bab4 |
---|---|
490 else: | 490 else: |
491 shutil.copy(src, dst) | 491 shutil.copy(src, dst) |
492 num += 1 | 492 num += 1 |
493 | 493 |
494 return hardlink, num | 494 return hardlink, num |
495 | |
496 _windows_reserved_filenames = '''con prn aux nul | |
497 com1 com2 com3 com4 com5 com6 com7 com8 com9 | |
498 lpt1 lpt2 lpt3 lpt4 lpt5 lpt6 lpt7 lpt8 lpt9'''.split() | |
499 _windows_reserved_chars = ':*?"<>|' | |
500 def checkwinfilename(path): | |
501 '''Check that the base-relative path is a valid filename on Windows. | |
502 Returns None if the path is ok, or a UI string describing the problem. | |
503 | |
504 >>> checkwinfilename("just/a/normal/path") | |
505 >>> checkwinfilename("foo/bar/con.xml") | |
506 "filename contains 'con', which is reserved on Windows" | |
507 >>> checkwinfilename("foo/con.xml/bar") | |
508 "filename contains 'con', which is reserved on Windows" | |
509 >>> checkwinfilename("foo/bar/xml.con") | |
510 >>> checkwinfilename("foo/bar/AUX/bla.txt") | |
511 "filename contains 'AUX', which is reserved on Windows" | |
512 >>> checkwinfilename("foo/bar/bla:.txt") | |
513 "filename contains ':', which is reserved on Windows" | |
514 >>> checkwinfilename("foo/bar/b\07la.txt") | |
515 "filename contains '\\x07', which is invalid on Windows" | |
516 >>> checkwinfilename("foo/bar/bla ") | |
517 "filename ends with ' ', which is not allowed on Windows" | |
518 ''' | |
519 for n in path.replace('\\', '/').split('/'): | |
520 if not n: | |
521 continue | |
522 for c in n: | |
523 if c in _windows_reserved_chars: | |
524 return _("filename contains '%s', which is reserved " | |
525 "on Windows") % c | |
526 if ord(c) <= 31: | |
527 return _("filename contains '%s', which is invalid " | |
528 "on Windows") % c | |
529 base = n.split('.')[0] | |
530 if base and base.lower() in _windows_reserved_filenames: | |
531 return _("filename contains '%s', which is reserved " | |
532 "on Windows") % base | |
533 t = n[-1] | |
534 if t in '. ': | |
535 return _("filename ends with '%s', which is not allowed " | |
536 "on Windows") % t | |
495 | 537 |
496 class path_auditor(object): | 538 class path_auditor(object): |
497 '''ensure that a filesystem path contains no banned components. | 539 '''ensure that a filesystem path contains no banned components. |
498 the following properties of a path are checked: | 540 the following properties of a path are checked: |
499 | 541 |
558 break | 600 break |
559 check(prefix) | 601 check(prefix) |
560 prefixes.append(prefix) | 602 prefixes.append(prefix) |
561 parts.pop() | 603 parts.pop() |
562 | 604 |
605 r = checkosfilename(path) | |
606 if r: | |
607 raise Abort("%s: %s" % (r, path)) | |
563 self.audited.add(path) | 608 self.audited.add(path) |
564 # only add prefixes to the cache after checking everything: we don't | 609 # only add prefixes to the cache after checking everything: we don't |
565 # want to add "foo/bar/baz" before checking if there's a "foo/.hg" | 610 # want to add "foo/bar/baz" before checking if there's a "foo/.hg" |
566 self.auditeddir.update(prefixes) | 611 self.auditeddir.update(prefixes) |
567 | 612 |
575 child process under Windows, unneeded on other systems. | 620 child process under Windows, unneeded on other systems. |
576 """ | 621 """ |
577 pass | 622 pass |
578 | 623 |
579 if os.name == 'nt': | 624 if os.name == 'nt': |
625 checkosfilename = checkwinfilename | |
580 from windows import * | 626 from windows import * |
581 else: | 627 else: |
582 from posix import * | 628 from posix import * |
583 | 629 |
584 def makelock(info, pathname): | 630 def makelock(info, pathname): |