diff --git a/offlineimap/head/debian/changelog b/offlineimap/head/debian/changelog index ef6f384..3ce9413 100644 --- a/offlineimap/head/debian/changelog +++ b/offlineimap/head/debian/changelog @@ -1,3 +1,19 @@ +offlineimap (3.99.17) unstable; urgency=low + + * Fixed two potential obscure race conditions in folder/Maildir.py. + + Condition 1 involved the gettimeseq() function. This function + accesses per-module variables but does not have a lock. It may have + been possible for this to have been called in such a way that timeseq + was not properly updated. + + Condition 2 involved the call to gettimeseq(). Since the timeseq is + based on the system clock, we now use the time as reported inside + timeseq() rather than outside. This way, we can be assured that the + same value is in use both places. + * Added debug code to savemessage in folder/Maildir.py to try to track + down a mysterious 0-length file bug. + + -- John Goerzen Tue, 6 May 2003 07:25:38 -0500 + offlineimap (3.99.16) unstable; urgency=low * This is a 4.0 TRACK release, and may be unstable or in flux! diff --git a/offlineimap/head/offlineimap/folder/Maildir.py b/offlineimap/head/offlineimap/folder/Maildir.py index 71d73fc..69cb033 100644 --- a/offlineimap/head/offlineimap/folder/Maildir.py +++ b/offlineimap/head/offlineimap/folder/Maildir.py @@ -18,6 +18,8 @@ from Base import BaseFolder from offlineimap import imaputil +from offlineimap.ui import UIBase +from threading import Lock import os.path, os, re, time, socket, md5 foldermatchre = re.compile(',FMD5=([0-9a-f]{32})') @@ -26,17 +28,22 @@ flagmatchre = re.compile(':.*2,([A-Z]+)') timeseq = 0 lasttime = long(0) +timelock = Lock() def gettimeseq(): - global lasttime, timeseq - thistime = long(time.time()) - if thistime == lasttime: - timeseq += 1 - return timeseq - else: - lasttime = long(time.time()) - timeseq = 0 - return timeseq + global lasttime, timeseq, timelock + timelock.acquire() + try: + thistime = long(time.time()) + if thistime == lasttime: + timeseq += 1 + return (thistime, timeseq) + else: + lasttime = thistime + timeseq = 0 + return (thistime, timeseq) + finally: + timelock.release() class MaildirFolder(BaseFolder): def __init__(self, root, name, sep, repository, accountname): @@ -118,6 +125,9 @@ class MaildirFolder(BaseFolder): return retval.replace("\r\n", "\n") def savemessage(self, uid, content, flags): + ui = UIBase.getglobalui() + ui.debug('maildir', 'savemessage: called to write with flags %s and content %s' % \ + (repr(flags), repr(content))) if uid < 0: # We cannot assign a new uid. return uid @@ -137,9 +147,10 @@ class MaildirFolder(BaseFolder): while 1: if attempts > 15: raise IOError, "Couldn't write to file %s" % messagename + timeval, timeseq = gettimeseq() messagename = '%d_%d.%d.%s,U=%d,FMD5=%s' % \ - (long(time.time()), - gettimeseq(), + (timeval, + timeseq, os.getpid(), socket.gethostname(), uid, @@ -150,15 +161,19 @@ class MaildirFolder(BaseFolder): else: break 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.close() + ui.debug('maildir', 'savemessage: moving from %s to %s' % \ + (tmpmessagename, messagename)) os.link(os.path.join(tmpdir, tmpmessagename), os.path.join(newdir, messagename)) os.unlink(os.path.join(tmpdir, tmpmessagename)) self.messagelist[uid] = {'uid': uid, 'flags': [], 'filename': os.path.join(newdir, messagename)} self.savemessageflags(uid, flags) + ui.debug('maildir', 'savemessage: returning uid %d' % uid) return uid def getmessageflags(self, uid):