summaryrefslogtreecommitdiff
path: root/src/setuptools_scm/win_py31_compat.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/setuptools_scm/win_py31_compat.py')
-rw-r--r--src/setuptools_scm/win_py31_compat.py214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/setuptools_scm/win_py31_compat.py b/src/setuptools_scm/win_py31_compat.py
new file mode 100644
index 0000000..82a11eb
--- /dev/null
+++ b/src/setuptools_scm/win_py31_compat.py
@@ -0,0 +1,214 @@
+"""
+Backport of os.path.samefile for Python prior to 3.2
+on Windows from jaraco.windows 3.8.
+
+DON'T EDIT THIS FILE!
+
+Instead, file tickets and PR's with `jaraco.windows
+<https://github.com/jaraco/jaraco.windows>`_ and request
+a port to setuptools_scm.
+"""
+
+import os
+import nt
+import posixpath
+import ctypes.wintypes
+import sys
+import __builtin__ as builtins
+
+
+##
+# From jaraco.windows.error
+
+def format_system_message(errno):
+ """
+ Call FormatMessage with a system error number to retrieve
+ the descriptive error message.
+ """
+ # first some flags used by FormatMessageW
+ ALLOCATE_BUFFER = 0x100
+ FROM_SYSTEM = 0x1000
+
+ # Let FormatMessageW allocate the buffer (we'll free it below)
+ # Also, let it know we want a system error message.
+ flags = ALLOCATE_BUFFER | FROM_SYSTEM
+ source = None
+ message_id = errno
+ language_id = 0
+ result_buffer = ctypes.wintypes.LPWSTR()
+ buffer_size = 0
+ arguments = None
+ bytes = ctypes.windll.kernel32.FormatMessageW(
+ flags,
+ source,
+ message_id,
+ language_id,
+ ctypes.byref(result_buffer),
+ buffer_size,
+ arguments,
+ )
+ # note the following will cause an infinite loop if GetLastError
+ # repeatedly returns an error that cannot be formatted, although
+ # this should not happen.
+ handle_nonzero_success(bytes)
+ message = result_buffer.value
+ ctypes.windll.kernel32.LocalFree(result_buffer)
+ return message
+
+
+class WindowsError(builtins.WindowsError):
+ """
+ More info about errors at
+ http://msdn.microsoft.com/en-us/library/ms681381(VS.85).aspx
+ """
+
+ def __init__(self, value=None):
+ if value is None:
+ value = ctypes.windll.kernel32.GetLastError()
+ strerror = format_system_message(value)
+ if sys.version_info > (3, 3):
+ args = 0, strerror, None, value
+ else:
+ args = value, strerror
+ super(WindowsError, self).__init__(*args)
+
+ @property
+ def message(self):
+ return self.strerror
+
+ @property
+ def code(self):
+ return self.winerror
+
+ def __str__(self):
+ return self.message
+
+ def __repr__(self):
+ return '{self.__class__.__name__}({self.winerror})'.format(**vars())
+
+
+def handle_nonzero_success(result):
+ if result == 0:
+ raise WindowsError()
+
+
+##
+# From jaraco.windows.api.filesystem
+
+FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000
+FILE_FLAG_BACKUP_SEMANTICS = 0x2000000
+OPEN_EXISTING = 3
+FILE_ATTRIBUTE_NORMAL = 0x80
+FILE_READ_ATTRIBUTES = 0x80
+INVALID_HANDLE_VALUE = ctypes.wintypes.HANDLE(-1).value
+
+
+class BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
+ _fields_ = [
+ ('file_attributes', ctypes.wintypes.DWORD),
+ ('creation_time', ctypes.wintypes.FILETIME),
+ ('last_access_time', ctypes.wintypes.FILETIME),
+ ('last_write_time', ctypes.wintypes.FILETIME),
+ ('volume_serial_number', ctypes.wintypes.DWORD),
+ ('file_size_high', ctypes.wintypes.DWORD),
+ ('file_size_low', ctypes.wintypes.DWORD),
+ ('number_of_links', ctypes.wintypes.DWORD),
+ ('file_index_high', ctypes.wintypes.DWORD),
+ ('file_index_low', ctypes.wintypes.DWORD),
+ ]
+
+ @property
+ def file_size(self):
+ return (self.file_size_high << 32) + self.file_size_low
+
+ @property
+ def file_index(self):
+ return (self.file_index_high << 32) + self.file_index_low
+
+
+class SECURITY_ATTRIBUTES(ctypes.Structure):
+ _fields_ = (
+ ('length', ctypes.wintypes.DWORD),
+ ('p_security_descriptor', ctypes.wintypes.LPVOID),
+ ('inherit_handle', ctypes.wintypes.BOOLEAN),
+ )
+
+
+LPSECURITY_ATTRIBUTES = ctypes.POINTER(SECURITY_ATTRIBUTES)
+
+
+CreateFile = ctypes.windll.kernel32.CreateFileW
+CreateFile.argtypes = (
+ ctypes.wintypes.LPWSTR,
+ ctypes.wintypes.DWORD,
+ ctypes.wintypes.DWORD,
+ LPSECURITY_ATTRIBUTES,
+ ctypes.wintypes.DWORD,
+ ctypes.wintypes.DWORD,
+ ctypes.wintypes.HANDLE,
+)
+CreateFile.restype = ctypes.wintypes.HANDLE
+
+GetFileInformationByHandle = ctypes.windll.kernel32.GetFileInformationByHandle
+GetFileInformationByHandle.restype = ctypes.wintypes.BOOL
+GetFileInformationByHandle.argtypes = (
+ ctypes.wintypes.HANDLE,
+ ctypes.POINTER(BY_HANDLE_FILE_INFORMATION),
+)
+
+
+##
+# From jaraco.windows.filesystem
+
+def compat_stat(path):
+ """
+ Generate stat as found on Python 3.2 and later.
+ """
+ stat = os.stat(path)
+ info = get_file_info(path)
+ # rewrite st_ino, st_dev, and st_nlink based on file info
+ return nt.stat_result(
+ (stat.st_mode,) +
+ (info.file_index, info.volume_serial_number, info.number_of_links) +
+ stat[4:]
+ )
+
+
+def samefile(f1, f2):
+ """
+ Backport of samefile from Python 3.2 with support for Windows.
+ """
+ return posixpath.samestat(compat_stat(f1), compat_stat(f2))
+
+
+def get_file_info(path):
+ # open the file the same way CPython does in posixmodule.c
+ desired_access = FILE_READ_ATTRIBUTES
+ share_mode = 0
+ security_attributes = None
+ creation_disposition = OPEN_EXISTING
+ flags_and_attributes = (
+ FILE_ATTRIBUTE_NORMAL |
+ FILE_FLAG_BACKUP_SEMANTICS |
+ FILE_FLAG_OPEN_REPARSE_POINT
+ )
+ template_file = None
+
+ handle = CreateFile(
+ path,
+ desired_access,
+ share_mode,
+ security_attributes,
+ creation_disposition,
+ flags_and_attributes,
+ template_file,
+ )
+
+ if handle == INVALID_HANDLE_VALUE:
+ raise WindowsError()
+
+ info = BY_HANDLE_FILE_INFORMATION()
+ res = GetFileInformationByHandle(handle, info)
+ handle_nonzero_success(res)
+
+ return info