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