web/lib/django/utils/_os.py
changeset 38 77b6da96e6f1
parent 0 0d40e90630ef
equal deleted inserted replaced
37:8d941af65caf 38:77b6da96e6f1
       
     1 import os
       
     2 from os.path import join, normcase, normpath, abspath, isabs, sep
       
     3 from django.utils.encoding import force_unicode
       
     4 
       
     5 # Define our own abspath function that can handle joining 
       
     6 # unicode paths to a current working directory that has non-ASCII
       
     7 # characters in it.  This isn't necessary on Windows since the 
       
     8 # Windows version of abspath handles this correctly.  The Windows
       
     9 # abspath also handles drive letters differently than the pure 
       
    10 # Python implementation, so it's best not to replace it.
       
    11 if os.name == 'nt':
       
    12     abspathu = abspath
       
    13 else:
       
    14     def abspathu(path):
       
    15         """
       
    16         Version of os.path.abspath that uses the unicode representation
       
    17         of the current working directory, thus avoiding a UnicodeDecodeError
       
    18         in join when the cwd has non-ASCII characters.
       
    19         """
       
    20         if not isabs(path):
       
    21             path = join(os.getcwdu(), path)
       
    22         return normpath(path)
       
    23 
       
    24 def safe_join(base, *paths):
       
    25     """
       
    26     Joins one or more path components to the base path component intelligently.
       
    27     Returns a normalized, absolute version of the final path.
       
    28 
       
    29     The final path must be located inside of the base path component (otherwise
       
    30     a ValueError is raised).
       
    31     """
       
    32     # We need to use normcase to ensure we don't false-negative on case
       
    33     # insensitive operating systems (like Windows).
       
    34     base = force_unicode(base)
       
    35     paths = [force_unicode(p) for p in paths]
       
    36     final_path = normcase(abspathu(join(base, *paths)))
       
    37     base_path = normcase(abspathu(base))
       
    38     base_path_len = len(base_path)
       
    39     # Ensure final_path starts with base_path and that the next character after
       
    40     # the final path is os.sep (or nothing, in which case final_path must be
       
    41     # equal to base_path).
       
    42     if not final_path.startswith(base_path) \
       
    43        or final_path[base_path_len:base_path_len+1] not in ('', sep):
       
    44         raise ValueError('the joined path is located outside of the base path'
       
    45                          ' component')
       
    46     return final_path