diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py index 2c48571787..33d8e5f7a3 100644 --- a/django/conf/global_settings.py +++ b/django/conf/global_settings.py @@ -252,6 +252,10 @@ FILE_UPLOAD_MAX_MEMORY_SIZE = 2621440 # i.e. 2.5 MB # (i.e. "/tmp" on *nix systems). FILE_UPLOAD_TEMP_DIR = None +# The numeric mode to set newly-uploaded files to. The value should be a mode +# you'd pass directly to os.chmod; see http://docs.python.org/lib/os-file-dir.html. +FILE_UPLOAD_PERMISSIONS = None + # Default formatting for date objects. See all available format strings here: # http://www.djangoproject.com/documentation/templates/#now DATE_FORMAT = 'N j, Y' diff --git a/django/core/files/storage.py b/django/core/files/storage.py index a320b8e447..8451485915 100644 --- a/django/core/files/storage.py +++ b/django/core/files/storage.py @@ -172,7 +172,10 @@ class FileSystemStorage(Storage): else: # OK, the file save worked. Break out of the loop. break - + + if settings.FILE_UPLOAD_PERMISSIONS is not None: + os.chmod(full_path, settings.FILE_UPLOAD_PERMISSIONS) + return name def delete(self, name): diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index e4e32742ea..6273a3676f 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -453,6 +453,8 @@ Default: ``'utf-8'`` The character encoding used to decode any files read from disk. This includes template files and initial SQL data files. +.. setting:: FILE_UPLOAD_HANDLERS + FILE_UPLOAD_HANDLERS -------------------- @@ -465,6 +467,8 @@ Default:: A tuple of handlers to use for uploading. See :ref:`topics-files` for details. +.. setting:: FILE_UPLOAD_MAX_MEMORY_SIZE + FILE_UPLOAD_MAX_MEMORY_SIZE --------------------------- @@ -475,6 +479,8 @@ 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 :ref:`topics-files` for details. +.. setting:: FILE_UPLOAD_TEMP_DIR + FILE_UPLOAD_TEMP_DIR -------------------- @@ -488,6 +494,34 @@ example, this will default to '/tmp' on \*nix-style operating systems. See :ref:`topics-files` for details. +.. setting:: FILE_UPLOAD_PERMISSIONS + +FILE_UPLOAD_PERMISSIONS +----------------------- + +Default: ``None`` + +The numeric mode (i.e. ``0644``) to set newly uploaded files to. For +more information about what these modes mean, see the `documentation for +os.chmod`_ + +If this isn't given or is ``None``, you'll get operating-system +dependent behavior. On most platforms, temporary files will have a mode +of ``0600``, and files saved from memory will be saved using the +system's standard umask. + +.. warning:: + + **Always prefix the mode with a 0.** + + If you're not familiar with file modes, please note that the leading + ``0`` is very important: it indicates an octal number, which is the + way that modes must be specified. If you try to use ``644``, you'll + get totally incorrect behavior. + + +.. _documentation for os.chmod: http://docs.python.org/lib/os-file-dir.html + .. setting:: FIXTURE_DIRS FIXTURE_DIRS diff --git a/docs/topics/http/file-uploads.txt b/docs/topics/http/file-uploads.txt index 54edd9e72d..6f7c5fbe83 100644 --- a/docs/topics/http/file-uploads.txt +++ b/docs/topics/http/file-uploads.txt @@ -122,25 +122,43 @@ Changing upload handler behavior Three settings control Django's file upload behavior: - ``FILE_UPLOAD_MAX_MEMORY_SIZE`` - The maximum size, in bytes, for files that will be uploaded - into memory. Files larger than ``FILE_UPLOAD_MAX_MEMORY_SIZE`` - will be streamed to disk. + :setting:`FILE_UPLOAD_MAX_MEMORY_SIZE` + The maximum size, in bytes, for files that will be uploaded into memory. + Files larger than :setting:`FILE_UPLOAD_MAX_MEMORY_SIZE` will be + streamed to disk. Defaults to 2.5 megabytes. - ``FILE_UPLOAD_TEMP_DIR`` - The directory where uploaded files larger than ``FILE_UPLOAD_TEMP_DIR`` - will be stored. + :setting:`FILE_UPLOAD_TEMP_DIR` + The directory where uploaded files larger than + :setting:`FILE_UPLOAD_TEMP_DIR` will be stored. Defaults to your system's standard temporary directory (i.e. ``/tmp`` on most Unix-like systems). + + :setting:`FILE_UPLOAD_PERMISSIONS` + The numeric mode (i.e. ``0644``) to set newly uploaded files to. For + more information about what these modes mean, see the `documentation for + os.chmod`_ + + If this isn't given or is ``None``, you'll get operating-system + dependent behavior. On most platforms, temporary files will have a mode + of ``0600``, and files saved from memory will be saved using the + system's standard umask. + + .. warning:: + + If you're not familiar with file modes, please note that the leading + ``0`` is very important: it indicates an octal number, which is the + way that modes must be specified. If you try to use ``644``, you'll + get totally incorrect behavior. + + **Always prefix the mode with a ``0``.** - ``FILE_UPLOAD_HANDLERS`` - The actual handlers for uploaded files. Changing this setting - allows complete customization -- even replacement -- of - Django's upload process. See `upload handlers`_, below, - for details. + :setting:`FILE_UPLOAD_HANDLERS` + The actual handlers for uploaded files. Changing this setting allows + complete customization -- even replacement -- of Django's upload + process. See `upload handlers`_, below, for details. Defaults to:: @@ -150,6 +168,8 @@ Three settings control Django's file upload behavior: Which means "try to upload to memory first, then fall back to temporary files." +.. _documentation for os.chmod: http://docs.python.org/lib/os-file-dir.html + ``UploadedFile`` objects ======================== diff --git a/tests/regressiontests/file_storage/tests.py b/tests/regressiontests/file_storage/tests.py index 3f059c7f3c..181c551c24 100644 --- a/tests/regressiontests/file_storage/tests.py +++ b/tests/regressiontests/file_storage/tests.py @@ -86,9 +86,10 @@ u'custom_storage.2' # Tests for a race condition on file saving (#4948). # This is written in such a way that it'll always pass on platforms # without threading. - +import os import time from unittest import TestCase +from django.conf import settings from django.core.files.base import ContentFile from models import temp_storage try: @@ -117,3 +118,15 @@ class FileSaveRaceConditionTest(TestCase): temp_storage.delete('conflict') temp_storage.delete('conflict_') +class FileStoragePermissions(TestCase): + def setUp(self): + self.old_perms = settings.FILE_UPLOAD_PERMISSIONS + settings.FILE_UPLOAD_PERMISSIONS = 0666 + + def test_file_upload_permissions(self): + name = temp_storage.save("the_file", ContentFile("data")) + actual_mode = os.stat(temp_storage.path(name))[0] & 0777 + self.assertEqual(actual_mode, 0666) + + def tearDown(self): + settings.FILE_UPLOAD_PERMISSIONS = self.old_perms \ No newline at end of file