Skip to content

Commit 33a36ca

Browse files
serhiy-storchakaaisk
authored andcommitted
pythongh-66515: Fix locking of an MH mailbox without ".mh_sequences" file (pythonGH-113482)
Guarantee that it either open an existing ".mh_sequences" file or create a new ".mh_sequences" file, but do not replace existing ".mh_sequences" file.
1 parent 4820089 commit 33a36ca

File tree

2 files changed

+26
-2
lines changed

2 files changed

+26
-2
lines changed

Lib/mailbox.py

+17-2
Original file line numberDiff line numberDiff line change
@@ -1141,10 +1141,24 @@ def __len__(self):
11411141
"""Return a count of messages in the mailbox."""
11421142
return len(list(self.iterkeys()))
11431143

1144+
def _open_mh_sequences_file(self, text):
1145+
mode = '' if text else 'b'
1146+
kwargs = {'encoding': 'ASCII'} if text else {}
1147+
path = os.path.join(self._path, '.mh_sequences')
1148+
while True:
1149+
try:
1150+
return open(path, 'r+' + mode, **kwargs)
1151+
except FileNotFoundError:
1152+
pass
1153+
try:
1154+
return open(path, 'x+' + mode, **kwargs)
1155+
except FileExistsError:
1156+
pass
1157+
11441158
def lock(self):
11451159
"""Lock the mailbox."""
11461160
if not self._locked:
1147-
self._file = open(os.path.join(self._path, '.mh_sequences'), 'rb+')
1161+
self._file = self._open_mh_sequences_file(text=False)
11481162
_lock_file(self._file)
11491163
self._locked = True
11501164

@@ -1225,8 +1239,9 @@ def get_sequences(self):
12251239

12261240
def set_sequences(self, sequences):
12271241
"""Set sequences using the given name-to-key-list dictionary."""
1228-
f = open(os.path.join(self._path, '.mh_sequences'), 'w', encoding='ASCII')
1242+
f = self._open_mh_sequences_file(text=True)
12291243
try:
1244+
os.close(os.open(f.name, os.O_WRONLY | os.O_TRUNC))
12301245
for name, keys in sequences.items():
12311246
if len(keys) == 0:
12321247
continue

Lib/test/test_mailbox.py

+9
Original file line numberDiff line numberDiff line change
@@ -1360,6 +1360,15 @@ def test_no_dot_mh_sequences_file(self):
13601360
box.set_sequences({})
13611361
self.assertEqual(os.listdir(path), ['.mh_sequences'])
13621362

1363+
def test_lock_unlock_no_dot_mh_sequences_file(self):
1364+
path = os.path.join(self._path, 'foo.bar')
1365+
os.mkdir(path)
1366+
box = self._factory(path)
1367+
self.assertEqual(os.listdir(path), [])
1368+
box.lock()
1369+
box.unlock()
1370+
self.assertEqual(os.listdir(path), ['.mh_sequences'])
1371+
13631372
def test_issue2625(self):
13641373
msg0 = mailbox.MHMessage(self._template % 0)
13651374
msg0.add_sequence('foo')

0 commit comments

Comments
 (0)