mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Further simplify windows exclusive file by using open_osfhandle
This commit is contained in:
parent
55844a8b8e
commit
58840260cf
@ -13,13 +13,13 @@ import time
|
|||||||
|
|
||||||
from calibre.constants import (
|
from calibre.constants import (
|
||||||
__appname__, fcntl, filesystem_encoding, ishaiku, islinux, iswindows, win32api,
|
__appname__, fcntl, filesystem_encoding, ishaiku, islinux, iswindows, win32api,
|
||||||
win32event, winerror
|
win32event
|
||||||
)
|
)
|
||||||
from calibre.utils.monotonic import monotonic
|
from calibre.utils.monotonic import monotonic
|
||||||
|
|
||||||
if iswindows:
|
if iswindows:
|
||||||
excl_file_mode = stat.S_IREAD | stat.S_IWRITE
|
excl_file_mode = stat.S_IREAD | stat.S_IWRITE
|
||||||
import msvcrt
|
import msvcrt, win32file, pywintypes, winerror
|
||||||
else:
|
else:
|
||||||
excl_file_mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
|
excl_file_mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
|
||||||
|
|
||||||
@ -44,28 +44,40 @@ def unix_open(path):
|
|||||||
return os.fdopen(fd, 'r+b')
|
return os.fdopen(fd, 'r+b')
|
||||||
|
|
||||||
|
|
||||||
|
def unix_retry(err):
|
||||||
|
return err.errno in (errno.EACCES, errno.EAGAIN, errno.ENOLCK, errno.EINTR)
|
||||||
|
|
||||||
|
|
||||||
def windows_open(path):
|
def windows_open(path):
|
||||||
flags = os.O_RDWR | os.O_CREAT | os.O_NOINHERIT | os.O_BINARY
|
try:
|
||||||
fd = os.open(path, flags, excl_file_mode)
|
h = win32file.CreateFile(
|
||||||
return os.fdopen(fd, 'r+bN')
|
path,
|
||||||
|
win32file.GENERIC_READ | win32file.GENERIC_WRITE, # Open for reading and writing
|
||||||
|
0, # Open exclusive
|
||||||
|
None, # No security attributes, ensures handle is not inherited by children
|
||||||
|
win32file.OPEN_ALWAYS, # If file does not exist, create it
|
||||||
|
win32file.FILE_ATTRIBUTE_NORMAL, # Normal attributes
|
||||||
|
None, # No template file
|
||||||
|
)
|
||||||
|
except pywintypes.error as err:
|
||||||
|
raise WindowsError(err[0], err[2], path)
|
||||||
|
fd = msvcrt.open_osfhandle(h.Detach(), 0)
|
||||||
|
return os.fdopen(fd, 'r+b')
|
||||||
|
|
||||||
|
|
||||||
class TimeoutError(Exception):
|
def windows_retry(err):
|
||||||
pass
|
return err.winerror in (winerror.ERROR_SHARING_VIOLATION, winerror.ERROR_LOCK_VIOLATION)
|
||||||
|
|
||||||
|
|
||||||
def retry_for_a_time(timeout, sleep_time, func, *args):
|
def retry_for_a_time(timeout, sleep_time, func, error_retry, *args):
|
||||||
limit = monotonic() + timeout
|
limit = monotonic() + timeout
|
||||||
last_error = None
|
while True:
|
||||||
while monotonic() <= limit:
|
|
||||||
try:
|
try:
|
||||||
return func(*args)
|
return func(*args)
|
||||||
except EnvironmentError as err:
|
except EnvironmentError as err:
|
||||||
last_error = err.args
|
if not error_retry(err) or monotonic() > limit:
|
||||||
if monotonic() > limit:
|
raise
|
||||||
break
|
|
||||||
time.sleep(sleep_time)
|
time.sleep(sleep_time)
|
||||||
raise TimeoutError(*last_error)
|
|
||||||
|
|
||||||
|
|
||||||
class ExclusiveFile(object):
|
class ExclusiveFile(object):
|
||||||
@ -79,30 +91,20 @@ class ExclusiveFile(object):
|
|||||||
self.sleep_time = sleep_time
|
self.sleep_time = sleep_time
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
try:
|
if iswindows:
|
||||||
if iswindows:
|
self.file = retry_for_a_time(
|
||||||
f = windows_open(self.path)
|
self.timeout, self.sleep_time, windows_open, windows_retry, self.path
|
||||||
retry_for_a_time(
|
)
|
||||||
self.timeout, self.sleep_time, msvcrt.locking,
|
else:
|
||||||
f.fileno(), msvcrt.LK_NBLCK, 1
|
f = unix_open(self.path)
|
||||||
)
|
retry_for_a_time(
|
||||||
else:
|
self.timeout, self.sleep_time, fcntl.flock, unix_retry,
|
||||||
f = unix_open(self.path)
|
f.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB
|
||||||
retry_for_a_time(
|
)
|
||||||
self.timeout, self.sleep_time, fcntl.flock,
|
|
||||||
f.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB
|
|
||||||
)
|
|
||||||
self.file = f
|
self.file = f
|
||||||
except TimeoutError as err:
|
|
||||||
raise OSError(*(list(err.args)[:2] + [self.path]))
|
|
||||||
return self.file
|
return self.file
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
def __exit__(self, type, value, traceback):
|
||||||
if iswindows:
|
|
||||||
try:
|
|
||||||
msvcrt.locking(self.file.fileno(), msvcrt.LK_UNLCK, 1)
|
|
||||||
except EnvironmentError:
|
|
||||||
pass
|
|
||||||
self.file.close()
|
self.file.close()
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user