refs #8391 std/os now shows runtime context for raiseOSError exceptions (#13294)

* refs #8391: fix errmsg for setCurrentDir

* raiseOSError calls for copyFile

* refs #8391 std/os now shows runtime context for raiseOSError exceptions
This commit is contained in:
Timothee Cour 2020-01-30 02:06:04 -08:00 • committed by GitHub
commit adc52b0039
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1169,7 +1169,7 @@ proc findExe*(exe: string, followSymlinks: bool = true;
var r = newString(256) var r = newString(256)
var len = readlink(x, r, 256) var len = readlink(x, r, 256)
if len < 0: if len < 0:
raiseOSError(osLastError()) raiseOSError(osLastError(), exe)
if len > 256: if len > 256:
r = newString(len+1) r = newString(len+1)
len = readlink(x, r, len) len = readlink(x, r, len)
@ -1196,12 +1196,12 @@ proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1",
## * `fileNewer proc <#fileNewer,string,string>`_ ## * `fileNewer proc <#fileNewer,string,string>`_
when defined(posix): when defined(posix):
var res: Stat var res: Stat
if stat(file, res) < 0'i32: raiseOSError(osLastError()) if stat(file, res) < 0'i32: raiseOSError(osLastError(), file)
result = res.st_mtim.toTime result = res.st_mtim.toTime
else: else:
var f: WIN32_FIND_DATA var f: WIN32_FIND_DATA
var h = findFirstFile(file, f) var h = findFirstFile(file, f)
if h == -1'i32: raiseOSError(osLastError()) if h == -1'i32: raiseOSError(osLastError(), file)
result = fromWinTime(rdFileTime(f.ftLastWriteTime)) result = fromWinTime(rdFileTime(f.ftLastWriteTime))
findClose(h) findClose(h)
@ -1214,12 +1214,12 @@ proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1", noNimS
## * `fileNewer proc <#fileNewer,string,string>`_ ## * `fileNewer proc <#fileNewer,string,string>`_
when defined(posix): when defined(posix):
var res: Stat var res: Stat
if stat(file, res) < 0'i32: raiseOSError(osLastError()) if stat(file, res) < 0'i32: raiseOSError(osLastError(), file)
result = res.st_atim.toTime result = res.st_atim.toTime
else: else:
var f: WIN32_FIND_DATA var f: WIN32_FIND_DATA
var h = findFirstFile(file, f) var h = findFirstFile(file, f)
if h == -1'i32: raiseOSError(osLastError()) if h == -1'i32: raiseOSError(osLastError(), file)
result = fromWinTime(rdFileTime(f.ftLastAccessTime)) result = fromWinTime(rdFileTime(f.ftLastAccessTime))
findClose(h) findClose(h)
@ -1236,12 +1236,12 @@ proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1", noNimScr
## * `fileNewer proc <#fileNewer,string,string>`_ ## * `fileNewer proc <#fileNewer,string,string>`_
when defined(posix): when defined(posix):
var res: Stat var res: Stat
if stat(file, res) < 0'i32: raiseOSError(osLastError()) if stat(file, res) < 0'i32: raiseOSError(osLastError(), file)
result = res.st_ctim.toTime result = res.st_ctim.toTime
else: else:
var f: WIN32_FIND_DATA var f: WIN32_FIND_DATA
var h = findFirstFile(file, f) var h = findFirstFile(file, f)
if h == -1'i32: raiseOSError(osLastError()) if h == -1'i32: raiseOSError(osLastError(), file)
result = fromWinTime(rdFileTime(f.ftCreationTime)) result = fromWinTime(rdFileTime(f.ftCreationTime))
findClose(h) findClose(h)
@ -1329,11 +1329,11 @@ proc setCurrentDir*(newDir: string) {.inline, tags: [], noNimScript.} =
when defined(Windows): when defined(Windows):
when useWinUnicode: when useWinUnicode:
if setCurrentDirectoryW(newWideCString(newDir)) == 0'i32: if setCurrentDirectoryW(newWideCString(newDir)) == 0'i32:
raiseOSError(osLastError()) raiseOSError(osLastError(), newDir)
else: else:
if setCurrentDirectoryA(newDir) == 0'i32: raiseOSError(osLastError()) if setCurrentDirectoryA(newDir) == 0'i32: raiseOSError(osLastError(), newDir)
else: else:
if chdir(newDir) != 0'i32: raiseOSError(osLastError()) if chdir(newDir) != 0'i32: raiseOSError(osLastError(), newDir)
when not weirdTarget: when not weirdTarget:
proc absolutePath*(path: string, root = getCurrentDir()): string {.noNimScript.} = proc absolutePath*(path: string, root = getCurrentDir()): string {.noNimScript.} =
@ -1470,11 +1470,11 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
discard closeHandle(f1) discard closeHandle(f1)
discard closeHandle(f2) discard closeHandle(f2)
if not success: raiseOSError(lastErr) if not success: raiseOSError(lastErr, $(path1, path2))
else: else:
var a, b: Stat var a, b: Stat
if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32: if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
raiseOSError(osLastError()) raiseOSError(osLastError(), $(path1, path2))
else: else:
result = a.st_dev == b.st_dev and a.st_ino == b.st_ino result = a.st_dev == b.st_dev and a.st_ino == b.st_ino
@ -1542,7 +1542,7 @@ proc getFilePermissions*(filename: string): set[FilePermission] {.
## * `FilePermission enum <#FilePermission>`_ ## * `FilePermission enum <#FilePermission>`_
when defined(posix): when defined(posix):
var a: Stat var a: Stat
if stat(filename, a) < 0'i32: raiseOSError(osLastError()) if stat(filename, a) < 0'i32: raiseOSError(osLastError(), filename)
result = {} result = {}
if (a.st_mode and S_IRUSR.Mode) != 0.Mode: result.incl(fpUserRead) if (a.st_mode and S_IRUSR.Mode) != 0.Mode: result.incl(fpUserRead)
if (a.st_mode and S_IWUSR.Mode) != 0.Mode: result.incl(fpUserWrite) if (a.st_mode and S_IWUSR.Mode) != 0.Mode: result.incl(fpUserWrite)
@ -1560,7 +1560,7 @@ proc getFilePermissions*(filename: string): set[FilePermission] {.
wrapUnary(res, getFileAttributesW, filename) wrapUnary(res, getFileAttributesW, filename)
else: else:
var res = getFileAttributesA(filename) var res = getFileAttributesA(filename)
if res == -1'i32: raiseOSError(osLastError()) if res == -1'i32: raiseOSError(osLastError(), filename)
if (res and FILE_ATTRIBUTE_READONLY) != 0'i32: if (res and FILE_ATTRIBUTE_READONLY) != 0'i32:
result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead, result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead,
fpOthersExec, fpOthersRead} fpOthersExec, fpOthersRead}
@ -1592,13 +1592,13 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {.
if fpOthersWrite in permissions: p = p or S_IWOTH.Mode if fpOthersWrite in permissions: p = p or S_IWOTH.Mode
if fpOthersExec in permissions: p = p or S_IXOTH.Mode if fpOthersExec in permissions: p = p or S_IXOTH.Mode
if chmod(filename, cast[Mode](p)) != 0: raiseOSError(osLastError()) if chmod(filename, cast[Mode](p)) != 0: raiseOSError(osLastError(), $(filename, permissions))
else: else:
when useWinUnicode: when useWinUnicode:
wrapUnary(res, getFileAttributesW, filename) wrapUnary(res, getFileAttributesW, filename)
else: else:
var res = getFileAttributesA(filename) var res = getFileAttributesA(filename)
if res == -1'i32: raiseOSError(osLastError()) if res == -1'i32: raiseOSError(osLastError(), filename)
if fpUserWrite in permissions: if fpUserWrite in permissions:
res = res and not FILE_ATTRIBUTE_READONLY res = res and not FILE_ATTRIBUTE_READONLY
else: else:
@ -1607,7 +1607,7 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {.
wrapBinary(res2, setFileAttributesW, filename, res) wrapBinary(res2, setFileAttributesW, filename, res)
else: else:
var res2 = setFileAttributesA(filename, res) var res2 = setFileAttributesA(filename, res)
if res2 == - 1'i32: raiseOSError(osLastError()) if res2 == - 1'i32: raiseOSError(osLastError(), $(filename, permissions))
proc copyFile*(source, dest: string) {.rtl, extern: "nos$1", proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
tags: [ReadIOEffect, WriteIOEffect], noNimScript.} = tags: [ReadIOEffect, WriteIOEffect], noNimScript.} =
@ -1640,17 +1640,17 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
when useWinUnicode: when useWinUnicode:
let s = newWideCString(source) let s = newWideCString(source)
let d = newWideCString(dest) let d = newWideCString(dest)
if copyFileW(s, d, 0'i32) == 0'i32: raiseOSError(osLastError()) if copyFileW(s, d, 0'i32) == 0'i32: raiseOSError(osLastError(), $(source, dest))
else: else:
if copyFileA(source, dest, 0'i32) == 0'i32: raiseOSError(osLastError()) if copyFileA(source, dest, 0'i32) == 0'i32: raiseOSError(osLastError(), $(source, dest))
else: else:
# generic version of copyFile which works for any platform: # generic version of copyFile which works for any platform:
const bufSize = 8000 # better for memory manager const bufSize = 8000 # better for memory manager
var d, s: File var d, s: File
if not open(s, source): raiseOSError(osLastError()) if not open(s, source): raiseOSError(osLastError(), source)
if not open(d, dest, fmWrite): if not open(d, dest, fmWrite):
close(s) close(s)
raiseOSError(osLastError()) raiseOSError(osLastError(), dest)
var buf = alloc(bufSize) var buf = alloc(bufSize)
while true: while true:
var bytesread = readBuffer(s, buf, bufSize) var bytesread = readBuffer(s, buf, bufSize)
@ -1660,7 +1660,7 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
dealloc(buf) dealloc(buf)
close(s) close(s)
close(d) close(d)
raiseOSError(osLastError()) raiseOSError(osLastError(), dest)
if bytesread != bufSize: break if bytesread != bufSize: break
dealloc(buf) dealloc(buf)
close(s) close(s)
@ -1733,10 +1733,7 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect], n
## * `tryRemoveFile proc <#tryRemoveFile,string>`_ ## * `tryRemoveFile proc <#tryRemoveFile,string>`_
## * `moveFile proc <#moveFile,string,string>`_ ## * `moveFile proc <#moveFile,string,string>`_
if not tryRemoveFile(file): if not tryRemoveFile(file):
when defined(Windows): raiseOSError(osLastError(), file)
raiseOSError(osLastError())
else:
raiseOSError(osLastError(), $strerror(errno))
proc tryMoveFSObject(source, dest: string): bool {.noNimScript.} = proc tryMoveFSObject(source, dest: string): bool {.noNimScript.} =
## Moves a file or directory from `source` to `dest`. ## Moves a file or directory from `source` to `dest`.
@ -1748,16 +1745,17 @@ proc tryMoveFSObject(source, dest: string): bool {.noNimScript.} =
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) == 0'i32: raiseOSError(osLastError()) if moveFileExW(s, d, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError(), $(source, dest))
else: else:
if moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError()) if moveFileExA(source, dest, MOVEFILE_COPY_ALLOWED) == 0'i32: raiseOSError(osLastError(), $(source, dest))
else: else:
if c_rename(source, dest) != 0'i32: if c_rename(source, dest) != 0'i32:
let err = osLastError() let err = osLastError()
if err == EXDEV.OSErrorCode: if err == EXDEV.OSErrorCode:
return false return false
else: else:
raiseOSError(err, $strerror(errno)) # see whether `strerror(errno)` is redundant with what raiseOSError already shows
raiseOSError(err, $(source, dest, strerror(errno)))
return true return true
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
@ -1927,7 +1925,7 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
while true: while true:
var L = getFullPathNameW(newWideCString(filename), bufsize, res, unused) var L = getFullPathNameW(newWideCString(filename), bufsize, res, unused)
if L == 0'i32: if L == 0'i32:
raiseOSError(osLastError()) raiseOSError(osLastError(), filename)
elif L > bufsize: elif L > bufsize:
res = newWideCString("", L) res = newWideCString("", L)
bufsize = L bufsize = L
@ -1940,7 +1938,7 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
while true: while true:
var L = getFullPathNameA(filename, bufsize, result, unused) var L = getFullPathNameA(filename, bufsize, result, unused)
if L == 0'i32: if L == 0'i32:
raiseOSError(osLastError()) raiseOSError(osLastError(), filename)
elif L > bufsize: elif L > bufsize:
result = newString(L) result = newString(L)
bufsize = L bufsize = L
@ -1952,13 +1950,14 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
for x in walkFiles(result): for x in walkFiles(result):
result = x result = x
if not existsFile(result) and not existsDir(result): if not existsFile(result) and not existsDir(result):
# consider using: `raiseOSError(osLastError(), result)`
raise newException(OSError, "file '" & result & "' does not exist") raise newException(OSError, "file '" & result & "' does not exist")
else: else:
# according to Posix we don't need to allocate space for result pathname. # according to Posix we don't need to allocate space for result pathname.
# But we need to free return value with free(3). # But we need to free return value with free(3).
var r = realpath(filename, nil) var r = realpath(filename, nil)
if r.isNil: if r.isNil:
raiseOSError(osLastError()) raiseOSError(osLastError(), filename)
else: else:
result = $r result = $r
c_free(cast[pointer](r)) c_free(cast[pointer](r))
@ -2145,9 +2144,9 @@ proc rawRemoveDir(dir: string) {.noNimScript.} =
let lastError = osLastError() let lastError = osLastError()
if res == 0'i32 and lastError.int32 != 3'i32 and if res == 0'i32 and lastError.int32 != 3'i32 and
lastError.int32 != 18'i32 and lastError.int32 != 2'i32: lastError.int32 != 18'i32 and lastError.int32 != 2'i32:
raiseOSError(lastError) raiseOSError(lastError, dir)
else: else:
if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError()) if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError(), dir)
proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [ proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
WriteDirEffect, ReadDirEffect], benign, noNimScript.} = WriteDirEffect, ReadDirEffect], benign, noNimScript.} =
@ -2336,13 +2335,13 @@ proc createSymlink*(src, dest: string) {.noNimScript.} =
var wSrc = newWideCString(src) var wSrc = newWideCString(src)
var wDst = newWideCString(dest) var wDst = newWideCString(dest)
if createSymbolicLinkW(wDst, wSrc, flag) == 0 or getLastError() != 0: if createSymbolicLinkW(wDst, wSrc, flag) == 0 or getLastError() != 0:
raiseOSError(osLastError()) raiseOSError(osLastError(), $(src, dest))
else: else:
if createSymbolicLinkA(dest, src, flag) == 0 or getLastError() != 0: if createSymbolicLinkA(dest, src, flag) == 0 or getLastError() != 0:
raiseOSError(osLastError()) raiseOSError(osLastError(), $(src, dest))
else: else:
if symlink(src, dest) != 0: if symlink(src, dest) != 0:
raiseOSError(osLastError()) raiseOSError(osLastError(), $(src, dest))
proc createHardlink*(src, dest: string) {.noNimScript.} = proc createHardlink*(src, dest: string) {.noNimScript.} =
## Create a hard link at `dest` which points to the item specified ## Create a hard link at `dest` which points to the item specified
@ -2358,13 +2357,13 @@ proc createHardlink*(src, dest: string) {.noNimScript.} =
var wSrc = newWideCString(src) var wSrc = newWideCString(src)
var wDst = newWideCString(dest) var wDst = newWideCString(dest)
if createHardLinkW(wDst, wSrc, nil) == 0: if createHardLinkW(wDst, wSrc, nil) == 0:
raiseOSError(osLastError()) raiseOSError(osLastError(), $(src, dest))
else: else:
if createHardLinkA(dest, src, nil) == 0: if createHardLinkA(dest, src, nil) == 0:
raiseOSError(osLastError()) raiseOSError(osLastError(), $(src, dest))
else: else:
if link(src, dest) != 0: if link(src, dest) != 0:
raiseOSError(osLastError()) raiseOSError(osLastError(), $(src, dest))
proc copyFileWithPermissions*(source, dest: string, proc copyFileWithPermissions*(source, dest: string,
ignorePermissionErrors = true) {.noNimScript.} = ignorePermissionErrors = true) {.noNimScript.} =
@ -2473,7 +2472,7 @@ proc expandSymlink*(symlinkPath: string): string {.noNimScript.} =
result = newString(256) result = newString(256)
var len = readlink(symlinkPath, result, 256) var len = readlink(symlinkPath, result, 256)
if len < 0: if len < 0:
raiseOSError(osLastError()) raiseOSError(osLastError(), symlinkPath)
if len > 256: if len > 256:
result = newString(len+1) result = newString(len+1)
len = readlink(symlinkPath, result, len) len = readlink(symlinkPath, result, len)
@ -2942,7 +2941,7 @@ proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
when defined(windows): when defined(windows):
var a: WIN32_FIND_DATA var a: WIN32_FIND_DATA
var resA = findFirstFile(file, a) var resA = findFirstFile(file, a)
if resA == -1: raiseOSError(osLastError()) if resA == -1: raiseOSError(osLastError(), file)
result = rdFileSize(a) result = rdFileSize(a)
findClose(resA) findClose(resA)
else: else:
@ -2950,7 +2949,7 @@ proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
if open(f, file): if open(f, file):
result = getFileSize(f) result = getFileSize(f)
close(f) close(f)
else: raiseOSError(osLastError()) else: raiseOSError(osLastError(), file)
when defined(Windows) or weirdTarget: when defined(Windows) or weirdTarget:
type type
@ -3061,12 +3060,12 @@ proc getFileInfo*(handle: FileHandle): FileInfo {.noNimScript.} =
# To transform the C file descriptor to a native file handle. # To transform the C file descriptor to a native file handle.
var realHandle = get_osfhandle(handle) var realHandle = get_osfhandle(handle)
if getFileInformationByHandle(realHandle, addr rawInfo) == 0: if getFileInformationByHandle(realHandle, addr rawInfo) == 0:
raiseOSError(osLastError()) raiseOSError(osLastError(), $handle)
rawToFormalFileInfo(rawInfo, "", result) rawToFormalFileInfo(rawInfo, "", result)
else: else:
var rawInfo: Stat var rawInfo: Stat
if fstat(handle, rawInfo) < 0'i32: if fstat(handle, rawInfo) < 0'i32:
raiseOSError(osLastError()) raiseOSError(osLastError(), $handle)
rawToFormalFileInfo(rawInfo, "", result) rawToFormalFileInfo(rawInfo, "", result)
proc getFileInfo*(file: File): FileInfo {.noNimScript.} = proc getFileInfo*(file: File): FileInfo {.noNimScript.} =
@ -3102,19 +3101,19 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo {.noNimScript.}
handle = openHandle(path, followSymlink) handle = openHandle(path, followSymlink)
rawInfo: BY_HANDLE_FILE_INFORMATION rawInfo: BY_HANDLE_FILE_INFORMATION
if handle == INVALID_HANDLE_VALUE: if handle == INVALID_HANDLE_VALUE:
raiseOSError(osLastError()) raiseOSError(osLastError(), path)
if getFileInformationByHandle(handle, addr rawInfo) == 0: if getFileInformationByHandle(handle, addr rawInfo) == 0:
raiseOSError(osLastError()) raiseOSError(osLastError(), path)
rawToFormalFileInfo(rawInfo, path, result) rawToFormalFileInfo(rawInfo, path, result)
discard closeHandle(handle) discard closeHandle(handle)
else: else:
var rawInfo: Stat var rawInfo: Stat
if followSymlink: if followSymlink:
if stat(path, rawInfo) < 0'i32: if stat(path, rawInfo) < 0'i32:
raiseOSError(osLastError()) raiseOSError(osLastError(), path)
else: else:
if lstat(path, rawInfo) < 0'i32: if lstat(path, rawInfo) < 0'i32:
raiseOSError(osLastError()) raiseOSError(osLastError(), path)
rawToFormalFileInfo(rawInfo, path, result) rawToFormalFileInfo(rawInfo, path, result)
proc isHidden*(path: string): bool {.noNimScript.} = proc isHidden*(path: string): bool {.noNimScript.} =
@ -3167,14 +3166,14 @@ proc setLastModificationTime*(file: string, t: times.Time) {.noNimScript.} =
let micro = convert(Nanoseconds, Microseconds, t.nanosecond) let micro = convert(Nanoseconds, Microseconds, t.nanosecond)
var timevals = [Timeval(tv_sec: unixt, tv_usec: micro), var timevals = [Timeval(tv_sec: unixt, tv_usec: micro),
Timeval(tv_sec: unixt, tv_usec: micro)] # [last access, last modification] Timeval(tv_sec: unixt, tv_usec: micro)] # [last access, last modification]
if utimes(file, timevals.addr) != 0: raiseOSError(osLastError()) if utimes(file, timevals.addr) != 0: raiseOSError(osLastError(), file)
else: else:
let h = openHandle(path = file, writeAccess = true) let h = openHandle(path = file, writeAccess = true)
if h == INVALID_HANDLE_VALUE: raiseOSError(osLastError()) if h == INVALID_HANDLE_VALUE: raiseOSError(osLastError(), file)
var ft = t.toWinTime.toFILETIME var ft = t.toWinTime.toFILETIME
let res = setFileTime(h, nil, nil, ft.addr) let res = setFileTime(h, nil, nil, ft.addr)
discard h.closeHandle discard h.closeHandle
if res == 0'i32: raiseOSError(osLastError()) if res == 0'i32: raiseOSError(osLastError(), file)
when isMainModule: when isMainModule: