153 lines
3.7 KiB
Python
153 lines
3.7 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
# portalocker.py - Cross-platform (posix/nt) API for flock-style file locking.
|
|
# Requires python 1.5.2 or better.
|
|
|
|
"""
|
|
Cross-platform (posix/nt) API for flock-style file locking.
|
|
|
|
Synopsis:
|
|
|
|
import portalocker
|
|
file = open(\"somefile\", \"r+\")
|
|
portalocker.lock(file, portalocker.LOCK_EX)
|
|
file.seek(12)
|
|
file.write(\"foo\")
|
|
file.close()
|
|
|
|
If you know what you're doing, you may choose to
|
|
|
|
portalocker.unlock(file)
|
|
|
|
before closing the file, but why?
|
|
|
|
Methods:
|
|
|
|
lock( file, flags )
|
|
unlock( file )
|
|
|
|
Constants:
|
|
|
|
LOCK_EX
|
|
LOCK_SH
|
|
LOCK_NB
|
|
|
|
I learned the win32 technique for locking files from sample code
|
|
provided by John Nielsen <nielsenjf@my-deja.com> in the documentation
|
|
that accompanies the win32 modules.
|
|
|
|
Author: Jonathan Feinberg <jdf@pobox.com>
|
|
Version: $Id: portalocker.py,v 1.3 2001/05/29 18:47:55 Administrator Exp $
|
|
"""
|
|
|
|
import logging
|
|
import platform
|
|
logger = logging.getLogger("web2py")
|
|
|
|
os_locking = None
|
|
try:
|
|
import google.appengine
|
|
os_locking = 'gae'
|
|
except:
|
|
try:
|
|
import fcntl
|
|
os_locking = 'posix'
|
|
except:
|
|
try:
|
|
import win32con
|
|
import win32file
|
|
import pywintypes
|
|
os_locking = 'windows'
|
|
except:
|
|
pass
|
|
|
|
if os_locking == 'windows':
|
|
LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
|
|
LOCK_SH = 0 # the default
|
|
LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
|
|
|
|
# is there any reason not to reuse the following structure?
|
|
|
|
__overlapped = pywintypes.OVERLAPPED()
|
|
|
|
def lock(file, flags):
|
|
hfile = win32file._get_osfhandle(file.fileno())
|
|
win32file.LockFileEx(hfile, flags, 0, 0x7fff0000, __overlapped)
|
|
|
|
def unlock(file):
|
|
hfile = win32file._get_osfhandle(file.fileno())
|
|
win32file.UnlockFileEx(hfile, 0, 0x7fff0000, __overlapped)
|
|
|
|
|
|
elif os_locking == 'posix':
|
|
LOCK_EX = fcntl.LOCK_EX
|
|
LOCK_SH = fcntl.LOCK_SH
|
|
LOCK_NB = fcntl.LOCK_NB
|
|
|
|
def lock(file, flags):
|
|
fcntl.flock(file.fileno(), flags)
|
|
|
|
def unlock(file):
|
|
fcntl.flock(file.fileno(), fcntl.LOCK_UN)
|
|
|
|
|
|
else:
|
|
if platform.system() == 'Windows':
|
|
logger.error('no file locking, you must install the win32 extensions from: http://sourceforge.net/projects/pywin32/files/')
|
|
elif os_locking != 'gae':
|
|
logger.debug('no file locking, this will cause problems')
|
|
|
|
LOCK_EX = None
|
|
LOCK_SH = None
|
|
LOCK_NB = None
|
|
|
|
def lock(file, flags):
|
|
pass
|
|
|
|
def unlock(file):
|
|
pass
|
|
|
|
|
|
class LockedFile(object):
|
|
def __init__(self,filename, mode='rb'):
|
|
self.filename = filename
|
|
self.mode = mode
|
|
self.file = None
|
|
if 'r' in mode:
|
|
self.file = open(filename,mode)
|
|
lock(self.file,LOCK_SH)
|
|
elif 'w' in mode or 'a' in mode:
|
|
self.file = open(filename,mode.replace('w','a'))
|
|
lock(self.file,LOCK_EX)
|
|
if not 'a' in mode:
|
|
self.file.seek(0)
|
|
self.file.truncate()
|
|
else:
|
|
raise RuntimeError, "invalid LockedFile(...,mode)"
|
|
def read(self,size=None):
|
|
return self.file.read() if size is None else self.file.read(size)
|
|
def readline(self):
|
|
return self.file.readline()
|
|
def readlines(self):
|
|
return self.file.readlines()
|
|
def write(self,data):
|
|
self.file.write(data)
|
|
self.file.flush()
|
|
def close(self):
|
|
if not self.file is None:
|
|
unlock(self.file)
|
|
self.file.close()
|
|
self.file = None
|
|
def __del__(self):
|
|
self.close()
|
|
|
|
if __name__=='__main__':
|
|
f = LockedFile('test.txt',mode='wb')
|
|
f.write('test ok')
|
|
f.close()
|
|
f = LockedFile('test.txt',mode='rb')
|
|
print f.read()
|
|
f.close()
|
|
|
|
|