# # Chronos SendFile # (c) Copyright 2018-Present # Status Research & Development GmbH # # Licensed under either of # Apache License, version 2.0, (LICENSE-APACHEv2) # MIT license (LICENSE-MIT) ## This module provides cross-platform wrapper for ``sendfile()`` syscall. {.push raises: [].} when defined(nimdoc): proc sendfile*(outfd, infd: int, offset: int, count: var int): int = ## Copies data between file descriptor ``infd`` and ``outfd``. Because this ## copying is done within the kernel, ``sendfile()`` is more efficient than ## the combination of ``read(2)`` and ``write(2)``, which would require ## transferring data to and from user space. ## ## ``infd`` should be a file descriptor opened for reading and ## ``outfd`` should be a descriptor opened for writing. ## ## The ``infd`` argument must correspond to a file which supports ## ``mmap(2)``-like operations (i.e., it cannot be a socket). ## ## ``offset`` the file offset from which ``sendfile()`` will start reading ## data from ``infd``. ## ## ``count`` is the number of bytes to copy between the file descriptors. ## On exit ``count`` will hold number of bytes actually transferred between ## file descriptors. May be >0 even in the case of error return, if some ## bytes were sent before the error occurred. ## ## If the transfer was successful, the number of bytes written to ``outfd`` ## is stored in ``count``, and ``0`` returned. Note that a successful call ## to ``sendfile()`` may write fewer bytes than requested; the caller should ## be prepared to retry the call if there were unsent bytes. ## ## On error, ``-1`` is returned. elif defined(emscripten): proc sendfile*(outfd, infd: int, offset: int, count: var int): int = raiseAssert "sendfile() is not implemented yet" elif (defined(linux) or defined(android)) and not(defined(emscripten)): proc osSendFile*(outfd, infd: cint, offset: ptr int, count: int): int {.importc: "sendfile", header: "".} proc sendfile*(outfd, infd: int, offset: int, count: var int): int = var o = offset let res = osSendFile(cint(outfd), cint(infd), addr o, count) if res >= 0: count = res 0 else: count = 0 -1 elif defined(freebsd) or defined(openbsd) or defined(netbsd) or defined(dragonflybsd): import oserrno type SendfileHeader* {.importc: "struct sf_hdtr", header: """#include #include #include """, pure, final.} = object proc osSendFile*(outfd, infd: cint, offset: uint, size: uint, hdtr: ptr SendfileHeader, sbytes: ptr uint, flags: int): int {.importc: "sendfile", header: """#include #include #include """.} proc sendfile*(outfd, infd: int, offset: int, count: var int): int = var o = 0'u let res = osSendFile(cint(infd), cint(outfd), uint(offset), uint(count), nil, addr o, 0) if res >= 0: count = int(o) 0 else: let err = osLastError() count = if err == EAGAIN: int(o) else: 0 -1 elif defined(macosx): import oserrno type SendfileHeader* {.importc: "struct sf_hdtr", header: """#include #include #include """, pure, final.} = object proc osSendFile*(fd, s: cint, offset: int, size: ptr int, hdtr: ptr SendfileHeader, flags: int): int {.importc: "sendfile", header: """#include #include #include """.} proc sendfile*(outfd, infd: int, offset: int, count: var int): int = var o = count let res = osSendFile(cint(infd), cint(outfd), offset, addr o, nil, 0) if res >= 0: count = int(o) 0 else: let err = osLastError() count = if err == EAGAIN: int(o) else: 0 -1