* return false if AccessDeniedError in tryMoveFSObject - fixes #18216 * add moveDir & moveFile tests * rename `isMoveDir` parameter to `isDir`
This commit is contained in:
parent
8a9b20579e
commit
7bf0404dd8
2 changed files with 70 additions and 19 deletions
|
|
@ -2009,28 +2009,32 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect], n
|
||||||
if not tryRemoveFile(file):
|
if not tryRemoveFile(file):
|
||||||
raiseOSError(osLastError(), file)
|
raiseOSError(osLastError(), file)
|
||||||
|
|
||||||
proc tryMoveFSObject(source, dest: string): bool {.noWeirdTarget.} =
|
proc tryMoveFSObject(source, dest: string, isDir: bool): bool {.noWeirdTarget.} =
|
||||||
## Moves a file or directory from `source` to `dest`.
|
## Moves a file (or directory if `isDir` is true) from `source` to `dest`.
|
||||||
##
|
##
|
||||||
## Returns false in case of `EXDEV` error.
|
## Returns false in case of `EXDEV` error or `AccessDeniedError` on windows (if `isDir` is true).
|
||||||
## In case of other errors `OSError` is raised.
|
## In case of other errors `OSError` is raised.
|
||||||
## Returns true in case of success.
|
## Returns true in case of success.
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
let s = newWideCString(source)
|
let s = newWideCString(source)
|
||||||
let d = newWideCString(dest)
|
let d = newWideCString(dest)
|
||||||
if moveFileExW(s, d, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) == 0'i32: raiseOSError(osLastError(), $(source, dest))
|
result = moveFileExW(s, d, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) != 0'i32
|
||||||
else:
|
else:
|
||||||
if moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) == 0'i32: raiseOSError(osLastError(), $(source, dest))
|
result = moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED or MOVEFILE_REPLACE_EXISTING) != 0'i32
|
||||||
else:
|
else:
|
||||||
if c_rename(source, dest) != 0'i32:
|
result = c_rename(source, dest) == 0'i32
|
||||||
let err = osLastError()
|
|
||||||
if err == EXDEV.OSErrorCode:
|
if not result:
|
||||||
return false
|
let err = osLastError()
|
||||||
|
let isAccessDeniedError =
|
||||||
|
when defined(windows):
|
||||||
|
const AccessDeniedError = OSErrorCode(5)
|
||||||
|
isDir and err == AccessDeniedError
|
||||||
else:
|
else:
|
||||||
# see whether `strerror(errno)` is redundant with what raiseOSError already shows
|
err == EXDEV.OSErrorCode
|
||||||
raiseOSError(err, $(source, dest, strerror(errno)))
|
if not isAccessDeniedError:
|
||||||
return true
|
raiseOSError(err, $(source, dest))
|
||||||
|
|
||||||
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
tags: [ReadDirEffect, ReadIOEffect, WriteIOEffect], noWeirdTarget.} =
|
tags: [ReadDirEffect, ReadIOEffect, WriteIOEffect], noWeirdTarget.} =
|
||||||
|
|
@ -2051,8 +2055,10 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
## * `removeFile proc <#removeFile,string>`_
|
## * `removeFile proc <#removeFile,string>`_
|
||||||
## * `tryRemoveFile proc <#tryRemoveFile,string>`_
|
## * `tryRemoveFile proc <#tryRemoveFile,string>`_
|
||||||
|
|
||||||
if not tryMoveFSObject(source, dest):
|
if not tryMoveFSObject(source, dest, isDir = false):
|
||||||
when not defined(windows):
|
when defined(windows):
|
||||||
|
doAssert false
|
||||||
|
else:
|
||||||
# Fallback to copy & del
|
# Fallback to copy & del
|
||||||
copyFile(source, dest, {cfSymlinkAsIs})
|
copyFile(source, dest, {cfSymlinkAsIs})
|
||||||
try:
|
try:
|
||||||
|
|
@ -2060,6 +2066,7 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
except:
|
except:
|
||||||
discard tryRemoveFile(dest)
|
discard tryRemoveFile(dest)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
proc exitStatusLikeShell*(status: cint): cint =
|
proc exitStatusLikeShell*(status: cint): cint =
|
||||||
## Converts exit code from `c_system` into a shell exit code.
|
## Converts exit code from `c_system` into a shell exit code.
|
||||||
|
|
@ -2614,11 +2621,10 @@ proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect], noWei
|
||||||
## * `removeDir proc <#removeDir,string>`_
|
## * `removeDir proc <#removeDir,string>`_
|
||||||
## * `existsOrCreateDir proc <#existsOrCreateDir,string>`_
|
## * `existsOrCreateDir proc <#existsOrCreateDir,string>`_
|
||||||
## * `createDir proc <#createDir,string>`_
|
## * `createDir proc <#createDir,string>`_
|
||||||
if not tryMoveFSObject(source, dest):
|
if not tryMoveFSObject(source, dest, isDir = true):
|
||||||
when not defined(windows):
|
# Fallback to copy & del
|
||||||
# Fallback to copy & del
|
copyDir(source, dest)
|
||||||
copyDir(source, dest)
|
removeDir(source)
|
||||||
removeDir(source)
|
|
||||||
|
|
||||||
proc createHardlink*(src, dest: string) {.noWeirdTarget.} =
|
proc createHardlink*(src, dest: string) {.noWeirdTarget.} =
|
||||||
## Create a hard link at `dest` which points to the item specified
|
## Create a hard link at `dest` which points to the item specified
|
||||||
|
|
|
||||||
|
|
@ -261,6 +261,51 @@ block fileOperations:
|
||||||
|
|
||||||
removeDir(dname)
|
removeDir(dname)
|
||||||
|
|
||||||
|
block: # moveFile
|
||||||
|
let tempDir = getTempDir() / "D20210609T151608"
|
||||||
|
createDir(tempDir)
|
||||||
|
defer: removeDir(tempDir)
|
||||||
|
|
||||||
|
writeFile(tempDir / "a.txt", "")
|
||||||
|
moveFile(tempDir / "a.txt", tempDir / "b.txt")
|
||||||
|
doAssert not fileExists(tempDir / "a.txt")
|
||||||
|
doAssert fileExists(tempDir / "b.txt")
|
||||||
|
removeFile(tempDir / "b.txt")
|
||||||
|
|
||||||
|
createDir(tempDir / "moveFile_test")
|
||||||
|
writeFile(tempDir / "moveFile_test/a.txt", "")
|
||||||
|
moveFile(tempDir / "moveFile_test/a.txt", tempDir / "moveFile_test/b.txt")
|
||||||
|
doAssert not fileExists(tempDir / "moveFile_test/a.txt")
|
||||||
|
doAssert fileExists(tempDir / "moveFile_test/b.txt")
|
||||||
|
removeDir(tempDir / "moveFile_test")
|
||||||
|
|
||||||
|
createDir(tempDir / "moveFile_test")
|
||||||
|
writeFile(tempDir / "a.txt", "")
|
||||||
|
moveFile(tempDir / "a.txt", tempDir / "moveFile_test/b.txt")
|
||||||
|
doAssert not fileExists(tempDir / "a.txt")
|
||||||
|
doAssert fileExists(tempDir / "moveFile_test/b.txt")
|
||||||
|
removeDir(tempDir / "moveFile_test")
|
||||||
|
|
||||||
|
block: # moveDir
|
||||||
|
let tempDir = getTempDir() / "D20210609T161443"
|
||||||
|
createDir(tempDir)
|
||||||
|
defer: removeDir(tempDir)
|
||||||
|
|
||||||
|
createDir(tempDir / "moveDir_test")
|
||||||
|
moveDir(tempDir / "moveDir_test/", tempDir / "moveDir_test_dest")
|
||||||
|
doAssert not dirExists(tempDir / "moveDir_test")
|
||||||
|
doAssert dirExists(tempDir / "moveDir_test_dest")
|
||||||
|
removeDir(tempDir / "moveDir_test_dest")
|
||||||
|
|
||||||
|
createDir(tempDir / "moveDir_test")
|
||||||
|
writeFile(tempDir / "moveDir_test/a.txt", "")
|
||||||
|
moveDir(tempDir / "moveDir_test", tempDir / "moveDir_test_dest")
|
||||||
|
doAssert not dirExists(tempDir / "moveDir_test")
|
||||||
|
doAssert not fileExists(tempDir / "moveDir_test/a.txt")
|
||||||
|
doAssert dirExists(tempDir / "moveDir_test_dest")
|
||||||
|
doAssert fileExists(tempDir / "moveDir_test_dest/a.txt")
|
||||||
|
removeDir(tempDir / "moveDir_test_dest")
|
||||||
|
|
||||||
import times
|
import times
|
||||||
block modificationTime:
|
block modificationTime:
|
||||||
# Test get/set modification times
|
# Test get/set modification times
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue