diff options
author | Araq <rumpf_a@web.de> | 2014-02-02 10:00:22 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2014-02-02 10:00:22 +0100 |
commit | 48888b9034017b28ba1cf8c432620e62ed784c0b (patch) | |
tree | 7a63d277fa84a9b10646305289f0a784a31cb359 | |
parent | 47e4f9698cca68a96fbffa6acc0c6d39a6f6420b (diff) | |
parent | 20cf73669df65dc699dd73e2988e8c0ba3bf5b9d (diff) | |
download | Nim-48888b9034017b28ba1cf8c432620e62ed784c0b.tar.gz |
Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
-rw-r--r-- | lib/pure/os.nim | 74 | ||||
-rw-r--r-- | lib/windows/winlean.nim | 18 |
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 |