This commit is contained in:
Kovid Goyal 2017-02-01 13:24:33 +05:30
parent 0b9aa7d119
commit f8202dc3e3

View File

@ -1,7 +1,6 @@
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
'''
Secure access to locked files from multiple processes.
'''
@ -24,7 +23,8 @@ class WindowsExclFile(object):
while timeout > 0:
timeout -= 1
try:
self._handle = w.CreateFile(path,
self._handle = w.CreateFile(
path,
w.GENERIC_READ | w.GENERIC_WRITE, # Open for reading and writing
0, # Open exclusive
None, # No security attributes, ensures handle is not inherited by children
@ -118,15 +118,24 @@ def unix_open(path):
has_cloexec = False
if hasattr(speedup, 'O_CLOEXEC'):
try:
fd = os.open(path, flags | speedup.O_CLOEXEC, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
fd = os.open(
path, flags | speedup.O_CLOEXEC, stat.S_IRUSR | stat.S_IWUSR |
stat.S_IRGRP | stat.S_IROTH
)
has_cloexec = True
except EnvironmentError as err:
if getattr(err, 'errno', None) == errno.EINVAL: # Kernel does not support O_CLOEXEC
fd = os.open(path, flags, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
if getattr(err, 'errno', None) == errno.EINVAL:
# Kernel does not support O_CLOEXEC
fd = os.open(
path, flags, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP |
stat.S_IROTH
)
else:
raise
else:
fd = os.open(path, flags, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
fd = os.open(
path, flags, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
)
if not has_cloexec:
fcntl.fcntl(fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
@ -140,7 +149,8 @@ class ExclusiveFile(object):
self.timeout = timeout
def __enter__(self):
self.file = WindowsExclFile(self.path, self.timeout) if iswindows else unix_open(self.path)
self.file = WindowsExclFile(self.path, self.timeout
) if iswindows else unix_open(self.path)
self.file.seek(0)
timeout = self.timeout
if not iswindows:
@ -168,18 +178,23 @@ def test_exclusive_file(path=None):
# Try same process lock
try:
with ExclusiveFile(f, timeout=1):
raise LockError("ExclusiveFile failed to prevent multiple uses in the same process!")
raise LockError(
"ExclusiveFile failed to prevent multiple uses in the same process!"
)
except LockError:
pass
# Try different process lock
from calibre.utils.ipc.simple_worker import fork_job
err = fork_job('calibre.utils.lock', 'test_exclusive_file', (f,))['result']
err = fork_job('calibre.utils.lock', 'test_exclusive_file',
(f, ))['result']
if err is not None:
raise LockError('ExclusiveFile failed with error: %s' % err)
else:
try:
with ExclusiveFile(path, timeout=1):
raise Exception('ExclusiveFile failed to prevent multiple uses in different processes!')
raise Exception(
'ExclusiveFile failed to prevent multiple uses in different processes!'
)
except LockError:
pass
except Exception as err:
@ -196,7 +211,9 @@ def _clean_lock_file(file):
except:
pass
if iswindows:
def singleinstance(name):
mutexname = 'mutexforsingleinstanceof' + __appname__ + name
mutex = win32event.CreateMutex(None, False, mutexname)
@ -209,6 +226,7 @@ if iswindows:
atexit.register(win32api.CloseHandle, mutex)
return not err == winerror.ERROR_ALREADY_EXISTS
elif islinux:
def singleinstance(name):
import socket
from calibre.utils.ipc import eintr_retry_call
@ -229,10 +247,12 @@ elif islinux:
atexit.register(sock.close)
return True
elif ishaiku:
def singleinstance(name):
# Somebody should fix this.
return True
else:
def singleinstance_path(name):
home = os.path.expanduser('~')
if os.access(home, os.W_OK | os.R_OK | os.X_OK):
@ -240,7 +260,9 @@ else:
return os.path.expanduser('~/.' + basename)
import tempfile
tdir = tempfile.gettempdir()
return os.path.join(tdir, '%s_%s_%s.lock' % (__appname__, name, os.geteuid()))
return os.path.join(
tdir, '%s_%s_%s.lock' % (__appname__, name, os.geteuid())
)
def singleinstance(name):
'''