| .\"This manpage is Copyright (C) 2015 Anna Schumaker <Anna.Schumaker@Netapp.com> |
| .\" |
| .\" SPDX-License-Identifier: Linux-man-pages-copyleft |
| .\" |
| .TH copy_file_range 2 (date) "Linux man-pages (unreleased)" |
| .SH NAME |
| copy_file_range \- Copy a range of data from one file to another |
| .SH LIBRARY |
| Standard C library |
| .RI ( libc ,\~ \-lc ) |
| .SH SYNOPSIS |
| .nf |
| .B #define _GNU_SOURCE |
| .B #define _FILE_OFFSET_BITS 64 |
| .B #include <unistd.h> |
| .P |
| .BI "ssize_t copy_file_range(int " fd_in ", off_t *_Nullable " off_in , |
| .BI " int " fd_out ", off_t *_Nullable " 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. |
| .P |
| The following semantics apply for |
| .IR off_in , |
| and similar statements apply to |
| .IR off_out : |
| .IP \[bu] 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 \[bu] |
| 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. |
| .P |
| .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. |
| .P |
| 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. |
| .P |
| 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 |
| .BR EOPNOTSUPP " (since Linux 5.19)" |
| .\" commit 868f9f2f8e004bfe0d3935b1976f625b2924893b |
| The filesystem does not support this operation. |
| .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 |
| .BR EXDEV " (before Linux 5.3)" |
| .\" commit 5dae222a5ff0c269730393018a5539cc970a4726 |
| The files referred to by |
| .IR fd_in " and " fd_out |
| are not on the same filesystem. |
| .TP |
| .BR EXDEV " (since Linux 5.19)" |
| .\" commit 868f9f2f8e004bfe0d3935b1976f625b2924893b |
| The files referred to by |
| .IR fd_in " and " fd_out |
| are not on the same filesystem, |
| and the source and target filesystems are not of the same type, |
| or do not support cross-filesystem copy. |
| .SH VERSIONS |
| A major rework of the kernel implementation occurred in Linux 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. |
| .P |
| Since Linux 5.19, |
| cross-filesystem copies can be achieved |
| when both filesystems are of the same type, |
| and that filesystem implements support for it. |
| See BUGS for behavior prior to Linux 5.19. |
| .P |
| Applications should target the behaviour and requirements of Linux 5.19, |
| that was also backported to earlier stable kernels. |
| .SH STANDARDS |
| Linux, GNU. |
| .SH HISTORY |
| 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 |
| .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) |
| .B SEEK_DATA |
| and |
| .B SEEK_HOLE |
| operations to find the locations of data segments. |
| .P |
| .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). |
| .P |
| .B _FILE_OFFSET_BITS |
| should be defined to be 64 in code that uses non-null |
| .I off_in |
| or |
| .I off_out |
| or that takes the address of |
| .BR copy_file_range , |
| if the code is intended to be portable |
| to traditional 32-bit x86 and ARM platforms where |
| .BR off_t 's |
| width defaults to 32 bits. |
| .SH BUGS |
| In Linux 5.3 to Linux 5.18, |
| cross-filesystem copies were implemented by the kernel, |
| if the operation was not supported by individual filesystems. |
| However, on some virtual filesystems, |
| the call failed to copy, while still reporting success. |
| .SH EXAMPLES |
| .\" SRC BEGIN (copy_file_range.c) |
| .EX |
| #define _GNU_SOURCE |
| #define _FILE_OFFSET_BITS 64 |
| #include <fcntl.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| \& |
| int |
| main(int argc, char *argv[]) |
| { |
| int fd_in, fd_out; |
| off_t len, ret; |
| struct stat stat; |
| \& |
| if (argc != 3) { |
| fprintf(stderr, "Usage: %s <source> <destination>\[rs]n", 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 |
| .\" SRC END |
| .SH SEE ALSO |
| .BR lseek (2), |
| .BR sendfile (2), |
| .BR splice (2) |