dwww Home | Manual pages | Find package

open_by_handle_at(2)          System Calls Manual         open_by_handle_at(2)

NOM
       name_to_handle_at,  open_by_handle_at  - Récupérer le gestionnaire d'un
       chemin et ouvrir le fichier au moyen d'un gestionnaire

BIBLIOTHÈQUE
       Bibliothèque C standard (libc, -lc)

SYNOPSIS
       #define _GNU_SOURCE         /* Consultez feature_test_macros(7) */
       #include <fcntl.h>

       int name_to_handle_at(int dirfd, const char *pathname,
                             struct file_handle *handle,
                             int *mount_id, int flags);
       int open_by_handle_at(int mount_fd, struct file_handle *handle,
                             int flags);

DESCRIPTION
       Les appels système name_to_handle_at() et open_by_handle_at()  scindent
       la  fonction de openat(2) en deux parties : name_to_handle_at() renvoie
       un  gestionnaire  opaque  qui  correspond  à   un   fichier   indiqué ;
       open_by_handle_at()  ouvre  le  fichier correspondant à un gestionnaire
       renvoyé par un appel antérieur à name_to_handle_at() et renvoie le des-
       cripteur d'un fichier ouvert.

   name_to_handle_at()
       L'appel  système name_to_handle_at() renvoie un gestionnaire de fichier
       et un identifiant de montage (« mount ID »)  correspondant  au  fichier
       désigné par les arguments dirfd et pathname. Le gestionnaire de fichier
       est renvoyé au moyen de l'argument handle. Cet argument est un pointeur
       vers une structure qui présente la forme suivante :

           struct file_handle {
               unsigned int  handle_bytes;   /* taille de f_handle [in, out] */
               int           handle_type;    /* type du gestionnaire [out] */
               unsigned char f_handle[0];    /* identifiant du fichier (taille
                                                définie par l’appelant) [out] */
           };

       L'appelant  à  l'origine de l'appel doit s'assurer que la structure est
       créée avec une taille suffisante pour contenir le gestionnaire  renvoyé
       dans  f_handle.  Avant l'appel, le champ handle_bytes devrait être ini-
       tialisé de sorte que l'espace  alloué  puisse  recevoir  f_handle.  (La
       constante  MAX_HANDLE_SZ,  définie  dans  <fcntl.h>,  précise la taille
       maximale autorisée pour un gestionnaire de  fichier.  La  limite  supé-
       rieure n'est pas garantie car de futurs systèmes de fichiers pourraient
       avoir besoin de davantage d'espace). Lorsque l'appel réussit, le  champ
       handle_bytes  est mis à jour afin de contenir le nombre d'octets effec-
       tivement écrits dans f_handle.

       L'appelant peut prendre connaissance de l'espace nécessaire à la struc-
       ture    file_handle    en    effectuant    un    appel    dans   lequel
       handle->handle_bytes vaut zéro ; dans ce cas, l'appel  échoue  en  ren-
       voyant  l'erreur EOVERFLOW et handle->handle_bytes prend pour valeur la
       taille requise ; l'appelant peut alors utiliser cette information  pour
       allouer  une  structure  ayant la taille convenable (consultez EXEMPLES
       ci-dessous). Il faut faire attention ici car  EOVERFLOW  peut  indiquer
       qu'aucun  gestionnaire de fichier n'est disponible pour ce nom particu-
       lier dans un système de fichiers qui prend normalement en charge la re-
       cherche  de  gestionnaire  de  fichiers.  Ce cas peut se détecter quand
       l'erreur EOVERFLOW est renvoyée sans que handle_bytes ne soit augmenté.

       Mise à part l'utilisation du champ handle_bytes, l'appelant doit consi-
       dérer  la  structure  file_handle comme de type opaque de données : les
       champs handle_type et f_handle ne sont utiles que pour un  appel  ulté-
       rieur à open_by_handle_at().

       L'argument  flags  est un masque de bits construit par OU binaire entre
       zéro ou plus de AT_EMPTY_PATH et AT_SYMLINK_FOLLOW, décrits plus bas.

       Ensemble, les arguments pathname et dirfd désignent le fichier pour le-
       quel on souhaite obtenir un gestionnaire. On distingue quatre cas :

       •  Si  pathname est une chaîne non vide contenant un chemin d'accès ab-
          solu, alors un gestionnaire est renvoyé pour le fichier indiqué  par
          ce chemin. Dans ce cas, dirfd est ignoré.

       •  Si  pathname est une chaîne non vide contenant un chemin relatif, et
          si dirfd a la valeur spéciale AT_FDCWD, alors  pathname  est  inter-
          prété par rapport au répertoire courant du processus appelant, et un
          gestionnaire est renvoyé pour le fichier indiqué par le chemin.

       •  Si pathname est une chaîne non vide contenant un chemin d'accès  re-
          latif  et  si  dirfd  est le descripteur de fichier d'un répertoire,
          alors pathname est interprété par rapport au répertoire désigné  par
          dirfd, et un gestionnaire est renvoyé pour le fichier indiqué par le
          chemin. (Consultez openat(3) si vous  souhaitez  comprendre  à  quoi
          servent les « descripteurs de fichier de répertoires »).

       •  Si  pathname  est  une chaîne vide, et si flags précise la valeur de
          AT_EMPTY_PATH, alors dirfd peut être un descripteur de fichiers  ou-
          vert  faisant  référence  à  n'importe  quel  type  de  fichier ou à
          AT_FDCWD (répertoire de travail courant),  et  un  gestionnaire  est
          renvoyé pour le fichier auquel il fait référence.

       L'argument  mount_id renvoie un identifiant pour le point de montage du
       système de fichiers correspondant à pathname. Cet  identifiant  corres-
       pond  au premier champ des entrées de /proc/self/mountinfo. L'ouverture
       du chemin indiqué dans le cinquième champ délivre un descripteur de fi-
       chier  pour  le  point de montage ; ce descripteur de fichier peut être
       utilisé par la suite lors d'un appel  à  open_by_handle_at().  mount_id
       est renvoyé tant en cas de succès qu'en cas d'erreur EOVERFLOW de l'ap-
       pel.

       Par défaut, name_to_handle_at() ne déréférence pas pathname s'il s'agit
       d'un  lien  symbolique,  et  donc  renvoie un gestionnaire pour le lien
       lui-même. Si AT_SYMLINK_FOLLOW est précisé dans flags, pathname est dé-
       référencé  s'il  s'agit d'un lien symbolique (de sorte que l'appel ren-
       voie un indicateur pour le fichier vers lequel pointe  le  lien  symbo-
       lique).

       name_to_handle_at() ne récupère pas un montage quand le composant final
       du chemin est un point de montage automatique. Quand un système de  fi-
       chiers  gère  à  la  fois les gestionnaires de fichier et les points de
       montage automatique, un appel name_to_handle_at() sur un point de  mon-
       tage   automatique   renverra   une  erreur  EOVERFLOW  sans  augmenter
       handle_bytes. Cela peut arriver depuis Linux 4.13 avec  NFS  lors  d'un
       accès  à  un  répertoire  sur un système de fichiers séparé du serveur.
       Dans ce cas, le montage automatique peut être provoqué en  ajoutant  un
       « / » à la fin du chemin.

   open_by_handle_at()
       L'appel système open_by_handle_at() ouvre le fichier auquel handle fait
       référence, via un indicateur de fichier renvoyé lors d'un précédent ap-
       pel à name_to_handle_at().

       L'argument  mount_fd  est un descripteur de fichier pour n'importe quel
       type d'objet (fichier, répertoire, etc.) du système de  fichiers  monté
       qui  permet  d'interpréter  l'indicateur de fichier (handle). La valeur
       spéciale AT_FDCWD peut être précisée, et indique le répertoire  courant
       du processus appelant.

       L'argument  flags  a la même fonction que pour open(2). Si l'indicateur
       handle fait référence à un lien symbolique, le processus appelant  doit
       préciser l'attribut O_PATH et le lien symbolique n'est pas déréférencé.
       L'attribut O_NOFOLLOW est ignoré.

       L'appelant doit avoir la  capacité  CAP_DAC_READ_SEARCH  pour  utiliser
       open_by_handle_at().

