Django

Code

root/django/trunk/django/core/files/move.py

Revision 8720, 2.9 kB (checked in by jacob, 3 months ago)

Fixed #8673: fixed a missing import in django.core.files.move.

Line 
1 """
2 Move a file in the safest way possible::
3
4     >>> from django.core.files.move import file_move_save
5     >>> file_move_save("/tmp/old_file", "/tmp/new_file")
6 """
7
8 import os
9 from django.core.files import locks
10
11 try:
12     from shutil import copystat
13 except ImportError:
14     import stat
15     def copystat(src, dst):
16         """Copy all stat info (mode bits, atime and mtime) from src to dst"""
17         st = os.stat(src)
18         mode = stat.S_IMODE(st.st_mode)
19         if hasattr(os, 'utime'):
20             os.utime(dst, (st.st_atime, st.st_mtime))
21         if hasattr(os, 'chmod'):
22             os.chmod(dst, mode)
23
24 __all__ = ['file_move_safe']
25
26 def _samefile(src, dst):
27     # Macintosh, Unix.
28     if hasattr(os.path,'samefile'):
29         try:
30             return os.path.samefile(src, dst)
31         except OSError:
32             return False
33
34     # All other platforms: check for same pathname.
35     return (os.path.normcase(os.path.abspath(src)) ==
36             os.path.normcase(os.path.abspath(dst)))
37
38 def file_move_safe(old_file_name, new_file_name, chunk_size = 1024*64, allow_overwrite=False):
39     """
40     Moves a file from one location to another in the safest way possible.
41
42     First, try using ``shutils.move``, which is OS-dependent but doesn't break
43     if moving across filesystems. Then, try ``os.rename``, which will break
44     across filesystems. Finally, streams manually from one file to another in
45     pure Python.
46
47     If the destination file exists and ``allow_overwrite`` is ``False``, this
48     function will throw an ``IOError``.
49     """
50
51     # There's no reason to move if we don't have to.
52     if _samefile(old_file_name, new_file_name):
53         return
54
55     try:
56         os.rename(old_file_name, new_file_name)
57         return
58     except OSError:
59         # This will happen with os.rename if moving to another filesystem
60         # or when moving opened files on certain operating systems
61         pass
62
63     # first open the old file, so that it won't go away
64     old_file = open(old_file_name, 'rb')
65     try:
66         # now open the new file, not forgetting allow_overwrite
67         fd = os.open(new_file_name, os.O_WRONLY | os.O_CREAT | getattr(os, 'O_BINARY', 0) |
68                                     (not allow_overwrite and os.O_EXCL or 0))
69         try:
70             locks.lock(fd, locks.LOCK_EX)
71             current_chunk = None
72             while current_chunk != '':
73                 current_chunk = old_file.read(chunk_size)
74                 os.write(fd, current_chunk)
75         finally:
76             locks.unlock(fd)
77             os.close(fd)
78     finally:
79         old_file.close()
80     copystat(old_file_name, new_file_name)
81
82     try:
83         os.remove(old_file_name)
84     except OSError, e:
85         # Certain operating systems (Cygwin and Windows)
86         # fail when deleting opened files, ignore it
87         if getattr(e, 'winerror', 0) != 32:
88             # FIXME: should we also ignore errno 13?
89             raise
Note: See TracBrowser for help on using the browser.