5 # This software may be used and distributed according to the terms of the |
5 # This software may be used and distributed according to the terms of the |
6 # GNU General Public License version 2 or any later version. |
6 # GNU General Public License version 2 or any later version. |
7 |
7 |
8 from i18n import _ |
8 from i18n import _ |
9 import osutil, error |
9 import osutil, error |
10 import errno, msvcrt, os, re, sys, random, subprocess |
10 import errno, msvcrt, os, re, sys, subprocess |
11 |
11 |
12 nulldev = 'NUL:' |
12 nulldev = 'NUL:' |
13 umask = 002 |
13 umask = 002 |
14 |
14 |
15 # wrap osutil.posixfile to provide friendlier exceptions |
15 # wrap osutil.posixfile to provide friendlier exceptions |
291 try: |
291 try: |
292 _removedirs(os.path.dirname(f)) |
292 _removedirs(os.path.dirname(f)) |
293 except OSError: |
293 except OSError: |
294 pass |
294 pass |
295 |
295 |
296 def unlink(f): |
|
297 '''try to implement POSIX' unlink semantics on Windows''' |
|
298 |
|
299 # POSIX allows to unlink and rename open files. Windows has serious |
|
300 # problems with doing that: |
|
301 # - Calling os.unlink (or os.rename) on a file f fails if f or any |
|
302 # hardlinked copy of f has been opened with Python's open(). There is no |
|
303 # way such a file can be deleted or renamed on Windows (other than |
|
304 # scheduling the delete or rename for the next reboot). |
|
305 # - Calling os.unlink on a file that has been opened with Mercurial's |
|
306 # posixfile (or comparable methods) will delay the actual deletion of |
|
307 # the file for as long as the file is held open. The filename is blocked |
|
308 # during that time and cannot be used for recreating a new file under |
|
309 # that same name ("zombie file"). Directories containing such zombie files |
|
310 # cannot be removed or moved. |
|
311 # A file that has been opened with posixfile can be renamed, so we rename |
|
312 # f to a random temporary name before calling os.unlink on it. This allows |
|
313 # callers to recreate f immediately while having other readers do their |
|
314 # implicit zombie filename blocking on a temporary name. |
|
315 |
|
316 for tries in xrange(10): |
|
317 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff)) |
|
318 try: |
|
319 os.rename(f, temp) # raises OSError EEXIST if temp exists |
|
320 break |
|
321 except OSError, e: |
|
322 if e.errno != errno.EEXIST: |
|
323 raise |
|
324 else: |
|
325 raise IOError, (errno.EEXIST, "No usable temporary filename found") |
|
326 |
|
327 try: |
|
328 os.unlink(temp) |
|
329 except: |
|
330 # Some very rude AV-scanners on Windows may cause this unlink to fail. |
|
331 # Not aborting here just leaks the temp file, whereas aborting at this |
|
332 # point may leave serious inconsistencies. Ideally, we would notify |
|
333 # the user in this case here. |
|
334 pass |
|
335 |
|
336 def rename(src, dst): |
296 def rename(src, dst): |
337 '''atomically rename file src to dst, replacing dst if it exists''' |
297 '''atomically rename file src to dst, replacing dst if it exists''' |
338 try: |
298 try: |
339 os.rename(src, dst) |
299 os.rename(src, dst) |
340 except OSError, e: |
300 except OSError, e: |