VALEUR RENVOYÉE
       Lorsqu'il   réussit,   l'appel   name_to_handle_at()   renvoie   0   et
       open_by_handle_at() renvoie un descripteur de fichier  (un  entier  non
       négatif).

       En  cas d'échec, les deux appels renvoient -1 et définissent errno pour
       indiquer l'erreur.

ERREURS
       Les appels name_to_handle_at() et open_by_handle_at()  peuvent  échouer
       pour  les  mêmes raisons que openat(2). En outre, ils peuvent également
       échouer pour les motifs décrits plus bas.

       name_to_handle_at() peut échouer avec les erreurs suivantes :

       EFAULT pathname, mount_id  ou  handle  pointe  en  dehors  de  l'espace
              d'adressage accessible.

       EINVAL flags comprend un bit incorrect.

       EINVAL handle->handle_bytes est supérieur à MAX_HANDLE_SZ.

       ENOENT pathname  est une chaîne vide et AT_EMPTY_PATH n’était pas indi-
              qué dans flags.

       ENOTDIR
              Le descripteur de fichiers fourni dans dirfd ne fait  pas  réfé-
              rence  à un répertoire, et il ne s'agit pas du cas où flags com-
              prend AT_EMPTY_PATH et pathname est une chaîne vide.

       EOPNOTSUPP
              Le système de fichiers ne permet pas la transcription du  chemin
              de fichier en indicateur de fichier.

       EOVERFLOW
              La  valeur  handle->handle_bytes transmise dans l'appel est trop
              faible. Lorsque cette erreur  se  produit,  handle->handle_bytes
              est  modifié  afin d'indiquer la taille requise pour cet indica-
              teur.

       open_by_handle_at() peut échouer avec les erreurs suivantes :

       EBADF  mount_fd n'est pas un descripteur de fichier ouvert.

       EBADF  pathname est relatif mais dirfd n'est ni AT_FDWCD ni un descrip-
              teur de fichier valable.

       EFAULT handle pointe en dehors de l'espace d'adressage accessible.

       EINVAL handle->handle_bytes  est  supérieur  à  MAX_HANDLE_SZ ou égal à
              zéro.

       ELOOP  handle correspond à un lien symbolique et O_PATH n’était pas in-
              diqué dans flags.

       EPERM  L'appelant n'a pas la capacité CAP_DAC_READ_SEARCH.

       ESTALE La valeur handle indiquée n'est pas correcte. Cet erreur se pro-
              duit par exemple lorsque le fichier a été supprimé.

