You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

locks.py 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. """
  2. Portable file locking utilities.
  3. Based partially on an example by Jonathan Feignberg in the Python
  4. Cookbook [1] (licensed under the Python Software License) and a ctypes port by
  5. Anatoly Techtonik for Roundup [2] (license [3]).
  6. [1] http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65203
  7. [2] https://sourceforge.net/p/roundup/code/ci/default/tree/roundup/backends/portalocker.py
  8. [3] https://sourceforge.net/p/roundup/code/ci/default/tree/COPYING.txt
  9. Example Usage::
  10. >>> from django.core.files import locks
  11. >>> with open('./file', 'wb') as f:
  12. ... locks.lock(f, locks.LOCK_EX)
  13. ... f.write('Django')
  14. """
  15. import os
  16. __all__ = ('LOCK_EX', 'LOCK_SH', 'LOCK_NB', 'lock', 'unlock')
  17. def _fd(f):
  18. """Get a filedescriptor from something which could be a file or an fd."""
  19. return f.fileno() if hasattr(f, 'fileno') else f
  20. if os.name == 'nt':
  21. import msvcrt
  22. from ctypes import (sizeof, c_ulong, c_void_p, c_int64,
  23. Structure, Union, POINTER, windll, byref)
  24. from ctypes.wintypes import BOOL, DWORD, HANDLE
  25. LOCK_SH = 0 # the default
  26. LOCK_NB = 0x1 # LOCKFILE_FAIL_IMMEDIATELY
  27. LOCK_EX = 0x2 # LOCKFILE_EXCLUSIVE_LOCK
  28. # --- Adapted from the pyserial project ---
  29. # detect size of ULONG_PTR
  30. if sizeof(c_ulong) != sizeof(c_void_p):
  31. ULONG_PTR = c_int64
  32. else:
  33. ULONG_PTR = c_ulong
  34. PVOID = c_void_p
  35. # --- Union inside Structure by stackoverflow:3480240 ---
  36. class _OFFSET(Structure):
  37. _fields_ = [
  38. ('Offset', DWORD),
  39. ('OffsetHigh', DWORD)]
  40. class _OFFSET_UNION(Union):
  41. _anonymous_ = ['_offset']
  42. _fields_ = [
  43. ('_offset', _OFFSET),
  44. ('Pointer', PVOID)]
  45. class OVERLAPPED(Structure):
  46. _anonymous_ = ['_offset_union']
  47. _fields_ = [
  48. ('Internal', ULONG_PTR),
  49. ('InternalHigh', ULONG_PTR),
  50. ('_offset_union', _OFFSET_UNION),
  51. ('hEvent', HANDLE)]
  52. LPOVERLAPPED = POINTER(OVERLAPPED)
  53. # --- Define function prototypes for extra safety ---
  54. LockFileEx = windll.kernel32.LockFileEx
  55. LockFileEx.restype = BOOL
  56. LockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, DWORD, LPOVERLAPPED]
  57. UnlockFileEx = windll.kernel32.UnlockFileEx
  58. UnlockFileEx.restype = BOOL
  59. UnlockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, LPOVERLAPPED]
  60. def lock(f, flags):
  61. hfile = msvcrt.get_osfhandle(_fd(f))
  62. overlapped = OVERLAPPED()
  63. ret = LockFileEx(hfile, flags, 0, 0, 0xFFFF0000, byref(overlapped))
  64. return bool(ret)
  65. def unlock(f):
  66. hfile = msvcrt.get_osfhandle(_fd(f))
  67. overlapped = OVERLAPPED()
  68. ret = UnlockFileEx(hfile, 0, 0, 0xFFFF0000, byref(overlapped))
  69. return bool(ret)
  70. else:
  71. try:
  72. import fcntl
  73. LOCK_SH = fcntl.LOCK_SH # shared lock
  74. LOCK_NB = fcntl.LOCK_NB # non-blocking
  75. LOCK_EX = fcntl.LOCK_EX
  76. except (ImportError, AttributeError):
  77. # File locking is not supported.
  78. LOCK_EX = LOCK_SH = LOCK_NB = 0
  79. # Dummy functions that don't do anything.
  80. def lock(f, flags):
  81. # File is not locked
  82. return False
  83. def unlock(f):
  84. # File is unlocked
  85. return True
  86. else:
  87. def lock(f, flags):
  88. ret = fcntl.flock(_fd(f), flags)
  89. return ret == 0
  90. def unlock(f):
  91. ret = fcntl.flock(_fd(f), fcntl.LOCK_UN)
  92. return ret == 0