summaryrefslogtreecommitdiff
path: root/django/core/files/storage.py
diff options
context:
space:
mode:
Diffstat (limited to 'django/core/files/storage.py')
-rw-r--r--django/core/files/storage.py9
1 files changed, 8 insertions, 1 deletions
diff --git a/django/core/files/storage.py b/django/core/files/storage.py
index 3e68853b59..22984f9498 100644
--- a/django/core/files/storage.py
+++ b/django/core/files/storage.py
@@ -51,7 +51,10 @@ class Storage:
content = File(content, name)
name = self.get_available_name(name, max_length=max_length)
- return self._save(name, content)
+ name = self._save(name, content)
+ # Ensure that the name returned from the storage system is still valid.
+ validate_file_name(name, allow_relative_path=True)
+ return name
# These methods are part of the public API, with default implementations.
@@ -75,6 +78,7 @@ class Storage:
Return a filename that's free on the target storage system and
available for new content to be written to.
"""
+ name = str(name).replace('\\', '/')
dir_name, file_name = os.path.split(name)
if '..' in pathlib.PurePath(dir_name).parts:
raise SuspiciousFileOperation("Detected path traversal attempt in '%s'" % dir_name)
@@ -108,6 +112,7 @@ class Storage:
Validate the filename by calling get_valid_name() and return a filename
to be passed to the save() method.
"""
+ filename = str(filename).replace('\\', '/')
# `filename` may include a path as returned by FileField.upload_to.
dirname, filename = os.path.split(filename)
if '..' in pathlib.PurePath(dirname).parts:
@@ -297,6 +302,8 @@ class FileSystemStorage(Storage):
if self.file_permissions_mode is not None:
os.chmod(full_path, self.file_permissions_mode)
+ # Ensure the saved path is always relative to the storage root.
+ name = os.path.relpath(full_path, self.location)
# Store filenames with forward slashes, even on Windows.
return str(name).replace('\\', '/')