[Python-Dev] Ext4 data loss

Valentino Volonghi dialtone at gmail.com
Mon Mar 16 21:33:06 CET 2009


On Mar 15, 2009, at 3:25 PM, Greg Ewing wrote:

>  with renaming_file("blarg.txt", "w") as f:
>    ...


By chance during the weekend I actually wrote something like that:

from __future__ import with_statement

import os
import codecs
import shutil
import tempfile

from contextlib import contextmanager

TDIR = tempfile.mktemp(dir='/tmp/')

@contextmanager
def topen(filepath, mode='wb', bufsize=-1, encoding=None,
           inplace=False, tmpd=TDIR, sync=False):
     """
     C{topen} is a transactional version of the Python builtin C{open}
     function for file IO. It manages transactionality by using a
     temporary file and then moving it to the final position once its
     content has been written to disk.
     If the mode used to open the file doesn't modify the file, this
     function is equivalent to the built-in C{open} with automatic
     file closing behavior.

     @param filepath: The path of the file that you want to open
     @type filepath: C{str}

     @param mode: POSIX mode in which you want to open the file.
     @type mode: C{str} see documentation for the format.

     @param bufsize: Buffer size for file IO
     @type bufsize: C{int} see documentation for the meaning

     @param encoding: Encoding that should be used to read the file
     @type encoding: C{str}

     @param inplace: Indicates if the temporary file should reside
                     in the same directory of the final file.
     @type inplace: C{bool}

     @param tmpd: The temporary directory in which file IO is
                  performed. Then files are moved from here to
                  their original destination.
     @type tmpd: C{str}

     @param sync: Force topen to fsync the file before closing it
     @type sync: C{bool}
     """
     if 'r' in mode or 'a' in mode:
         fp = filepath
     else:
         if inplace:
             source_dir, _ = os.path.split(filepath)
             tmpd = source_dir

         if not os.path.exists(tmpd):
             os.makedirs(tmpd)
         _f, fp = tempfile.mkstemp(dir=tmpd)

     if encoding is not None:
         f = codecs.open(fp, mode, encoding=encoding)
     else:
         f = open(fp, mode, bufsize)

     try:
         yield f
     finally:
         if 'r' in mode:
             if "+" in mode:
                 f.flush()
                 if sync:
                     os.fsync(f.fileno())
             f.close()
             return

         f.flush()
         if sync:
             os.fsync(f.fileno())
         f.close()
         if 'w' in mode:
             shutil.move(fp, filepath)

if __name__ == "__main__":
     with topen("a_test") as f:
         f.write("hello")
     assert file("a_test", "rb").read() == 'hello'
     assert os.path.exists(TDIR)
     os.rmdir(TDIR)

     with topen("a_test", mode="rb") as f:
         assert f.read() == "hello"
     assert not os.path.exists(TDIR)
     os.remove("a_test")


--
Valentino Volonghi aka Dialtone
Now running MacOS X 10.5
Home Page: http://www.twisted.it
http://www.adroll.com

-------------- next part --------------
A non-text attachment was scrubbed...
Name: PGP.sig
Type: application/pgp-signature
Size: 194 bytes
Desc: This is a digitally signed message part
URL: <http://mail.python.org/pipermail/python-dev/attachments/20090316/774d297d/attachment.pgp>


More information about the Python-Dev mailing list