copy_file_range - Copier une plage de données d'un fichier vers un autre
Bibliothèque C standard (
libc,
-lc)
#define _GNU_SOURCE
#include <unistd.h>
ssize_t copy_file_range(int fd_in, off64_t *_Nullable off_in,
int fd_out, off64_t *_Nullable off_out,
size_t len, unsigned int flags);
L'appel système
copy_file_range() effectue une copie interne au
noyau entre deux descripteurs de fichier sans devoir en plus transférer
des données du noyau à l'espace utilisateur puis revenir au
noyau. Jusqu'à
len octets de données sont
transférés du descripteur de fichier
fd_in au descripteur
de fichier
fd_out, écrasant toute donnée se trouvant dans
la plage du fichier cible sollicité.
La sémantique suivante s'applique à
off_in et des
déclarations identiques s'appliquent à
off_out :
- •
- Si off_in est NULL, les octets sont lus dans
fd_in à partir de la position du fichier, laquelle est
ajustée par le nombre d'octets copiés.
- •
- Si off_in n'est pas NULL, off_in doit pointer
vers un tampon qui indique le point de départ à partir
duquel les octets de fd_in seront lus. La position du fichier de
fd_in n'est pas modifiée mais off_in est
ajusté correctement.
fd_in et
fd_out peuvent se rapporter au même fichier. Dans
ce cas, les plages de la source et de la cible ne sont pas autorisées
à se chevaucher.
L'argument
flags est fourni pour de futures extensions et doit
être positionné actuellement sur
0.
En cas de succès,
copy_file_range() renverra le nombre d'octets
copiés entre les fichiers. Il pourrait être inférieur
à la taille demandée au départ. Si la position du fichier
de
fd_in est à la fin du fichier ou au-delà, aucun octet
n'est copié et
copy_file_range() renvoie zéro.
En cas d'erreur,
copy_file_range() renvoie
-1 et
errno est
configuré pour indiquer l'erreur.
- EBADF
- Un ou plusieurs descripteurs de fichier ne sont pas
valables.
- EBADF
-
fd_in n'est pas ouvert en lecture ou fd_out
n'est pas ouvert en écriture.
- EBADF
- L'attribut O_APPEND est configuré pour une
description d'un fichier ouvert (voir open(2)) auquel renvoie le
descripteur de fichier fd_out.
- EFBIG
- Tentative d'écriture sur une position
dépassant la position maximale du fichier gérée par
le noyau.
- EFBIG
- Tentative d'écriture d'une plage dépassant la
taille maximale d'un fichier permise. La taille maximale d'un fichier
varie selon les implémentations de système de fichiers et
peut être différente de la position du fichier maximale
autorisée.
- EFBIG
- Tentative d'écriture au-delà de la limite de
ressource de la taille du fichier du processus. Cela peut aussi avoir pour
conséquence la réception, par le processus, d'un signal
SIGXFSZ.
- EINVAL
- Le paramètre flags ne vaut pas 0.
- EINVAL
-
fd_in et fd_out se rapportent au même
fichier et les plages de la source et de la cible se chevauchent.
- EINVAL
-
fd_in ou fd_out n'est pas un fichier
normal.
- EIO
- Une erreur E/S de bas niveau s'est produite lors de la
copie.
- EISDIR
-
fd_in ou fd_out se rapporte à un
répertoire.
- ENOMEM
- Plus assez de mémoire.
- ENOSPC
- Il n'y a pas assez d'espace sur le système de
fichiers cible pour terminer la copie.
-
EOPNOTSUPP (depuis Linux 5.19)
- Le système de fichiers ne prend pas en charge cette
opération.
- EOVERFLOW
- La plage source ou de destination demandée est trop
grande pour être représentée dans les types de
données indiqués.
- EPERM
-
fd_out se rapporte à un fichier
immuable.
- ETXTBSY
-
fd_in ou fd_out se rapporte à un
fichier d'échange actif.
-
EXDEV (depuis Linux 5.3)
- Les fichiers auxquels se rapportent fd_in et
fd_out ne sont pas sur le même système de
fichiers.
-
EXDEV (depuis Linux 5.19)
- Les fichiers auxquels se rapportent fd_in et
fd_out ne sont pas sur le même système de fichiers et
les systèmes de fichiers source et cible ne sont pas du même
type ou ne prennent pas en charge la copie entre systèmes de
fichiers.
L'appel système
copy_file_range() est apparu pour la
première fois dans Linux 4.5, mais la glibc 2.27 offre une
émulation dans l'espace utilisateur s'il n'est pas disponible.
L'implémentation du noyau a été profondément
retravaillée dans Linux 5.3. Les zones de l'API qui
n'étaient pas clairement définies ont été
clarifiées et les limites de l'API sont vérifiées
beaucoup plus strictement que sur les noyaux précédents. Les
applications devraient cibler le comportement et les exigences des noyaux 5.3.
Depuis Linux 5.19, les copies entre systèmes de fichiers peuvent
se faire quand les deux systèmes de fichiers sont du même type
et si le système de fichiers le prend en charge. Voir BOGUES pour le
comportement avant la 5.19.
Les applications devraient cibler le comportement et les exigences de
Linux 5.3 qui ont aussi été rétroportés
dans les noyaux stable plus récents.
L'appel système
copy_file_range() est une extension GNU et un non
standard de Linux.
Si
fd_in est un fichier éparpillé, il se peut que
copy_file_range() agrandisse les trous existant dans la plage
demandée. Les utilisateurs peuvent bénéficier d'un appel
à
copy_file_range() dans une boucle et utiliser les
opérations
SEEK_DATA et
SEEK_HOLE de
lseek(2) pour
chercher des emplacements de segments de données.
copy_file_range() donne aux systèmes de fichiers la
possibilité d'implémenter des techniques de
« copie accélérée » telles
que l'utilisation de reflink (c'est-à-dire deux ou plusieurs
i-nœuds partageant des pointeurs avec les mêmes blocs de disque
copy-on-write) ou server-side-copy (dans le cas de NFS).
De Linux 5.3 à Linux 5.18, les copies entre système
de fichiers étaient implémentées par le noyau si
l'opération n'était pas gérée par les
systèmes de fichiers eux-mêmes. Cependant, sur certains
systèmes de fichiers virtuels, le code n'arrivait pas à faire la
copie mais la présentait comme réussie.
#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;
off64_t len, ret;
struct stat stat;
if (argc != 3) {
fprintf(stderr, "Utilisation : %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);
}
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);
}
lseek(2),
sendfile(2),
splice(2)
La traduction française de cette page de manuel a été
créée par Christophe Blaess
<
https://www.blaess.fr/christophe/>, Stéphan Rafin
<
[email protected]>, Thierry Vignaud
<
[email protected]>, François Micaux, Alain Portal
<
[email protected]>, Jean-Philippe Guérard
<
[email protected]>, Jean-Luc Coulon (f5ibh)
<
[email protected]>, Julien Cristau
<
[email protected]>, Thomas Huriaux <
[email protected]>,
Nicolas François <
[email protected]>, Florentin
Duneau <
[email protected]>, Simon Paillard
<
[email protected]>, Denis Barbier
<
[email protected]>, David Prévot <
[email protected]> et
Jean-Philippe MENGUAL <
[email protected]>
Cette traduction est une documentation libre ; veuillez vous reporter
à la
GNU
General Public License version 3 concernant les conditions de copie
et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel,
veuillez envoyer un message à
[email protected]