[Python-checkins] r54598 - in python/branches/amk-mailbox: Lib/mailbox.py Misc/ACKS
andrew.kuchling
python-checkins at python.org
Wed Mar 28 19:23:05 CEST 2007
Author: andrew.kuchling
Date: Wed Mar 28 19:23:00 2007
New Revision: 54598
Modified:
python/branches/amk-mailbox/Lib/mailbox.py
python/branches/amk-mailbox/Misc/ACKS
Log:
Patch from David Watson (the unified2-module.diff attached to bug #1599254).
This patch still has a race condition on platforms where there's no file.truncate(),
but it's not clear that any such platforms actually exist at this time.
Is it worth keeping that branch of code?
Modified: python/branches/amk-mailbox/Lib/mailbox.py
==============================================================================
--- python/branches/amk-mailbox/Lib/mailbox.py (original)
+++ python/branches/amk-mailbox/Lib/mailbox.py Wed Mar 28 19:23:00 2007
@@ -20,6 +20,7 @@
import email.generator
import rfc822
import StringIO
+import shutil
import warnings
try:
if sys.platform == 'os2emx':
@@ -587,6 +588,15 @@
'(expected %i, found %i)' %
(self._file_length, cur_len))
+ if fcntl and self._locked and not hasattr(self._file, 'truncate'):
+ warnings.warn('file.truncate() unavailable, flush() may '
+ 'momentarily release the fcntl lock; if you depend '
+ 'on fcntl locking, you should regard flush() as '
+ 'invalidating the message keys', RuntimeWarning,
+ stacklevel=2)
+
+ orig_file = self._file
+ remove_temp_file = True
new_file = _create_temporary(self._path)
try:
new_toc = {}
@@ -604,27 +614,45 @@
new_file.write(buffer)
new_toc[key] = (new_start, new_file.tell())
self._post_message_hook(new_file)
- except:
- new_file.close()
- os.remove(new_file.name)
- raise
- _sync_close(new_file)
- # self._file is about to get replaced, so no need to sync.
- self._file.close()
- try:
- os.rename(new_file.name, self._path)
- except OSError, e:
- if e.errno == errno.EEXIST or \
- (os.name == 'os2' and e.errno == errno.EACCES):
- os.remove(self._path)
- os.rename(new_file.name, self._path)
- else:
- raise
- self._file = open(self._path, 'rb+')
- self._toc = new_toc
- self._pending = False
- if self._locked:
- _lock_file(self._file, dotlock=False)
+ new_len = new_file.tell()
+ _sync_flush(new_file)
+ new_file.seek(0)
+ self._file.seek(0)
+ if new_len < cur_len and not hasattr(self._file, 'truncate'):
+ try:
+ if not os.path.samestat(os.fstat(self._file.fileno()),
+ os.stat(self._path)):
+ raise ExternalClashError("Mailbox has been replaced: "
+ "%s" % self._path)
+ except OSError, e:
+ if e.errno == errno.ENOENT:
+ raise NoSuchMailboxError(self._path)
+ raise
+ except AttributeError:
+ # No stat(), etc.
+ pass
+ # *** race condition ***
+ remove_temp_file = False
+ self._file = open(self._path, 'wb+')
+ remove_temp_file = False
+ shutil.copyfileobj(new_file, self._file)
+ if hasattr(self._file, 'truncate'):
+ self._file.truncate(new_len)
+ self._file_length = new_len
+ self._toc = new_toc
+ _sync_flush(self._file)
+ remove_temp_file = True
+ self._pending = False
+ finally:
+ try:
+ new_file.close()
+ if remove_temp_file:
+ os.remove(new_file.name)
+ finally:
+ if self._file is not orig_file:
+ orig_file.close()
+ if self._locked:
+ _lock_file(self._file, dotlock=False)
def _pre_mailbox_hook(self, f):
"""Called before writing the mailbox to file f."""
Modified: python/branches/amk-mailbox/Misc/ACKS
==============================================================================
--- python/branches/amk-mailbox/Misc/ACKS (original)
+++ python/branches/amk-mailbox/Misc/ACKS Wed Mar 28 19:23:00 2007
@@ -677,6 +677,7 @@
Barry Warsaw
Steve Waterbury
Bob Watson
+David Watson
Aaron Watters
Henrik Weber
Corran Webster
More information about the Python-checkins
mailing list