VERSIONS
       Ces appels système sont apparus dans Linux 2.6.39. La prise  en  charge
       de la bibliothèque a été ajoutée dans la glibc 2.14.

STANDARDS
       Ces appels système sont des extensions spécifiques à Linux.

       FreeBSD  offre  un  couple  d'appels  système  similaires :  getfh() et
       openfh().

NOTES
       Un indicateur de fichier peut être créé dans un processus au  moyen  de
       name_to_handle_at()  et  utilisé  plus tard dans un autre processus qui
       appelle open_by_handle_at().

       Certains systèmes de fichiers ne permettent pas  la  transcription  des
       chemins  de fichier en indicateurs (par exemple, /proc, /sys, ainsi que
       divers systèmes de fichiers en réseaux).

       Un indicateur de fichier peut devenir non valable (« stale ») si un fi-
       chier  est  supprimé, ou pour une raison propre au système de fichiers.
       Les indicateurs non autorisés sont signalés par une erreur ESTALE  pro-
       venant de open_by_handle_at().

       Ces  appels systèmes sont conçus pour être utilisés par des serveurs de
       fichiers en espace utilisateur. Par exemple, un serveur NFS  en  espace
       utilisateur  produit  un indicateur de fichier et le transmet au client
       NFS. Plus tard, lorsque le client souhaite accéder au fichier, il  peut
       renvoyer l'indicateur au serveur. Ce type de fonctionnalité permet à un
       serveur de fichiers en espace utilisateur d'opérer sans état vis à  vis
       des fichiers qu'il délivre.

       Si  pathname fait référence à un lien symbolique et si flags ne précise
       pas AT_SYMLINK_FOLLOW, alors name_to_handle_at() renvoie un  indicateur
       pour  le  lien (plutôt que pour le fichier vers lequel le lien pointe).
       Le processus recevant l'indicateur peut effectuer plus tard une  opéra-
       tion  sur ce lien symbolique, en convertissant l'indicateur en descrip-
       teur de fichier au moyen de open_by_handle_at() utilisé avec l'argument
       O_PATH, et en passant le descripteur de fichier en argument dirfd d’ap-
       pels système (tels que readlinkat(2) et fchownat(2)).

   Obtenir un identifiant persistant de système de fichier
       Les identifiants de  montage  dans  /proc/self/mountinfo  peuvent  être
       réutilisés  même  lorsque les systèmes de fichiers sont démontés et re-
       montés. Ainsi, l'identifiant de montage renvoyé par name_to_handle_at()
       (dans  *mount_id)  ne doit pas être considéré comme un identifiant per-
       sistant pour le système de fichiers considéré. Néanmoins, il  est  pos-
       sible  pour une application d'utiliser l'information fournie dans moun-
       tinfo et correspondant à l'identifiant de montage pour  en  déduire  un
       identifiant persistant.

       Par  exemple,  on  peut utiliser le nom de périphérique présent dans le
       cinquième champ de mountinfo pour retrouver l'UUID du périphérique cor-
       respondant  au moyen des liens symboliques dans /dev/disks/by-uuid. (Un
       moyen plus simple d'obtenir cet UUID consiste  à  utiliser  la  biblio-
       thèque  libblkid(3)).  Cette  façon  de procéder peut être inversée, en
       utilisant l'UUID pour retrouver le nom du périphérique, et ainsi  obte-
       nir  le  point de montage correspondant, et enfin construire l'argument
       de mount_fd utile à open_by_handle_at().

