File: plock.py

package info (click to toggle)
pymilter 1.0.6-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,100 kB
  • sloc: python: 3,371; ansic: 1,333; makefile: 34; sh: 8
file content (66 lines) | stat: -rw-r--r-- 1,760 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# Author: Stuart D. Gathman <stuart@bmsi.com>
# Copyright 2001 Business Management Systems, Inc.
# This code is under the GNU General Public License.  See COPYING for details.

import os
from time import sleep

class PLock(object):
  "A simple /etc/passwd style lock,update,rename protocol for updating files."
  def __init__(self,basename):
    self.basename = basename
    self.fp = None

  def lock(self,lockname=None,mode=0o660,strict_perms=False):
    "Start an update transaction.  Return FILE to write new version."
    self.unlock()
    if not lockname:
      lockname = self.basename + '.lock'
    self.lockname = lockname
    try:
      st = os.stat(self.basename)
      mode |= st.st_mode
    except OSError: pass
    u = os.umask(0o2)
    try:
      fd = os.open(lockname,os.O_WRONLY+os.O_CREAT+os.O_EXCL,mode)
    finally:
      os.umask(u)
    self.fp = os.fdopen(fd,'w')
    try:
      os.chown(self.lockname,-1,st.st_gid)
    except:
      if strict_perms:
        self.unlock()
        raise
    return self.fp

  def wlock(self,lockname=None):
    "Wait until lock is free, then start an update transaction."
    while True:
      try:
        return self.lock(lockname)
      except OSError:
        sleep(2)

  def commit(self,backname=None):
    "Commit update transaction with optional backup file."
    if not self.fp:
      raise IOError("File not locked")
    self.fp.close()
    self.fp = None
    if backname:
      try:
        os.remove(backname)
      except OSError: pass
      os.link(self.basename,backname)
    os.rename(self.lockname,self.basename)

  def unlock(self):
    "Cancel update transaction."
    if self.fp:
      try:
        self.fp.close()
      except: pass
      self.fp = None
      os.remove(self.lockname)