summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorHendrik <mail@hendrikalbers.de>2018-04-16 22:03:24 +0200
committerAndreas Rumpf <rumpf_a@web.de>2018-04-16 22:03:24 +0200
commitb1b517128e9ab4d1c1e8e16543008cbdecef0468 (patch)
tree9333c4b13d766081380b874315b56968382c5172
parentc4d7cc3da0e127b54deb29fa70e225ffa1899dc2 (diff)
downloadNim-b1b517128e9ab4d1c1e8e16543008cbdecef0468.tar.gz
os.setLastModificationTime*(file: string, t: times.Time) (#7543)
* add proc toFILETIME to winlean
* add proc toWinTime to times
* add proc setFileTime to winlean
* openHandle with write access
* add proc setLastModificationTime to os
* moved epochDiff,rateDiff constants and proc toWinTime
The constants were moved out of the when defined(JS) block so that they
are alsways available in proc toWinTime.
proc toWinTime was moved above the # Deprecated procs comment. Best new
location seemed to be with the toUnix proc.
-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".}