1
0
mirror of https://github.com/django/django.git synced 2025-06-05 11:39:13 +00:00

Fixed #26691 -- Removed checking for a file's existence before deleting.

File operations always raise a ENOENT error when a file doesn't exist.
Checking the file exists before the operation adds a race condition
condition where the file could be removed between operations. As the
operation already raises an error on a missing file, avoid this race and
avoid checking the file exists twice. Instead only check a file exists
by catching the ENOENT error.
This commit is contained in:
Jon Dufresne 2016-05-26 08:36:00 -07:00 committed by Tim Graham
parent e3877c53ed
commit 359be1c870
3 changed files with 19 additions and 23 deletions

View File

@ -35,14 +35,13 @@ class FileBasedCache(BaseCache):
def get(self, key, default=None, version=None): def get(self, key, default=None, version=None):
fname = self._key_to_file(key, version) fname = self._key_to_file(key, version)
if os.path.exists(fname): try:
try: with io.open(fname, 'rb') as f:
with io.open(fname, 'rb') as f: if not self._is_expired(f):
if not self._is_expired(f): return pickle.loads(zlib.decompress(f.read()))
return pickle.loads(zlib.decompress(f.read())) except IOError as e:
except IOError as e: if e.errno == errno.ENOENT:
if e.errno == errno.ENOENT: pass # Cache file doesn't exist.
pass # Cache file was removed after the exists check
return default return default
def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None): def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):

View File

@ -380,15 +380,13 @@ class FileSystemStorage(Storage):
assert name, "The name argument is not allowed to be empty." assert name, "The name argument is not allowed to be empty."
name = self.path(name) name = self.path(name)
# If the file exists, delete it from the filesystem. # If the file exists, delete it from the filesystem.
# Note that there is a race between os.path.exists and os.remove: # If os.remove() fails with ENOENT, the file may have been removed
# if os.remove fails with ENOENT, the file was removed # concurrently, and it's safe to continue normally.
# concurrently, and we can continue normally. try:
if os.path.exists(name): os.remove(name)
try: except OSError as e:
os.remove(name) if e.errno != errno.ENOENT:
except OSError as e: raise
if e.errno != errno.ENOENT:
raise
def exists(self, name): def exists(self, name):
return os.path.exists(self.path(name)) return os.path.exists(self.path(name))

View File

@ -48,12 +48,11 @@ class PathNotImplementedStorage(storage.Storage):
def delete(self, name): def delete(self, name):
name = self._path(name) name = self._path(name)
if os.path.exists(name): try:
try: os.remove(name)
os.remove(name) except OSError as e:
except OSError as e: if e.errno != errno.ENOENT:
if e.errno != errno.ENOENT: raise
raise
def path(self, name): def path(self, name):
raise NotImplementedError raise NotImplementedError