| .\"This manpage is Copyright (C) 2015 Anna Schumaker <Anna.Schumaker@Netapp.com> |
| .\" |
| .\" %%%LICENSE_START(VERBATIM) |
| .\" Permission is granted to make and distribute verbatim copies of this |
| .\" manual provided the copyright notice and this permission notice are |
| .\" preserved on all copies. |
| .\" |
| .\" Permission is granted to copy and distribute modified versions of |
| .\" this manual under the conditions for verbatim copying, provided that |
| .\" the entire resulting derived work is distributed under the terms of |
| .\" a permission notice identical to this one. |
| .\" |
| .\" Since the Linux kernel and libraries are constantly changing, this |
| .\" manual page may be incorrect or out-of-date. The author(s) assume |
| .\" no responsibility for errors or omissions, or for damages resulting |
| .\" from the use of the information contained herein. The author(s) may |
| .\" not have taken the same level of care in the production of this |
| .\" manual, which is licensed free of charge, as they might when working |
| .\" professionally. |
| .\" |
| .\" Formatted or processed versions of this manual, if unaccompanied by |
| .\" the source, must acknowledge the copyright and authors of this work. |
| .\" %%%LICENSE_END |
| .\" |
| .TH COPY_FILE_RANGE 2 2021-03-22 "Linux" "Linux Programmer's Manual" |
| .SH NAME |
| copy_file_range \- Copy a range of data from one file to another |
| .SH SYNOPSIS |
| .nf |
| .B #define _GNU_SOURCE |
| .B #include <unistd.h> |
| .PP |
| .BI "ssize_t copy_file_range(int " fd_in ", off64_t *" off_in , |
| .BI " int " fd_out ", off64_t *" off_out , |
| .BI " size_t " len ", unsigned int " flags ); |
| .fi |
| .SH DESCRIPTION |
| The |
| .BR copy_file_range () |
| system call performs an in-kernel copy between two file descriptors |
| without the additional cost of transferring data from the kernel to user space |
| and then back into the kernel. |
| It copies up to |
| .I len |
| bytes of data from the source file descriptor |
| .I fd_in |
| to the target file descriptor |
| .IR fd_out , |
| overwriting any data that exists within the requested range of the target file. |
| .PP |
| The following semantics apply for |
| .IR off_in , |
| and similar statements apply to |
| .IR off_out : |
| .IP * 3 |
| If |
| .I off_in |
| is NULL, then bytes are read from |
| .I fd_in |
| starting from the file offset, and the file offset is |
| adjusted by the number of bytes copied. |
| .IP * |
| If |
| .I off_in |
| is not NULL, then |
| .I off_in |
| must point to a buffer that specifies the starting |
| offset where bytes from |
| .I fd_in |
| will be read. |
| The file offset of |
| .I fd_in |
| is not changed, but |
| .I off_in |
| is adjusted appropriately. |
| .PP |
| .I fd_in |
| and |
| .I fd_out |
| can refer to the same file. |
| If they refer to the same file, then the source and target ranges are not |
| allowed to overlap. |
| .PP |
| The |
| .I flags |
| argument is provided to allow for future extensions |
| and currently must be set to 0. |
| .SH RETURN VALUE |
| Upon successful completion, |
| .BR copy_file_range () |
| will return the number of bytes copied between files. |
| This could be less than the length originally requested. |
| If the file offset of |
| .I fd_in |
| is at or past the end of file, no bytes are copied, and |
| .BR copy_file_range () |
| returns zero. |
| .PP |
| On error, |
| .BR copy_file_range () |
| returns \-1 and |
| .I errno |
| is set to indicate the error. |
| .SH ERRORS |
| .TP |
| .B EBADF |
| One or more file descriptors are not valid. |
| .TP |
| .B EBADF |
| .I fd_in |
| is not open for reading; or |
| .I fd_out |
| is not open for writing. |
| .TP |
| .B EBADF |
| The |
| .B O_APPEND |
| flag is set for the open file description (see |
| .BR open (2)) |
| referred to by the file descriptor |
| .IR fd_out . |
| .TP |
| .B EFBIG |
| An attempt was made to write at a position past the maximum file offset the |
| kernel supports. |
| .TP |
| .B EFBIG |
| An attempt was made to write a range that exceeds the allowed maximum file size. |
| The maximum file size differs between filesystem implementations and can be |
| different from the maximum allowed file offset. |
| .TP |
| .B EFBIG |
| An attempt was made to write beyond the process's file size resource limit. |
| This may also result in the process receiving a |
| .B SIGXFSZ |
| signal. |
| .TP |
| .B EINVAL |
| The |
| .I flags |
| argument is not 0. |
| .TP |
| .B EINVAL |
| .I fd_in |
| and |
| .I fd_out |
| refer to the same file and the source and target ranges overlap. |
| .TP |
| .B EINVAL |
| Either |
| .I fd_in |
| or |
| .I fd_out |
| is not a regular file. |
| .TP |
| .B EIO |
| A low-level I/O error occurred while copying. |
| .TP |
| .B EISDIR |
| Either |
| .I fd_in |
| or |
| .I fd_out |
| refers to a directory. |
| .TP |
| .B ENOMEM |
| Out of memory. |
| .TP |
| .B ENOSPC |
| There is not enough space on the target filesystem to complete the copy. |
| .TP |
| .B EOVERFLOW |
| The requested source or destination range is too large to represent in the |
| specified data types. |
| .TP |
| .B EPERM |
| .I fd_out |
| refers to an immutable file. |
| .TP |
| .B ETXTBSY |
| Either |
| .I fd_in |
| or |
| .I fd_out |
| refers to an active swap file. |
| .TP |
| .B EXDEV |
| The files referred to by |
| .IR fd_in " and " fd_out |
| are not on the same mounted filesystem (pre Linux 5.3). |
| .SH VERSIONS |
| The |
| .BR copy_file_range () |
| system call first appeared in Linux 4.5, but glibc 2.27 provides a user-space |
| emulation when it is not available. |
| .\" https://sourceware.org/git/?p=glibc.git;a=commit;f=posix/unistd.h;h=bad7a0c81f501fbbcc79af9eaa4b8254441c4a1f |
| .PP |
| A major rework of the kernel implementation occurred in 5.3. |
| Areas of the API that weren't clearly defined were clarified and the API bounds |
| are much more strictly checked than on earlier kernels. |
| Applications should target the behaviour and requirements of 5.3 kernels. |
| .PP |
| First support for cross-filesystem copies was introduced in Linux 5.3. |
| Older kernels will return -EXDEV when cross-filesystem copies are attempted. |
| .SH CONFORMING TO |
| The |
| .BR copy_file_range () |
| system call is a nonstandard Linux and GNU extension. |
| .SH NOTES |
| If |
| .I fd_in |
| is a sparse file, then |
| .BR copy_file_range () |
| may expand any holes existing in the requested range. |
| Users may benefit from calling |
| .BR copy_file_range () |
| in a loop, and using the |
| .BR lseek (2) |
| .BR SEEK_DATA |
| and |
| .BR SEEK_HOLE |
| operations to find the locations of data segments. |
| .PP |
| .BR copy_file_range () |
| gives filesystems an opportunity to implement "copy acceleration" techniques, |
| such as the use of reflinks (i.e., two or more inodes that share |
| pointers to the same copy-on-write disk blocks) |
| or server-side-copy (in the case of NFS). |
| .SH EXAMPLES |
| .EX |
| #define _GNU_SOURCE |
| #include <fcntl.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/stat.h> |
| #include <unistd.h> |
| |
| int |
| main(int argc, char **argv) |
| { |
| int fd_in, fd_out; |
| struct stat stat; |
| off64_t len, ret; |
| |
| if (argc != 3) { |
| fprintf(stderr, "Usage: %s <source> <destination>\en", argv[0]); |
| exit(EXIT_FAILURE); |
| } |
| |
| fd_in = open(argv[1], O_RDONLY); |
| if (fd_in == \-1) { |
| perror("open (argv[1])"); |
| exit(EXIT_FAILURE); |
| } |
| |
| if (fstat(fd_in, &stat) == \-1) { |
| perror("fstat"); |
| exit(EXIT_FAILURE); |
| } |
| |
| len = stat.st_size; |
| |
| fd_out = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0644); |
| if (fd_out == \-1) { |
| perror("open (argv[2])"); |
| exit(EXIT_FAILURE); |
| } |
| |
| do { |
| ret = copy_file_range(fd_in, NULL, fd_out, NULL, len, 0); |
| if (ret == \-1) { |
| perror("copy_file_range"); |
| exit(EXIT_FAILURE); |
| } |
| |
| len \-= ret; |
| } while (len > 0 && ret > 0); |
| |
| close(fd_in); |
| close(fd_out); |
| exit(EXIT_SUCCESS); |
| } |
| .EE |
| .SH SEE ALSO |
| .BR lseek (2), |
| .BR sendfile (2), |
| .BR splice (2) |