copy_file_range(2)

NAZWA
copy_file_range - kopiuje zakres danych z jednego pliku do drugiego

BIBLIOTEKA
Standardowa biblioteka C (libc, -lc)

SKŁADNIA
#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);

OPIS
Wywołanie systemowe copy_file_range() przeprowadza kopiowanie wewnątrz jądra pomiędzy dwoma deskryptorami plików, bez dodatkowego kosztu transferu danych z jądro do przestrzeni użytkownika, a następnie z powrotem do jądra. Kopiuje maksymalnie size bajtów danych ze źródłowego deskryptora pliku fd_in do docelowego deskryptora pliku fd_out, nadpisując wszelkie dane, które istniały w żądanym zakresie pliku docelowego.

off_in jest objęte następującą semantyką i podobne stwierdzenia odnoszą się do off_out:

•   Jeśli off_in wynosi NULL, to bajty są odczytywane z fd_in począwszy od przesunięcia pliku, a przesunięcie pliku jest dostosowywane o liczbę skopiowanych bajtów.

•   Jeśli off_in nie wynosi NULL, to off_in musi wskazywać na bufor określający początkowe przesunięcie, od którego zostaną odczytane bajty z fd_in. Przesunięcie pliku fd_in nie jest zmieniane, ale off_in jest odpowiednio dostosowywane.

fd_in i fd_out mogą odnosić się do tego samego pliku. Jeśli odnoszą się do tego samego pliku, to zakres źródłowy i docelowy nie mogą na siebie nachodzić.

Argument flags jest przeznaczony na przyszłe rozszerzenia i obecnie musi być ustawiony na 0.

WARTOŚĆ ZWRACANA
Po pomyślnym zakończeniu, copy_file_range() zwróci liczbę bajtów skopiowanych pomiędzy dwoma plikami. Może być to rozmiar mniejszy od pierwotnie żądanego. Jeśli przesunięcie pliku fd_in znajduje się na końcu, lub za końcem, pliku, to nie są kopiowane żadne bajty, a copy_file_range() zwraca zero.

W razie wystąpienia błędu copy_file_range zwraca -1 i ustawia errno, wskazując błąd.

BŁĘDY

EBADF
    Jeden lub więcej deskryptorów plików nie jest prawidłowych.

EBADF
    fd_in nie jest otwarty do odczytu; albo fd_out nie jest otwarty do zapisu.

EBADF
    Znacznik O_APPEND jest ustawiony na opis otwartego pliku (ODF, zob. open(2)), do którego odnosi się deskryptor pliku fd_out.

EFBIG
    Podjęto próbę zapisu w pozycji poza maksymalnym przesunięciem pliku obsługiwanym przez jądro.

EFBIG
    Podjęto próbę zapisu zakresu, który przekracza maksymalny dopuszczalny rozmiar pliku. Maksymalny rozmiar pliku różni się pomiędzy implementacjami systemów plików i może być inny niż maksymalne dopuszczalne przesunięcie pliku.

EFBIG
    Podjęto próbę zapisu poza limit zasobu procesu dotyczący rozmiaru pliku. Może to też spowodować otrzymanie przez proces sygnału SIGXFSZ.

EINVAL
    Argument flags nie wynosi 0.

EINVAL
    fd_in i fd_out odnoszą się do tego samego pliku, a źródłowy i docelowy zakres nachodzą na siebie.

EINVAL
    fd_in albo fd_out nie jest zwykłym plikiem.

EIO Przy kopiowaniu wystąpił niskopoziomowy błąd wejścia/wyjścia.

EISDIR
    fd_in albo fd_out odnoszą się do katalogu.

ENOMEM
    Brak pamięci.

ENOSPC
    Na docelowym systemie plików nie ma wystarczająco dużo miejsca, aby ukończyć kopiowanie.

EOPNOTSUPP (od Linuksa 5.19)
    System plików nie obsługuje tej operacji.

