Mercurial > hg
changeset 8255:ea82a23cf887
util.rename: use temporary file name for rename-targets on windows
Use a temporary file name as target for a forced rename on Windows. The
target file name is not opened at any time; just renamed into and then
unlinked. Using a temporary instead of a static name is necessary since
otherwise a hg crash can leave the file lying around, blocking future
attempts at renaming.
author | Sune Foldager <cryo@cyanite.org> |
---|---|
date | Wed, 29 Apr 2009 09:30:28 +0200 |
parents | 965b11c1bd82 |
children | e68e149f4d44 609ce91670d0 |
files | mercurial/util.py |
diffstat | 1 files changed, 20 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/util.py Wed Apr 29 21:44:25 2009 +0200 +++ b/mercurial/util.py Wed Apr 29 09:30:28 2009 +0200 @@ -737,13 +737,28 @@ try: os.rename(src, dst) except OSError, err: # FIXME: check err (EEXIST ?) - # on windows, rename to existing file is not allowed, so we - # must delete destination first. but if file is open, unlink - # schedules it for delete but does not delete it. rename + + # On windows, rename to existing file is not allowed, so we + # must delete destination first. But if a file is open, unlink + # schedules it for delete but does not delete it. Rename # happens immediately even for open files, so we rename - # destination to a temporary name, then delete that. then + # destination to a temporary name, then delete that. Then # rename is safe to do. - temp = dst + "-force-rename" + # The temporary name is chosen at random to avoid the situation + # where a file is left lying around from a previous aborted run. + # The usual race condition this introduces can't be avoided as + # we need the name to rename into, and not the file itself. Due + # to the nature of the operation however, any races will at worst + # lead to the rename failing and the current operation aborting. + + def tempname(prefix): + for tries in xrange(10): + temp = '%s-%08x' % (prefix, random.randint(0, 0xffffffff)) + if not os.path.exists(temp): + return temp + raise IOError, (errno.EEXIST, "No usable temporary filename found") + + temp = tempname(dst) os.rename(dst, temp) os.unlink(temp) os.rename(src, dst)