summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xlib/pure/os.nim49
-rwxr-xr-xlib/pure/times.nim2
-rwxr-xr-xlib/windows/winlean.nim40
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,