Skip to content

Commit

Permalink
pythongh-66515: Fix locking of an MH mailbox without ".mh_sequences" …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
serhiy-storchaka authored and Glyphack committed Jan 27, 2024
1 parent 262aeee commit 5d09364
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 2 deletions.
19 changes: 17 additions & 2 deletions Lib/mailbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -1141,10 +1141,24 @@ def __len__(self):
"""Return a count of messages in the mailbox."""
return len(list(self.iterkeys()))

def _open_mh_sequences_file(self, text):
mode = '' if text else 'b'
kwargs = {'encoding': 'ASCII'} if text else {}
path = os.path.join(self._path, '.mh_sequences')
while True:
try:
return open(path, 'r+' + mode, **kwargs)
except FileNotFoundError:
pass
try:
return open(path, 'x+' + mode, **kwargs)
except FileExistsError:
pass

def lock(self):
"""Lock the mailbox."""
if not self._locked:
self._file = open(os.path.join(self._path, '.mh_sequences'), 'rb+')
self._file = self._open_mh_sequences_file(text=False)
_lock_file(self._file)
self._locked = True

Expand Down Expand Up @@ -1225,8 +1239,9 @@ def get_sequences(self):

def set_sequences(self, sequences):
"""Set sequences using the given name-to-key-list dictionary."""
f = open(os.path.join(self._path, '.mh_sequences'), 'w', encoding='ASCII')
f = self._open_mh_sequences_file(text=True)
try:
os.close(os.open(f.name, os.O_WRONLY | os.O_TRUNC))
for name, keys in sequences.items():
if len(keys) == 0:
continue
Expand Down
9 changes: 9 additions & 0 deletions Lib/test/test_mailbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -1360,6 +1360,15 @@ def test_no_dot_mh_sequences_file(self):
box.set_sequences({})
self.assertEqual(os.listdir(path), ['.mh_sequences'])

def test_lock_unlock_no_dot_mh_sequences_file(self):
path = os.path.join(self._path, 'foo.bar')
os.mkdir(path)
box = self._factory(path)
self.assertEqual(os.listdir(path), [])
box.lock()
box.unlock()
self.assertEqual(os.listdir(path), ['.mh_sequences'])

def test_issue2625(self):
msg0 = mailbox.MHMessage(self._template % 0)
msg0.add_sequence('foo')
Expand Down

0 comments on commit 5d09364

Please sign in to comment.