open_by_handle_at
Table des matières
Retour à l'index
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
descripteur 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 initialisé
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
effectivement écrits dans f_handle.
L'appelant peut prendre connaissance de l'espace nécessaire à la structure
file_handle en effectuant un appel dans lequel
handle->handle_bytes vaut zéro ; dans ce cas, l'appel échoue en
renvoyant 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 particulier
dans un système de fichiers qui prend normalement en charge la recherche de
gestionnaire de fichiers. Ce cas peut se détecter quand l'erreur
EOVERFLOW est renvoyée sans que handle_bytes ne soit augmenté.
Other than the use of the handle_bytes field, the caller should treat the
file_handle structure as an opaque data type: the handle_type and
f_handle fields can be used in a subsequent call to
open_by_handle_at(). The caller can also use the opaque file_handle
to compare the identity of filesystem objects that were queried at different
times and possibly at different paths. The fanotify(7) subsystem can
report events with an information record containing a file_handle to
identify the filesystem object.
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.
When flags contain the AT_HANDLE_FID (since Linux 6.5) flag, the
caller indicates that the returned file_handle is needed to identify the
filesystem object, and not for opening the file later, so it should be
expected that a subsequent call to open_by_handle_at() with the returned
file_handle may fail.
Ensemble, les arguments pathname et dirfd désignent le fichier pour
lequel on souhaite obtenir un gestionnaire. On distingue quatre cas :
- -
-
Si pathname est une chaîne non vide contenant un chemin d'accès absolu,
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 interpré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 relatif
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 ouvert
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 correspond
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 fichier
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'appel.
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 renvoie
un indicateur pour le fichier vers lequel pointe le lien symbolique).
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 fichiers
gère à la fois les gestionnaires de fichier et les points de montage
automatique, un appel name_to_handle_at() sur un point de montage
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
appel à 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 indiqué 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 comprend 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 indicateur.
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 descripteur
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 indiqué
dans flags.
- EPERM
-
L'appelant n'a pas la capacité CAP_DAC_READ_SEARCH.
- ESTALE
-
The specified handle is not valid for opening a file. This error will
occur if, for example, the file has been deleted. This error can also occur
if the handle was acquired using the AT_HANDLE_FID flag and the
filesystem does not support open_by_handle_at().
VERSIONS
FreeBSD has a broadly similar pair of system calls in the form of getfh()
and fhopen().
STANDARDS
Linux.
HISTORIQUE
Linux 2.6.39, glibc 2.14.
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
en indicateurs de fichier, par exemple, /proc, /sys, ainsi que divers
systèmes de fichiers en réseaux. Certains systèmes de fichiers permettent la
transcription des chemins en indicateurs de fichier, mais ne prennent pas en
charge l'utilisation de ces indicateurs de fichier dans
open_by_handle_at().
Un indicateur de fichier peut devenir non valable (« stale ») si un fichier
est supprimé, ou pour une raison propre au système de fichiers. Les
indicateurs non autorisés sont signalés par une erreur ESTALE provenant
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ération sur
ce lien symbolique, en convertissant l'indicateur en descripteur 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’appels 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
remontés. Ainsi, l'identifiant de montage renvoyé par name_to_handle_at()
(dans *mount_id) ne doit pas être considéré comme un identifiant
persistant pour le système de fichiers considéré. Néanmoins, il est possible
pour une application d'utiliser l'information fournie dans mountinfo 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
correspondant au moyen des liens symboliques dans /dev/disks/by-uuid. (Un
moyen plus simple d'obtenir cet UUID consiste à utiliser la bibliothè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 obtenir 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 montage
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 obtenu 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. Cependant,
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 # Display inode number
4072121
$ rm cecilia.txt
$ echo 'Can you please think about it?' > cecilia.txt
$ stat --printf="%i\n" cecilia.txt # Check inode number
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];
/* Allocate file_handle structure. */
fhsize = sizeof(*fhp);
fhp = malloc(fhsize);
if (fhp == NULL)
err(EXIT_FAILURE, "malloc");
/* Make an initial call to name_to_handle_at() to discover
the size required for file handle. */
dirfd = AT_FDCWD; /* For name_to_handle_at() calls */
flags = 0; /* For name_to_handle_at() calls */
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);
}
/* Reallocate file_handle structure with correct size. */
fhsize = sizeof(*fhp) + fhp->handle_bytes;
fhp = realloc(fhp, fhsize); /* Copies fhp->handle_bytes */
if (fhp == NULL)
err(EXIT_FAILURE, "realloc");
/* Get file handle from pathname supplied on command line. */
if (name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags) == -1)
err(EXIT_FAILURE, "name_to_handle_at");
/* Write mount ID, file handle size, and file handle to stdout,
for later reuse by 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 <sys/types.h>
#include <unistd.h>
/* Scan /proc/self/mountinfo to find the line whose mount ID matches
'mount_id'. (An easier way to do this is to install and use the
'libmount' library provided by the 'util-linux' project.)
Open the corresponding mount path and return the resulting file
descriptor. */
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, "Could not find mount point\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);
}
/* Standard input contains mount ID and file handle information:
Line 1: <mount_id>
Line 2: <handle_bytes> <handle_type> <bytes of handle in hex>
*/
if (fgets(line1, sizeof(line1), stdin) == NULL ||
fgets(line2, sizeof(line2), stdin) == NULL)
{
fprintf(stderr, "Missing mount_id / file handle\n");
exit(EXIT_FAILURE);
}
mount_id = atoi(line1);
handle_bytes = strtoul(line2, &nextp, 0);
/* Given handle_bytes, we can now allocate file_handle structure. */
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);
/* Obtain file descriptor for mount point, either by opening
the pathname specified on the command line, or by scanning
/proc/self/mounts to find a mount that matches the 'mount_id'
that we received from 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");
/* Open file using handle and mount point. */
fd = open_by_handle_at(mount_fd, fhp, O_RDONLY);
if (fd == -1)
err(EXIT_FAILURE, "open_by_handle_at");
/* Try reading a few bytes from the file. */
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
publication de util-linux à
TRADUCTION
La traduction française de cette page de manuel a été créée par
Christophe Blaess <https://www.blaess.fr/christophe/>,
Stéphan Rafin <stephan.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.coulon@wanadoo.fr>,
Julien Cristau <jcristau@debian.org>,
Thomas Huriaux <thomas.huriaux@gmail.com>,
Nicolas François <nicolas.francois@centraliens.net>,
Florentin Duneau <fduneau@gmail.com>,
Simon Paillard <simon.paillard@resel.enst-bretagne.fr>,
Denis Barbier <barbier@debian.org>,
David Prévot <david@tilapin.org>,
Frédéric Hantrais <fhantrais@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
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 à
Index
- NOM
-
- BIBLIOTHÈQUE
-
- SYNOPSIS
-
- DESCRIPTION
-
- name_to_handle_at()
-
- open_by_handle_at()
-
- VALEUR RENVOYÉE
-
- ERREURS
-
- VERSIONS
-
- STANDARDS
-
- HISTORIQUE
-
- NOTES
-
- Obtenir un identifiant persistant de système de fichier
-
- EXEMPLES
-
- Source du programme : t_name_to_handle_at.c
-
- Source du programme : t_open_by_handle_at.c
-
- VOIR AUSSI
-
- TRADUCTION
-
This document was created by
man2html,
using the manual pages.
Time: 05:06:03 GMT, September 19, 2025