#19037: adjust file times *before* moving maildir files into place.

This avoids race conditions when other programs are monitoring
the maildir directory.  Patch by janzert.
This commit is contained in:
R David Murray 2013-09-18 08:34:40 -04:00
parent 825b50a40f
commit 41a22f1a77
2 changed files with 17 additions and 5 deletions

View File

@ -311,6 +311,12 @@ class Maildir(Mailbox):
suffix = '' suffix = ''
uniq = os.path.basename(tmp_file.name).split(self.colon)[0] uniq = os.path.basename(tmp_file.name).split(self.colon)[0]
dest = os.path.join(self._path, subdir, uniq + suffix) dest = os.path.join(self._path, subdir, uniq + suffix)
if isinstance(message, MaildirMessage):
os.utime(tmp_file.name,
(os.path.getatime(tmp_file.name), message.get_date()))
# No file modification should be done after the file is moved to its
# final position in order to prevent race conditions with changes
# from other programs
try: try:
if hasattr(os, 'link'): if hasattr(os, 'link'):
os.link(tmp_file.name, dest) os.link(tmp_file.name, dest)
@ -324,8 +330,6 @@ class Maildir(Mailbox):
% dest) % dest)
else: else:
raise raise
if isinstance(message, MaildirMessage):
os.utime(dest, (os.path.getatime(dest), message.get_date()))
return uniq return uniq
def remove(self, key): def remove(self, key):
@ -360,11 +364,15 @@ class Maildir(Mailbox):
else: else:
suffix = '' suffix = ''
self.discard(key) self.discard(key)
tmp_path = os.path.join(self._path, temp_subpath)
new_path = os.path.join(self._path, subdir, key + suffix) new_path = os.path.join(self._path, subdir, key + suffix)
os.rename(os.path.join(self._path, temp_subpath), new_path)
if isinstance(message, MaildirMessage): if isinstance(message, MaildirMessage):
os.utime(new_path, (os.path.getatime(new_path), os.utime(tmp_path,
message.get_date())) (os.path.getatime(tmp_path), message.get_date()))
# No file modification should be done after the file is moved to its
# final position in order to prevent race conditions with changes
# from other programs
os.rename(tmp_path, new_path)
def get_message(self, key): def get_message(self, key):
"""Return a Message representation or raise a KeyError.""" """Return a Message representation or raise a KeyError."""

View File

@ -68,6 +68,10 @@ Core and Builtins
Library Library
------- -------
- Issue #19037: The mailbox module now makes all changes to maildir files
before moving them into place, to avoid race conditions with other programs
that may be accessing the maildir directory.
- Issue #14984: On POSIX systems, when netrc is called without a filename - Issue #14984: On POSIX systems, when netrc is called without a filename
argument (and therefore is reading the user's $HOME/.netrc file), it now argument (and therefore is reading the user's $HOME/.netrc file), it now
enforces the same security rules as typical ftp clients: the .netrc file must enforces the same security rules as typical ftp clients: the .netrc file must