diff --git a/django/core/files/storage.py b/django/core/files/storage.py index a6498724eb..9a7d8793fc 100644 --- a/django/core/files/storage.py +++ b/django/core/files/storage.py @@ -240,9 +240,9 @@ class FileSystemStorage(Storage): os.umask(old_umask) else: os.makedirs(directory) - except FileNotFoundError: + except FileExistsError: # There's a race between os.path.exists() and os.makedirs(). - # If os.makedirs() fails with FileNotFoundError, the directory + # If os.makedirs() fails with FileExistsError, the directory # was created concurrently. pass if not os.path.isdir(directory): diff --git a/docs/releases/2.1.3.txt b/docs/releases/2.1.3.txt index 72ec3e4a32..f4f33803bb 100644 --- a/docs/releases/2.1.3.txt +++ b/docs/releases/2.1.3.txt @@ -20,3 +20,7 @@ Bugfixes * Fixed a regression where cached foreign keys that use ``to_field`` were incorrectly cleared in ``Model.save()`` (:ticket:`29896`). + +* Fixed a regression in Django 2.0 where ``FileSystemStorage`` crashes with + ``FileExistsError`` if concurrent saves try to create the same directory + (:ticket:`29890`). diff --git a/tests/file_storage/tests.py b/tests/file_storage/tests.py index f3011749f8..8c50abc9b0 100644 --- a/tests/file_storage/tests.py +++ b/tests/file_storage/tests.py @@ -415,9 +415,9 @@ class FileStorageTests(SimpleTestCase): real_makedirs(path) elif path == os.path.join(self.temp_dir, 'raced'): real_makedirs(path) - raise FileNotFoundError() - elif path == os.path.join(self.temp_dir, 'error'): raise FileExistsError() + elif path == os.path.join(self.temp_dir, 'error'): + raise PermissionError() else: self.fail('unexpected argument %r' % path) @@ -432,8 +432,8 @@ class FileStorageTests(SimpleTestCase): with self.storage.open('raced/test.file') as f: self.assertEqual(f.read(), b'saved with race') - # Exceptions aside from FileNotFoundError are raised. - with self.assertRaises(FileExistsError): + # Exceptions aside from FileExistsError are raised. + with self.assertRaises(PermissionError): self.storage.save('error/test.file', ContentFile('not saved')) finally: os.makedirs = real_makedirs