I'm learning POSIX and Linux syscalls. At the moment, I'm developing a basic program for copying files using different capabilities, in addition to read()/write(), for different systems in order to better understand how I can complete this task. While I was writing under Linux, I saw syscalls sendfile() and splice(), which allow me to move data from one file descriptor to another without an intermediate buffer (at least in the program), but I did not find such syscalls in FreeBSD so far.
Is there any way I can do a similar thing? I expect about the same syscall (or wrapper for it) to copy from fd to fd without an intermediate buffer. sendfile() in FreeBSD is intended only for sockets and doesn't suit me.
As said in the comments, when one file descriptor is a file on a storage device and another is a network socket, you can use the
sendfile(2)syscall that has been improved by Netflix on FreeBSD to transfer data with zero-copy at the userspace level.When both of the file descriptors are files on a storage device, you can use the
mmap(2)syscall that is based on the Mach micro-kernel virtual memory implementation that is at the heart of the FreeBSD kernel: just mmap the input file descriptor to get a pointer corresponding to the input file data, open a file descriptor to create the output file, extend the size of the output file to the size of the input file (for instance withlseek(2)to go to the second last position of the file, followed by writing a null byte), usemmap(2)on the output file descriptor to get a pointer corresponding to the output file content, and finally usememcpy(3)orbcopy(3)with those two pointers to copy the input file content to the output file content.This way, you have made a copy of your file without having used any intermediate buffer: there is no intermediate buffer allocated in userland, even if the copy is done in userland. If you had used
read(2)andwrite(2)syscalls, you would have needed to allocate and use an intermediate buffer.Here is a basic example without error handlers to stay short, that compiles and runs correctly on FreeBSD, it copies an input file of 4096 bytes to an output file that it first creates: