summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/pure/os.nim64
-rw-r--r--lib/windows/winlean.nim3
2 files changed, 44 insertions, 23 deletions
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 25f3b940e..bfc63dfc6 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1771,7 +1771,8 @@ type
     lastWriteTime: TTime # Time file was last modified/written to.
     creationTime: TTime # Time file was created. Not supported on all systems!
 
-proc rawToFormalFileInfo(rawInfo, formalInfo): expr =
+template rawToFormalFileInfo(rawInfo, formalInfo): expr =
+  ## Transforms the native file info structure into the one nimrod uses.
   ## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows,
   ## or a 'TStat' structure on posix
   when defined(Windows):
@@ -1786,7 +1787,7 @@ proc rawToFormalFileInfo(rawInfo, formalInfo): expr =
     formalInfo.creationTime = toTime(rawInfo.ftCreationTime)
     
     # Retrieve basic permissions
-    if (info.dwFileAttributes and FILE_ATTRIBUTE_READONLY) != 0'i32:
+    if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_READONLY) != 0'i32:
       formalInfo.permissions = {fpUserExec, fpUserRead, fpGroupExec, 
                                 fpGroupRead, fpOthersExec, fpOthersRead}
     else:
@@ -1794,37 +1795,40 @@ proc rawToFormalFileInfo(rawInfo, formalInfo): expr =
 
     # Retrieve basic file kind
     result.kind = pcFile
-    if (info.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32:
+    if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32:
       formalInfo.kind = pcDir
-    if (info.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32:
+    if (rawInfo.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32:
       formalInfo.kind = succ(result.kind)
 
   else:
+    template checkAndIncludeMode(rawMode, formalMode: expr) = 
+      if (rawInfo.st_mode and rawMode) != 0'i32:
+        formalInfo.permissions.incl(formalMode)
     formalInfo.id = (rawInfo.st_dev, rawInfo.st_ino)
-    formalInfo.size = getFileSize(handle)
-    formalInfo.linkCount = BiggestInt(rawInfo.st_Nlink)
+    formalInfo.size = rawInfo.st_size
+    formalInfo.linkCount = rawInfo.st_Nlink
     formalInfo.lastAccessTime = rawInfo.st_atime
     formalInfo.lastWriteTime = rawInfo.st_mtime
     formalInfo.creationTime = rawInfo.st_ctime
 
     result.permissions = {}
-    if (a.st_mode and S_IRUSR) != 0'i32: result.incl(fpUserRead)
-    if (a.st_mode and S_IWUSR) != 0'i32: result.incl(fpUserWrite)
-    if (a.st_mode and S_IXUSR) != 0'i32: result.incl(fpUserExec)
+    checkAndIncludeMode(S_IRUSR, fpUserRead)
+    checkAndIncludeMode(S_IWUSR, fpUserWrite)
+    checkAndIncludeMode(S_IXUSR, fpUserExec)
 
-    if (a.st_mode and S_IRGRP) != 0'i32: result.incl(fpGroupRead)
-    if (a.st_mode and S_IWGRP) != 0'i32: result.incl(fpGroupWrite)
-    if (a.st_mode and S_IXGRP) != 0'i32: result.incl(fpGroupExec)
+    checkAndIncludeMode(S_IRGRP, fpGroupRead)
+    checkAndIncludeMode(S_IWGRP, fpGroupWrite)
+    checkAndIncludeMode(S_IXGRP, fpGroupExec)
 
-    if (a.st_mode and S_IROTH) != 0'i32: result.incl(fpOthersRead)
-    if (a.st_mode and S_IWOTH) != 0'i32: result.incl(fpOthersWrite)
-    if (a.st_mode and S_IXOTH) != 0'i32: result.incl(fpOthersExec)
+    checkAndIncludeMode(S_IROTH, fpOthersRead)
+    checkAndIncludeMode(S_IWOTH, fpOthersWrite)
+    checkAndIncludeMode(S_IXOTH, fpOthersExec)
 
-    result.kind = pcFile
-    if S_ISDIR(s.st_mode): result.kind = pcDir
-    if S_ISLNK(s.st_mode): succ(result.kind)
+    formalInfo.kind = pcFile
+    if S_ISDIR(rawInfo.st_mode): formalInfo.kind = pcDir
+    if S_ISLNK(rawInfo.st_mode): formalInfo.kind.inc()
 
-proc getFileInfo*(handle: THandle, result: var FileInfo) =
+proc getFileInfo*(handle: TFileHandle, result: var FileInfo) =
   ## Retrieves file information for the file object represented by the given
   ## handle.
   ##
@@ -1833,7 +1837,10 @@ proc getFileInfo*(handle: THandle, result: var FileInfo) =
   # Done: ID, Kind, Size, Permissions, Link Count
   when defined(Windows):
     var rawInfo: TBY_HANDLE_FILE_INFORMATION
-    if getFileInformationByHandle(handle, addr rawInfo) == 0:
+    # We have to use the super special '_get_osfhandle' call (wrapped above)
+    # To transform the C file descripter to a native file handle.
+    var realHandle = get_osfhandle(handle)
+    if getFileInformationByHandle(realHandle, addr rawInfo) == 0:
       osError(osLastError())
     rawToFormalFileInfo(rawInfo, result)
   else:
@@ -1857,12 +1864,23 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo =
   ## exist, or when permission restrictions prevent the program from retrieving
   ## file information, an error will be thrown.
   when defined(Windows):
-    var handle = openHandle(path, followSymlink)
+    var 
+      handle = openHandle(path, followSymlink)
+      rawInfo: TBY_HANDLE_FILE_INFORMATION
     if handle == INVALID_HANDLE_VALUE:
       osError(osLastError())
-    getFileInfo(handle, result)
+    if getFileInformationByHandle(handle, addr rawInfo) == 0:
+      osError(osLastError())
+    rawToFormalFileInfo(rawInfo, result)
     discard closeHandle(handle)
   else:
-    var 
+    var rawInfo: TStat
+    if followSymlink:
+      if lstat(path, rawInfo) < 0'i32:
+        osError(osLastError())
+    else:
+      if stat(path, rawInfo) < 0'i32:
+        osError(osLastError())
+    rawToFormalFileInfo(rawInfo, result)
 
 {.pop.}
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 51b6021ae..683f8cc23 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -716,3 +716,6 @@ proc WSASend*(s: TSocketHandle, buf: ptr TWSABuf, bufCount: DWORD,
   bytesSent: PDWord, flags: DWORD, lpOverlapped: POverlapped,
   completionProc: POVERLAPPED_COMPLETION_ROUTINE): cint {.
   stdcall, importc: "WSASend", dynlib: "Ws2_32.dll".}
+
+proc get_osfhandle*(fd:TFileHandle): THandle {.
+  importc:"__get_osfhandle", header:"<io.h>".}
\ No newline at end of file