@@ -3111,6 +3111,121 @@ pub fn send(
31113111 return sendto (sockfd , buf , flags , null , 0 );
31123112}
31133113
3114+ pub const SendFileError = error {
3115+ /// There was an unspecified error while reading from infd.
3116+ InputOutput ,
3117+
3118+ /// There was insufficient resources for processing.
3119+ SystemResources ,
3120+
3121+ /// The value provided for count overflows the maximum size of either
3122+ /// infd or outfd.
3123+ Overflow ,
3124+
3125+ /// Offset was provided, but infd is not seekable.
3126+ Unseekable ,
3127+
3128+ /// The outfd is marked nonblocking and the requested operation would block, and
3129+ /// there is no global event loop configured.
3130+ WouldBlock ,
3131+ } || WriteError || UnexpectedError ;
3132+
3133+ pub const sf_hdtr = struct {
3134+ headers : []iovec_const ,
3135+ trailers : []iovec_const ,
3136+ };
3137+
3138+ /// Transfer data between file descriptors.
3139+ ///
3140+ /// The `sendfile` call copies `count` bytes from one file descriptor to another within the kernel. This can
3141+ /// be more performant than transferring data from the kernel to user space and back, such as with
3142+ /// `read` and `write` calls.
3143+ ///
3144+ /// The `infd` should be a file descriptor opened for reading, and `outfd` should be a file descriptor
3145+ /// opened for writing. Copying will begin at `offset`, if not null, which will be updated to reflect
3146+ /// the number of bytes read. If `offset` is null, the copying will begin at the current seek position,
3147+ /// and the file position will be updated.
3148+ pub fn sendfile (infd : fd_t , outfd : fd_t , offset : u64 , count : usize , optional_hdtr : ? * const sf_hdtr , flags : u32 ) SendFileError ! usize {
3149+ // XXX: check if offset is > length of file, return 0 bytes written
3150+ // XXX: document systems where headers are sent atomically.
3151+ // XXX: compute new offset on EINTR/EAGAIN
3152+ var rc : usize = undefined ;
3153+ var err : usize = undefined ;
3154+ if (builtin .os == .linux ) {
3155+ while (true ) {
3156+ try lseek_SET (infd , offset );
3157+
3158+ if (optional_hdtr ) | hdtr | {
3159+ try writev (outfd , hdtr .headers );
3160+ }
3161+
3162+ rc = system .sendfile (outfd , infd , null , count );
3163+ err = errno (rc );
3164+
3165+ if (optional_hdtr ) | hdtr | {
3166+ try writev (outfd , hdtr .trailers );
3167+ }
3168+
3169+ switch (err ) {
3170+ 0 = > return @intCast (usize , rc ),
3171+ else = > return unexpectedErrno (err ),
3172+
3173+ EBADF = > unreachable ,
3174+ EINVAL = > unreachable ,
3175+ EFAULT = > unreachable ,
3176+ EAGAIN = > if (std .event .Loop .instance ) | loop | {
3177+ loop .waitUntilFdWritable (outfd );
3178+ continue ;
3179+ } else {
3180+ return error .WouldBlock ;
3181+ },
3182+ EIO = > return error .InputOutput ,
3183+ ENOMEM = > return error .SystemResources ,
3184+ EOVERFLOW = > return error .Overflow ,
3185+ ESPIPE = > return error .Unseekable ,
3186+ }
3187+ }
3188+ } else if (builtin .os == .freebsd ) {
3189+ while (true ) {
3190+ var rcount : u64 = 0 ;
3191+ var hdtr : std.c.sf_hdtr = undefined ;
3192+ if (optional_hdtr ) | h | {
3193+ hdtr = std.c.sf_hdtr {
3194+ .headers = h .headers .ptr ,
3195+ .hdr_cnt = @intCast (c_int , h .headers .len ),
3196+ .trailers = h .trailers .ptr ,
3197+ .trl_cnt = @intCast (c_int , h .trailers .len ),
3198+ };
3199+ }
3200+ err = errno (system .sendfile (infd , outfd , offset , count , & hdtr , & rcount , @intCast (c_int , flags )));
3201+ switch (err ) {
3202+ 0 = > return @intCast (usize , rcount ),
3203+ else = > return unexpectedErrno (err ),
3204+
3205+ EBADF = > unreachable ,
3206+ EFAULT = > unreachable ,
3207+ EINVAL = > unreachable ,
3208+ ENOTCAPABLE = > unreachable ,
3209+ ENOTCONN = > unreachable ,
3210+ ENOTSOCK = > unreachable ,
3211+ EAGAIN = > if (std .event .Loop .instance ) | loop | {
3212+ loop .waitUntilFdWritable (outfd );
3213+ continue ;
3214+ } else {
3215+ return error .WouldBlock ;
3216+ },
3217+ EBUSY = > return error .DeviceBusy ,
3218+ EINTR = > continue ,
3219+ EIO = > return error .InputOutput ,
3220+ ENOBUFS = > return error .SystemResources ,
3221+ EPIPE = > return error .BrokenPipe ,
3222+ }
3223+ }
3224+ } else {
3225+ @compileError ("sendfile unimplemented for this target" );
3226+ }
3227+ }
3228+
31143229pub const PollError = error {
31153230 /// The kernel had no space to allocate file descriptor tables.
31163231 SystemResources ,
0 commit comments