copy_file_range(2)

НАИМЕНОВАНИЕ
copy_file_range - копирует часть данных из одного файла в другой

БИБЛИОТЕКА
Стандартная библиотека языка C (libc, -lc)

ОБЗОР
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include <unistd.h>

ssize_t copy_file_range(int fd_in, off_t *_Nullable off_in,
                        int fd_out, off_t *_Nullable off_out,
                        size_t size, unsigned int flags);

ОПИСАНИЕ
The 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 size bytes of data from the source file descriptor fd_in to the target file descriptor fd_out, overwriting any data that exists within the requested range of the target file.

Следующая семантика применяется к off_in и подобная ей к off_out:

•   Если off_in равно NULL, то байты читаются из fd_in начиная с файлового смещения, а файловое смещение корректируется на количество скопированных байт.

•   Если off_in не равно NULL, то off_in должно указывать на буфер, задающий начальное смещение в fd_in, из которого будут читаться байты. Файловое смещение fd_in не изменяется, но off_in изменяется соответствующим образом.

Значения fd_in и fd_out могут ссылаться на один и тот же файл. Если это так, то диапазонам источника и приёмника нельзя перекрываться.

Аргумент flags предназначен для будущих расширений, а пока его значение должно быть равно 0.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Upon successful completion, copy_file_range() will return the number of bytes copied between files. This could be less than the size originally requested. If the file offset of fd_in is at or past the end of file, no bytes are copied, and copy_file_range() returns zero.

В случае ошибки copy_file_range() возвращает -1, а errno устанавливается в соответствующее значение.

ОШИБКИ

EBADF
    Один или оба файловых дескриптора недействительны.

EBADF
    Дескриптор fd_in не открыт на чтение или дескриптор fd_out не открыт на запись.

EBADF
    В открытом файловом описании, на которое ссылается файловый дескриптор fd_out, установлен флаг O_APPEND (смотрите open(2)).

EFBIG
    Попытка записать в позицию вне максимально поддерживаемого ядром файлового смещения.

EFBIG
    Попытка записи диапазона, который превышает разрешённый максимальный размер файла. Максимальный размер файла различается в реализациях файловых систем и может отличаться от разрешённого максимального файлового смещения.

EFBIG
    Попытка записи, выходящее за ограничение ресурса процесса на размер файла. Также это может вызвать получение процессом сигнала SIGXFSZ.

EINVAL
    Аргумент flags не равен 0.

EINVAL
    Значения fd_in и fd_out ссылаются на один и тот же файл и диапазоны источника и приёмника перекрываются.

EINVAL
    Значение fd_in или fd_out указывает на необычный файл.

EIO Во время копирования возникла низкоуровневая ошибка ввода-вывода.

EISDIR
    Значение fd_in или fd_out указывает на каталог.

ENOMEM
    Не хватает памяти.

ENOSPC
    Недостаточно места на файловой системе назначения для завершения копирования.

EOPNOTSUPP (начиная с Linux 5.19)
    Файловая система не поддерживает эту операцию.

EOVERFLOW
    Запрошенный диапазон источника и приёмника слишком большой для представления в указанном типе данных.

EPERM
    Значение fd_out ссылается на файл с постоянными данными (immutable).

ETXTBSY
    Значение fd_in или fd_out указывает на активный файл подкачки.

EXDEV (до Linux 5.3)
    The files referred to by fd_in and fd_out are not on the same filesystem.

EXDEV (начиная с Linux 5.19)
    The files referred to by 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.

ВЕРСИИ
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.

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.

Applications should target the behavior and requirements of Linux 5.19, that was also backported to earlier stable kernels.

СТАНДАРТЫ
Linux, GNU.

ИСТОРИЯ
Linux 4.5.

Before glibc 2.30, starting with glibc 2.27, the glibc wrapper function provided a user-space fallback implementation when the kernel did not implement this system call. Since glibc 2.30, that fallback has been removed; the function now fails with ENOSYS if the kernel lacks support for .BR copy_file_range ().

ПРИМЕЧАНИЯ
Если файл fd_in является разреженным (sparse), то copy_file_range() может расширить дыры, существующие в запрашиваемой области. Пользователи могут получить преимущество от вызова copy_file_range() в цикле, и используя операции lseek(2) SEEK_DATA и SEEK_HOLE для поиска расположений сегментов данных.

Вызов copy_file_range() даёт файловым системам возможность реализовать «ускорение копирования», например, использовать ссылочные связи (т. е., две или более инод, использующих общие указатели для одного копирования-при-записи дисковых блоков) или копирование-на-сервере (server-side-copy, в случае использования NFS).

_FILE_OFFSET_BITS should be defined to be 64 in code that uses non-null off_in or off_out or that takes the address of copy_file_range, if the code is intended to be portable to traditional 32-bit x86 and ARM platforms where off_t's width defaults to 32 bits.

ОШИБКИ
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.

ПРИМЕРЫ
    #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        size, ret;
        struct stat  stat;

        if (argc != 3) {
            fprintf(stderr, "Usage: %s <source> <destination>\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);
        }

        size = 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, size, 0);
            if (ret == -1) {
                perror("copy_file_range");
                exit(EXIT_FAILURE);
            }

            size -= ret;
        } while (size > 0 && ret > 0);

        close(fd_in);
        close(fd_out);
        exit(EXIT_SUCCESS);
    }

СМОТРИТЕ ТАКЖЕ
lseek(2), sendfile(2), splice(2)

ПЕРЕВОД
Русский перевод этой страницы руководства разработал(и) Azamat Hackimov <azamat.hackimov@gmail.com>, Dmitriy S. Seregin <dseregin@59.ru>, Dmitry Bolkhovskikh <d20052005@yandex.ru>, Katrin Kutepova <blackkatelv@gmail.com>, Yuri Kozlov <yuray@komyakino.ru> и Иван Павлов <pavia00@gmail.com>

Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.

Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу списка рассылки русских переводчиков (<debian-l10n-russian@lists.debian.org>).