diff options
-rw-r--r-- | lib/pure/os.nim | 41 | ||||
-rw-r--r-- | lib/windows/winlean.nim | 14 |
2 files changed, 43 insertions, 12 deletions
diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 98b6aa309..b4cbd200c 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -666,29 +666,38 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} else: raiseOSError(osLastError(), $strerror(errno)) -proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", - tags: [ReadIOEffect, WriteIOEffect].} = - ## Moves a file from `source` to `dest`. If this fails, `OSError` is raised. +proc tryMoveFSObject(source, dest: string): bool = + ## Moves a file or directory from `source` to `dest`. Returns false in case + ## of `EXDEV` error. In case of other errors `OSError` is raised. Returns + ## true in case of success. when defined(Windows): when useWinUnicode: let s = newWideCString(source) let d = newWideCString(dest) - if moveFileW(s, d) == 0'i32: raiseOSError(osLastError()) + if moveFileExW(s, d, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError()) else: - if moveFileA(source, dest) == 0'i32: raiseOSError(osLastError()) + if moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError()) else: if c_rename(source, dest) != 0'i32: let err = osLastError() if err == EXDEV.OSErrorCode: - # Fallback to copy & del - copyFile(source, dest) - try: - removeFile(source) - except: - discard tryRemoveFile(dest) - raise + return false else: raiseOSError(err, $strerror(errno)) + return true + +proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", + tags: [ReadIOEffect, WriteIOEffect].} = + ## Moves a file from `source` to `dest`. If this fails, `OSError` is raised. + if not tryMoveFSObject(source, dest): + when not defined(windows): + # Fallback to copy & del + copyFile(source, dest) + try: + removeFile(source) + except: + discard tryRemoveFile(dest) + raise proc execShellCmd*(command: string): int {.rtl, extern: "nos$1", tags: [ExecIOEffect].} = @@ -1369,6 +1378,14 @@ proc exclFilePermissions*(filename: string, ## setFilePermissions(filename, getFilePermissions(filename)-permissions) setFilePermissions(filename, getFilePermissions(filename)-permissions) +proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect].} = + ## Moves a directory from `source` to `dest`. If this fails, `OSError` is raised. + if not tryMoveFSObject(source, dest): + when not defined(windows): + # Fallback to copy & del + copyDir(source, dest) + removeDir(source) + include ospaths proc expandSymlink*(symlinkPath: string): string = diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 164499543..7a221ceb1 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -291,6 +291,14 @@ const FILE_ATTRIBUTE_TEMPORARY* = 256'i32 MAX_PATH* = 260 + + MOVEFILE_COPY_ALLOWED* = 0x2'i32 + MOVEFILE_CREATE_HARDLINK* = 0x10'i32 + MOVEFILE_DELAY_UNTIL_REBOOT* = 0x4'i32 + MOVEFILE_FAIL_IF_NOT_TRACKABLE* = 0x20'i32 + MOVEFILE_REPLACE_EXISTING* = 0x1'i32 + MOVEFILE_WRITE_THROUGH* = 0x8'i32 + type WIN32_FIND_DATA* {.pure.} = object dwFileAttributes*: int32 @@ -342,6 +350,9 @@ when useWinUnicode: proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString): WINBOOL {. importc: "MoveFileW", stdcall, dynlib: "kernel32".} + proc moveFileExW*(lpExistingFileName, lpNewFileName: WideCString, + flags: DWORD): WINBOOL {. + importc: "MoveFileExW", stdcall, dynlib: "kernel32".} proc getEnvironmentStringsW*(): WideCString {. stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".} @@ -369,6 +380,9 @@ else: proc moveFileA*(lpExistingFileName, lpNewFileName: cstring): WINBOOL {. importc: "MoveFileA", stdcall, dynlib: "kernel32".} + proc moveFileExA*(lpExistingFileName, lpNewFileName: WideCString, + flags: DWORD): WINBOOL {. + importc: "MoveFileExA", stdcall, dynlib: "kernel32".} proc getEnvironmentStringsA*(): cstring {. stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA".} |