306
303
if have_pywin32 and sys.platform == 'win32':
307
LOCK_SH = 0 # the default
308
LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
309
LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
304
if os.path.supports_unicode_filenames:
305
# for Windows NT/2K/XP/etc
306
win32file_CreateFile = win32file.CreateFileW
309
win32file_CreateFile = win32file.CreateFile
312
311
class _w32c_FileLock(_OSLock):
314
def _lock(self, filename, openmode, lockmode):
315
self._open(filename, openmode)
317
self.hfile = msvcrt.get_osfhandle(self.f.fileno())
318
overlapped = pywintypes.OVERLAPPED()
313
def _open(self, filename, access, share, cflags, pymode):
314
self.filename = osutils.realpath(filename)
320
win32file.LockFileEx(self.hfile, lockmode, 0, 0x7fff0000,
316
self._handle = win32file_CreateFile(filename, access, share,
317
None, win32file.OPEN_ALWAYS,
318
win32file.FILE_ATTRIBUTE_NORMAL, None)
322
319
except pywintypes.error, e:
324
if e.args[0] in (winerror.ERROR_LOCK_VIOLATION,):
325
raise errors.LockContention(filename)
326
## import pdb; pdb.set_trace()
320
if e.args[0] == winerror.ERROR_ACCESS_DENIED:
321
raise errors.LockFailed(filename, e)
322
if e.args[0] == winerror.ERROR_SHARING_VIOLATION:
323
raise errors.LockContention(filename, e)
330
raise errors.LockContention(filename, e)
325
fd = win32file._open_osfhandle(self._handle, cflags)
326
self.f = os.fdopen(fd, pymode)
332
329
def unlock(self):
333
overlapped = pywintypes.OVERLAPPED()
335
win32file.UnlockFileEx(self.hfile, 0, 0x7fff0000, overlapped)
338
raise errors.LockContention(self.filename, e)
341
334
class _w32c_ReadLock(_w32c_FileLock):
342
335
def __init__(self, filename):
343
336
super(_w32c_ReadLock, self).__init__()
344
self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
337
self._open(filename, win32file.GENERIC_READ,
338
win32file.FILE_SHARE_READ, os.O_RDONLY, "rb")
346
340
def temporary_write_lock(self):
347
341
"""Try to grab a write lock on the file.
382
378
if have_ctypes_win32:
383
# These constants were copied from the win32con.py module.
384
LOCKFILE_FAIL_IMMEDIATELY = 1
385
LOCKFILE_EXCLUSIVE_LOCK = 2
386
# Constant taken from winerror.py module
387
ERROR_LOCK_VIOLATION = 33
390
LOCK_EX = LOCKFILE_EXCLUSIVE_LOCK
391
LOCK_NB = LOCKFILE_FAIL_IMMEDIATELY
392
_LockFileEx = ctypes.windll.kernel32.LockFileEx
393
_UnlockFileEx = ctypes.windll.kernel32.UnlockFileEx
395
### Define the OVERLAPPED structure.
396
# http://msdn2.microsoft.com/en-us/library/ms684342.aspx
397
# typedef struct _OVERLAPPED {
398
# ULONG_PTR Internal;
399
# ULONG_PTR InternalHigh;
410
class _inner_struct(ctypes.Structure):
411
_fields_ = [('Offset', ctypes.c_uint), # DWORD
412
('OffsetHigh', ctypes.c_uint), # DWORD
415
class _inner_union(ctypes.Union):
416
_fields_ = [('anon_struct', _inner_struct), # struct
417
('Pointer', ctypes.c_void_p), # PVOID
420
class OVERLAPPED(ctypes.Structure):
421
_fields_ = [('Internal', ctypes.c_void_p), # ULONG_PTR
422
('InternalHigh', ctypes.c_void_p), # ULONG_PTR
423
('_inner_union', _inner_union),
424
('hEvent', ctypes.c_void_p), # HANDLE
379
from ctypes.wintypes import DWORD, LPCSTR, LPCWSTR
380
LPSECURITY_ATTRIBUTES = ctypes.c_void_p # used as NULL no need to declare
381
HANDLE = ctypes.c_int # rather than unsigned as in ctypes.wintypes
382
if os.path.supports_unicode_filenames:
383
_function_name = "CreateFileW"
386
_function_name = "CreateFileA"
387
class LPTSTR(LPCSTR):
388
def __new__(cls, obj):
389
return LPCSTR.__new__(cls, obj.encode("mbcs"))
391
# CreateFile <http://msdn.microsoft.com/en-us/library/aa363858.aspx>
392
_CreateFile = ctypes.WINFUNCTYPE(
393
HANDLE, # return value
395
DWORD, # dwDesiredAccess
397
LPSECURITY_ATTRIBUTES, # lpSecurityAttributes
398
DWORD, # dwCreationDisposition
399
DWORD, # dwFlagsAndAttributes
400
HANDLE # hTemplateFile
401
)((_function_name, ctypes.windll.kernel32))
403
INVALID_HANDLE_VALUE = -1
405
GENERIC_READ = 0x80000000
406
GENERIC_WRITE = 0x40000000
409
FILE_ATTRIBUTE_NORMAL = 128
411
ERROR_ACCESS_DENIED = 5
412
ERROR_SHARING_VIOLATION = 32
427
414
class _ctypes_FileLock(_OSLock):
429
def _lock(self, filename, openmode, lockmode):
430
self._open(filename, openmode)
432
self.hfile = msvcrt.get_osfhandle(self.f.fileno())
433
overlapped = OVERLAPPED()
434
result = _LockFileEx(self.hfile, # HANDLE hFile
435
lockmode, # DWORD dwFlags
436
0, # DWORD dwReserved
437
0x7fffffff, # DWORD nNumberOfBytesToLockLow
438
0x00000000, # DWORD nNumberOfBytesToLockHigh
439
ctypes.byref(overlapped), # lpOverlapped
442
last_err = ctypes.GetLastError()
444
if last_err in (ERROR_LOCK_VIOLATION,):
445
raise errors.LockContention(filename)
446
raise errors.LockContention(filename,
447
'Unknown locking error: %s' % (last_err,))
416
def _open(self, filename, access, share, cflags, pymode):
417
self.filename = osutils.realpath(filename)
418
handle = _CreateFile(filename, access, share, None, OPEN_ALWAYS,
419
FILE_ATTRIBUTE_NORMAL, 0)
420
if handle in (INVALID_HANDLE_VALUE, 0):
421
e = ctypes.WinError()
422
if e.args[0] == ERROR_ACCESS_DENIED:
423
raise errors.LockFailed(filename, e)
424
if e.args[0] == ERROR_SHARING_VIOLATION:
425
raise errors.LockContention(filename, e)
427
fd = msvcrt.open_osfhandle(handle, cflags)
428
self.f = os.fdopen(fd, pymode)
449
431
def unlock(self):
450
overlapped = OVERLAPPED()
451
result = _UnlockFileEx(self.hfile, # HANDLE hFile
452
0, # DWORD dwReserved
453
0x7fffffff, # DWORD nNumberOfBytesToLockLow
454
0x00000000, # DWORD nNumberOfBytesToLockHigh
455
ctypes.byref(overlapped), # lpOverlapped
458
last_err = ctypes.GetLastError()
460
raise errors.LockContention(self.filename,
461
'Unknown unlocking error: %s' % (last_err,))
465
435
class _ctypes_ReadLock(_ctypes_FileLock):
466
436
def __init__(self, filename):
467
437
super(_ctypes_ReadLock, self).__init__()
468
self._lock(filename, 'rb', LOCK_SH + LOCK_NB)
438
self._open(filename, GENERIC_READ, FILE_SHARE_READ, os.O_RDONLY,
470
441
def temporary_write_lock(self):
471
442
"""Try to grab a write lock on the file.