summary refs log tree commit diff stats
path: root/lib/pure
diff options
context:
space:
mode:
authorClay Sweetser <clay.sweetser@gmail.com>2014-02-01 20:56:34 -0500
committerClay Sweetser <clay.sweetser@gmail.com>2014-02-01 20:56:34 -0500
commit7cd5e79464c13b6a8047bdc3d58f0ddc4069431b (patch)
tree37b056a24ac9201b09d253b36416b368a0da2dc4 /lib/pure
parent69bc0779378bf3684d2138d2b6c0a423ae56f2c6 (diff)
downloadNim-7cd5e79464c13b6a8047bdc3d58f0ddc4069431b.tar.gz
Added symlink procs
Diffstat (limited to 'lib/pure')
-rw-r--r--lib/pure/os.nim74
1 files changed, 72 insertions, 2 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;