From 296c8a6146e482f11c0b70c6be16066985d24c10 Mon Sep 17 00:00:00 2001 From: Nicolas Sebrecht Date: Tue, 28 Jun 2016 15:38:35 +0200 Subject: [PATCH] UIDMaps: correctly protect from concurrent writes Signed-off-by: Nicolas Sebrecht --- offlineimap/folder/UIDMaps.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/offlineimap/folder/UIDMaps.py b/offlineimap/folder/UIDMaps.py index 8c676f7..52cc0fd 100644 --- a/offlineimap/folder/UIDMaps.py +++ b/offlineimap/folder/UIDMaps.py @@ -77,10 +77,19 @@ class MappedIMAPFolder(IMAPFolder): def _savemaps(self): mapfilename = self._getmapfilename() - with open(mapfilename + ".tmp", 'wt') as mapfilefd: - for (key, value) in self.diskl2r.items(): - mapfilefd.write("%d:%d\n"% (key, value)) - os.rename(mapfilename + '.tmp', mapfilename) + mapfilenamelock = "%s.lock"% mapfilename + with open(mapfilenamelock, 'w') as mapfilelock: + # The "account" lock already prevents from multiple access by + # different processes. However, we still need to protect for + # multiple access from different threads. + try: + fnctl.lockf(mapfilelock, fnctl.LOCK_EX) # Blocks until acquired. + except NameError: + pass # Windows... + with open(mapfilename, 'wt') as mapfilefd: + for (key, value) in self.diskl2r.items(): + mapfilefd.write("%d:%d\n"% (key, value)) + # The lock is released when the file descriptor ends. def _uidlist(self, mapping, items): try: