comparison mercurial/util.py @ 29204:ce2d81aafbae

util: make copyfile avoid ambiguity of file stat if needed In some cases below, copying from backup is used to restore original contents of a file. If copying keeps ctime, mtime and size of a file, restoring is overlooked, and old contents cached before restoring isn't invalidated as expected. - failure of transaction before closing (from '.hg/journal.backup.*') - rollback of previous transaction (from '.hg/undo.backup.*') To avoid such problem, this patch makes copyfile() avoid ambiguity of file stat, if needed. Ambiguity check is executed, only if: - checkambig=True is specified (not all copying needs ambiguity check), and - destination file exists before copying This patch also adds 'not (copystat and checkambig)' assertion, because combination of copystat and checkambig is meaningless. This patch is a part of preparation for "Exact Cache Validation Plan": https://www.mercurial-scm.org/wiki/ExactCacheValidationPlan
author FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
date Thu, 19 May 2016 00:20:38 +0900
parents a109bf7e0dc2
children 1eff545cef52
comparison
equal deleted inserted replaced
29203:731ced087a4b 29204:ce2d81aafbae
1008 raise error.SignatureError 1008 raise error.SignatureError
1009 raise 1009 raise
1010 1010
1011 return check 1011 return check
1012 1012
1013 def copyfile(src, dest, hardlink=False, copystat=False): 1013 def copyfile(src, dest, hardlink=False, copystat=False, checkambig=False):
1014 '''copy a file, preserving mode and optionally other stat info like 1014 '''copy a file, preserving mode and optionally other stat info like
1015 atime/mtime''' 1015 atime/mtime'''
1016 assert not (copystat and checkambig)
1017 oldstat = None
1016 if os.path.lexists(dest): 1018 if os.path.lexists(dest):
1019 if checkambig:
1020 oldstat = checkambig and filestat(dest)
1017 unlink(dest) 1021 unlink(dest)
1018 # hardlinks are problematic on CIFS, quietly ignore this flag 1022 # hardlinks are problematic on CIFS, quietly ignore this flag
1019 # until we find a way to work around it cleanly (issue4546) 1023 # until we find a way to work around it cleanly (issue4546)
1020 if False and hardlink: 1024 if False and hardlink:
1021 try: 1025 try:
1033 if copystat: 1037 if copystat:
1034 # copystat also copies mode 1038 # copystat also copies mode
1035 shutil.copystat(src, dest) 1039 shutil.copystat(src, dest)
1036 else: 1040 else:
1037 shutil.copymode(src, dest) 1041 shutil.copymode(src, dest)
1042 if oldstat and oldstat.stat:
1043 newstat = filestat(dest)
1044 if newstat.isambig(oldstat):
1045 # stat of copied file is ambiguous to original one
1046 advanced = (oldstat.stat.st_mtime + 1) & 0x7fffffff
1047 os.utime(dest, (advanced, advanced))
1038 except shutil.Error as inst: 1048 except shutil.Error as inst:
1039 raise Abort(str(inst)) 1049 raise Abort(str(inst))
1040 1050
1041 def copyfiles(src, dst, hardlink=None, progress=lambda t, pos: None): 1051 def copyfiles(src, dst, hardlink=None, progress=lambda t, pos: None):
1042 """Copy a directory tree using hardlinks if possible.""" 1052 """Copy a directory tree using hardlinks if possible."""