Fix Maildir race

fixes deb#439384

From: martin f krafft
Subject: race condition in Maildir writing

The offlineimap Maildir code checks for file existence and then
opens a file. That's open to a race condition. It's better to open
the file and fail if it already exists. The following patch does
this. It catches OSError 17 (file exists) and re-raises all others.
I'll leave it up to you to decide whether this is appropriate.
This commit is contained in:
John Goerzen 2007-10-19 01:06:18 +01:00
parent c476e8c98c
commit 6caaea36e0

View File

@ -158,7 +158,8 @@ class MaildirFolder(BaseFolder):
# Otherwise, save the message in tmp/ and then call savemessageflags() # Otherwise, save the message in tmp/ and then call savemessageflags()
# to give it a permanent home. # to give it a permanent home.
tmpdir = os.path.join(self.getfullname(), 'tmp') tmpdir = os.path.join(self.getfullname(), 'tmp')
messagename = None file = fd = None
messagename = tmpmessaename = None
attempts = 0 attempts = 0
while 1: while 1:
if attempts > 15: if attempts > 15:
@ -171,19 +172,24 @@ class MaildirFolder(BaseFolder):
socket.gethostname(), socket.gethostname(),
uid, uid,
md5.new(self.getvisiblename()).hexdigest()) md5.new(self.getvisiblename()).hexdigest())
if os.path.exists(os.path.join(tmpdir, messagename)): tmpmessagename = messagename.split(',')[0]
try:
fd = os.open(os.path.join(tmpdir, tmpmessagename),
os.O_WRONLY + os.O_CREAT + os.O_EXCL)
file = os.fdopen(fd, 'w')
ui.debug('maildir', 'savemessage: using temporary name %s' % tmpmessagename)
except OSError, e:
if e.errno == 17:
time.sleep(2) time.sleep(2)
attempts += 1 attempts += 1
else: continue
break raise
tmpmessagename = messagename.split(',')[0]
ui.debug('maildir', 'savemessage: using temporary name %s' % tmpmessagename)
file = open(os.path.join(tmpdir, tmpmessagename), "wt")
file.write(content) file.write(content)
# Make sure the data hits the disk # Make sure the data hits the disk
file.flush() file.flush()
os.fsync(file.fileno()) os.fsync(fd)
file.close() file.close()
if rtime != None: if rtime != None: