source: OpenRLabs-Git/deploy/rlabs-docker/web2py-rlabs/gluon/packages/dal/pydal/contrib/portalocker.py

main
Last change on this file was 42bd667, checked in by David Fuertes <dfuertes@…>, 4 years ago

Historial Limpio

  • Property mode set to 100755
File size: 5.5 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4"""
5Cross-platform (posix/nt) API for flock-style file locking.
6
7Synopsis::
8
9   import portalocker
10   file = open(\"somefile\", \"r+\")
11   portalocker.lock(file, portalocker.LOCK_EX)
12   file.seek(12)
13   file.write(\"foo\")
14   file.close()
15
16If you know what you're doing, you may choose to::
17
18   portalocker.unlock(file)
19
20before closing the file, but why?
21
22Methods::
23
24   lock( file, flags )
25   unlock( file )
26
27Constants::
28
29   LOCK_EX - exclusive lock
30   LOCK_SH - shared lock
31   LOCK_NB - don't lock when locking
32
33Original
34---------
35http://code.activestate.com/recipes/65203-portalocker-cross-platform-posixnt-api-for-flock-s/
36
37I learned the win32 technique for locking files from sample code
38provided by John Nielsen <nielsenjf@my-deja.com> in the documentation
39that accompanies the win32 modules.
40
41Author: Jonathan Feinberg <jdf@pobox.com>
42
43
44Roundup Changes
45---------------
462012-11-28 (anatoly techtonik)
47   - Ported to ctypes
48   - Dropped support for Win95, Win98 and WinME
49   - Added return result
50
51Web2py Changes
52--------------
532016-07-28 (niphlod)
54   - integrated original recipe, web2py's GAE warnings and roundup in a unique
55     solution
56
57"""
58import sys
59import logging
60
61PY2 = sys.version_info[0] == 2
62
63logger = logging.getLogger("pydal")
64
65
66os_locking = None
67try:
68    import google.appengine
69
70    os_locking = "gae"
71except:
72    try:
73        import fcntl
74
75        os_locking = "posix"
76    except:
77        try:
78            import msvcrt
79            import ctypes
80            from ctypes.wintypes import BOOL, DWORD, HANDLE
81            from ctypes import windll
82
83            os_locking = "windows"
84        except:
85            pass
86
87if os_locking == "windows":
88    LOCK_SH = 0  # the default
89    LOCK_NB = 0x1  # LOCKFILE_FAIL_IMMEDIATELY
90    LOCK_EX = 0x2  # LOCKFILE_EXCLUSIVE_LOCK
91
92    # --- the code is taken from pyserial project ---
93    #
94    # detect size of ULONG_PTR
95    def is_64bit():
96        return ctypes.sizeof(ctypes.c_ulong) != ctypes.sizeof(ctypes.c_void_p)
97
98    if is_64bit():
99        ULONG_PTR = ctypes.c_int64
100    else:
101        ULONG_PTR = ctypes.c_ulong
102    PVOID = ctypes.c_void_p
103
104    # --- Union inside Structure by stackoverflow:3480240 ---
105    class _OFFSET(ctypes.Structure):
106        _fields_ = [("Offset", DWORD), ("OffsetHigh", DWORD)]
107
108    class _OFFSET_UNION(ctypes.Union):
109        _anonymous_ = ["_offset"]
110        _fields_ = [("_offset", _OFFSET), ("Pointer", PVOID)]
111
112    class OVERLAPPED(ctypes.Structure):
113        _anonymous_ = ["_offset_union"]
114        _fields_ = [
115            ("Internal", ULONG_PTR),
116            ("InternalHigh", ULONG_PTR),
117            ("_offset_union", _OFFSET_UNION),
118            ("hEvent", HANDLE),
119        ]
120
121    LPOVERLAPPED = ctypes.POINTER(OVERLAPPED)
122
123    # --- Define function prototypes for extra safety ---
124    LockFileEx = windll.kernel32.LockFileEx
125    LockFileEx.restype = BOOL
126    LockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, DWORD, LPOVERLAPPED]
127    UnlockFileEx = windll.kernel32.UnlockFileEx
128    UnlockFileEx.restype = BOOL
129    UnlockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, LPOVERLAPPED]
130
131    def lock(file, flags):
132        hfile = msvcrt.get_osfhandle(file.fileno())
133        overlapped = OVERLAPPED()
134        LockFileEx(hfile, flags, 0, 0, 0xFFFF0000, ctypes.byref(overlapped))
135
136    def unlock(file):
137        hfile = msvcrt.get_osfhandle(file.fileno())
138        overlapped = OVERLAPPED()
139        UnlockFileEx(hfile, 0, 0, 0xFFFF0000, ctypes.byref(overlapped))
140
141
142elif os_locking == "posix":
143    LOCK_EX = fcntl.LOCK_EX
144    LOCK_SH = fcntl.LOCK_SH
145    LOCK_NB = fcntl.LOCK_NB
146
147    def lock(file, flags):
148        fcntl.flock(file.fileno(), flags)
149
150    def unlock(file):
151        fcntl.flock(file.fileno(), fcntl.LOCK_UN)
152
153
154else:
155    if os_locking != "gae":
156        logger.debug("no file locking, this will cause problems")
157
158    LOCK_EX = None
159    LOCK_SH = None
160    LOCK_NB = None
161
162    def lock(file, flags):
163        pass
164
165    def unlock(file):
166        pass
167
168
169def open_file(filename, mode):
170    if PY2 or "b" in mode:
171        f = open(filename, mode)
172    else:
173        f = open(filename, mode, encoding="utf8")
174    return f
175
176
177class LockedFile(object):
178    def __init__(self, filename, mode="rb"):
179        self.filename = filename
180        self.mode = mode
181        self.file = None
182        if "r" in mode:
183            self.file = open_file(filename, mode)
184            lock(self.file, LOCK_SH)
185        elif "w" in mode or "a" in mode:
186            self.file = open_file(filename, mode.replace("w", "a"))
187            lock(self.file, LOCK_EX)
188            if "a" not in mode:
189                self.file.seek(0)
190                self.file.truncate(0)
191        else:
192            raise RuntimeError("invalid LockedFile(...,mode)")
193
194    def read(self, size=None):
195        return self.file.read() if size is None else self.file.read(size)
196
197    def readinto(self, b):
198        b[:] = self.file.read()
199
200    def readline(self):
201        return self.file.readline()
202
203    def readlines(self):
204        return self.file.readlines()
205
206    def write(self, data):
207        self.file.write(data)
208        self.file.flush()
209
210    def close(self):
211        if self.file is not None:
212            unlock(self.file)
213            self.file.close()
214            self.file = None
215
216    def __del__(self):
217        if self.file is not None:
218            self.close()
219
220
221def read_locked(filename):
222    fp = LockedFile(filename, "rb")
223    data = fp.read()
224    fp.close()
225    return data
226
227
228def write_locked(filename, data):
229    fp = LockedFile(filename, "wb")
230    data = fp.write(data)
231    fp.close()
Note: See TracBrowser for help on using the repository browser.