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.
This commit is contained in:
Hendrik
2018-04-16 22:03:24 +02:00
committed by Andreas Rumpf
parent c4d7cc3da0
commit b1b517128e
3 changed files with 35 additions and 6 deletions

View File

@@ -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())

View File

@@ -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

View File

@@ -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".}