summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/pure/os.nim22
-rw-r--r--lib/pure/times.nim8
-rw-r--r--lib/windows/winlean.nim11
3 files changed, 35 insertions, 6 deletions
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index a77bee99d..255a9a8de 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -329,20 +329,21 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
       c_free(cast[pointer](r))
 
 when defined(Windows):
-  proc openHandle(path: string, followSymlink=true): Handle =
+  proc openHandle(path: string, followSymlink=true, writeAccess=false): Handle =
     var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
     if not followSymlink:
       flags = flags or FILE_FLAG_OPEN_REPARSE_POINT
+    let access = if writeAccess: GENERIC_WRITE else: 0'i32
 
     when useWinUnicode:
       result = createFileW(
-        newWideCString(path), 0'i32,
+        newWideCString(path), access,
         FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
         nil, OPEN_EXISTING, flags, 0
         )
     else:
       result = createFileA(
-        path, 0'i32,
+        path, access,
         FILE_SHARE_DELETE or FILE_SHARE_READ or FILE_SHARE_WRITE,
         nil, OPEN_EXISTING, flags, 0
         )
@@ -1654,3 +1655,18 @@ proc isHidden*(path: string): bool =
         result = (fileName[0] == '.') and (fileName[3] != '.')
 
 {.pop.}
+
+proc setLastModificationTime*(file: string, t: times.Time) =
+  ## Sets the `file`'s last modification time. `OSError` is raised in case of
+  ## an error.
+  when defined(posix):
+    let unixt = t.toUnix.int
+    var timevals = [Timeval(tv_sec: unixt), Timeval(tv_sec: unixt)] # [last access, last modification]
+    if utimes(file, timevals.addr) != 0: raiseOSError(osLastError())
+  else:
+    let h = openHandle(path = file, writeAccess = true)
+    if h == INVALID_HANDLE_VALUE: raiseOSError(osLastError())
+    var ft = t.toWinTime.toFILETIME
+    let res = setFileTime(h, nil, nil, ft.addr)
+    discard h.closeHandle
+    if res == 0'i32: raiseOSError(osLastError())
\ No newline at end of file
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index dc216477b..673f0b030 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -191,6 +191,7 @@ const
   secondsInHour = 60*60
   secondsInDay = 60*60*24
   minutesInHour = 60
+  rateDiff = 10000000'i64 # 100 nsecs
   # The number of hectonanoseconds between 1601/01/01 (windows epoch)
   # and 1970/01/01 (unix epoch).
   epochDiff = 116444736000000000'i64
@@ -371,6 +372,10 @@ proc toUnix*(t: Time): int64 {.benign, tags: [], raises: [], noSideEffect.} =
   ## Convert ``t`` to a unix timestamp (seconds since ``1970-01-01T00:00:00Z``).
   t.seconds
 
+proc toWinTime*(t: Time): int64 =
+  ## Convert ``t`` to a Windows file time (100-nanosecond intervals since ``1601-01-01T00:00:00Z``).
+  result = t.seconds * rateDiff + epochDiff
+
 proc isLeapYear*(year: int): bool =
   ## Returns true if ``year`` is a leap year.
   year mod 4 == 0 and (year mod 100 != 0 or year mod 400 == 0)
@@ -1713,9 +1718,6 @@ when not defined(JS):
   var
     clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
 
-  const
-    rateDiff = 10000000'i64 # 100 nsecs
-
   proc unixTimeToWinTime*(time: CTime): int64 =
     ## converts a UNIX `Time` (``time_t``) to a Windows file time
     result = int64(time) * rateDiff + epochDiff
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index f40344396..62bc38da9 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -1086,3 +1086,14 @@ proc ConvertThreadToFiberEx*(param: pointer, flags: int32): pointer {.stdcall, d
 proc DeleteFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.}
 proc SwitchToFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.}
 proc GetCurrentFiber*(): pointer {.stdcall, importc, header: "Windows.h".}
+
+proc toFILETIME*(t: int64): FILETIME =
+  ## Convert the Windows file time timestamp ``t`` to ``FILETIME``.
+  result = FILETIME(dwLowDateTime: cast[DWORD](t), dwHighDateTime: DWORD(t shr 32))
+
+type
+  LPFILETIME* = ptr FILETIME
+
+proc setFileTime*(hFile: HANDLE, lpCreationTime: LPFILETIME,
+                 lpLastAccessTime: LPFILETIME, lpLastWriteTime: LPFILETIME): WINBOOL
+     {.stdcall, dynlib: "kernel32", importc: "SetFileTime".}