summary refs log tree commit diff stats
path: root/lib/pure/os.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure/os.nim')
-rwxr-xr-xlib/pure/os.nim49
1 files changed, 34 insertions, 15 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