Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.0.X]: Fixed #9610 -- Fixed duplicate uploaded file name mangling w…

…hen directory contained a dot and file didn't. Based on patches from fadlytabrani and adurdin.

Backport of r10701 from trunk.


git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@10702 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit e93b3a7b02ab3c8fb04a794458c85a5f6d7f26b1 1 parent 1b9893f
Gary Wilson Jr. authored May 08, 2009
16  django/core/files/storage.py
@@ -62,15 +62,15 @@ def get_available_name(self, name):
62 62
         Returns a filename that's free on the target storage system, and
63 63
         available for new content to be written to.
64 64
         """
65  
-        # If the filename already exists, keep adding an underscore to the name
66  
-        # of the file until the filename doesn't exist.
  65
+        dir_name, file_name = os.path.split(name)
  66
+        file_root, file_ext = os.path.splitext(file_name)
  67
+        # If the filename already exists, keep adding an underscore (before the
  68
+        # file extension, if one exists) to the filename until the generated
  69
+        # filename doesn't exist.
67 70
         while self.exists(name):
68  
-            try:
69  
-                dot_index = name.rindex('.')
70  
-            except ValueError: # filename has no dot
71  
-                name += '_'
72  
-            else:
73  
-                name = name[:dot_index] + '_' + name[dot_index:]
  71
+            file_root += '_'
  72
+            # file_ext includes the dot.
  73
+            name = os.path.join(dir_name, file_root + file_ext)
74 74
         return name
75 75
 
76 76
     def path(self, name):
47  tests/regressiontests/file_storage/tests.py
@@ -84,11 +84,12 @@
84 84
 """
85 85
 
86 86
 # Tests for a race condition on file saving (#4948).
87  
-# This is written in such a way that it'll always pass on platforms 
  87
+# This is written in such a way that it'll always pass on platforms
88 88
 # without threading.
89 89
 import os
90 90
 import time
91 91
 import shutil
  92
+import sys
92 93
 import tempfile
93 94
 from unittest import TestCase
94 95
 from django.conf import settings
@@ -109,13 +110,13 @@ def setUp(self):
109 110
         self.storage_dir = tempfile.mkdtemp()
110 111
         self.storage = FileSystemStorage(self.storage_dir)
111 112
         self.thread = threading.Thread(target=self.save_file, args=['conflict'])
112  
-    
  113
+
113 114
     def tearDown(self):
114 115
         shutil.rmtree(self.storage_dir)
115  
-    
  116
+
116 117
     def save_file(self, name):
117 118
         name = self.storage.save(name, SlowFile("Data"))
118  
-    
  119
+
119 120
     def test_race_condition(self):
120 121
         self.thread.start()
121 122
         name = self.save_file('conflict')
@@ -141,3 +142,41 @@ def test_file_upload_permissions(self):
141 142
         actual_mode = os.stat(self.storage.path(name))[0] & 0777
142 143
         self.assertEqual(actual_mode, 0666)
143 144
 
  145
+
  146
+class FileStoragePathParsing(TestCase):
  147
+    def setUp(self):
  148
+        self.storage_dir = tempfile.mkdtemp()
  149
+        self.storage = FileSystemStorage(self.storage_dir)
  150
+
  151
+    def tearDown(self):
  152
+        shutil.rmtree(self.storage_dir)
  153
+
  154
+    def test_directory_with_dot(self):
  155
+        """Regression test for #9610.
  156
+
  157
+        If the directory name contains a dot and the file name doesn't, make
  158
+        sure we still mangle the file name instead of the directory name.
  159
+        """
  160
+
  161
+        self.storage.save('dotted.path/test', ContentFile("1"))
  162
+        self.storage.save('dotted.path/test', ContentFile("2"))
  163
+
  164
+        self.assertFalse(os.path.exists(os.path.join(self.storage_dir, 'dotted_.path')))
  165
+        self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/test')))
  166
+        self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/test_')))
  167
+
  168
+    def test_first_character_dot(self):
  169
+        """
  170
+        File names with a dot as their first character don't have an extension,
  171
+        and the underscore should get added to the end.
  172
+        """
  173
+        self.storage.save('dotted.path/.test', ContentFile("1"))
  174
+        self.storage.save('dotted.path/.test', ContentFile("2"))
  175
+
  176
+        self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/.test')))
  177
+        # Before 2.6, a leading dot was treated as an extension, and so
  178
+        # underscore gets added to beginning instead of end.
  179
+        if sys.version_info < (2, 6):
  180
+            self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/_.test')))
  181
+        else:
  182
+            self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/.test_')))

0 notes on commit e93b3a7

Please sign in to comment.
Something went wrong with that request. Please try again.