EOVERFLOW
    Żądany zakres źródłowy lub docelowy jest zbyt duży, aby dało się go przedstawić w podanych typach danych.

EPERM
    fd_out odnosi się do niezmiennego pliku (ang. immutable).

ETXTBSY
    fd_in albo fd_out odnoszą się do aktywnego pliku wymiany.

EXDEV (przed Linuksem 5.3)
    Pliki, do których odnoszą się fd_in i fd_out nie są położone w tym samym systemie plików.

EXDEV (od Linuksa 5.19)
    Pliki, do których odnoszą się fd_in i fd_out nie są położone w tym samym systemie plików, a źródłowy i docelowy system plików nie jest tego samego typu lub nie obsługuje kopii pomiędzy systemami plików.

WERSJE
W Linuksie 5.3 doszło do znaczącej modyfikacji implementacji w jądrze. Jasno zdefiniowano miejsca w API, którym wcześniej tego brakowało, a granice API są znacznie ściślej sprawdzane, niż we wcześniejszych jądrach.

Od Linuksa 5.19, możliwe jest kopiowanie pomiędzy systemami plików, jeśli oba są tego samego typu i dany system plików zaimplementował wsparcie tej operacji. W USTERKACH opisano zachowanie przed Linuksem 5.19.

Aplikacje powinny dostosować się do zachowania i wymogów Linuksa 5.19, które zostało również przeportowane na wcześniejsze stabilne jądra.

STANDARDY
Linux, GNU.

HISTORIA
Linux 4.5, lecz glibc 2.27 dostarcza emulację w przestrzeni użytkownika tam, gdzie wywołanie nie jest dostępne.

UWAGI
Jeśli fd_in jest rzadkim (ang. sparse) plikiem, to copy_file_range() może wykroczyć poza istniejące dziury w żądanym zakresie. Użytkownicy mogą zechcieć wywoływać copy_file_range() w pętli, korzystając z operacji SEEK_DATA i SEEK_HOLE wywołania lseek(2), aby odnaleźć położenie segmentów danych.

copy_file_range() daje systemom plików sposobność na implementację technik „przyspieszonego kopiowania”, takich jak korzystanie z dowiązań lekkich (reflinków tj. dwóch lub więcej i-węzłów, które dzielą wskaźniki do tych samych bloków dyskowych kopii przy zapisie) lub kopiowania po stronie serwera (w przypadku NFS).

_FILE_OFFSET_BITS powinno być zdefiniowane jako 64 w kodzie, który używa wartości off_in lub off_out innych niż null lub takim, który przyjmuje adres copy_file_range, jeśli kod ma być przenośny na tradycyjne, 32-bitowe platformy x86 i ARM, w których szerokość off_t domyślnie wynosi 32 bity.

USTERKI
W Linuksie 5.3 do Linuksa 5.18, kopie pomiędzy systemami plików były zaimplementowane w jądrze, jeśli operacja nie była obsługiwana przez poszczególne systemy plików. Jednak w niektórych wirtualnych systemach plików, kopiowanie się nie powodziło, a mimo to wywołanie wciąż zgłaszało sukces.

PRZYKŁADY
    #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, "Użycie: %s <źródło> <cel>\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);
    }

ZOBACZ TAKŻE
lseek(2), sendfile(2), splice(2)

TŁUMACZENIE
Tłumaczenie niniejszej strony podręcznika: Michał Kułach <michal.kulach@gmail.com>

Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje o warunkach licencji można uzyskać zapoznając się z GNU General Public License w wersji 3 (https://www.gnu.org/licenses/gpl-3.0.html) lub nowszej. Nie przyjmuje się ŻADNEJ ODPOWIEDZIALNOŚCI.

Błędy w tłumaczeniu strony podręcznika prosimy zgłaszać na adres listy dyskusyjnej manpages-pl-list@lists.sourceforge.net.