628 def rename(src, dst): |
628 def rename(src, dst): |
629 """forcibly rename a file""" |
629 """forcibly rename a file""" |
630 try: |
630 try: |
631 os.rename(src, dst) |
631 os.rename(src, dst) |
632 except OSError, err: # FIXME: check err (EEXIST ?) |
632 except OSError, err: # FIXME: check err (EEXIST ?) |
633 # on windows, rename to existing file is not allowed, so we |
633 |
634 # must delete destination first. but if file is open, unlink |
634 # On windows, rename to existing file is not allowed, so we |
635 # schedules it for delete but does not delete it. rename |
635 # must delete destination first. But if a file is open, unlink |
|
636 # schedules it for delete but does not delete it. Rename |
636 # happens immediately even for open files, so we rename |
637 # happens immediately even for open files, so we rename |
637 # destination to a temporary name, then delete that. then |
638 # destination to a temporary name, then delete that. Then |
638 # rename is safe to do. |
639 # rename is safe to do. |
639 temp = dst + "-force-rename" |
640 # The temporary name is chosen at random to avoid the situation |
|
641 # where a file is left lying around from a previous aborted run. |
|
642 # The usual race condition this introduces can't be avoided as |
|
643 # we need the name to rename into, and not the file itself. Due |
|
644 # to the nature of the operation however, any races will at worst |
|
645 # lead to the rename failing and the current operation aborting. |
|
646 |
|
647 def tempname(prefix): |
|
648 for tries in xrange(10): |
|
649 temp = '%s-%08x' % (prefix, random.randint(0, 0xffffffff)) |
|
650 if not os.path.exists(temp): |
|
651 return temp |
|
652 raise IOError, (errno.EEXIST, "No usable temporary filename found") |
|
653 |
|
654 temp = tempname(dst) |
640 os.rename(dst, temp) |
655 os.rename(dst, temp) |
641 os.unlink(temp) |
656 os.unlink(temp) |
642 os.rename(src, dst) |
657 os.rename(src, dst) |
643 |
658 |
644 def unlink(f): |
659 def unlink(f): |