"""capisuite.fileutils File handling utility function. """ __author__ = "Hartmut Goebel " __copyright__ = "Copyright (c) 2004 by Hartmut Goebel" __version__ = "$Revision: 0.0 $" __credits__ = "This file is part of www.capisuite.de; some ideas taken from Gernot Hillier" import fcntl, os, re, errno from types import IntType class UnknownUserError(KeyError): pass class LockTakenError(Exception): pass def lockname(path): return "%s.lock" % os.path.splitext(path)[0] def controlname(path): return "%s.txt" % os.path.splitext(path)[0] def _getLock(lockname_=None, forfile=None, blocking=0): if forfile: lockname_ = lockname(forfile) elif not lockname_: raise ValueError, lockname_ lockfile = open(lockname_, "w") try: if blocking: fcntl.lockf(lockfile, fcntl.LOCK_EX) else: fcntl.lockf(lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError, err: # can't get the lock if err.errno in (errno.EACCES, errno.EAGAIN): lockfile.close() raise LockTakenError else: raise return (lockname_, lockfile) def _releaseLock((lockname, lockfile)): fcntl.lockf(lockfile, fcntl.LOCK_UN) lockfile.close() try: os.unlink(lockname) except OSError, err: # as we don't hold the lock any more, the other thread can be quicker # in deleting than we; this doesn't harm, so ignore it if (err.errno!=2): raise def _setProtection(user, mode=0600, *files): import pwd try: userdata = pwd.getpwnam(user) except KeyError: raise UnknownUserError(user) print files if os.getuid() == 0: # running as root, change ownership for f in files: os.chmod(f, mode) os.chown(f, userdata.pw_uid, userdata.pw_gid) else: for f in files: os.chmod(f, mode) os.chown(f, os.getuid(), userdata.pw_gid) def _mkuserdir(user, parrentdir, *dirs): import pwd try: userdata = pwd.getpwnam(user) except KeyError: raise UnknownUserError(user) path = parrentdir for d in dirs: path = os.path.join(path, d) # todo: use os.path.exists? if not os.access(path, os.F_OK): os.mkdir(path, 0700) os.chown(path, userdata.pw_uid, userdata.pw_gid) return path ###--- counter files ---### def readCounter(default=0, *fileparts): assert isinstance(default, IntType) filename = os.path.join(*fileparts) if os.path.exists(filename): lastfile = open(filename, "r") count = int(lastfile.readline()) lastfile.close() return count else: return default def writeCounter(count, *fileparts): assert isinstance(count, IntType) filename = os.path.join(*fileparts) lastfile = open(filename, "w") print >> lastfile, count lastfile.close() ###--- ... ---### def __makeCountedFilePattern(basename, suffix): # todo: group should be digits only return re.compile("%s-([0-9]+)\.%s" % (re.escape(basename), re.escape(suffix))) # @brief thread-safe creation of a unique filename in a directory # # This function reads the nextnumber from then "nextnr"-file in the given # directory and updates it. It holds the next free file number. # # If nextnr doesn't exist, it's created. # # The filenames created will have the format # # basename-number.suffix # # @param directory name of the directory to work in # @param basename the basename of the filename # @param suffix the suffix of the filename (without ".") # # @return job number, new file name def uniqueName(directory, basename, suffix): nextfile = "%s-nextnr" % os.path.join(directory, basename) lock = _getLock(os.path.join(directory,"cs_lock"), blocking=1) try: nextnum = readCounter(-10, nextfile) if nextnum < 0: # search for next free sequence number pattern = __makeCountedFilePattern(basename, suffix) numbers = [0] for f in os.listdir(directory): m = pattern.match(f) if m: numbers.append(int(m.group(1))) # take number of last file and increase it by one nextnum = max(numbers)+1 writeCounter(nextnum+1, nextfile) except: _releaseLock(lock) raise else: _releaseLock(lock) newname = "%s-%03i.%s" % (os.path.join(directory,basename), nextnum, suffix) return nextnum, newname