mirror of
https://github.com/HeyPuter/gex.git
synced 2026-11-13 20:12:43 -10:00
A syscall probe found both unimplemented. They are how a static file server
sends a file to a socket without bouncing every byte through userspace, and how
node's fs.copyFile takes its fast path -- leaving them ENOSYS forces the slow
read/write loop and, for sendfile, can defeat a server's whole design.
Both share one helper that copies through a single kernel buffer:
- The offset-pointer forms (sendfile with a non-null offset, copy_file_range's
off_in/off_out) read/write at an absolute offset without moving the
descriptor's own position, then advance the caller's pointer -- so a server
serves one open file to many clients without seeking.
- The positional-less form uses and advances the descriptor's position. If the
output takes fewer bytes than were read, the input is rewound by the
shortfall so nothing is silently dropped.
- One call moves at most one buffer (16 MiB cap), as Linux does; callers loop.
- copy_file_range rejects non-zero flags with EINVAL (reserved).
Integration test covers sendfile no-offset, sendfile with an offset pointer, and
copy_file_range with both offsets -- byte-identical to QEMU.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_019b4VWMhJUWoGKQh4EeFfPm
59 lines
1.8 KiB
C
59 lines
1.8 KiB
C
/* sendfile and copy_file_range: in-kernel descriptor-to-descriptor copies that
|
|
* static file servers and node's fs fast paths use. Exercises the no-offset
|
|
* form (advances the input position), the offset-pointer form (leaves it, bumps
|
|
* the pointer), and copy_file_range with both offsets. Deterministic -> QEMU
|
|
* is the oracle. */
|
|
#define _GNU_SOURCE
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/sendfile.h>
|
|
#include <sys/syscall.h>
|
|
#include <unistd.h>
|
|
|
|
static const char *rd(const char *p) {
|
|
static char b[128];
|
|
int f = open(p, O_RDONLY);
|
|
if (f < 0) return "<none>";
|
|
int n = read(f, b, 127);
|
|
close(f);
|
|
if (n < 0) n = 0;
|
|
b[n] = 0;
|
|
return b;
|
|
}
|
|
|
|
int main(void) {
|
|
chdir("/tmp");
|
|
unlink("src"); unlink("dst"); unlink("dst2"); unlink("dst3");
|
|
int s = open("src", O_CREAT | O_WRONLY | O_TRUNC, 0644);
|
|
write(s, "Hello, sendfile world!", 22);
|
|
close(s);
|
|
|
|
int in = open("src", O_RDONLY);
|
|
int out = open("dst", O_CREAT | O_WRONLY | O_TRUNC, 0644);
|
|
ssize_t r = sendfile(out, in, NULL, 22);
|
|
close(in);
|
|
close(out);
|
|
printf("sendfile-noff ret=%zd dst=%s\n", r, rd("dst"));
|
|
|
|
in = open("src", O_RDONLY);
|
|
out = open("dst2", O_CREAT | O_WRONLY | O_TRUNC, 0644);
|
|
off_t off = 7;
|
|
r = sendfile(out, in, &off, 15);
|
|
close(in);
|
|
close(out);
|
|
printf("sendfile-off ret=%zd off=%ld dst2=%s\n", r, (long)off, rd("dst2"));
|
|
|
|
in = open("src", O_RDONLY);
|
|
out = open("dst3", O_CREAT | O_WRONLY | O_TRUNC, 0644);
|
|
loff_t io = 0, oo = 0;
|
|
r = syscall(SYS_copy_file_range, in, &io, out, &oo, 5, 0);
|
|
close(in);
|
|
close(out);
|
|
printf("cfr ret=%zd io=%ld oo=%ld dst3=%s\n", r, (long)io, (long)oo, rd("dst3"));
|
|
|
|
unlink("src"); unlink("dst"); unlink("dst2"); unlink("dst3");
|
|
printf("sendfile ok\n");
|
|
return 0;
|
|
}
|