summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2014-02-02 10:00:22 +0100
committerAraq <rumpf_a@web.de>2014-02-02 10:00:22 +0100
commit48888b9034017b28ba1cf8c432620e62ed784c0b (patch)
tree7a63d277fa84a9b10646305289f0a784a31cb359
parent47e4f9698cca68a96fbffa6acc0c6d39a6f6420b (diff)
parent20cf73669df65dc699dd73e2988e8c0ba3bf5b9d (diff)
downloadNim-48888b9034017b28ba1cf8c432620e62ed784c0b.tar.gz
Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
-rw-r--r--lib/pure/os.nim74
-rw-r--r--lib/windows/winlean.nim18
2 files changed, 89 insertions, 3 deletions
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 8cb3919a7..4bdb0e7e7 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -287,12 +287,18 @@ proc osLastError*(): TOSErrorCode =
     result = TOSErrorCode(errno)
 {.pop.}
 
-proc unixToNativePath*(path: string): string {.
+proc unixToNativePath*(path: string, drive=""): string {.
   noSideEffect, rtl, extern: "nos$1".} =
   ## Converts an UNIX-like path to a native one.
   ##
   ## On an UNIX system this does nothing. Else it converts
   ## '/', '.', '..' to the appropriate things.
+  ##
+  ## On systems with a concept of "drives", `drive` is used to determine
+  ## which drive label to use during absolute path conversion.
+  ## `drive` defaults to the drive of the current working directory, and is
+  ## ignored on systems that do not have a concept of "drives".
+
   when defined(unix):
     result = path
   else:
@@ -300,7 +306,10 @@ proc unixToNativePath*(path: string): string {.
     if path[0] == '/':
       # an absolute path
       when doslike:
-        result = r"C:\"
+        if drive != "":
+          result = drive & ":" & DirSep
+        else:
+          result = $DirSep
       elif defined(macos):
         result = "" # must not start with ':'
       else:
@@ -387,6 +396,21 @@ proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [FReadDir].} =
     var res: TStat
     return stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode)
 
+proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
+                                          tags: [FReadDir].} =
+  ## Returns true iff the symlink `link` exists. Will return true
+  ## regardless of whether the link points to a directory or file.
+  when defined(windows):
+    when useWinUnicode:
+      wrapUnary(a, GetFileAttributesW, link)
+    else:
+      var a = GetFileAttributesA(link)
+    if a != -1'i32:
+      result = (a and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32
+  else:
+    var res: TStat
+    return lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode)
+
 proc fileExists*(filename: string): bool {.inline.} =
   ## Synonym for existsFile
   existsFile(filename)
@@ -1221,6 +1245,8 @@ iterator walkDir*(dir: string): tuple[kind: TPathComponent, path: string] {.
         if not skipFindData(f):
           if (f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32:
             k = pcDir
+          if (f.dwFileAttributes and FILE_ATTRIBUTE_REPARSE_POINT) != 0'i32:
+            k = succ(k)
           yield (k, dir / extractFilename(getFilename(f)))
         if findNextFile(h, f) == 0'i32: break
       findClose(h)
@@ -1245,6 +1271,10 @@ iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {.
   tags: [FReadDir].} =
   ## walks over the directory `dir` and yields for each file in `dir`. The
   ## full path for each file is returned.
+  ## **Warning**:
+  ## Modifying the directory structure while the iterator 
+  ## is traversing may result in undefined behavior! 
+  ## 
   ## Walking is recursive. `filter` controls the behaviour of the iterator:
   ##
   ## ---------------------   ---------------------------------------------
@@ -1336,6 +1366,46 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
       copyDir(path, dest / noSource)
     else: discard
 
+proc createSymlink*(src, dest: string) =
+  ## Create a symbolic link at `dest` which points to the item specified
+  ## by `src`. On most operating systems, will fail if a lonk
+  ##
+  ## **Warning**:
+  ## Some OS's (such as Microsoft Windows) restrict the creation 
+  ## of symlinks to root users (administrators).
+  when defined(Windows):
+    let flag = dirExists(src).int32
+    when useWinUnicode:
+      var wSrc = newWideCString(src)
+      var wDst = newWideCString(dest)
+      if CreateSymbolicLinkW(wDst, wSrc, flag) == 0 or GetLastError() != 0:
+          osError(osLastError())
+    else:
+      if CreateSymbolicLinkA(dest, src, flag) == 0 or GetLastError() != 0:
+          osError(osLastError())
+  else:
+    if symlink(src, dest) != 0:
+      OSError(OSLastError())
+
+proc createHardlink*(src, dest: string) =
+  ## Create a hard link at `dest` which points to the item specified
+  ## by `src`.
+  ##
+  ## **Warning**: Most OS's restrict the creation of hard links to 
+  ## root users (administrators) .
+  when defined(Windows):
+    when useWinUnicode:
+      var wSrc = newWideCString(src)
+      var wDst = newWideCString(dest)
+      if createHardLinkW(wDst, wSrc, nil) == 0:
+          OSError(OSLastError())
+    else:
+      if createHardLinkA(dest, src, nil) == 0:
+          OSError(OSLastError())
+  else:
+    if link(src, dest) != 0:
+      OSError(OSLastError())
+
 proc parseCmdLine*(c: string): seq[string] {.
   noSideEffect, rtl, extern: "nos$1".} =
   ## Splits a command line into several components;
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 91c6495ce..3aec2bd52 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -204,7 +204,22 @@ else:
 
   proc getModuleFileNameA*(handle: THandle, buf: CString, size: int32): int32 {.
     importc: "GetModuleFileNameA", dynlib: "kernel32", stdcall.}
-  
+
+when useWinUnicode:
+  proc createSymbolicLinkW*(lpSymlinkFileName, lpTargetFileName: wideCString,
+                         flags: DWORD): int32 {.
+    importc:"CreateSymbolicLinkW", dynlib: "kernel32", stdcall.}
+  proc createHardLinkW*(lpFileName, lpExistingFileName: wideCString,
+                         security: Pointer=nil): int32 {.
+    importc:"CreateHardLinkW", dynlib: "kernel32", stdcall.}
+else:
+  proc createSymbolicLinkA*(lpSymlinkFileName, lpTargetFileName: cstring,
+                           flags: DWORD): int32 {.
+    importc:"CreateSymbolicLinkA", dynlib: "kernel32", stdcall.}
+  proc createHardLinkA*(lpFileName, lpExistingFileName: cstring,
+                           security: Pointer=nil): int32 {.
+    importc:"CreateHardLinkA", dynlib: "kernel32", stdcall.}
+
 const
   FILE_ATTRIBUTE_ARCHIVE* = 32'i32
   FILE_ATTRIBUTE_COMPRESSED* = 2048'i32
@@ -212,6 +227,7 @@ const
   FILE_ATTRIBUTE_DIRECTORY* = 16'i32
   FILE_ATTRIBUTE_HIDDEN* = 2'i32
   FILE_ATTRIBUTE_READONLY* = 1'i32
+  FILE_ATTRIBUTE_REPARSE_POINT* = 1024'i32
   FILE_ATTRIBUTE_SYSTEM* = 4'i32
   FILE_ATTRIBUTE_TEMPORARY* = 256'i32