Django

Code

Ticket #8203: django-win32-8203+samefile+copystat+test.patch

File django-win32-8203+samefile+copystat+test.patch, 6.5 kB (added by snaury, 2 years ago)

A more thorough implementation that has some necessary bits copied from shutil (plus removed forgotten import sys in django.core.files.temp)

  • django/core/files/move.py

    old new  
    77 
    88import os 
    99from django.core.files import locks 
    10  
    11 __all__ = ['file_move_safe'] 
    12  
    1310try: 
    14     import shutil 
    15     file_move = shutil.move 
     11    from shutil import copystat 
    1612except ImportError: 
    17     file_move = os.rename 
     13    def copystat(src, dst): 
     14        """Copy all stat info (mode bits, atime and mtime) from src to dst""" 
     15        st = os.stat(src) 
     16        mode = stat.S_IMODE(st.st_mode) 
     17        if hasattr(os, 'utime'): 
     18            os.utime(dst, (st.st_atime, st.st_mtime)) 
     19        if hasattr(os, 'chmod'): 
     20            os.chmod(dst, mode) 
     21 
     22__all__ = ['file_move_safe'] 
     23 
     24def _samefile(src, dst): 
     25    # Macintosh, Unix. 
     26    if hasattr(os.path,'samefile'): 
     27        try: 
     28            return os.path.samefile(src, dst) 
     29        except OSError: 
     30            return False 
     31 
     32    # All other platforms: check for same pathname. 
     33    return (os.path.normcase(os.path.abspath(src)) == 
     34            os.path.normcase(os.path.abspath(dst))) 
    1835 
    1936def file_move_safe(old_file_name, new_file_name, chunk_size = 1024*64, allow_overwrite=False): 
    2037    """ 
     
    3047    """ 
    3148 
    3249    # There's no reason to move if we don't have to. 
    33     if old_file_name == new_file_name
     50    if _samefile(old_file_name, new_file_name)
    3451        return 
    3552 
    36     if not allow_overwrite and os.path.exists(new_file_name): 
    37         raise IOError("Cannot overwrite existing file '%s'." % new_file_name) 
    38  
    3953    try: 
    40         file_move(old_file_name, new_file_name) 
     54        os.rename(old_file_name, new_file_name) 
    4155        return 
    4256    except OSError: 
    4357        # This will happen with os.rename if moving to another filesystem 
     58        # or when moving opened files on certain operating systems 
    4459        pass 
    4560 
    46     # If the built-in didn't work, do it the hard way. 
    47     fd = os.open(new_file_name, os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, 'O_BINARY', 0)
     61    # first open the old file, so that it won't go away 
     62    old_file = open(old_file_name, 'rb'
    4863    try: 
    49         locks.lock(fd, locks.LOCK_EX) 
    50         old_file = open(old_file_name, 'rb') 
    51         current_chunk = None 
    52         while current_chunk != '': 
    53             current_chunk = old_file.read(chunk_size) 
    54             os.write(fd, current_chunk) 
     64        # now open the new file, not forgetting allow_overwrite 
     65        fd = os.open(new_file_name, os.O_WRONLY | os.O_CREAT | getattr(os, 'O_BINARY', 0) | 
     66                                    (not allow_overwrite and os.O_EXCL or 0)) 
     67        try: 
     68            locks.lock(fd, locks.LOCK_EX) 
     69            current_chunk = None 
     70            while current_chunk != '': 
     71                current_chunk = old_file.read(chunk_size) 
     72                os.write(fd, current_chunk) 
     73        finally: 
     74            locks.unlock(fd) 
     75            os.close(fd) 
    5576    finally: 
    56         locks.unlock(fd) 
    57         os.close(fd) 
    5877        old_file.close() 
     78    copystat(old_file_name, new_file_name) 
    5979 
    60     os.remove(old_file_name) 
     80    try: 
     81        os.remove(old_file_name) 
     82    except OSError, e: 
     83        # Certain operating systems (Cygwin and Windows) 
     84        # fail when deleting opened files, ignore it 
     85        if getattr(e, 'winerror', 0) != 32: 
     86            # FIXME: should we also ignore errno 13? 
     87            raise 
  • django/core/files/temp.py

    old new  
    2525            fd, name = tempfile.mkstemp(suffix=suffix, prefix=prefix, 
    2626                                          dir=dir) 
    2727            self.name = name 
    28             self._file = os.fdopen(fd, mode, bufsize) 
     28            self.file = os.fdopen(fd, mode, bufsize) 
     29            self.close_called = False 
     30 
     31        # Because close can be called during shutdown 
     32        # we need to cache os.unlink and access it 
     33        # as self.unlink only 
     34        unlink = os.unlink 
     35 
     36        def close(self): 
     37            if not self.close_called: 
     38                self.close_called = True 
     39                try: 
     40                    self.file.close() 
     41                except (OSError, IOError): 
     42                    pass 
     43                try: 
     44                    self.unlink(self.name) 
     45                except (OSError): 
     46                    pass 
    2947 
    3048        def __del__(self): 
    31             try: 
    32                 self._file.close() 
    33             except (OSError, IOError): 
    34                 pass 
    35             try: 
    36                 os.unlink(self.name) 
    37             except (OSError): 
    38                 pass 
    39  
    40             try: 
    41                 super(TemporaryFile, self).__del__() 
    42             except AttributeError: 
    43                 pass 
    44  
    45  
    46         def read(self, *args):          return self._file.read(*args) 
    47         def seek(self, offset):         return self._file.seek(offset) 
    48         def write(self, s):             return self._file.write(s) 
    49         def close(self):                return self._file.close() 
    50         def __iter__(self):             return iter(self._file) 
    51         def readlines(self, size=None): return self._file.readlines(size) 
    52         def xreadlines(self):           return self._file.xreadlines() 
     49            self.close() 
     50 
     51        def read(self, *args):          return self.file.read(*args) 
     52        def seek(self, offset):         return self.file.seek(offset) 
     53        def write(self, s):             return self.file.write(s) 
     54        def __iter__(self):             return iter(self.file) 
     55        def readlines(self, size=None): return self.file.readlines(size) 
     56        def xreadlines(self):           return self.file.xreadlines() 
    5357 
    5458    NamedTemporaryFile = TemporaryFile 
    5559else: 
  • tests/regressiontests/file_uploads/views.py

    old new  
    22from django.core.files.uploadedfile import UploadedFile 
    33from django.http import HttpResponse, HttpResponseServerError 
    44from django.utils import simplejson 
     5from models import FileModel 
    56from uploadhandler import QuotaUploadHandler 
    67from django.utils.hashcompat import sha_constructor 
    78 
     
    4546        if new_hash != submitted_hash: 
    4647            return HttpResponseServerError() 
    4748 
     49    # Adding large file to the database should succeed 
     50    largefile = request.FILES['file_field2'] 
     51    obj = FileModel() 
     52    obj.testfile.save(largefile.name, largefile) 
     53 
    4854    return HttpResponse('') 
    4955 
    5056def file_upload_echo(request):