join one or more path components to the base path component intelligently return a normalized absolute version of the final path raise suspiciousfileoperation if the final path isn t located inside of the base path component ensure finalpath starts with basepath using normcase to ensure we don t falsenegative on case insensitive operating systems like windows further one of the following conditions must be true a the next character is the path separator to prevent conditions like safejoindir d b the final path must be the same as the base path c the base path must be the most root path meaning either or c return whether or not creating symlinks are supported in the host platform andor if they are allowed to be created e g on windows it requires admin permissions convert value to a pathlib path instance if not already a path if isinstancevalue path return value elif not isinstancevalue str raise typeerrorinvalid path type s typevalue name return pathvalue join one or more path components to the base path component intelligently return a normalized absolute version of the final path raise suspiciousfileoperation if the final path isn t located inside of the base path component ensure final_path starts with base_path using normcase to ensure we don t false negative on case insensitive operating systems like windows further one of the following conditions must be true a the next character is the path separator to prevent conditions like safe_join dir d b the final path must be the same as the base path c the base path must be the most root path meaning either or c return whether or not creating symlinks are supported in the host platform and or if they are allowed to be created e g on windows it requires admin permissions convert value to a pathlib path instance if not already a path
import os
import tempfile
from os.path import abspath, dirname, join, normcase, sep
from pathlib import Path

from django.core.exceptions import SuspiciousFileOperation


def safe_join(base, *paths):
    
    final_path = abspath(join(base, *paths))
    base_path = abspath(base)
    
    
    
    
    
    
    
    if (
        not normcase(final_path).startswith(normcase(base_path + sep))
        and normcase(final_path) != normcase(base_path)
        and dirname(normcase(base_path)) != normcase(base_path)
    ):
        raise SuspiciousFileOperation(
            "The joined path ({}) is located outside of the base path "
            "component ({})".format(final_path, base_path)
        )
    return final_path


def symlinks_supported():
    
    with tempfile.TemporaryDirectory() as temp_dir:
        original_path = os.path.join(temp_dir, "original")
        symlink_path = os.path.join(temp_dir, "symlink")
        os.makedirs(original_path)
        try:
            os.symlink(original_path, symlink_path)
            supported = True
        except (OSError, NotImplementedError):
            supported = False
        return supported


def to_path(value):
    
    if isinstance(value, Path):
        return value
    elif not isinstance(value, str):
        raise TypeError("Invalid path type: %s" % type(value).__name__)
    return Path(value)