@@ -3111,6 +3111,84 @@ pub fn send(
3111
3111
return sendto (sockfd , buf , flags , null , 0 );
3112
3112
}
3113
3113
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
+ var rc : usize = undefined ;
3152
+ var err : usize = undefined ;
3153
+ if (builtin .os == .linux ) {
3154
+ while (true ) {
3155
+ try lseek_SET (infd , offset );
3156
+
3157
+ if (optional_hdtr ) | hdtr | {
3158
+ try writev (outfd , hdtr .headers );
3159
+ }
3160
+
3161
+ rc = system .sendfile (outfd , infd , null , count );
3162
+ err = errno (rc );
3163
+
3164
+ if (optional_hdtr ) | hdtr | {
3165
+ try writev (outfd , hdtr .trailers );
3166
+ }
3167
+
3168
+ switch (err ) {
3169
+ 0 = > return @intCast (usize , rc ),
3170
+ else = > return unexpectedErrno (err ),
3171
+
3172
+ EBADF = > unreachable ,
3173
+ EINVAL = > unreachable ,
3174
+ EFAULT = > unreachable ,
3175
+ EAGAIN = > if (std .event .Loop .instance ) | loop | {
3176
+ loop .waitUntilFdWritable (outfd );
3177
+ continue ;
3178
+ } else {
3179
+ return error .WouldBlock ;
3180
+ },
3181
+ EIO = > return error .InputOutput ,
3182
+ ENOMEM = > return error .SystemResources ,
3183
+ EOVERFLOW = > return error .Overflow ,
3184
+ ESPIPE = > return error .Unseekable ,
3185
+ }
3186
+ }
3187
+ } else {
3188
+ @compileError ("sendfile unimplemented for this target" );
3189
+ }
3190
+ }
3191
+
3114
3192
pub const PollError = error {
3115
3193
/// The kernel had no space to allocate file descriptor tables.
3116
3194
SystemResources ,
0 commit comments