win32stat.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright 2014 Thomas Amland <thomas.amland@gmail.com>
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. """
  17. :module: watchdog.utils.win32stat
  18. :synopsis: Implementation of stat with st_ino and st_dev support.
  19. Functions
  20. ---------
  21. .. autofunction:: stat
  22. """
  23. import ctypes
  24. import ctypes.wintypes
  25. import stat as stdstat
  26. from collections import namedtuple
  27. INVALID_HANDLE_VALUE = ctypes.c_void_p(-1).value
  28. OPEN_EXISTING = 3
  29. FILE_READ_ATTRIBUTES = 0x80
  30. FILE_ATTRIBUTE_NORMAL = 0x80
  31. FILE_ATTRIBUTE_READONLY = 0x1
  32. FILE_ATTRIBUTE_DIRECTORY = 0x10
  33. FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
  34. FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000
  35. class FILETIME(ctypes.Structure):
  36. _fields_ = [("dwLowDateTime", ctypes.wintypes.DWORD),
  37. ("dwHighDateTime", ctypes.wintypes.DWORD)]
  38. class BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
  39. _fields_ = [('dwFileAttributes', ctypes.wintypes.DWORD),
  40. ('ftCreationTime', FILETIME),
  41. ('ftLastAccessTime', FILETIME),
  42. ('ftLastWriteTime', FILETIME),
  43. ('dwVolumeSerialNumber', ctypes.wintypes.DWORD),
  44. ('nFileSizeHigh', ctypes.wintypes.DWORD),
  45. ('nFileSizeLow', ctypes.wintypes.DWORD),
  46. ('nNumberOfLinks', ctypes.wintypes.DWORD),
  47. ('nFileIndexHigh', ctypes.wintypes.DWORD),
  48. ('nFileIndexLow', ctypes.wintypes.DWORD)]
  49. kernel32 = ctypes.WinDLL("kernel32")
  50. CreateFile = kernel32.CreateFileW
  51. CreateFile.restype = ctypes.wintypes.HANDLE
  52. CreateFile.argtypes = (
  53. ctypes.c_wchar_p,
  54. ctypes.wintypes.DWORD,
  55. ctypes.wintypes.DWORD,
  56. ctypes.c_void_p,
  57. ctypes.wintypes.DWORD,
  58. ctypes.wintypes.DWORD,
  59. ctypes.wintypes.HANDLE,
  60. )
  61. GetFileInformationByHandle = kernel32.GetFileInformationByHandle
  62. GetFileInformationByHandle.restype = ctypes.wintypes.BOOL
  63. GetFileInformationByHandle.argtypes = (
  64. ctypes.wintypes.HANDLE,
  65. ctypes.wintypes.POINTER(BY_HANDLE_FILE_INFORMATION),
  66. )
  67. CloseHandle = kernel32.CloseHandle
  68. CloseHandle.restype = ctypes.wintypes.BOOL
  69. CloseHandle.argtypes = (ctypes.wintypes.HANDLE,)
  70. StatResult = namedtuple('StatResult', 'st_dev st_ino st_mode st_mtime st_size')
  71. def _to_mode(attr):
  72. m = 0
  73. if (attr & FILE_ATTRIBUTE_DIRECTORY):
  74. m |= stdstat.S_IFDIR | 0o111
  75. else:
  76. m |= stdstat.S_IFREG
  77. if (attr & FILE_ATTRIBUTE_READONLY):
  78. m |= 0o444
  79. else:
  80. m |= 0o666
  81. return m
  82. def _to_unix_time(ft):
  83. t = (ft.dwHighDateTime) << 32 | ft.dwLowDateTime
  84. return (t / 10000000) - 11644473600
  85. def stat(path):
  86. hfile = CreateFile(path,
  87. FILE_READ_ATTRIBUTES,
  88. 0,
  89. None,
  90. OPEN_EXISTING,
  91. FILE_ATTRIBUTE_NORMAL
  92. | FILE_FLAG_BACKUP_SEMANTICS
  93. | FILE_FLAG_OPEN_REPARSE_POINT,
  94. None)
  95. if hfile == INVALID_HANDLE_VALUE:
  96. raise ctypes.WinError()
  97. info = BY_HANDLE_FILE_INFORMATION()
  98. r = GetFileInformationByHandle(hfile, info)
  99. CloseHandle(hfile)
  100. if not r:
  101. raise ctypes.WinError()
  102. return StatResult(st_dev=info.dwVolumeSerialNumber,
  103. st_ino=(info.nFileIndexHigh << 32) + info.nFileIndexLow,
  104. st_mode=_to_mode(info.dwFileAttributes),
  105. st_mtime=_to_unix_time(info.ftLastWriteTime),
  106. st_size=(info.nFileSizeHigh << 32) + info.nFileSizeLow
  107. )