You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import os
  2. import tempfile
  3. from os.path import abspath, dirname, join, normcase, sep
  4. from django.core.exceptions import SuspiciousFileOperation
  5. # For backwards-compatibility in Django 2.0
  6. abspathu = abspath
  7. def upath(path):
  8. """Always return a unicode path (did something for Python 2)."""
  9. return path
  10. def npath(path):
  11. """
  12. Always return a native path, that is unicode on Python 3 and bytestring on
  13. Python 2. Noop for Python 3.
  14. """
  15. return path
  16. def safe_join(base, *paths):
  17. """
  18. Join one or more path components to the base path component intelligently.
  19. Return a normalized, absolute version of the final path.
  20. Raise ValueError if the final path isn't located inside of the base path
  21. component.
  22. """
  23. final_path = abspath(join(base, *paths))
  24. base_path = abspath(base)
  25. # Ensure final_path starts with base_path (using normcase to ensure we
  26. # don't false-negative on case insensitive operating systems like Windows),
  27. # further, one of the following conditions must be true:
  28. # a) The next character is the path separator (to prevent conditions like
  29. # safe_join("/dir", "/../d"))
  30. # b) The final path must be the same as the base path.
  31. # c) The base path must be the most root path (meaning either "/" or "C:\\")
  32. if (not normcase(final_path).startswith(normcase(base_path + sep)) and
  33. normcase(final_path) != normcase(base_path) and
  34. dirname(normcase(base_path)) != normcase(base_path)):
  35. raise SuspiciousFileOperation(
  36. 'The joined path ({}) is located outside of the base path '
  37. 'component ({})'.format(final_path, base_path))
  38. return final_path
  39. def symlinks_supported():
  40. """
  41. Return whether or not creating symlinks are supported in the host platform
  42. and/or if they are allowed to be created (e.g. on Windows it requires admin
  43. permissions).
  44. """
  45. with tempfile.TemporaryDirectory() as temp_dir:
  46. original_path = os.path.join(temp_dir, 'original')
  47. symlink_path = os.path.join(temp_dir, 'symlink')
  48. os.makedirs(original_path)
  49. try:
  50. os.symlink(original_path, symlink_path)
  51. supported = True
  52. except (OSError, NotImplementedError):
  53. supported = False
  54. return supported