24Utilities for safe file IO
26from contextlib
import contextmanager
39def safeMakeDir(directory):
40 """Make a directory in a manner avoiding race conditions"""
41 if directory !=
"" and not os.path.exists(directory):
43 os.makedirs(directory)
46 if e.errno != errno.EEXIST:
51 """Set a file mode according to the user's umask"""
53 umask = os.umask(0o077)
57 os.chmod(filename, (~umask & 0o666))
66 """Context manager to get a file that can be written only once and all other writes will succeed only if
67 they match the initial write.
69 The context manager provides a temporary file object. After the user is done, the temporary file becomes
70 the permanent file
if the file at name does
not already exist. If the file at name does exist the
71 temporary file
is compared to the file at name. If they are the same then this
is good
and the temp file
72 is silently thrown away. If they are
not the same then a runtime error
is raised.
74 outDir, outName = os.path.split(name)
76 temp = tempfile.NamedTemporaryFile(mode="w", dir=outDir, prefix=outName, delete=
False)
84 os.symlink(temp.name, name)
87 os.rename(temp.name, name)
92 if e.errno != errno.EEXIST:
94 filesMatch = filecmp.cmp(temp.name, name, shallow=
False)
107 """Context manager to create a file in a manner avoiding race conditions
109 The context manager provides a temporary file object. After the user is done,
110 we move that file into the desired place
and close the fd to avoid resource
113 outDir, outName = os.path.split(name)
116 with tempfile.NamedTemporaryFile(mode=
"w", dir=outDir, prefix=outName, delete=
False)
as temp:
123 os.rename(temp.name, name)
128def SafeFilename(name):
129 """Context manager for creating a file in a manner avoiding race conditions
131 The context manager provides a temporary filename with no open file descriptors
132 (
as this can cause trouble on some systems). After the user
is done, we move the
133 file into the desired place.
135 outDir, outName = os.path.split(name)
137 temp = tempfile.NamedTemporaryFile(mode="w", dir=outDir, prefix=outName, delete=
False)
143 os.rename(tempName, name)
149 """Context manager for reading a file that may be locked with an exclusive lock via
150 SafeLockedFileForWrite. This will first acquire a shared lock before returning the file. When the file is
151 closed the shared lock will be unlocked.
156 The file name to be opened, may include path.
161 The file to be read
from.
163 log = Log.getLogger("daf.persistence.butler")
165 with open(name,
'r')
as f:
166 log.debug(
"Acquiring shared lock on {}".format(name))
167 fcntl.flock(f, fcntl.LOCK_SH)
168 log.debug(
"Acquired shared lock on {}".format(name))
171 log.debug(
"Releasing shared lock on {}".format(name))
175 """File-like object that is used to create a file if needed, lock it with an exclusive lock, and contain
176 file descriptors to readable and writable versions of the file.
178 This will only open a file descriptor
in 'write' mode
if a write operation
is performed. If no write
179 operation
is performed, the existing file (
if there
is one) will
not be overwritten.
181 Contains __enter__
and __exit__ functions so this can be used by a context manager.
184 self.
log = Log.getLogger(
"daf.persistence.butler")
188 safeMakeDir(os.path.split(name)[0])
199 self.
log.debug(
"Acquiring exclusive lock on {}".format(self.
name))
201 self.
log.debug(
"Acquired exclusive lock on {}".format(self.
name))
204 self.
log.debug(
"Releasing exclusive lock on {}".format(self.
name))
def read(self, size=None)
def __exit__(self, type, value, traceback)
def SafeLockedFileForRead(name)
def FileForWriteOnceCompareSame(name)
def setFileMode(filename)