[Python-checkins] r52720 - in python/branches/release25-maint: Lib/mailbox.py Misc/NEWS

andrew.kuchling python-checkins at python.org
Fri Nov 10 14:15:59 CET 2006


Author: andrew.kuchling
Date: Fri Nov 10 14:15:58 2006
New Revision: 52720

Modified:
   python/branches/release25-maint/Lib/mailbox.py
   python/branches/release25-maint/Misc/NEWS
Log:
[Patch #1514543] mailbox (Maildir): avoid losing messages on name clash

Two changes:

Where possible, use link()/remove() to move files into a directory; this
makes it easier to avoid overwriting an existing file.

Use _create_carefully() to create files in tmp/, which uses O_EXCL.


Modified: python/branches/release25-maint/Lib/mailbox.py
==============================================================================
--- python/branches/release25-maint/Lib/mailbox.py	(original)
+++ python/branches/release25-maint/Lib/mailbox.py	Fri Nov 10 14:15:58 2006
@@ -255,7 +255,19 @@
             suffix = ''
         uniq = os.path.basename(tmp_file.name).split(self.colon)[0]
         dest = os.path.join(self._path, subdir, uniq + suffix)
-        os.rename(tmp_file.name, dest)
+        try:
+            if hasattr(os, 'link'):
+                os.link(tmp_file.name, dest)
+                os.remove(tmp_file.name)
+            else:
+                os.rename(tmp_file.name, dest)
+        except OSError, e:
+            os.remove(tmp_file.name)
+            if e.errno == errno.EEXIST:
+                raise ExternalClashError('Name clash with existing message: %s'
+                                         % dest)
+            else:
+                raise
         if isinstance(message, MaildirMessage):
             os.utime(dest, (os.path.getatime(dest), message.get_date()))
         return uniq
@@ -431,12 +443,17 @@
         except OSError, e:
             if e.errno == errno.ENOENT:
                 Maildir._count += 1
-                return open(path, 'wb+')
+                try:
+                    return _create_carefully(path)
+                except OSError, e:
+                    if e.errno != errno.EEXIST:
+                        raise
             else:
                 raise
-        else:
-            raise ExternalClashError('Name clash prevented file creation: %s' %
-                                     path)
+
+        # Fall through to here if stat succeeded or open raised EEXIST.
+        raise ExternalClashError('Name clash prevented file creation: %s' %
+                                 path)
 
     def _refresh(self):
         """Update table of contents mapping."""

Modified: python/branches/release25-maint/Misc/NEWS
==============================================================================
--- python/branches/release25-maint/Misc/NEWS	(original)
+++ python/branches/release25-maint/Misc/NEWS	Fri Nov 10 14:15:58 2006
@@ -140,6 +140,10 @@
 - Bug #1575506: mailbox.py: Single-file mailboxes didn't re-lock
   properly in their flush() method.
 
+- Patch #1514543: mailbox.py: In the Maildir class, report errors if there's 
+  a filename clash instead of possibly losing a message.  (Patch by David
+  Watson.)
+
 - Patch #1514544: mailbox.py: Try to ensure that messages/indexes have
   been physically written to disk after calling .flush() or
   .close(). (Patch by David Watson.)


More information about the Python-checkins mailing list