_setctime.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import os
  2. import sys
  3. try:
  4. from ctypes import byref, get_last_error, wintypes, FormatError, WinDLL, WinError
  5. kernel32 = WinDLL("kernel32", use_last_error=True)
  6. CreateFileW = kernel32.CreateFileW
  7. SetFileTime = kernel32.SetFileTime
  8. CloseHandle = kernel32.CloseHandle
  9. CreateFileW.argtypes = (
  10. wintypes.LPWSTR,
  11. wintypes.DWORD,
  12. wintypes.DWORD,
  13. wintypes.LPVOID,
  14. wintypes.DWORD,
  15. wintypes.DWORD,
  16. wintypes.HANDLE,
  17. )
  18. CreateFileW.restype = wintypes.HANDLE
  19. SetFileTime.argtypes = (
  20. wintypes.HANDLE,
  21. wintypes.PFILETIME,
  22. wintypes.PFILETIME,
  23. wintypes.PFILETIME,
  24. )
  25. SetFileTime.restype = wintypes.BOOL
  26. CloseHandle.argtypes = (wintypes.HANDLE,)
  27. CloseHandle.restype = wintypes.BOOL
  28. except (ImportError, AttributeError, OSError, ValueError):
  29. SUPPORTED = False
  30. else:
  31. SUPPORTED = os.name == "nt"
  32. if sys.version_info >= (3, 6):
  33. PathLike = os.PathLike
  34. else:
  35. from pathlib import PurePath as PathLike
  36. from typing import Union
  37. def setctime(
  38. filepath: Union[str, PathLike], timestamp: float, *, follow_symlinks: bool = True
  39. ) -> None:
  40. """Set the "ctime" (creation time) attribute of a file given an unix timestamp (Windows only)."""
  41. if not SUPPORTED:
  42. raise OSError("This function is only available for the Windows platform.")
  43. filepath = os.path.normpath(os.path.abspath(str(filepath)))
  44. timestamp = int(timestamp * 10000000) + 116444736000000000
  45. if not 0 < timestamp < (1 << 64):
  46. raise ValueError("The system value of the timestamp exceeds u64 size: %d" % timestamp)
  47. atime = wintypes.FILETIME(0xFFFFFFFF, 0xFFFFFFFF)
  48. mtime = wintypes.FILETIME(0xFFFFFFFF, 0xFFFFFFFF)
  49. ctime = wintypes.FILETIME(timestamp & 0xFFFFFFFF, timestamp >> 32)
  50. flags = 128 | 0x02000000
  51. if not follow_symlinks:
  52. flags |= 0x00200000
  53. handle = wintypes.HANDLE(CreateFileW(filepath, 256, 0, None, 3, flags, None))
  54. if handle.value == wintypes.HANDLE(-1).value:
  55. raise WinError(get_last_error())
  56. if not wintypes.BOOL(SetFileTime(handle, byref(ctime), byref(atime), byref(mtime))):
  57. raise WinError(get_last_error())
  58. if not wintypes.BOOL(CloseHandle(handle)):
  59. raise WinError(get_last_error())