EXEMPLES
       Les   deux   programmes   suivants    illustrent    l'utilisation    de
       name_to_handle_at()  et  de  open_by_handle_at().  Le premier programme
       (t_name_to_handle_at.c)  utilise  name_to_handle_at()  pour   récupérer
       l'indicateur  de fichier et l'identifiant de montage du fichier indiqué
       dans les arguments en ligne de commande ; l'indicateur et l'identifiant
       de montage sont écrits sur la sortie standard.

       Le  second programme (t_open_by_handle_at.c) lit un identifiant de mon-
       tage et un indicateur de fichier depuis l'entrée standard. Le programme
       utilise  ensuite  open_by_handle_at()  pour lire le fichier au moyen de
       cet indicateur. Si un argument optionnel est fourni dans  la  ligne  de
       commande,  alors  l'argument mount_fd de open_by_handle_at() est obtenu
       en ouvrant le répertoire précisé en argument. Sinon, mount_fd  est  ob-
       tenu en parcourant /proc/self/mountinfo à la recherche d'un identifiant
       de montage correspondant à celui fourni via l'entrée  standard,  et  le
       répertoire  monté  qui  a  été  trouvé  est  ouvert. (Ces programmes ne
       tiennent pas compte du fait que les identifiants de montage ne sont pas
       persistants.)

       La session shell suivante montre des exemples d'utilisation de ces deux
       programmes :

           $ echo 'Can you please think about it?' > cecilia.txt
           $ ./t_name_to_handle_at cecilia.txt > fh
           $ ./t_open_by_handle_at < fh
           open_by_handle_at: Operation not permitted
           $ sudo ./t_open_by_handle_at < fh      # Nécessite CAP_SYS_ADMIN
           Read 31 bytes
           $ rm cecilia.txt

       A ce stade, on supprime et recrée (rapidement)  le  fichier,  de  sorte
       qu'il ait le même contenu et (avec un peu de chance) le même inœud. Ce-
       pendant, open_by_handle_at() s'aperçoit que le fichier original  auquel
       l'indicateur fait référence n'existe plus.

           $ stat --printf="%i\n" cecilia.txt     # Affiche le numéro d'inœud
           4072121
           $ rm cecilia.txt
           $ echo 'Can you please think about it?' > cecilia.txt
           $ stat --printf="%i\n" cecilia.txt     # Vérifie le numéro d'inœud
           4072121
           $ sudo ./t_open_by_handle_at < fh
           open_by_handle_at: Stale NFS file handle

   Source du programme : t_name_to_handle_at.c

       #define _GNU_SOURCE
       #include <err.h>
       #include <errno.h>
       #include <fcntl.h>
       #include <stdio.h>
       #include <stdlib.h>

       int
       main(int argc, char *argv[])
       {
           int                 mount_id, fhsize, flags, dirfd;
           char                *pathname;
           struct file_handle  *fhp;

           if (argc != 2) {
               fprintf(stderr, "Usage: %s pathname\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           pathname = argv[1];

           /* Alloue la structure file_handle. */

           fhsize = sizeof(*fhp);
           fhp = malloc(fhsize);
           if (fhp == NULL)
               err(EXIT_FAILURE, "malloc");

           /* Effectue un appel initial à name_to_handle_at() afin de connaître
              la taille nécessaire à l'indicateur de fichier. */

           dirfd = AT_FDCWD;           /* Pour les appels à name_to_handle_at() */
           flags = 0;                  /* Pour les appels à name_to_handle_at() */
           fhp->handle_bytes = 0;
           if (name_to_handle_at(dirfd, pathname, fhp,
                                 &mount_id, flags) != -1
               || errno != EOVERFLOW)
           {
               fprintf(stderr, "Unexpected result from name_to_handle_at()\n");
               exit(EXIT_FAILURE);
           }

           /* Ré-alloue la structure file_handle avec la bonne taille. */

           fhsize = sizeof(*fhp) + fhp->handle_bytes;
           fhp = realloc(fhp, fhsize);         /* Copie fhp->handle_bytes */
           if (fhp == NULL)
               err(EXIT_FAILURE, "realloc");

           /* Retrouve l'indicateur de fichier à partir
              du chemin fourni dans la ligne de commande. */

           if (name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags) == -1)
               err(EXIT_FAILURE, "name_to_handle_at");

           /* Écrit l'identifiant de montage, la taille de l'indicateur et
              l'indicateur vers la sortie standard
              pour être utilisés plus tard par t_open_by_handle_at.c. */

           printf("%d\n", mount_id);
           printf("%u %d   ", fhp->handle_bytes, fhp->handle_type);
           for (size_t j = 0; j < fhp->handle_bytes; j++)
               printf(" %02x", fhp->f_handle[j]);
           printf("\n");

           exit(EXIT_SUCCESS);
       }

   Source du programme : t_open_by_handle_at.c

       #define _GNU_SOURCE
       #include <err.h>
       #include <fcntl.h>
       #include <limits.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <string.h>
       #include <unistd.h>

       /* Parcourt /proc/self/mountinfo pour trouver la ligne correspondant à
          l'ID de montage 'mount_id'. (Une méthode plus simple consiste à
          installer et à utiliser la bibliothèque ('libmount' fournie par
          le projet 'util-linux'.) Ouvre le point de montage correspondant
          et renvoie le descripteur de fichier associé. */

       static int
       open_mount_path_by_id(int mount_id)
       {
           int      mi_mount_id, found;
           char     mount_path[PATH_MAX];
           char     *linep;
           FILE     *fp;
           size_t   lsize;
           ssize_t  nread;

           fp = fopen("/proc/self/mountinfo", "r");
           if (fp == NULL)
               err(EXIT_FAILURE, "fopen");

           found = 0;
           linep = NULL;
           while (!found) {
               nread = getline(&linep, &lsize, fp);
               if (nread == -1)
                   break;

               nread = sscanf(linep, "%d %*d %*s %*s %s",
                              &mi_mount_id, mount_path);
               if (nread != 2) {
                   fprintf(stderr, "Bad sscanf()\n");
                   exit(EXIT_FAILURE);
               }

               if (mi_mount_id == mount_id)
                   found = 1;
           }
           free(linep);

           fclose(fp);

           if (!found) {
               fprintf(stderr, "Point de montage non trouvé\n");
               exit(EXIT_FAILURE);
           }

           return open(mount_path, O_RDONLY);
       }

       int
       main(int argc, char *argv[])
       {
           int                 mount_id, fd, mount_fd, handle_bytes;
           char                buf[1000];
       #define LINE_SIZE 100
           char                line1[LINE_SIZE], line2[LINE_SIZE];
           char                *nextp;
           ssize_t             nread;
           struct file_handle  *fhp;

           if ((argc > 1 && strcmp(argv[1], "--help") == 0) || argc > 2) {
               fprintf(stderr, "Usage: %s [mount-path]\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           /* L'entrée standard contient l'identifiant de montage et
              les informations de l'indicateur :

                Ligne 1: <mount_id>
                Ligne 2: <handle_bytes> <handle_type>   <octets du descripteur en hexadécimal>
           */

           if (fgets(line1, sizeof(line1), stdin) == NULL ||
               fgets(line2, sizeof(line2), stdin) == NULL)
           {
               fprintf(stderr, "mount_id ou descripteur de fichier absent\n");
               exit(EXIT_FAILURE);
           }

           mount_id = atoi(line1);

           handle_bytes = strtoul(line2, &nextp, 0);

           /* handle_bytes étant connu, on peut maintenant allouer la structure file_handle. */

           fhp = malloc(sizeof(*fhp) + handle_bytes);
           if (fhp == NULL)
               err(EXIT_FAILURE, "malloc");

           fhp->handle_bytes = handle_bytes;

           fhp->handle_type = strtoul(nextp, &nextp, 0);

           for (size_t j = 0; j < fhp->handle_bytes; j++)
               fhp->f_handle[j] = strtoul(nextp, &nextp, 16);

           /* Récupère le descripteur de fichier du point de montage, soit en ouvrant
              le chemin indiqué dans la ligne de commande, soit en parcourant
              /proc/self/mounts pour retrouver un montage qui corresponde à 'mount_id'
              qui a été reçu de stdin. */

           if (argc > 1)
               mount_fd = open(argv[1], O_RDONLY);
           else
               mount_fd = open_mount_path_by_id(mount_id);

           if (mount_fd == -1)
               err(EXIT_FAILURE, "opening mount fd");

           /* Ouvre le fichier en utilisant l'indicateur et le point de montage. */

           fd = open_by_handle_at(mount_fd, fhp, O_RDONLY);
           if (fd == -1)
               err(EXIT_FAILURE, "open_by_handle_at");

           /* On essaie de lire quelques octets depuis le fichier. */

           nread = read(fd, buf, sizeof(buf));
           if (nread == -1)
               err(EXIT_FAILURE, "read");

           printf("Read %zd bytes\n", nread);

           exit(EXIT_SUCCESS);
       }

VOIR AUSSI
       open(2), libblkid(3), blkid(8), findfs(8), mount(8)

       La  documentation  relative à libblkid et à libmount de la dernière pu-
       blication                de                util-linux                 à
       ⟨https://www.kernel.org/pub/linux/utils/util-linux/TRADUCTION
       La  traduction française de cette page de manuel a été créée par Chris-
       tophe Blaess <https://www.blaess.fr/christophe/>, Stéphan  Rafin  <ste-
       phan.rafin@laposte.net>, Thierry Vignaud <tvignaud@mandriva.com>, Fran-
       çois Micaux, Alain Portal <aportal@univ-montp2.fr>, Jean-Philippe  Gué-
       rard  <fevrier@tigreraye.org>,  Jean-Luc  Coulon (f5ibh) <jean-luc.cou-
       lon@wanadoo.fr>, Julien Cristau <jcristau@debian.org>,  Thomas  Huriaux
       <thomas.huriaux@gmail.com>,  Nicolas François <nicolas.francois@centra-
       liens.net>, Florentin Duneau <fduneau@gmail.com>, Simon  Paillard  <si-
       mon.paillard@resel.enst-bretagne.fr>,    Denis   Barbier   <barbier@de-
       bian.org>, David Prévot <david@tilapin.org>, Frédéric  Hantrais  <fhan-
       trais@gmail.com> et Jean-Philippe MENGUAL <jpmengual@debian.org>

       Cette traduction est une documentation libre ; veuillez vous reporter à
       la       GNU       General       Public        License        version 3
       ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩  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 à ⟨debian-l10n-french@lists.debian.org⟩.

Pages du manuel de Linux 6.03   5 février 2023            open_by_handle_at(2)

Generated by dwww version 1.15 on Sat Jun 29 00:40:23 CEST 2024.