Deprecated OSError, and modified it to require an explicit OS error code.
The deprecated functions include the OSError and OSErrorMsg, the name did not change however the signature of the new functions did. They now require a TOSErrorCode value be passed to them. This value can be retrieved using OSLastError. The reason this was done is because on Windows any win api call can reset the last error code to 0, this change allows the user to immediately grab the error code and worry about the string representation later if needs be.
This commit is contained in:
parent
9540a93d95
commit
bacb20a379
5 changed files with 196 additions and 126 deletions
|
|
@ -167,7 +167,7 @@ proc AsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
|
||||||
result = newAsyncSocket()
|
result = newAsyncSocket()
|
||||||
result.socket = socket(domain, typ, protocol, buffered)
|
result.socket = socket(domain, typ, protocol, buffered)
|
||||||
result.proto = protocol
|
result.proto = protocol
|
||||||
if result.socket == InvalidSocket: OSError()
|
if result.socket == InvalidSocket: OSError(OSLastError())
|
||||||
result.socket.setBlocking(false)
|
result.socket.setBlocking(false)
|
||||||
|
|
||||||
proc toAsyncSocket*(sock: TSocket, state: TInfo = SockConnected): PAsyncSocket =
|
proc toAsyncSocket*(sock: TSocket, state: TInfo = SockConnected): PAsyncSocket =
|
||||||
|
|
@ -349,7 +349,7 @@ proc acceptAddr*(server: PAsyncSocket, client: var PAsyncSocket,
|
||||||
client.sslNeedAccept = false
|
client.sslNeedAccept = false
|
||||||
client.info = SockConnected
|
client.info = SockConnected
|
||||||
|
|
||||||
if c == InvalidSocket: OSError()
|
if c == InvalidSocket: SocketError(server.socket)
|
||||||
c.setBlocking(false) # TODO: Needs to be tested.
|
c.setBlocking(false) # TODO: Needs to be tested.
|
||||||
|
|
||||||
# deleg.open is set in ``toDelegate``.
|
# deleg.open is set in ``toDelegate``.
|
||||||
|
|
@ -642,8 +642,7 @@ when isMainModule:
|
||||||
proc testRead(s: PAsyncSocket, no: int) =
|
proc testRead(s: PAsyncSocket, no: int) =
|
||||||
echo("Reading! " & $no)
|
echo("Reading! " & $no)
|
||||||
var data = ""
|
var data = ""
|
||||||
if not s.readLine(data):
|
if not s.readLine(data): return
|
||||||
OSError()
|
|
||||||
if data == "":
|
if data == "":
|
||||||
echo("Closing connection. " & $no)
|
echo("Closing connection. " & $no)
|
||||||
s.close()
|
s.close()
|
||||||
|
|
|
||||||
174
lib/pure/os.nim
174
lib/pure/os.nim
|
|
@ -39,6 +39,8 @@ type
|
||||||
FWriteDir* = object of FWriteIO ## effect that denotes a write operation to
|
FWriteDir* = object of FWriteIO ## effect that denotes a write operation to
|
||||||
## the directory structure
|
## the directory structure
|
||||||
|
|
||||||
|
TOSErrorCode* = distinct int32 ## Specifies an OS Error Code.
|
||||||
|
|
||||||
const
|
const
|
||||||
doslike = defined(windows) or defined(OS2) or defined(DOS)
|
doslike = defined(windows) or defined(OS2) or defined(DOS)
|
||||||
# DOS-like filesystem
|
# DOS-like filesystem
|
||||||
|
|
@ -171,10 +173,13 @@ const
|
||||||
## The character which separates the base filename from the extension;
|
## The character which separates the base filename from the extension;
|
||||||
## for example, the '.' in ``os.nim``.
|
## for example, the '.' in ``os.nim``.
|
||||||
|
|
||||||
proc OSErrorMsg*(): string {.rtl, extern: "nos$1".} =
|
proc OSErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} =
|
||||||
## Retrieves the operating system's error flag, ``errno``.
|
## Retrieves the operating system's error flag, ``errno``.
|
||||||
## On Windows ``GetLastError`` is checked before ``errno``.
|
## On Windows ``GetLastError`` is checked before ``errno``.
|
||||||
## Returns "" if no error occured.
|
## Returns "" if no error occured.
|
||||||
|
##
|
||||||
|
## **Deprecated since version 0.9.4**: use the other ``OSErrorMsg`` proc.
|
||||||
|
|
||||||
result = ""
|
result = ""
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
var err = GetLastError()
|
var err = GetLastError()
|
||||||
|
|
@ -194,17 +199,89 @@ proc OSErrorMsg*(): string {.rtl, extern: "nos$1".} =
|
||||||
if errno != 0'i32:
|
if errno != 0'i32:
|
||||||
result = $os.strerror(errno)
|
result = $os.strerror(errno)
|
||||||
|
|
||||||
proc OSError*(msg: string = "") {.noinline, rtl, extern: "nos$1".} =
|
{.push warning[deprecated]: off.}
|
||||||
|
proc OSError*(msg: string = "") {.noinline, rtl, extern: "nos$1", deprecated.} =
|
||||||
## raises an EOS exception with the given message ``msg``.
|
## raises an EOS exception with the given message ``msg``.
|
||||||
## If ``msg == ""``, the operating system's error flag
|
## If ``msg == ""``, the operating system's error flag
|
||||||
## (``errno``) is converted to a readable error message. On Windows
|
## (``errno``) is converted to a readable error message. On Windows
|
||||||
## ``GetLastError`` is checked before ``errno``.
|
## ``GetLastError`` is checked before ``errno``.
|
||||||
## If no error flag is set, the message ``unknown OS error`` is used.
|
## If no error flag is set, the message ``unknown OS error`` is used.
|
||||||
|
##
|
||||||
|
## **Deprecated since version 0.9.4**: use the other ``OSError`` proc.
|
||||||
if len(msg) == 0:
|
if len(msg) == 0:
|
||||||
var m = OSErrorMsg()
|
var m = OSErrorMsg()
|
||||||
raise newException(EOS, if m.len > 0: m else: "unknown OS error")
|
raise newException(EOS, if m.len > 0: m else: "unknown OS error")
|
||||||
else:
|
else:
|
||||||
raise newException(EOS, msg)
|
raise newException(EOS, msg)
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
|
proc `==`*(err1, err2: TOSErrorCode): bool {.borrow.}
|
||||||
|
proc `$`*(err: TOSErrorCode): string {.borrow.}
|
||||||
|
|
||||||
|
proc OSErrorMsg*(errorCode: TOSErrorCode): string =
|
||||||
|
## Converts an OS error code into a human readable string.
|
||||||
|
##
|
||||||
|
## The error code can be retrieved using the ``OSLastError`` proc.
|
||||||
|
##
|
||||||
|
## If conversion fails, or ``errorCode`` is ``0`` then ``""`` will be
|
||||||
|
## returned.
|
||||||
|
##
|
||||||
|
## On Windows, the ``-d:useWinAnsi`` compilation flag can be used to
|
||||||
|
## make this procedure use the non-unicode Win API calls to retrieve the
|
||||||
|
## message.
|
||||||
|
result = ""
|
||||||
|
when defined(Windows):
|
||||||
|
if errorCode != TOSErrorCode(0'i32):
|
||||||
|
when useWinUnicode:
|
||||||
|
var msgbuf: widecstring
|
||||||
|
if FormatMessageW(0x00000100 or 0x00001000 or 0x00000200,
|
||||||
|
nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32:
|
||||||
|
result = $msgbuf
|
||||||
|
if msgbuf != nil: LocalFree(cast[pointer](msgbuf))
|
||||||
|
else:
|
||||||
|
var msgbuf: cstring
|
||||||
|
if FormatMessageA(0x00000100 or 0x00001000 or 0x00000200,
|
||||||
|
nil, errorCode.int32, 0, addr(msgbuf), 0, nil) != 0'i32:
|
||||||
|
result = $msgbuf
|
||||||
|
if msgbuf != nil: LocalFree(msgbuf)
|
||||||
|
else:
|
||||||
|
if errorCode != TOSErrorCode(0'i32):
|
||||||
|
result = $os.strerror(errorCode.int32)
|
||||||
|
|
||||||
|
proc OSError*(errorCode: TOSErrorCode) =
|
||||||
|
## Raises an ``EOS`` exception. The ``errorCode`` will determine the
|
||||||
|
## message, ``OSErrorMsg`` will be used to get this message.
|
||||||
|
##
|
||||||
|
## The error code can be retrieved using the ``OSLastError`` proc.
|
||||||
|
##
|
||||||
|
## If the error code is ``0`` or an error message could not be retrieved,
|
||||||
|
## the message ``unknown OS error`` will be used.
|
||||||
|
let msg = OSErrorMsg(errorCode)
|
||||||
|
if msg == "":
|
||||||
|
raise newException(EOS, "unknown OS error")
|
||||||
|
else:
|
||||||
|
raise newException(EOS, msg)
|
||||||
|
|
||||||
|
{.push stackTrace:off.}
|
||||||
|
proc OSLastError*(): TOSErrorCode =
|
||||||
|
## Retrieves the last operating system error code.
|
||||||
|
##
|
||||||
|
## This procedure is useful in the event when an OS call fails. In that case
|
||||||
|
## this procedure will return the error code describing the reason why the
|
||||||
|
## OS call failed. The ``OSErrorMsg`` procedure can then be used to convert
|
||||||
|
## this code into a string.
|
||||||
|
##
|
||||||
|
## **Warning**:
|
||||||
|
## The behaviour of this procedure varies between Windows and POSIX systems.
|
||||||
|
## On Windows some OS calls can reset the error code to ``0`` causing this
|
||||||
|
## procedure to return ``0``. It is therefore advised to call this procedure
|
||||||
|
## immediately after an OS call fails. On POSIX systems this is not a problem.
|
||||||
|
|
||||||
|
when defined(windows):
|
||||||
|
result = TOSErrorCode(GetLastError())
|
||||||
|
else:
|
||||||
|
result = TOSErrorCode(errno)
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
proc UnixToNativePath*(path: string): string {.
|
proc UnixToNativePath*(path: string): string {.
|
||||||
noSideEffect, rtl, extern: "nos$1".} =
|
noSideEffect, rtl, extern: "nos$1".} =
|
||||||
|
|
@ -311,12 +388,12 @@ proc getLastModificationTime*(file: string): TTime {.rtl, extern: "nos$1".} =
|
||||||
## Returns the `file`'s last modification time.
|
## Returns the `file`'s last modification time.
|
||||||
when defined(posix):
|
when defined(posix):
|
||||||
var res: TStat
|
var res: TStat
|
||||||
if stat(file, res) < 0'i32: OSError()
|
if stat(file, res) < 0'i32: OSError(OSLastError())
|
||||||
return res.st_mtime
|
return res.st_mtime
|
||||||
else:
|
else:
|
||||||
var f: TWIN32_Find_Data
|
var f: TWIN32_Find_Data
|
||||||
var h = findfirstFile(file, f)
|
var h = findfirstFile(file, f)
|
||||||
if h == -1'i32: OSError()
|
if h == -1'i32: OSError(OSLastError())
|
||||||
result = winTimeToUnixTime(rdFileTime(f.ftLastWriteTime))
|
result = winTimeToUnixTime(rdFileTime(f.ftLastWriteTime))
|
||||||
findclose(h)
|
findclose(h)
|
||||||
|
|
||||||
|
|
@ -324,12 +401,12 @@ proc getLastAccessTime*(file: string): TTime {.rtl, extern: "nos$1".} =
|
||||||
## Returns the `file`'s last read or write access time.
|
## Returns the `file`'s last read or write access time.
|
||||||
when defined(posix):
|
when defined(posix):
|
||||||
var res: TStat
|
var res: TStat
|
||||||
if stat(file, res) < 0'i32: OSError()
|
if stat(file, res) < 0'i32: OSError(OSLastError())
|
||||||
return res.st_atime
|
return res.st_atime
|
||||||
else:
|
else:
|
||||||
var f: TWIN32_Find_Data
|
var f: TWIN32_Find_Data
|
||||||
var h = findfirstFile(file, f)
|
var h = findfirstFile(file, f)
|
||||||
if h == -1'i32: OSError()
|
if h == -1'i32: OSError(OSLastError())
|
||||||
result = winTimeToUnixTime(rdFileTime(f.ftLastAccessTime))
|
result = winTimeToUnixTime(rdFileTime(f.ftLastAccessTime))
|
||||||
findclose(h)
|
findclose(h)
|
||||||
|
|
||||||
|
|
@ -337,12 +414,12 @@ proc getCreationTime*(file: string): TTime {.rtl, extern: "nos$1".} =
|
||||||
## Returns the `file`'s creation time.
|
## Returns the `file`'s creation time.
|
||||||
when defined(posix):
|
when defined(posix):
|
||||||
var res: TStat
|
var res: TStat
|
||||||
if stat(file, res) < 0'i32: OSError()
|
if stat(file, res) < 0'i32: OSError(OSLastError())
|
||||||
return res.st_ctime
|
return res.st_ctime
|
||||||
else:
|
else:
|
||||||
var f: TWIN32_Find_Data
|
var f: TWIN32_Find_Data
|
||||||
var h = findfirstFile(file, f)
|
var h = findfirstFile(file, f)
|
||||||
if h == -1'i32: OSError()
|
if h == -1'i32: OSError(OSLastError())
|
||||||
result = winTimeToUnixTime(rdFileTime(f.ftCreationTime))
|
result = winTimeToUnixTime(rdFileTime(f.ftCreationTime))
|
||||||
findclose(h)
|
findclose(h)
|
||||||
|
|
||||||
|
|
@ -358,30 +435,30 @@ proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} =
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
var res = newWideCString("", bufsize)
|
var res = newWideCString("", bufsize)
|
||||||
var L = GetCurrentDirectoryW(bufsize, res)
|
var L = GetCurrentDirectoryW(bufsize, res)
|
||||||
if L == 0'i32: OSError()
|
if L == 0'i32: OSError(OSLastError())
|
||||||
result = res$L
|
result = res$L
|
||||||
else:
|
else:
|
||||||
result = newString(bufsize)
|
result = newString(bufsize)
|
||||||
var L = GetCurrentDirectoryA(bufsize, result)
|
var L = GetCurrentDirectoryA(bufsize, result)
|
||||||
if L == 0'i32: OSError()
|
if L == 0'i32: OSError(OSLastError())
|
||||||
setLen(result, L)
|
setLen(result, L)
|
||||||
else:
|
else:
|
||||||
result = newString(bufsize)
|
result = newString(bufsize)
|
||||||
if getcwd(result, bufsize) != nil:
|
if getcwd(result, bufsize) != nil:
|
||||||
setlen(result, c_strlen(result))
|
setlen(result, c_strlen(result))
|
||||||
else:
|
else:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
|
|
||||||
proc setCurrentDir*(newDir: string) {.inline, tags: [].} =
|
proc setCurrentDir*(newDir: string) {.inline, tags: [].} =
|
||||||
## Sets the `current working directory`:idx:; `EOS` is raised if
|
## Sets the `current working directory`:idx:; `EOS` is raised if
|
||||||
## `newDir` cannot been set.
|
## `newDir` cannot been set.
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
if SetCurrentDirectoryW(newWideCString(newDir)) == 0'i32: OSError()
|
if SetCurrentDirectoryW(newWideCString(newDir)) == 0'i32: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
if SetCurrentDirectoryA(newDir) == 0'i32: OSError()
|
if SetCurrentDirectoryA(newDir) == 0'i32: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
if chdir(newDir) != 0'i32: OSError()
|
if chdir(newDir) != 0'i32: OSError(OSLastError())
|
||||||
|
|
||||||
proc JoinPath*(head, tail: string): string {.
|
proc JoinPath*(head, tail: string): string {.
|
||||||
noSideEffect, rtl, extern: "nos$1".} =
|
noSideEffect, rtl, extern: "nos$1".} =
|
||||||
|
|
@ -571,23 +648,23 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
|
||||||
var res = newWideCString("", bufsize div 2)
|
var res = newWideCString("", bufsize div 2)
|
||||||
var L = GetFullPathNameW(newWideCString(filename), bufsize, res, unused)
|
var L = GetFullPathNameW(newWideCString(filename), bufsize, res, unused)
|
||||||
if L <= 0'i32 or L >= bufsize:
|
if L <= 0'i32 or L >= bufsize:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
result = res$L
|
result = res$L
|
||||||
else:
|
else:
|
||||||
var unused: cstring
|
var unused: cstring
|
||||||
result = newString(bufsize)
|
result = newString(bufsize)
|
||||||
var L = GetFullPathNameA(filename, bufsize, result, unused)
|
var L = GetFullPathNameA(filename, bufsize, result, unused)
|
||||||
if L <= 0'i32 or L >= bufsize: OSError()
|
if L <= 0'i32 or L >= bufsize: OSError(OSLastError())
|
||||||
setLen(result, L)
|
setLen(result, L)
|
||||||
elif defined(macosx) or defined(bsd):
|
elif defined(macosx) or defined(bsd):
|
||||||
# On Mac OS X 10.5, realpath does not allocate the buffer on its own
|
# On Mac OS X 10.5, realpath does not allocate the buffer on its own
|
||||||
var pathBuffer: cstring = newString(pathMax)
|
var pathBuffer: cstring = newString(pathMax)
|
||||||
var resultBuffer = realpath(filename, pathBuffer)
|
var resultBuffer = realpath(filename, pathBuffer)
|
||||||
if resultBuffer == nil: OSError()
|
if resultBuffer == nil: OSError(OSLastError())
|
||||||
result = $resultBuffer
|
result = $resultBuffer
|
||||||
else:
|
else:
|
||||||
var res = realpath(filename, nil)
|
var res = realpath(filename, nil)
|
||||||
if res == nil: OSError()
|
if res == nil: OSError(OSLastError())
|
||||||
result = $res
|
result = $res
|
||||||
c_free(res)
|
c_free(res)
|
||||||
|
|
||||||
|
|
@ -677,6 +754,7 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
|
||||||
var f1 = OpenHandle(path1)
|
var f1 = OpenHandle(path1)
|
||||||
var f2 = OpenHandle(path2)
|
var f2 = OpenHandle(path2)
|
||||||
|
|
||||||
|
var lastErr: TOSErrorCode
|
||||||
if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
|
if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE:
|
||||||
var fi1, fi2: TBY_HANDLE_FILE_INFORMATION
|
var fi1, fi2: TBY_HANDLE_FILE_INFORMATION
|
||||||
|
|
||||||
|
|
@ -685,17 +763,21 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
|
||||||
result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and
|
result = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber and
|
||||||
fi1.nFileIndexHigh == fi2.nFileIndexHigh and
|
fi1.nFileIndexHigh == fi2.nFileIndexHigh and
|
||||||
fi1.nFileIndexLow == fi2.nFileIndexLow
|
fi1.nFileIndexLow == fi2.nFileIndexLow
|
||||||
else: success = false
|
else:
|
||||||
else: success = false
|
lastErr = OSLastError()
|
||||||
|
success = false
|
||||||
|
else:
|
||||||
|
lastErr = OSLastError()
|
||||||
|
success = false
|
||||||
|
|
||||||
discard CloseHandle(f1)
|
discard CloseHandle(f1)
|
||||||
discard CloseHandle(f2)
|
discard CloseHandle(f2)
|
||||||
|
|
||||||
if not success: OSError()
|
if not success: OSError(lastErr)
|
||||||
else:
|
else:
|
||||||
var a, b: TStat
|
var a, b: TStat
|
||||||
if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
|
if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
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
|
||||||
|
|
||||||
|
|
@ -738,17 +820,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: OSError()
|
if CopyFileW(s, d, 0'i32) == 0'i32: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
if CopyFileA(source, dest, 0'i32) == 0'i32: OSError()
|
if CopyFileA(source, dest, 0'i32) == 0'i32: OSError(OSLastError())
|
||||||
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: TFile
|
var d, s: TFile
|
||||||
if not open(s, source): OSError()
|
if not open(s, source): OSError(OSLastError())
|
||||||
if not open(d, dest, fmWrite):
|
if not open(d, dest, fmWrite):
|
||||||
close(s)
|
close(s)
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
var buf = alloc(bufsize)
|
var buf = alloc(bufsize)
|
||||||
while True:
|
while True:
|
||||||
var bytesread = readBuffer(s, buf, bufsize)
|
var bytesread = readBuffer(s, buf, bufsize)
|
||||||
|
|
@ -758,7 +840,7 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
dealloc(buf)
|
dealloc(buf)
|
||||||
close(s)
|
close(s)
|
||||||
close(d)
|
close(d)
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
if bytesread != bufSize: break
|
if bytesread != bufSize: break
|
||||||
dealloc(buf)
|
dealloc(buf)
|
||||||
close(s)
|
close(s)
|
||||||
|
|
@ -767,7 +849,8 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
||||||
tags: [FReadIO, FWriteIO].} =
|
tags: [FReadIO, FWriteIO].} =
|
||||||
## Moves a file from `source` to `dest`. If this fails, `EOS` is raised.
|
## Moves a file from `source` to `dest`. If this fails, `EOS` is raised.
|
||||||
if crename(source, dest) != 0'i32: OSError()
|
if crename(source, dest) != 0'i32:
|
||||||
|
raise newException(EOS, $strerror(errno))
|
||||||
|
|
||||||
when not defined(ENOENT):
|
when not defined(ENOENT):
|
||||||
var ENOENT {.importc, header: "<errno.h>".}: cint
|
var ENOENT {.importc, header: "<errno.h>".}: cint
|
||||||
|
|
@ -775,7 +858,8 @@ when not defined(ENOENT):
|
||||||
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
|
proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
|
||||||
## Removes the `file`. If this fails, `EOS` is raised. This does not fail
|
## Removes the `file`. If this fails, `EOS` is raised. This does not fail
|
||||||
## if the file never existed in the first place.
|
## if the file never existed in the first place.
|
||||||
if cremove(file) != 0'i32 and errno != ENOENT: OSError()
|
if cremove(file) != 0'i32 and errno != ENOENT:
|
||||||
|
raise newException(EOS, $strerror(errno))
|
||||||
|
|
||||||
proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
|
proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
|
||||||
tags: [FExecIO].} =
|
tags: [FExecIO].} =
|
||||||
|
|
@ -907,14 +991,14 @@ proc putEnv*(key, val: string) {.tags: [FWriteEnv].} =
|
||||||
indx = high(environment)
|
indx = high(environment)
|
||||||
when defined(unix):
|
when defined(unix):
|
||||||
if cputenv(environment[indx]) != 0'i32:
|
if cputenv(environment[indx]) != 0'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
var k = newWideCString(key)
|
var k = newWideCString(key)
|
||||||
var v = newWideCString(val)
|
var v = newWideCString(val)
|
||||||
if SetEnvironmentVariableW(k, v) == 0'i32: OSError()
|
if SetEnvironmentVariableW(k, v) == 0'i32: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
if SetEnvironmentVariableA(key, val) == 0'i32: OSError()
|
if SetEnvironmentVariableA(key, val) == 0'i32: OSError(OSLastError())
|
||||||
|
|
||||||
iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [FReadEnv].} =
|
iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [FReadEnv].} =
|
||||||
## Iterate over all `environments variables`:idx:. In the first component
|
## Iterate over all `environments variables`:idx:. In the first component
|
||||||
|
|
@ -1044,10 +1128,12 @@ proc rawRemoveDir(dir: string) =
|
||||||
wrapUnary(res, RemoveDirectoryW, dir)
|
wrapUnary(res, RemoveDirectoryW, dir)
|
||||||
else:
|
else:
|
||||||
var res = RemoveDirectoryA(dir)
|
var res = RemoveDirectoryA(dir)
|
||||||
if res == 0'i32 and GetLastError() != 3'i32 and
|
let lastError = OSLastError()
|
||||||
GetLastError() != 18'i32: OSError()
|
if res == 0'i32 and lastError.int32 != 3'i32 and
|
||||||
|
lastError.int32 != 18'i32 and lastError.int32 != 2'i32:
|
||||||
|
OSError(lastError)
|
||||||
else:
|
else:
|
||||||
if rmdir(dir) != 0'i32 and errno != ENOENT: OSError()
|
if rmdir(dir) != 0'i32 and errno != ENOENT: OSError(OSLastError())
|
||||||
|
|
||||||
proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
|
proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
|
||||||
FWriteDir, FReadDir].} =
|
FWriteDir, FReadDir].} =
|
||||||
|
|
@ -1065,14 +1151,14 @@ proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
|
||||||
proc rawCreateDir(dir: string) =
|
proc rawCreateDir(dir: string) =
|
||||||
when defined(unix):
|
when defined(unix):
|
||||||
if mkdir(dir, 0o711) != 0'i32 and errno != EEXIST:
|
if mkdir(dir, 0o711) != 0'i32 and errno != EEXIST:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
when useWinUnicode:
|
when useWinUnicode:
|
||||||
wrapUnary(res, CreateDirectoryW, dir)
|
wrapUnary(res, CreateDirectoryW, dir)
|
||||||
else:
|
else:
|
||||||
var res = CreateDirectoryA(dir)
|
var res = CreateDirectoryA(dir)
|
||||||
if res == 0'i32 and GetLastError() != 183'i32:
|
if res == 0'i32 and GetLastError() != 183'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
|
|
||||||
proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
|
proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} =
|
||||||
## Creates the `directory`:idx: `dir`.
|
## Creates the `directory`:idx: `dir`.
|
||||||
|
|
@ -1213,7 +1299,7 @@ proc getFilePermissions*(filename: string): set[TFilePermission] {.
|
||||||
## permission is available in any case.
|
## permission is available in any case.
|
||||||
when defined(posix):
|
when defined(posix):
|
||||||
var a: TStat
|
var a: TStat
|
||||||
if stat(filename, a) < 0'i32: OSError()
|
if stat(filename, a) < 0'i32: OSError(OSLastError())
|
||||||
result = {}
|
result = {}
|
||||||
if (a.st_mode and S_IRUSR) != 0'i32: result.incl(fpUserRead)
|
if (a.st_mode and S_IRUSR) != 0'i32: result.incl(fpUserRead)
|
||||||
if (a.st_mode and S_IWUSR) != 0'i32: result.incl(fpUserWrite)
|
if (a.st_mode and S_IWUSR) != 0'i32: result.incl(fpUserWrite)
|
||||||
|
|
@ -1231,7 +1317,7 @@ proc getFilePermissions*(filename: string): set[TFilePermission] {.
|
||||||
wrapUnary(res, GetFileAttributesW, filename)
|
wrapUnary(res, GetFileAttributesW, filename)
|
||||||
else:
|
else:
|
||||||
var res = GetFileAttributesA(filename)
|
var res = GetFileAttributesA(filename)
|
||||||
if res == -1'i32: OSError()
|
if res == -1'i32: OSError(OSLastError())
|
||||||
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}
|
||||||
|
|
@ -1257,13 +1343,13 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
|
||||||
if fpOthersWrite in permissions: p = p or S_IWOTH
|
if fpOthersWrite in permissions: p = p or S_IWOTH
|
||||||
if fpOthersExec in permissions: p = p or S_IXOTH
|
if fpOthersExec in permissions: p = p or S_IXOTH
|
||||||
|
|
||||||
if chmod(filename, p) != 0: OSError()
|
if chmod(filename, p) != 0: OSError(OSLastError())
|
||||||
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: OSError()
|
if res == -1'i32: OSError(OSLastError())
|
||||||
if fpUserWrite in permissions:
|
if fpUserWrite in permissions:
|
||||||
res = res and not FILE_ATTRIBUTE_READONLY
|
res = res and not FILE_ATTRIBUTE_READONLY
|
||||||
else:
|
else:
|
||||||
|
|
@ -1272,7 +1358,7 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {.
|
||||||
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: OSError()
|
if res2 == - 1'i32: OSError(OSLastError())
|
||||||
|
|
||||||
proc inclFilePermissions*(filename: string,
|
proc inclFilePermissions*(filename: string,
|
||||||
permissions: set[TFilePermission]) {.
|
permissions: set[TFilePermission]) {.
|
||||||
|
|
@ -1448,7 +1534,7 @@ proc getFileSize*(file: string): biggestInt {.rtl, extern: "nos$1",
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var a: TWin32FindData
|
var a: TWin32FindData
|
||||||
var resA = findfirstFile(file, a)
|
var resA = findfirstFile(file, a)
|
||||||
if resA == -1: OSError()
|
if resA == -1: OSError(OSLastError())
|
||||||
result = rdFileSize(a)
|
result = rdFileSize(a)
|
||||||
findclose(resA)
|
findclose(resA)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1456,7 +1542,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: OSError()
|
else: OSError(OSLastError())
|
||||||
|
|
||||||
proc findExe*(exe: string): string {.tags: [FReadDir, FReadEnv].} =
|
proc findExe*(exe: string): string {.tags: [FReadDir, FReadEnv].} =
|
||||||
## Searches for `exe` in the current working directory and then
|
## Searches for `exe` in the current working directory and then
|
||||||
|
|
|
||||||
|
|
@ -370,6 +370,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
else:
|
else:
|
||||||
success = winlean.CreateProcessA(nil,
|
success = winlean.CreateProcessA(nil,
|
||||||
cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo)
|
cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo)
|
||||||
|
let lastError = OSLastError()
|
||||||
|
|
||||||
if poParentStreams notin options:
|
if poParentStreams notin options:
|
||||||
FileClose(si.hStdInput)
|
FileClose(si.hStdInput)
|
||||||
|
|
@ -379,7 +380,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
|
|
||||||
if e != nil: dealloc(e)
|
if e != nil: dealloc(e)
|
||||||
dealloc(cmdl)
|
dealloc(cmdl)
|
||||||
if success == 0: OSError()
|
if success == 0: OSError(lastError)
|
||||||
# Close the handle now so anyone waiting is woken:
|
# Close the handle now so anyone waiting is woken:
|
||||||
discard closeHandle(procInfo.hThread)
|
discard closeHandle(procInfo.hThread)
|
||||||
result.FProcessHandle = procInfo.hProcess
|
result.FProcessHandle = procInfo.hProcess
|
||||||
|
|
@ -450,7 +451,7 @@ when defined(Windows) and not defined(useNimRtl):
|
||||||
var res = winlean.CreateProcessA(nil, command, nil, nil, 0,
|
var res = winlean.CreateProcessA(nil, command, nil, nil, 0,
|
||||||
NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo)
|
NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo)
|
||||||
if res == 0:
|
if res == 0:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
Process = ProcInfo.hProcess
|
Process = ProcInfo.hProcess
|
||||||
discard CloseHandle(ProcInfo.hThread)
|
discard CloseHandle(ProcInfo.hThread)
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,7 @@ when defined(ssl):
|
||||||
if err == 0:
|
if err == 0:
|
||||||
raise newException(ESSL, "No error reported.")
|
raise newException(ESSL, "No error reported.")
|
||||||
if err == -1:
|
if err == -1:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
var errStr = ErrErrorString(err, nil)
|
var errStr = ErrErrorString(err, nil)
|
||||||
raise newException(ESSL, $errStr)
|
raise newException(ESSL, $errStr)
|
||||||
|
|
||||||
|
|
@ -347,24 +347,23 @@ proc SocketError*(socket: TSocket, err: int = -1, async = false) =
|
||||||
else: SSLError("Unknown Error")
|
else: SSLError("Unknown Error")
|
||||||
|
|
||||||
if err == -1 and not (when defined(ssl): socket.isSSL else: false):
|
if err == -1 and not (when defined(ssl): socket.isSSL else: false):
|
||||||
|
let lastError = OSLastError()
|
||||||
if async:
|
if async:
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
# TODO: Test on Windows
|
if lastError.int32 == WSAEWOULDBLOCK:
|
||||||
var err = WSAGetLastError()
|
|
||||||
if err == WSAEWOULDBLOCK:
|
|
||||||
return
|
return
|
||||||
else: OSError()
|
else: OSError(lastError)
|
||||||
else:
|
else:
|
||||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
if lastError.int32 == EAGAIN or lastError.int32 == EWOULDBLOCK:
|
||||||
return
|
return
|
||||||
else: OSError()
|
else: OSError(lastError)
|
||||||
else: OSError()
|
else: OSError(lastError)
|
||||||
|
|
||||||
proc listen*(socket: TSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} =
|
proc listen*(socket: TSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} =
|
||||||
## Marks ``socket`` as accepting connections.
|
## Marks ``socket`` as accepting connections.
|
||||||
## ``Backlog`` specifies the maximum length of the
|
## ``Backlog`` specifies the maximum length of the
|
||||||
## queue of pending connections.
|
## queue of pending connections.
|
||||||
if listen(socket.fd, cint(backlog)) < 0'i32: OSError()
|
if listen(socket.fd, cint(backlog)) < 0'i32: OSError(OSLastError())
|
||||||
|
|
||||||
proc invalidIp4(s: string) {.noreturn, noinline.} =
|
proc invalidIp4(s: string) {.noreturn, noinline.} =
|
||||||
raise newException(EInvalidValue, "invalid ip4 address: " & s)
|
raise newException(EInvalidValue, "invalid ip4 address: " & s)
|
||||||
|
|
@ -403,7 +402,7 @@ template gaiNim(a, p, h, list: expr): stmt =
|
||||||
var gaiResult = getAddrInfo(a, $p, addr(h), list)
|
var gaiResult = getAddrInfo(a, $p, addr(h), list)
|
||||||
if gaiResult != 0'i32:
|
if gaiResult != 0'i32:
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
OSError($gai_strerror(gaiResult))
|
OSError($gai_strerror(gaiResult))
|
||||||
|
|
||||||
|
|
@ -423,7 +422,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
|
||||||
name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
|
name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
|
||||||
if bindSocket(socket.fd, cast[ptr TSockAddr](addr(name)),
|
if bindSocket(socket.fd, cast[ptr TSockAddr](addr(name)),
|
||||||
sizeof(name).TSockLen) < 0'i32:
|
sizeof(name).TSockLen) < 0'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
var hints: TAddrInfo
|
var hints: TAddrInfo
|
||||||
var aiList: ptr TAddrInfo = nil
|
var aiList: ptr TAddrInfo = nil
|
||||||
|
|
@ -432,21 +431,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
|
||||||
hints.ai_protocol = toInt(IPPROTO_TCP)
|
hints.ai_protocol = toInt(IPPROTO_TCP)
|
||||||
gaiNim(address, port, hints, aiList)
|
gaiNim(address, port, hints, aiList)
|
||||||
if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrLen.TSockLen) < 0'i32:
|
if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrLen.TSockLen) < 0'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
|
|
||||||
when false:
|
|
||||||
proc bindAddr*(socket: TSocket, port = TPort(0)) =
|
|
||||||
## binds a port number to a socket.
|
|
||||||
var name: Tsockaddr_in
|
|
||||||
when defined(Windows):
|
|
||||||
name.sin_family = int16(ord(AF_INET))
|
|
||||||
else:
|
|
||||||
name.sin_family = posix.AF_INET
|
|
||||||
name.sin_port = sockets.htons(int16(port))
|
|
||||||
name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
|
|
||||||
if bindSocket(cint(socket), cast[ptr TSockAddr](addr(name)),
|
|
||||||
sizeof(name).TSockLen) < 0'i32:
|
|
||||||
OSError()
|
|
||||||
|
|
||||||
proc getSockName*(socket: TSocket): TPort =
|
proc getSockName*(socket: TSocket): TPort =
|
||||||
## returns the socket's associated port number.
|
## returns the socket's associated port number.
|
||||||
|
|
@ -460,7 +445,7 @@ proc getSockName*(socket: TSocket): TPort =
|
||||||
var namelen = sizeof(name).TSockLen
|
var namelen = sizeof(name).TSockLen
|
||||||
if getsockname(socket.fd, cast[ptr TSockAddr](addr(name)),
|
if getsockname(socket.fd, cast[ptr TSockAddr](addr(name)),
|
||||||
addr(namelen)) == -1'i32:
|
addr(namelen)) == -1'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
result = TPort(sockets.ntohs(name.sin_port))
|
result = TPort(sockets.ntohs(name.sin_port))
|
||||||
|
|
||||||
template acceptAddrPlain(noClientRet, successRet: expr,
|
template acceptAddrPlain(noClientRet, successRet: expr,
|
||||||
|
|
@ -472,26 +457,25 @@ template acceptAddrPlain(noClientRet, successRet: expr,
|
||||||
addr(addrLen))
|
addr(addrLen))
|
||||||
|
|
||||||
if sock < 0:
|
if sock < 0:
|
||||||
# TODO: Test on Windows.
|
let err = OSLastError()
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var err = WSAGetLastError()
|
if err.int32 == WSAEINPROGRESS:
|
||||||
if err == WSAEINPROGRESS:
|
|
||||||
client = InvalidSocket
|
client = InvalidSocket
|
||||||
address = ""
|
address = ""
|
||||||
when noClientRet.int == -1:
|
when noClientRet.int == -1:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
return noClientRet
|
return noClientRet
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
else:
|
else:
|
||||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
|
||||||
client = InvalidSocket
|
client = InvalidSocket
|
||||||
address = ""
|
address = ""
|
||||||
when noClientRet.int == -1:
|
when noClientRet.int == -1:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
return noClientRet
|
return noClientRet
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
else:
|
else:
|
||||||
client.fd = sock
|
client.fd = sock
|
||||||
client.isBuffered = server.isBuffered
|
client.isBuffered = server.isBuffered
|
||||||
|
|
@ -644,7 +628,7 @@ proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} =
|
||||||
var s = winlean.getservbyname(name, proto)
|
var s = winlean.getservbyname(name, proto)
|
||||||
else:
|
else:
|
||||||
var s = posix.getservbyname(name, proto)
|
var s = posix.getservbyname(name, proto)
|
||||||
if s == nil: OSError()
|
if s == nil: OSError(OSLastError())
|
||||||
result.name = $s.s_name
|
result.name = $s.s_name
|
||||||
result.aliases = cstringArrayToSeq(s.s_aliases)
|
result.aliases = cstringArrayToSeq(s.s_aliases)
|
||||||
result.port = TPort(s.s_port)
|
result.port = TPort(s.s_port)
|
||||||
|
|
@ -656,7 +640,7 @@ proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} =
|
||||||
var s = winlean.getservbyport(ze(int16(port)).cint, proto)
|
var s = winlean.getservbyport(ze(int16(port)).cint, proto)
|
||||||
else:
|
else:
|
||||||
var s = posix.getservbyport(ze(int16(port)).cint, proto)
|
var s = posix.getservbyport(ze(int16(port)).cint, proto)
|
||||||
if s == nil: OSError()
|
if s == nil: OSError(OSLastError())
|
||||||
result.name = $s.s_name
|
result.name = $s.s_name
|
||||||
result.aliases = cstringArrayToSeq(s.s_aliases)
|
result.aliases = cstringArrayToSeq(s.s_aliases)
|
||||||
result.port = TPort(s.s_port)
|
result.port = TPort(s.s_port)
|
||||||
|
|
@ -670,7 +654,7 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
|
var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
|
||||||
cint(sockets.AF_INET))
|
cint(sockets.AF_INET))
|
||||||
if s == nil: OSError()
|
if s == nil: OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSockLen,
|
var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSockLen,
|
||||||
cint(posix.AF_INET))
|
cint(posix.AF_INET))
|
||||||
|
|
@ -687,7 +671,7 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
|
||||||
elif s.h_addrtype == posix.AF_INET6:
|
elif s.h_addrtype == posix.AF_INET6:
|
||||||
result.addrType = AF_INET6
|
result.addrType = AF_INET6
|
||||||
else:
|
else:
|
||||||
OSError("unknown h_addrtype")
|
raise newException(EOS, "unknown h_addrtype")
|
||||||
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
||||||
result.length = int(s.h_length)
|
result.length = int(s.h_length)
|
||||||
|
|
||||||
|
|
@ -697,7 +681,7 @@ proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
|
||||||
var s = winlean.gethostbyname(name)
|
var s = winlean.gethostbyname(name)
|
||||||
else:
|
else:
|
||||||
var s = posix.gethostbyname(name)
|
var s = posix.gethostbyname(name)
|
||||||
if s == nil: OSError()
|
if s == nil: OSError(OSLastError())
|
||||||
result.name = $s.h_name
|
result.name = $s.h_name
|
||||||
result.aliases = cstringArrayToSeq(s.h_aliases)
|
result.aliases = cstringArrayToSeq(s.h_aliases)
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
@ -708,7 +692,7 @@ proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
|
||||||
elif s.h_addrtype == posix.AF_INET6:
|
elif s.h_addrtype == posix.AF_INET6:
|
||||||
result.addrType = AF_INET6
|
result.addrType = AF_INET6
|
||||||
else:
|
else:
|
||||||
OSError("unknown h_addrtype")
|
raise newException(EOS, "unknown h_addrtype")
|
||||||
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
result.addrList = cstringArrayToSeq(s.h_addr_list)
|
||||||
result.length = int(s.h_length)
|
result.length = int(s.h_length)
|
||||||
|
|
||||||
|
|
@ -719,7 +703,7 @@ proc getSockOptInt*(socket: TSocket, level, optname: int): int {.
|
||||||
var size = sizeof(res).TSockLen
|
var size = sizeof(res).TSockLen
|
||||||
if getsockopt(socket.fd, cint(level), cint(optname),
|
if getsockopt(socket.fd, cint(level), cint(optname),
|
||||||
addr(res), addr(size)) < 0'i32:
|
addr(res), addr(size)) < 0'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
result = int(res)
|
result = int(res)
|
||||||
|
|
||||||
proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
|
proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
|
||||||
|
|
@ -728,7 +712,7 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
|
||||||
var value = cint(optval)
|
var value = cint(optval)
|
||||||
if setsockopt(socket.fd, cint(level), cint(optname), addr(value),
|
if setsockopt(socket.fd, cint(level), cint(optname), addr(value),
|
||||||
sizeof(value).TSockLen) < 0'i32:
|
sizeof(value).TSockLen) < 0'i32:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
|
|
||||||
proc connect*(socket: TSocket, address: string, port = TPort(0),
|
proc connect*(socket: TSocket, address: string, port = TPort(0),
|
||||||
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
af: TDomain = AF_INET) {.tags: [FReadIO].} =
|
||||||
|
|
@ -746,15 +730,17 @@ proc connect*(socket: TSocket, address: string, port = TPort(0),
|
||||||
gaiNim(address, port, hints, aiList)
|
gaiNim(address, port, hints, aiList)
|
||||||
# try all possibilities:
|
# try all possibilities:
|
||||||
var success = false
|
var success = false
|
||||||
|
var lastError: TOSErrorCode
|
||||||
var it = aiList
|
var it = aiList
|
||||||
while it != nil:
|
while it != nil:
|
||||||
if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen) == 0'i32:
|
if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen) == 0'i32:
|
||||||
success = true
|
success = true
|
||||||
break
|
break
|
||||||
|
else: lastError = OSLastError()
|
||||||
it = it.ai_next
|
it = it.ai_next
|
||||||
|
|
||||||
freeaddrinfo(aiList)
|
freeaddrinfo(aiList)
|
||||||
if not success: OSError()
|
if not success: OSError(lastError)
|
||||||
|
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
|
|
@ -807,6 +793,7 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
|
||||||
gaiNim(name, port, hints, aiList)
|
gaiNim(name, port, hints, aiList)
|
||||||
# try all possibilities:
|
# try all possibilities:
|
||||||
var success = false
|
var success = false
|
||||||
|
var lastError: TOSErrorCode
|
||||||
var it = aiList
|
var it = aiList
|
||||||
while it != nil:
|
while it != nil:
|
||||||
var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen)
|
var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen)
|
||||||
|
|
@ -814,22 +801,21 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
|
||||||
success = true
|
success = true
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# TODO: Test on Windows.
|
lastError = OSLastError()
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var err = WSAGetLastError()
|
|
||||||
# Windows EINTR doesn't behave same as POSIX.
|
# Windows EINTR doesn't behave same as POSIX.
|
||||||
if err == WSAEWOULDBLOCK:
|
if lastError.int32 == WSAEWOULDBLOCK:
|
||||||
success = true
|
success = true
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
if errno == EINTR or errno == EINPROGRESS:
|
if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
|
||||||
success = true
|
success = true
|
||||||
break
|
break
|
||||||
|
|
||||||
it = it.ai_next
|
it = it.ai_next
|
||||||
|
|
||||||
freeaddrinfo(aiList)
|
freeaddrinfo(aiList)
|
||||||
if not success: OSError()
|
if not success: OSError(lastError)
|
||||||
when defined(ssl):
|
when defined(ssl):
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
socket.sslNoHandshake = true
|
socket.sslNoHandshake = true
|
||||||
|
|
@ -1110,7 +1096,7 @@ proc waitFor(socket: TSocket, waited: var float, timeout, size: int,
|
||||||
var s = @[socket]
|
var s = @[socket]
|
||||||
var startTime = epochTime()
|
var startTime = epochTime()
|
||||||
let selRet = select(s, timeout - int(waited * 1000.0))
|
let selRet = select(s, timeout - int(waited * 1000.0))
|
||||||
if selRet < 0: OSError()
|
if selRet < 0: OSError(OSLastError())
|
||||||
if selRet != 1:
|
if selRet != 1:
|
||||||
raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
|
raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
|
||||||
waited += (epochTime() - startTime)
|
waited += (epochTime() - startTime)
|
||||||
|
|
@ -1259,14 +1245,14 @@ proc readLine*(socket: TSocket, line: var TaintedString, timeout = -1) {.
|
||||||
var c: char
|
var c: char
|
||||||
discard waitFor(socket, waited, timeout, 1, "readLine")
|
discard waitFor(socket, waited, timeout, 1, "readLine")
|
||||||
var n = recv(socket, addr(c), 1)
|
var n = recv(socket, addr(c), 1)
|
||||||
if n < 0: OSError()
|
if n < 0: OSError(OSLastError())
|
||||||
elif n == 0: return
|
elif n == 0: return
|
||||||
if c == '\r':
|
if c == '\r':
|
||||||
discard waitFor(socket, waited, timeout, 1, "readLine")
|
discard waitFor(socket, waited, timeout, 1, "readLine")
|
||||||
n = peekChar(socket, c)
|
n = peekChar(socket, c)
|
||||||
if n > 0 and c == '\L':
|
if n > 0 and c == '\L':
|
||||||
discard recv(socket, addr(c), 1)
|
discard recv(socket, addr(c), 1)
|
||||||
elif n <= 0: OSError()
|
elif n <= 0: OSError(OSLastError())
|
||||||
addNlIfEmpty()
|
addNlIfEmpty()
|
||||||
return
|
return
|
||||||
elif c == '\L':
|
elif c == '\L':
|
||||||
|
|
@ -1326,6 +1312,7 @@ proc readLineAsync*(socket: TSocket,
|
||||||
while true:
|
while true:
|
||||||
var c: char
|
var c: char
|
||||||
var n = recv(socket, addr(c), 1)
|
var n = recv(socket, addr(c), 1)
|
||||||
|
#echo(n)
|
||||||
if n < 0:
|
if n < 0:
|
||||||
if line.len == 0: errorOrNone else: return ReadPartialLine
|
if line.len == 0: errorOrNone else: return ReadPartialLine
|
||||||
elif n == 0:
|
elif n == 0:
|
||||||
|
|
@ -1352,7 +1339,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} =
|
||||||
var pos = 0
|
var pos = 0
|
||||||
while true:
|
while true:
|
||||||
var bytesRead = recv(socket, addr(string(result)[pos]), bufSize-1)
|
var bytesRead = recv(socket, addr(string(result)[pos]), bufSize-1)
|
||||||
if bytesRead == -1: OSError()
|
if bytesRead == -1: OSError(OSLastError())
|
||||||
setLen(result.string, pos + bytesRead)
|
setLen(result.string, pos + bytesRead)
|
||||||
if bytesRead != bufSize-1: break
|
if bytesRead != bufSize-1: break
|
||||||
# increase capacity:
|
# increase capacity:
|
||||||
|
|
@ -1364,7 +1351,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} =
|
||||||
while true:
|
while true:
|
||||||
var bytesRead = recv(socket, cstring(buf), bufSize-1)
|
var bytesRead = recv(socket, cstring(buf), bufSize-1)
|
||||||
# Error
|
# Error
|
||||||
if bytesRead == -1: OSError()
|
if bytesRead == -1: OSError(OSLastError())
|
||||||
|
|
||||||
buf[bytesRead] = '\0' # might not be necessary
|
buf[bytesRead] = '\0' # might not be necessary
|
||||||
setLen(buf, bytesRead)
|
setLen(buf, bytesRead)
|
||||||
|
|
@ -1421,16 +1408,15 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool {.
|
||||||
else: SSLError("Unknown Error")
|
else: SSLError("Unknown Error")
|
||||||
|
|
||||||
if bytesRead == -1 and not (when defined(ssl): socket.isSSL else: false):
|
if bytesRead == -1 and not (when defined(ssl): socket.isSSL else: false):
|
||||||
|
let err = OSLastError()
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
# TODO: Test on Windows
|
if err.int32 == WSAEWOULDBLOCK:
|
||||||
var err = WSAGetLastError()
|
|
||||||
if err == WSAEWOULDBLOCK:
|
|
||||||
return False
|
return False
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
else:
|
else:
|
||||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
|
||||||
return False
|
return False
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
|
|
||||||
setLen(s.string, pos + bytesRead)
|
setLen(s.string, pos + bytesRead)
|
||||||
if bytesRead != bufSize-1: break
|
if bytesRead != bufSize-1: break
|
||||||
|
|
@ -1475,16 +1461,15 @@ proc recvFromAsync*(socket: TSocket, data: var String, length: int,
|
||||||
result = true
|
result = true
|
||||||
var callRes = recvFrom(socket, data, length, address, port, flags)
|
var callRes = recvFrom(socket, data, length, address, port, flags)
|
||||||
if callRes < 0:
|
if callRes < 0:
|
||||||
|
let err = OSLastError()
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
# TODO: Test on Windows
|
if err.int32 == WSAEWOULDBLOCK:
|
||||||
var err = WSAGetLastError()
|
|
||||||
if err == WSAEWOULDBLOCK:
|
|
||||||
return False
|
return False
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
else:
|
else:
|
||||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
|
||||||
return False
|
return False
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
|
|
||||||
proc skip*(socket: TSocket) {.tags: [FReadIO], deprecated.} =
|
proc skip*(socket: TSocket) {.tags: [FReadIO], deprecated.} =
|
||||||
## skips all the data that is pending for the socket
|
## skips all the data that is pending for the socket
|
||||||
|
|
@ -1531,7 +1516,7 @@ proc send*(socket: TSocket, data: string) {.tags: [FWriteIO].} =
|
||||||
if socket.isSSL:
|
if socket.isSSL:
|
||||||
SSLError()
|
SSLError()
|
||||||
|
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
|
|
||||||
proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} =
|
proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} =
|
||||||
## sends data to a non-blocking socket.
|
## sends data to a non-blocking socket.
|
||||||
|
|
@ -1561,16 +1546,15 @@ proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} =
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
if result == -1:
|
if result == -1:
|
||||||
|
let err = OSLastError()
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
var err = WSAGetLastError()
|
if err.int32 == WSAEINPROGRESS:
|
||||||
# TODO: Test on windows.
|
|
||||||
if err == WSAEINPROGRESS:
|
|
||||||
return 0
|
return 0
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
else:
|
else:
|
||||||
if errno == EAGAIN or errno == EWOULDBLOCK:
|
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
|
||||||
return 0
|
return 0
|
||||||
else: OSError()
|
else: OSError(err)
|
||||||
|
|
||||||
|
|
||||||
proc trySend*(socket: TSocket, data: string): bool {.tags: [FWriteIO].} =
|
proc trySend*(socket: TSocket, data: string): bool {.tags: [FWriteIO].} =
|
||||||
|
|
@ -1626,15 +1610,15 @@ proc setBlocking(s: TSocket, blocking: bool) =
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
|
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
|
||||||
if ioctlsocket(TWinSocket(s.fd), FIONBIO, addr(mode)) == -1:
|
if ioctlsocket(TWinSocket(s.fd), FIONBIO, addr(mode)) == -1:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else: # BSD sockets
|
else: # BSD sockets
|
||||||
var x: int = fcntl(s.fd, F_GETFL, 0)
|
var x: int = fcntl(s.fd, F_GETFL, 0)
|
||||||
if x == -1:
|
if x == -1:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
else:
|
else:
|
||||||
var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
|
var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
|
||||||
if fcntl(s.fd, F_SETFL, mode) == -1:
|
if fcntl(s.fd, F_SETFL, mode) == -1:
|
||||||
OSError()
|
OSError(OSLastError())
|
||||||
s.nonblocking = not blocking
|
s.nonblocking = not blocking
|
||||||
|
|
||||||
proc connect*(socket: TSocket, address: string, port = TPort(0), timeout: int,
|
proc connect*(socket: TSocket, address: string, port = TPort(0), timeout: int,
|
||||||
|
|
@ -1665,6 +1649,6 @@ proc getFD*(socket: TSocket): cint = return socket.fd
|
||||||
|
|
||||||
when defined(Windows):
|
when defined(Windows):
|
||||||
var wsa: TWSADATA
|
var wsa: TWSADATA
|
||||||
if WSAStartup(0x0101'i16, wsa) != 0: OSError()
|
if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -489,7 +489,7 @@ proc FD_SET*(Socket: TWinSocket, FDSet: var TFDSet) =
|
||||||
proc FD_ZERO*(FDSet: var TFDSet) =
|
proc FD_ZERO*(FDSet: var TFDSet) =
|
||||||
FDSet.fd_count = 0
|
FDSet.fd_count = 0
|
||||||
|
|
||||||
proc WSAStartup*(wVersionRequired: int16, WSData: var TWSAData): cint {.
|
proc WSAStartup*(wVersionRequired: int16, WSData: ptr TWSAData): cint {.
|
||||||
stdcall, importc: "WSAStartup", dynlib: ws2dll.}
|
stdcall, importc: "WSAStartup", dynlib: ws2dll.}
|
||||||
|
|
||||||
proc getaddrinfo*(nodename, servname: cstring, hints: ptr TAddrInfo,
|
proc getaddrinfo*(nodename, servname: cstring, hints: ptr TAddrInfo,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue