mercurial/util.py
changeset 13916 98ee3dd5bab4
parent 13910 93452579df9e
child 13926 61ba09d8d118
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):