1 from os
.path
import join
, normcase
, abspath
, sep
2 from django
.utils
.encoding
import force_unicode
4 def safe_join(base
, *paths
):
6 Joins one or more path components to the base path component intelligently.
7 Returns a normalized, absolute version of the final path.
9 The final path must be located inside of the base path component (otherwise
10 a ValueError is raised).
12 # We need to use normcase to ensure we don't false-negative on case
13 # insensitive operating systems (like Windows).
14 base
= force_unicode(base
)
15 paths
= [force_unicode(p
) for p
in paths
]
16 final_path
= normcase(abspath(join(base
, *paths
)))
17 base_path
= normcase(abspath(base
))
18 base_path_len
= len(base_path
)
19 # Ensure final_path starts with base_path and that the next character after
20 # the final path is os.sep (or nothing, in which case final_path must be
21 # equal to base_path).
22 if not final_path
.startswith(base_path
) \
23 or final_path
[base_path_len
:base_path_len
+1] not in ('', sep
):
24 raise ValueError('the joined path is located outside of the base path'