Added moveDir (#6015)

This commit is contained in:
Yuriy Glukhov
2017-06-27 11:09:41 +03:00
committed by Andreas Rumpf
parent baf685461b
commit 0345238d6e
2 changed files with 43 additions and 12 deletions

View File

@@ -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 =

View File

@@ -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".}