On windows add a wait when hardlinking to account for broken network

filesystems
This commit is contained in:
Kovid Goyal 2013-07-22 10:46:29 +05:30
parent f5eda364e6
commit 3b345d3ff5

View File

@ -3,7 +3,7 @@ Make strings safe for use as ASCII filenames, while trying to preserve as much
meaning as possible. meaning as possible.
''' '''
import os, errno import os, errno, time
from math import ceil from math import ceil
from calibre import sanitize_file_name, isbytestring, force_unicode from calibre import sanitize_file_name, isbytestring, force_unicode
@ -257,6 +257,19 @@ def samefile(src, dst):
os.path.normcase(os.path.abspath(dst))) os.path.normcase(os.path.abspath(dst)))
return samestring return samestring
def windows_get_size(path):
''' On windows file sizes are only accurately stored in the actual file,
not in the directory entry (which could be out of date). So we open the
file, and get the actual size. '''
import win32file
h = win32file.CreateFile(
path, 0, win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE | win32file.FILE_SHARE_DELETE,
None, win32file.OPEN_EXISTING, 0, None)
try:
return win32file.GetFileSize(h)
finally:
win32file.CloseHandle(h)
def windows_hardlink(src, dest): def windows_hardlink(src, dest):
import win32file, pywintypes import win32file, pywintypes
try: try:
@ -264,17 +277,21 @@ def windows_hardlink(src, dest):
except pywintypes.error as e: except pywintypes.error as e:
msg = u'Creating hardlink from %s to %s failed: %%s' % (src, dest) msg = u'Creating hardlink from %s to %s failed: %%s' % (src, dest)
raise Exception(msg % e) raise Exception(msg % e)
src_size = os.path.getsize(src)
# We open and close dest, to ensure its directory entry is updated # We open and close dest, to ensure its directory entry is updated
# see http://blogs.msdn.com/b/oldnewthing/archive/2011/12/26/10251026.aspx # see http://blogs.msdn.com/b/oldnewthing/archive/2011/12/26/10251026.aspx
h = win32file.CreateFile( for i in range(10):
dest, 0, win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE | win32file.FILE_SHARE_DELETE, # If we are on a network filesystem, we have to wait for some indeterminate time, since
None, win32file.OPEN_EXISTING, 0, None) # network file systems are the best thing since sliced bread
try: try:
sz = win32file.GetFileSize(h) if windows_get_size(dest) == src_size:
finally: return
win32file.CloseHandle(h) except EnvironmentError:
pass
time.sleep(0.3)
if sz != os.path.getsize(src): sz = windows_get_size(dest)
if sz != src_size:
msg = u'Creating hardlink from %s to %s failed: %%s' % (src, dest) msg = u'Creating hardlink from %s to %s failed: %%s' % (src, dest)
raise Exception(msg % ('hardlink size: %d not the same as source size' % sz)) raise Exception(msg % ('hardlink size: %d not the same as source size' % sz))