diff options
-rwxr-xr-x | lib/pure/os.nim | 49 | ||||
-rwxr-xr-x | lib/pure/times.nim | 2 | ||||
-rwxr-xr-x | lib/windows/winlean.nim | 40 |
3 files changed, 66 insertions, 25 deletions
diff --git a/lib/pure/os.nim b/lib/pure/os.nim index a8fafd5de..f22a53dd8 100755 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -567,26 +567,45 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1".} = result = path[0] == '/' proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1".} = - ## Returns True if both pathname arguments refer to the same file or - ## directory (as indicated by device number and i-node number). - ## Raises an exception if an stat() call on either pathname fails. + ## Returns True if both pathname arguments refer to the same physical + ## file or directory. Raises an exception if any of the files does not + ## exist or information about it can not be obtained. + ## + ## This proc will return true if given two alternative hard-linked or + ## sym-linked paths to the same file or directory. when defined(Windows): - var - a, b: TWin32FindData - var resA = findfirstFileA(path1, a) - var resB = findfirstFileA(path2, b) - if resA != -1 and resB != -1: - result = $a.cFileName == $b.cFileName - else: - # work around some ``findfirstFileA`` bugs - result = cmpPaths(path1, path2) == 0 - if resA != -1: findclose(resA) - if resB != -1: findclose(resB) + var success = true + + template OpenHandle(path: expr): expr = + CreateFileA(path, 0'i32, FILE_SHARE_DELETE or FILE_SHARE_READ or + FILE_SHARE_WRITE, nil, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL, 0) + + var f1 = OpenHandle(path1) + var f2 = OpenHandle(path2) + + if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE: + var fi1, fi2: TBY_HANDLE_FILE_INFORMATION + + if GetFileInformationByHandle(f1, addr(fi1)) != 0 and + GetFileInformationByHandle(f2, addr(fi2)) != 0: + result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and + fi1.nFileIndexHigh == fi2.nFileIndexHigh and + fi1.nFileIndexLow == fi2.nFileIndexLow + else: success = false + else: success = false + + discard CloseHandle(f1) + discard CloseHandle(f2) + + if not success: + OSError() + else: var a, b: TStat if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32: - result = cmpPaths(path1, path2) == 0 # be consistent with Windows + OSError() else: result = a.st_dev == b.st_dev and a.st_ino == b.st_ino diff --git a/lib/pure/times.nim b/lib/pure/times.nim index a4ac59673..f73a48bea 100755 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -302,7 +302,7 @@ when not defined(ECMAScript): posix_gettimeofday(a) result = toFloat(a.tv_sec) + toFloat(a.tv_usec)*0.00_0001 elif defined(windows): - var f: winlean.Filetime + var f: winlean.TFiletime GetSystemTimeAsFileTime(f) var i64 = rdFileTime(f) - epochDiff var secs = i64 div rateDiff diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 18e287bfa..acc28e58b 100755 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -47,6 +47,22 @@ type dwProcessId*: int32 dwThreadId*: int32 + TFILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT + dwLowDateTime*: DWORD + dwHighDateTime*: DWORD + + TBY_HANDLE_FILE_INFORMATION* {.final, pure.} = object + dwFileAttributes*: DWORD + ftCreationTime*: TFILETIME + ftLastAccessTime*: TFILETIME + ftLastWriteTime*: TFILETIME + dwVolumeSerialNumber*: DWORD + nFileSizeHigh*: DWORD + nFileSizeLow*: DWORD + nNumberOfLinks*: DWORD + nFileIndexHigh*: DWORD + nFileIndexLow*: DWORD + const STARTF_USESHOWWINDOW* = 1'i32 STARTF_USESTDHANDLES* = 256'i32 @@ -149,14 +165,11 @@ const MAX_PATH* = 260 type - FILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT - dwLowDateTime*: int32 - dwHighDateTime*: int32 TWIN32_FIND_DATA* {.pure.} = object dwFileAttributes*: int32 - ftCreationTime*: FILETIME - ftLastAccessTime*: FILETIME - ftLastWriteTime*: FILETIME + ftCreationTime*: TFILETIME + ftLastAccessTime*: TFILETIME + ftLastWriteTime*: TFILETIME nFileSizeHigh*: int32 nFileSizeLow*: int32 dwReserved0: int32 @@ -192,13 +205,13 @@ proc FreeEnvironmentStringsA*(para1: cstring): int32 {. proc GetCommandLineA*(): CString {.importc, stdcall, dynlib: "kernel32".} -proc rdFileTime*(f: FILETIME): int64 = +proc rdFileTime*(f: TFILETIME): int64 = result = ze64(f.dwLowDateTime) or (ze64(f.dwHighDateTime) shl 32) proc rdFileSize*(f: TWin32FindData): int64 = result = ze64(f.nFileSizeLow) or (ze64(f.nFileSizeHigh) shl 32) -proc GetSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var FileTime) {. +proc GetSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var TFILETIME) {. importc: "GetSystemTimeAsFileTime", dynlib: "kernel32", stdcall.} proc Sleep*(dwMilliseconds: int32){.stdcall, dynlib: "kernel32", @@ -209,12 +222,16 @@ proc ShellExecute*(HWND: THandle, lpOperation, lpFile, nShowCmd: int32): THandle{. stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA".} +proc GetFileInformationByHandle*(hFile: THandle, + lpFileInformation: ptr TBY_HANDLE_FILE_INFORMATION): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "GetFileInformationByHandle".} + const WSADESCRIPTION_LEN* = 256 WSASYS_STATUS_LEN* = 128 FD_SETSIZE* = 64 MSG_PEEK* = 2 - + INADDR_ANY* = 0 INADDR_LOOPBACK* = 0x7F000001 INADDR_BROADCAST* = -1 @@ -410,6 +427,9 @@ const GENERIC_READ* = 0x80000000'i32 GENERIC_ALL* = 0x10000000'i32 FILE_SHARE_READ* = 1'i32 + FILE_SHARE_DELETE* = 4'i32 + FILE_SHARE_WRITE* = 2'i32 + CREATE_ALWAYS* = 2'i32 OPEN_EXISTING* = 3'i32 FILE_BEGIN* = 0'i32 @@ -421,6 +441,8 @@ const FILE_MAP_WRITE* = 2'i32 INVALID_FILE_SIZE* = -1'i32 + FILE_FLAG_BACKUP_SEMANTICS* = 33554432'i32 + proc CreateFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD, lpSecurityAttributes: pointer, dwCreationDisposition, dwFlagsAndAttributes: DWORD, |