@@ -763,50 +763,55 @@ def interactive_open(targets, command=None):
763
763
return os .execlp (* command )
764
764
765
765
766
- def is_filesystem_case_sensitive (path ):
767
- """Checks if the filesystem at the given path is case sensitive.
768
- If the path does not exist, a case sensitive file system is
769
- assumed if the system is not windows.
766
+ def _windows_long_path_name (short_path ):
767
+ """Use Windows' `GetLongPathNameW` via ctypes to get the canonical,
768
+ long path given a short filename.
769
+ """
770
+ if not isinstance (short_path , unicode ):
771
+ short_path = unicode (short_path )
772
+ buf = ctypes .create_unicode_buffer (260 )
773
+ get_long_path_name_w = ctypes .windll .kernel32 .GetLongPathNameW
774
+ return_value = get_long_path_name_w (short_path , buf , 260 )
775
+ if return_value == 0 or return_value > 260 :
776
+ # An error occurred
777
+ return short_path
778
+ else :
779
+ long_path = buf .value
780
+ # GetLongPathNameW does not change the case of the drive
781
+ # letter.
782
+ if len (long_path ) > 1 and long_path [1 ] == ':' :
783
+ long_path = long_path [0 ].upper () + long_path [1 :]
784
+ return long_path
785
+
770
786
771
- :param path: The path to check for case sensitivity.
772
- :return: True if the file system is case sensitive, False else.
787
+ def case_sensitive (path ):
788
+ """Check whether the filesystem at the given path is case sensitive.
789
+
790
+ To work best, the path should point to a file or a directory. If the path
791
+ does not exist, assume a case sensitive file system on every platform
792
+ except Windows.
773
793
"""
774
- if os .path .exists (path ):
775
- # Check if the path to the library exists in lower and upper case
776
- if os .path .exists (path .lower ()) and \
777
- os .path .exists (path .upper ()):
778
- # All the paths may exist on the file system. Check if they
779
- # refer to different files
780
- if platform .system () != 'Windows' :
781
- # os.path.samefile is only available on Unix systems for
782
- # python < 3.0
783
- return not os .path .samefile (path .lower (),
784
- path .upper ())
785
-
786
- # On windows we use GetLongPathNameW to determine the real path
787
- # using the actual case.
788
- def get_long_path_name (short_path ):
789
- if not isinstance (short_path , unicode ):
790
- short_path = unicode (short_path )
791
- buf = ctypes .create_unicode_buffer (260 )
792
- get_long_path_name_w = ctypes .windll .kernel32 .GetLongPathNameW
793
- return_value = get_long_path_name_w (short_path , buf , 260 )
794
- if return_value == 0 or return_value > 260 :
795
- # An error occurred
796
- return short_path
797
- else :
798
- long_path = buf .value
799
- # GetLongPathNameW does not change the case of the drive
800
- # letter.
801
- if len (long_path ) > 1 and long_path [1 ] == ':' :
802
- long_path = long_path [0 ].upper () + long_path [1 :]
803
- return long_path
804
-
805
- lower = get_long_path_name (path .lower ())
806
- upper = get_long_path_name (path .upper ())
807
-
808
- return lower != upper
809
- else :
810
- return True
811
- # By default, the case sensitivity depends on the platform.
812
- return platform .system () != 'Windows'
794
+ # A fallback in case the path does not exist.
795
+ if not os .path .exists (path ):
796
+ # By default, the case sensitivity depends on the platform.
797
+ return platform .system () != 'Windows'
798
+
799
+ # If an upper-case version of the path exists but a lower-case
800
+ # version does not, then the filesystem must be case-sensitive.
801
+ # (Otherwise, we have more work to do.)
802
+ if not (os .path .exists (path .lower ()) and
803
+ os .path .exists (path .upper ())):
804
+ return True
805
+
806
+ # Both versions of the path exist on the file system. Check whether
807
+ # they refer to different files by their inodes. Alas,
808
+ # `os.path.samefile` is only available on Unix systems on Python 2.
809
+ if platform .system () != 'Windows' :
810
+ return not os .path .samefile (path .lower (),
811
+ path .upper ())
812
+
813
+ # On Windows, we check whether the canonical, long filenames for the
814
+ # files are the same.
815
+ lower = _windows_long_path_name (path .lower ())
816
+ upper = _windows_long_path_name (path .upper ())
817
+ return lower != upper
0 commit comments