summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMel Collins <mel@raumkraut.net>2013-05-13 13:38:53 +0200
committerTim Graham <timograham@gmail.com>2013-08-12 07:15:59 -0400
commit6bdb3b1135d1bd7b2dc24131b9d26ac19ebdba67 (patch)
tree4f9e44d7b494b737ed11d7346ff7258c182cfbb3
parentab680725bfb2f0d79cff26331b30a3d583c55a80 (diff)
Fixed #13518 -- Added FILE_UPLOAD_DIRECTORY_PERMISSIONS setting
This setting does for new directories what FILE_UPLOAD_PERMISSIONS does for new files. Thanks jacob@ for the suggestion.
-rw-r--r--django/conf/global_settings.py5
-rw-r--r--django/core/files/storage.py11
-rw-r--r--docs/ref/settings.txt13
-rw-r--r--docs/releases/1.7.txt4
-rw-r--r--docs/topics/http/file-uploads.txt7
-rw-r--r--tests/file_storage/tests.py12
6 files changed, 50 insertions, 2 deletions
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index 19258fbcd4..95deaa8d87 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -313,6 +313,11 @@ FILE_UPLOAD_TEMP_DIR = None
# you'd pass directly to os.chmod; see http://docs.python.org/lib/os-file-dir.html.
FILE_UPLOAD_PERMISSIONS = None
+# The numeric mode to assign to newly-created directories, when uploading files.
+# The value should be a mode as you'd pass to os.chmod;
+# see http://docs.python.org/lib/os-file-dir.html.
+FILE_UPLOAD_DIRECTORY_PERMISSIONS = None
+
# Python module path where user will place custom format definition.
# The directory where this setting is pointing should contain subdirectories
# named as the locales, containing a formats.py file
diff --git a/django/core/files/storage.py b/django/core/files/storage.py
index 5d301a317c..5e587da2da 100644
--- a/django/core/files/storage.py
+++ b/django/core/files/storage.py
@@ -172,7 +172,16 @@ class FileSystemStorage(Storage):
directory = os.path.dirname(full_path)
if not os.path.exists(directory):
try:
- os.makedirs(directory)
+ if settings.FILE_UPLOAD_DIRECTORY_PERMISSIONS is not None:
+ # os.makedirs applies the global umask, so we reset it,
+ # for consistency with FILE_UPLOAD_PERMISSIONS behavior.
+ old_umask = os.umask(0)
+ try:
+ os.makedirs(directory, settings.FILE_UPLOAD_DIRECTORY_PERMISSIONS)
+ finally:
+ os.umask(old_umask)
+ else:
+ os.makedirs(directory)
except OSError as e:
if e.errno != errno.EEXIST:
raise
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 38d7275aed..90545d96c5 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -1108,6 +1108,19 @@ Default: ``2621440`` (i.e. 2.5 MB).
The maximum size (in bytes) that an upload will be before it gets streamed to
the file system. See :doc:`/topics/files` for details.
+.. setting:: FILE_UPLOAD_DIRECTORY_PERMISSIONS
+
+FILE_UPLOAD_DIRECTORY_PERMISSIONS
+---------------------------------
+
+.. versionadded:: 1.7
+
+Default: ``None``
+
+The numeric mode to apply to directories created in the process of
+uploading files. This value mirrors the functionality and caveats of
+the :setting:`FILE_UPLOAD_PERMISSIONS` setting.
+
.. setting:: FILE_UPLOAD_PERMISSIONS
FILE_UPLOAD_PERMISSIONS
diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt
index ec37b382d4..6fda83ebc7 100644
--- a/docs/releases/1.7.txt
+++ b/docs/releases/1.7.txt
@@ -138,6 +138,10 @@ Minor features
* The :func:`~django.contrib.auth.decorators.permission_required` decorator can
take a list of permissions as well as a single permission.
+* The new :setting:`FILE_UPLOAD_DIRECTORY_PERMISSIONS` setting controls
+ the file system permissions of directories created during file upload, like
+ :setting:`FILE_UPLOAD_PERMISSIONS` does for the files themselves.
+
Backwards incompatible changes in 1.7
=====================================
diff --git a/docs/topics/http/file-uploads.txt b/docs/topics/http/file-uploads.txt
index 2cdab9ea9b..d88524ee20 100644
--- a/docs/topics/http/file-uploads.txt
+++ b/docs/topics/http/file-uploads.txt
@@ -132,7 +132,7 @@ upload behavior.
Changing upload handler behavior
--------------------------------
-Three settings control Django's file upload behavior:
+There are a few settings which control Django's file upload behavior:
:setting:`FILE_UPLOAD_MAX_MEMORY_SIZE`
The maximum size, in bytes, for files that will be uploaded into memory.
@@ -167,6 +167,11 @@ Three settings control Django's file upload behavior:
**Always prefix the mode with a 0.**
+:setting:`FILE_UPLOAD_DIRECTORY_PERMISSIONS`
+ The numeric mode to apply to directories created in the process of
+ uploading files. This value mirrors the functionality and caveats of
+ the :setting:`FILE_UPLOAD_PERMISSIONS` setting.
+
:setting:`FILE_UPLOAD_HANDLERS`
The actual handlers for uploaded files. Changing this setting allows
complete customization -- even replacement -- of Django's upload
diff --git a/tests/file_storage/tests.py b/tests/file_storage/tests.py
index cdd9720374..2a6f602e3e 100644
--- a/tests/file_storage/tests.py
+++ b/tests/file_storage/tests.py
@@ -462,6 +462,18 @@ class FileStoragePermissions(unittest.TestCase):
mode = os.stat(self.storage.path(fname))[0] & 0o777
self.assertEqual(mode, 0o666 & ~self.umask)
+ @override_settings(FILE_UPLOAD_DIRECTORY_PERMISSIONS=0o765)
+ def test_file_upload_directory_permissions(self):
+ name = self.storage.save("the_directory/the_file", ContentFile("data"))
+ dir_mode = os.stat(os.path.dirname(self.storage.path(name)))[0] & 0o777
+ self.assertEqual(dir_mode, 0o765)
+
+ @override_settings(FILE_UPLOAD_DIRECTORY_PERMISSIONS=None)
+ def test_file_upload_directory_default_permissions(self):
+ name = self.storage.save("the_directory/the_file", ContentFile("data"))
+ dir_mode = os.stat(os.path.dirname(self.storage.path(name)))[0] & 0o777
+ self.assertEqual(dir_mode, 0o777 & ~self.umask)
+
class FileStoragePathParsing(unittest.TestCase):
def setUp(self):
self.storage_dir = tempfile.mkdtemp()