diff options
author | Anatoly Galiulin <galiulin.anatoly@gmail.com> | 2017-03-24 05:40:03 +0700 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2017-03-23 23:40:03 +0100 |
commit | 434a7c842694469c532287319049e35340bb8494 (patch) | |
tree | dbf47d6d5cb9c22aa391a6e975997945d52709ca /lib | |
parent | 568c954062c203383be0073126b2e7090721364f (diff) | |
download | Nim-434a7c842694469c532287319049e35340bb8494.tar.gz |
Fix posix version of moveFile between different filesystems (#5580)
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/os.nim | 66 | ||||
-rw-r--r-- | lib/windows/winlean.nim | 2 |
2 files changed, 47 insertions, 21 deletions
diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 39cdf6d81..a7f7116ef 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -617,20 +617,6 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1", flushFile(d) close(d) -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. - when defined(Windows): - when useWinUnicode: - let s = newWideCString(source) - let d = newWideCString(dest) - if moveFileW(s, d) == 0'i32: raiseOSError(osLastError()) - else: - if moveFileA(source, dest) == 0'i32: raiseOSError(osLastError()) - else: - if c_rename(source, dest) != 0'i32: - raiseOSError(osLastError(), $strerror(errno)) - when not declared(ENOENT) and not defined(Windows): when NoFakeVars: const ENOENT = cint(2) # 2 on most systems including Solaris @@ -647,25 +633,63 @@ when defined(Windows): template setFileAttributes(file, attrs: untyped): untyped = setFileAttributesA(file, attrs) -proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} = - ## Removes the `file`. If this fails, `OSError` is raised. This does not fail +proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirEffect].} = + ## Removes the `file`. If this fails, returns `false`. This does not fail ## if the file never existed in the first place. ## On Windows, ignores the read-only attribute. + result = true when defined(Windows): when useWinUnicode: let f = newWideCString(file) else: let f = file if deleteFile(f) == 0: - if getLastError() == ERROR_ACCESS_DENIED: - if setFileAttributes(f, FILE_ATTRIBUTE_NORMAL) == 0: - raiseOSError(osLastError()) - if deleteFile(f) == 0: - raiseOSError(osLastError()) + result = false + let err = getLastError() + if err == ERROR_FILE_NOT_FOUND or err == ERROR_PATH_NOT_FOUND: + result = true + elif err == ERROR_ACCESS_DENIED and + setFileAttributes(f, FILE_ATTRIBUTE_NORMAL) != 0 and + deleteFile(f) != 0: + result = true else: if c_remove(file) != 0'i32 and errno != ENOENT: + result = false + +proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} = + ## Removes the `file`. If this fails, `OSError` is raised. This does not fail + ## if the file never existed in the first place. + ## On Windows, ignores the read-only attribute. + if not tryRemoveFile(file): + when defined(Windows): + raiseOSError(osLastError()) + 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. + when defined(Windows): + when useWinUnicode: + let s = newWideCString(source) + let d = newWideCString(dest) + if moveFileW(s, d) == 0'i32: raiseOSError(osLastError()) + else: + if moveFileA(source, dest) == 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 + else: + raiseOSError(err, $strerror(errno)) + proc execShellCmd*(command: string): int {.rtl, extern: "nos$1", tags: [ExecIOEffect].} = ## Executes a `shell command`:idx:. diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 1a251d0cc..1f8dc9ad6 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -667,6 +667,8 @@ const # Error Constants const + ERROR_FILE_NOT_FOUND* = 2 + ERROR_PATH_NOT_FOUND* = 3 ERROR_ACCESS_DENIED* = 5 ERROR_HANDLE_EOF* = 38 ERROR_BAD_ARGUMENTS* = 165 |