Fixed #9610 -- Fixed duplicate uploaded file name mangling when directory contained a dot and file didn't. Based on patches from fadlytabrani and adurdin.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@10701 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Gary Wilson Jr 2009-05-08 05:50:31 +00:00
parent 304785bf26
commit 59507753c7
2 changed files with 51 additions and 12 deletions

View File

@ -63,15 +63,15 @@ class Storage(object):
Returns a filename that's free on the target storage system, and Returns a filename that's free on the target storage system, and
available for new content to be written to. available for new content to be written to.
""" """
# If the filename already exists, keep adding an underscore to the name dir_name, file_name = os.path.split(name)
# of the file until the filename doesn't exist. file_root, file_ext = os.path.splitext(file_name)
# If the filename already exists, keep adding an underscore (before the
# file extension, if one exists) to the filename until the generated
# filename doesn't exist.
while self.exists(name): while self.exists(name):
try: file_root += '_'
dot_index = name.rindex('.') # file_ext includes the dot.
except ValueError: # filename has no dot name = os.path.join(dir_name, file_root + file_ext)
name += '_'
else:
name = name[:dot_index] + '_' + name[dot_index:]
return name return name
def path(self, name): def path(self, name):

View File

@ -84,11 +84,12 @@ u'custom_storage.2'
""" """
# Tests for a race condition on file saving (#4948). # Tests for a race condition on file saving (#4948).
# This is written in such a way that it'll always pass on platforms # This is written in such a way that it'll always pass on platforms
# without threading. # without threading.
import os import os
import time import time
import shutil import shutil
import sys
import tempfile import tempfile
from unittest import TestCase from unittest import TestCase
from django.conf import settings from django.conf import settings
@ -109,13 +110,13 @@ class FileSaveRaceConditionTest(TestCase):
self.storage_dir = tempfile.mkdtemp() self.storage_dir = tempfile.mkdtemp()
self.storage = FileSystemStorage(self.storage_dir) self.storage = FileSystemStorage(self.storage_dir)
self.thread = threading.Thread(target=self.save_file, args=['conflict']) self.thread = threading.Thread(target=self.save_file, args=['conflict'])
def tearDown(self): def tearDown(self):
shutil.rmtree(self.storage_dir) shutil.rmtree(self.storage_dir)
def save_file(self, name): def save_file(self, name):
name = self.storage.save(name, SlowFile("Data")) name = self.storage.save(name, SlowFile("Data"))
def test_race_condition(self): def test_race_condition(self):
self.thread.start() self.thread.start()
name = self.save_file('conflict') name = self.save_file('conflict')
@ -141,3 +142,41 @@ class FileStoragePermissions(TestCase):
actual_mode = os.stat(self.storage.path(name))[0] & 0777 actual_mode = os.stat(self.storage.path(name))[0] & 0777
self.assertEqual(actual_mode, 0666) self.assertEqual(actual_mode, 0666)
class FileStoragePathParsing(TestCase):
def setUp(self):
self.storage_dir = tempfile.mkdtemp()
self.storage = FileSystemStorage(self.storage_dir)
def tearDown(self):
shutil.rmtree(self.storage_dir)
def test_directory_with_dot(self):
"""Regression test for #9610.
If the directory name contains a dot and the file name doesn't, make
sure we still mangle the file name instead of the directory name.
"""
self.storage.save('dotted.path/test', ContentFile("1"))
self.storage.save('dotted.path/test', ContentFile("2"))
self.assertFalse(os.path.exists(os.path.join(self.storage_dir, 'dotted_.path')))
self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/test')))
self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/test_')))
def test_first_character_dot(self):
"""
File names with a dot as their first character don't have an extension,
and the underscore should get added to the end.
"""
self.storage.save('dotted.path/.test', ContentFile("1"))
self.storage.save('dotted.path/.test', ContentFile("2"))
self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/.test')))
# Before 2.6, a leading dot was treated as an extension, and so
# underscore gets added to beginning instead of end.
if sys.version_info < (2, 6):
self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/_.test')))
else:
self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/.test_')))