open(2) | System Calls Manual | open(2) |
open, openat, creat - Ouvrir ou créer éventuellement un fichier
Bibliothèque C standard (libc, -lc)
#include <fcntl.h>
int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);
int creat(const char *pathname, mode_t mode);
int openat(int dirfd, const char *pathname, int flags); int openat(int dirfd, const char *pathname, int flags, mode_t mode);
/* Documenté à part, dans openat2(2) : */ int openat2(int dirfd, const char *pathname, const struct open_how *how, size_t size);
openat() :
Depuis la version 2.10 de la glibc :
_POSIX_C_SOURCE >= 200809L
Avant la version 2.10 de la glibc :
_ATFILE_SOURCE
L'appel système open() ouvre le fichier indiqué par pathname. S'il n'existe pas, il peut (si O_CREAT est indiqué dans flags) être créé par open().
La valeur renvoyée par open() est un descripteur de fichier, un petit entier positif ou nul qui est un indice d'entrée dans la table de processus de descripteurs de fichiers ouverts. Le descripteur de fichier est ensuite utilisé dans d'autres appels système (read(2), write(2), lseek(2), fcntl(2), etc.) pour se référer au fichier ouvert. Le descripteur de fichier renvoyé par un appel réussi sera celui du plus petit numéro de descripteur de fichier non actuellement ouvert par le processus.
Par défaut, le nouveau descripteur de fichier est configuré pour rester ouvert après un appel à execve(2) (son attribut FD_CLOEXEC décrit dans fcntl(2) est initialement désactivé). L'attribut O_CLOEXEC décrit ci-dessous permet de modifier ce comportement par défaut. La position dans le fichier est définie au début du fichier (consultez lseek(2)).
Un appel à open() crée une nouvelle description de fichier ouvert, une entrée dans la table de fichiers ouverts du système. Cette description de fichier ouvert enregistre la position dans le fichier et les attributs d’état du fichier (voir ci-dessous). Un descripteur de fichier est une référence à une description de fichier ouvert ; cette référence n'est pas modifiée si pathname est ensuite supprimé ou modifié pour faire référence à un autre fichier. Pour obtenir plus de détails sur les descriptions de fichiers ouverts, consultez NOTES.
Le paramètre flags est l'un des éléments O_RDONLY, O_WRONLY ou O_RDWR qui réclament respectivement l'ouverture du fichier en lecture seule, écriture seule, ou lecture/écriture.
De plus, zéro ou plusieurs attributs de création de fichier et attributs d'état de fichier peuvent être indiqués dans flags avec un OU binaire. Les attributs de création de fichier sont O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TMPFILE et O_TRUNC. Les attributs d'état de fichier sont tous les autres attributs indiqués ci-dessous. La distinction entre ces deux groupes est que les attributs d'état de fichier modifient la sémantique de l'opération d'ouverture elle-même, tandis que les attributs de l'état du fichier modifient celle des opérations d'E/S qui suivent. Les attributs d'état de fichier peuvent être lus et (dans certains cas) modifiés ; consultez fcntl(2) pour plus de précisions.
La liste complète des attributs de création et d'état de fichier est la suivante.
char buf[PATH_MAX]; fd = open("un_programme", O_PATH); snprintf(buf, PATH_MAX, "/proc/self/fd/%d", fd); execl(buf, "un_programme", (char *) NULL);
char chemin[PATH_MAX]; df = open("/chemin/vers/rép.", O_TMPFILE | O_RDWR,
S_IRUSR | S_IWUSR); /* E/S du fichier sur 'fd'... */ linkat(fd, "", AT_FDCWD, "/chemin/du/fichier", AT_EMPTY_PATH); /* Si l'appelant n'a pas la capacité CAP_DAC_READ_SEARCH (nécessaire
pour utiliser AT_EMPTY_PATH avec linkat(2)) et s'il existe un
système de fichiers proc(5) monté, l'appel linkat(2) ci-dessus peut
être remplacé par : snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd); linkat(AT_FDCWD, path, AT_FDCWD, "/chemin/du/fichier",
AT_SYMLINK_FOLLOW); */
L'appel creat() est équivalent à open() avec l'attribut flags égal à O_CREAT|O_WRONLY|O_TRUNC.
L'appel système openat() fonctionne de la même façon que open(), les différences étant décrites ici.
L'argument dirfd est utilisé avec l'argument pathname comme suit :
Si le chemin fourni dans pathname est un chemin relatif et si dirfd n'est pas un descripteur de fichier valable, il en résulte une erreur (EBADF). (Spécifier un numéro de descripteur de fichier non valable dans dirfd peut être utilisé comme moyen de s'assurer que pathname est absolu.)
L'appel système openat2(2) est une extension de openat() et il fournit un ensemble supplémentaire aux fonctionnalités de openat(). Il est documenté à part dans openat2(2).
open(), openat() et creat() renvoient le nouveau descripteur de fichier (un entier non négatif) s'ils réussissent. En cas d'erreur, ou -1 est renvoyé et errno est défini pour indiquer l'erreur.
open(), openat() et creat() peuvent échouer avec les erreurs suivantes :
openat() a été ajouté dans Linux 2.6.16 ; la prise en charge de la bibliothèque a été ajoutée dans la glibc 2.4.
open(), creat() : SVr4, 4.3BSD, POSIX.1-2001, POSIX.1-2008.
openat() : POSIX.1-2008.
openat2(2) est spécifique à Linux.
Les attributs O_DIRECT, O_NOATIME, O_PATH et O_TMPFILE sont spécifiques à Linux. _GNU_SOURCE doit être définie pour obtenir leurs définitions.
Les attributs O_CLOEXEC, O_DIRECTORY et O_NOFOLLOW ne sont pas spécifiés dans POSIX.1-2001, mais le sont dans POSIX.1-2008. Depuis glibc 2.12, leurs définitions peuvent être obtenues en définissant soit _POSIX_C_SOURCE avec une valeur supérieure ou égale à 200809L, soit _XOPEN_SOURCE avec une valeur supérieure ou égale à 700. Dans glibc 2.11 et les versions précédentes, les définitions peuvent être obtenues en définissant _GNU_SOURCE.
Comme indiqué dans feature_test_macros(7), les macros de test de fonctionnalités comme _POSIX_C_SOURCE, _XOPEN_SOURCE et _GNU_SOURCE doivent être définies avant d'inclure n’importe quel fichier d'en-tête.
Sous Linux, l'attribut O_NONBLOCK est parfois utilisé pour indiquer qu'on veut ouvrir mais pas nécessairement dans l'intention de lire ou d'écrire. Il est typiquement utilisé pour ouvrir des périphériques dans le but de récupérer un descripteur de fichier pour l'utiliser avec ioctl(2).
L'effet (indéfini) de O_RDONLY | O_TRUNC varie selon l'implémentation. Sur de nombreux systèmes, le fichier est effectivement tronqué.
Notez que open() peut ouvrir des fichiers spéciaux mais creat() ne peut pas en créer, il faut utiliser mknod(2) à la place.
Si un fichier est créé, ses horodatages st_atime, st_ctime, st_mtime (respectivement heure de dernier accès, de dernière modification d'état, et de dernière modification ; consultez stat(2)) sont définis à l'heure actuelle, ainsi que les champs st_ctime et st_mtime du répertoire parent. Sinon, si le fichier est modifié à cause de l'attribut O_TRUNC, ses champs st_ctime et st_mtime sont remplis avec l'heure actuelle.
Les fichiers du répertoire /proc/[pid]/fd affichent les descripteurs de fichier ouverts du processus ayant l'identifiant pid. Les fichiers du répertoire /proc/[pid]/fdinfo présentent encore plus d'informations sur ces descripteurs de fichier. Voir proc(5) pour plus de détails sur ces deux répertoires.
Le fichier d'en-tête <asm/fcntl.h> du noyau Linux ne définit pas O_ASYNC ; son synonyme FASYNC (dérivé de BSD) l'est en revanche.
Le terme « description de fichier ouvert » correspond à la terminologie POSIX pour faire référence à des entrées dans la table des fichiers ouverts du système. Dans d'autres contextes, cet objet est également appelé « objet de fichier ouvert », « gestionnaire de fichier », « entrée de la table des fichiers ouverts » ou encore, dans le jargon des développeurs du noyau, struct file.
Lorsqu'un descripteur de fichiers est dupliqué (au moyen de dup(2) ou d'un équivalent), la copie fait référence à la même description de fichier ouvert que le descripteur de fichier d'origine. Les deux descripteurs de fichier partagent donc la même position dans le fichier et les mêmes attributs d'état. Un tel partage peut également se produire entre deux processus : un processus enfant créé au moyen de fork(2) hérite des copies des descripteurs de fichier de ses parents, et ces copies pointent vers les mêmes descriptions de fichier ouvert.
Chaque opération open(2) sur un fichier crée une nouvelle description de fichier ouvert ; ainsi, il peut y avoir plusieurs descriptions de fichier ouvert correspondant à un inœud de fichier.
Sur Linux, on peut utiliser KCMP_FILE de kcmp(2) pour tester si deux descripteurs de fichier (dans le même processus ou dans deux processus différents) se rapportent à la même description de fichier ouvert.
L'option POSIX-1.2008 « E/S synchrones » décrit des variantes des E/S synchrones, ainsi que plusieurs attributs de open() permettant d'en contrôler le comportement : O_SYNC, O_DSYNC et O_RSYNC. Sans chercher à savoir si une implémentation accepte cette option, elle doit au moins prendre en charge l'utilisation de O_SYNC pour les fichiers normaux.
Linux met en œuvre O_SYNC et O_DSYNC, mais pas O_RSYNC. De façon plus ou moins correcte, la glibc définit O_RSYNC de façon à avoir la même valeur que O_SYNC. (O_RSYNC est défini dans le fichier d'en-tête du noyau Linux <asm/fcntl.h> de HP PA-RISC, mais il n'est pas utilisé).
O_SYNC fournit l'exécution d'E/S synchrones avec garantie d'intégrité des fichiers, ce qui signifie que les opérations d'écriture envoient les données et les métadonnées associées au matériel. O_DSYNC fournit l'exécution d'E/S synchrones avec garantie d'intégrité des données, ce qui signifie que les opérations d'écriture envoient les données et les métadonnées associées au matériel, mais en envoyant seulement les mises à jour des métadonnées qui permettent d'assurer le bon déroulement d'une opération de lecture ultérieure. L'exécution avec garantie d'intégrité des données peut réduire le nombre d'accès au disque demandés par une application qui ne nécessite pas l'exécution avec garantie d'intégrité des fichiers.
Pour comprendre la différence entre ces deux types d'exécution, imaginez deux extraits de métadonnées d'un fichier : l'horodatage de la dernière modification (st_mtime) et la longueur du fichier. Toutes les opérations d'écriture modifieront l'horodatage de la dernière modification, mais seules les écritures en fin de fichier modifieront la longueur. L'horodatage de dernière modification n'est pas nécessaire pour garantir une lecture correcte du fichier, contrairement à la longueur. Ainsi, O_DSYNC transmettrait seulement la métadonnée relative à la longueur du fichier (quand O_SYNC y ajouterait l'horodatage de dernière modification).
Avant Linux 2.6.33, Linux mettait seulement en œuvre l'attribut O_SYNC de open(). Cependant, lorsque cet attribut était indiqué, la plupart des systèmes de fichiers fournissait des fonctionnalités équivalentes à l'exécution des E/S synchrones avec garantie de l'intégrité des données (autrement dit, O_SYNC était de fait mis en œuvre comme O_DSYNC).
A partir de Linux 2.6.33, une véritable prise de charge de O_SYNC est fournie. Cependant, pour assurer la compatibilité ascendante binaire, O_DSYNC a été défini avec la même valeur que le O_SYNC « historique », et O_SYNC a été défini comme un nouvel attribut (de deux bits) qui comprend l'attribut O_DSYNC. Ceci permet d'assurer que les applications compilées avec les nouveaux en-têtes auront au moins la sémantique de O_DSYNC avant Linux 2.6.33.
Depuis la glibc 2.26, la fonction enveloppe de la glibc de open() utilise l'appel système openat() au lieu de l'appel système open() du noyau. Pour certaines architectures, cela est aussi vrai avant la glibc 2.26.
Plusieurs problèmes se posent avec le protocole NFS, concernant entre autres O_SYNC, et O_NDELAY.
Sur les systèmes de fichiers NFS, où la correspondance d'UID est activée, open() peut renvoyer un descripteur de fichier alors qu'une requête read(2) par exemple sera refusée avec le code d'erreur EACCES. En effet, le client a effectué open() en vérifiant les autorisations d'accès, mais la correspondance d'UID est calculée par le serveur au moment des requêtes de lecture ou d'écriture.
Ouvrir les blocs de fin de FIFO en lecture et écriture jusqu'à ce que l'autre fin soit également ouverte (par un autre processus ou un autre thread). Voir fifo(7) pour plus de détails.
Contrairement aux autres valeurs qui peuvent être indiquées dans flags, les valeurs du mode d'accès O_RDONLY, O_WRONLY et O_RDWR ne sont pas des bits individuels. Ils définissent l'ordre des deux bits de poids faible de flags, et ont pour valeur respective 0, 1 et 2. En d'autres termes, l'association O_RDONLY | O_WRONLY est une erreur logique et n'a certainement pas la même signification que O_RDWR.
Linux réserve le sens suivant au mode 3 d'accès spécial et non standard (en binaire, 11) de l'attribut : vérification des droits en lecture et écriture du fichier, et renvoi d'un descripteur qui ne peut être utilisé ni en lecture, ni en écriture. Ce mode d'accès non standard est utilisé par certains pilotes Linux afin de renvoyer un descripteur qui n'est destiné qu'à des opérations ioctl(2) propres aux périphériques.
openat() et les autres appels système similaires, ainsi que les fonctions de bibliothèques qui reçoivent pour argument un descripteur de fichier de répertoire (c'est-à-dire, execveat(2), faccessat(2), fanotify_mark(2), fchmodat(2), fchownat(2), fspick(2), fstatat(2), futimesat(2), linkat(2), mkdirat(2), mknodat(2), mount_setattr(2), move_mount(2), name_to_handle_at(2), open_tree(2), openat2(2), readlinkat(2), renameat(2), renameat2(2), statx(2), symlinkat(2), unlinkat(2), utimensat(2), mkfifoat(3) et scandirat(3)) gèrent deux problèmes avec les anciennes interfaces. L'explication est ici donnée dans le contexte de l'appel openat(), mais elle est semblable pour les autres interfaces.
Tout d'abord, openat() permet à une application d'éviter les problèmes d'accès concurrents lors de l'utilisation de open() pour ouvrir des fichiers dans des répertoires autres que le répertoire courant. Ces problèmes sont dus au fait que l'un des composants du chemin donné à open() peut être modifié parallèlement à l'appel open(). Supposons par exemple qu'on veuille créer le fichier dir1/dir2/xxx.dep alors que le fichier dir1/dir2/xxx existe. Le problème est qu'entre la vérification de son existence et l'étape de création du fichier, dir1 ou dir2 (qui pourraient être des liens symboliques) pourraient être modifiés pour pointer vers un autre endroit. De tels problèmes peuvent être évités en ouvrant un descripteur de fichier sur le répertoire cible, puis en fournissant ce descripteur comme argument dirfd de (disons) fstatat(2) et openat(). L'utilisation du descripteur de fichier dirfd a également d'autres avantages :
Enfin, openat() permet d'implémenter un « répertoire courant » par thread, grâce à des descripteurs de fichier maintenus par l'application. Cette fonctionnalité peut également être obtenue en jouant avec /proc/self/fd/dirfd, mais de façon moins efficace.
L'argument dirfd de ces API peut être obtenu par l'utilisation de open() ou de openat() pour ouvrir un répertoire (avec le drapeau O_RDONLY ou O_PATH). Sinon, un tel descripteur de fichier peut être obtenu en appliquant un dirfd(3) au flux d'un répertoire créé avec opendir(3).
Quand on donne aux API un argument dirfd de AT_FDCWD ou qu'un chemin indiqué est absolu, ils gèrent leur argument de chemin de la même manière que les API conventionnelles correspondantes. Toutefois dans ce cas, plusieurs API ont un argument flags qui offre un accès à cette fonctionnalité non disponible avec les interfaces conventionnelles correspondantes.
L'attribut O_DIRECT peut imposer des restrictions d'alignement pour la longueur et l'adresse des tampons de l'espace utilisateur et des décalages de fichier pour les entrées-sorties. Sous Linux, les restrictions d'alignement varient en fonction du système de fichiers et de la version du noyau, et il peut aussi ne pas y en avoir. La manipulation des entrées-sorties O_DIRECT mal alignées varie aussi ; elles peuvent soit échouer avec l'erreur EINVAL soit se replier sur des entrées-sorties mises en tampon.
Depuis Linux 6.1, la prise en charge de O_DIRECT et les restrictions d'alignement pour un fichier peuvent être recherchées avec statx(2) en utilisant l'attribut STATX_DIOALIGN. La prise en charge de STATX_DIOALIGN varie selon le système de fichiers ; consultez statx(2).
Certains systèmes de fichiers fournissent leur propre interface pour rechercher les restrictions d'alignement de O_DIRECT, par exemple l'opération XFS_IOC_DIOINFO de xfsctl(3). STATX_DIOALIGN devrait être utilisé à la place quand il est disponible.
Si aucun de ces interfaces n'est disponible, alors la prise en charge directe des entrées-sorties et les restrictions d'alignement peuvent uniquement être présumées à partir des caractéristiques connues du système de fichiers, du fichier individuel, des périphériques de stockage sous-jacents et de la version du noyau. Dans Linux 2.4, la plupart des systèmes de fichiers basés sur des périphériques bloc requièrent que l'adresse du fichier et la longueur et l'adresse mémoire de tous les segments d'entrées-sorties soient des multiples de la taille de bloc du système de fichiers (habituellement 4096 octets). Dans Linux 2.6.0, cela a été assoupli à la taille du bloc logique du périphérique bloc (habituellement 512 octets). La taille de bloc logique d'un périphérique bloc peut être déterminée avec l'opération BLKSSZGET de ioctl(2) ou avec la commande shell suivante :
blockdev --getss
Les E/S O_DIRECT ne devraient jamais être exécutées en même temps que l'appel système fork(2), si le tampon mémoire est une projection privée (c'est-à-dire n'importe quelle projection en mémoire créée avec l'attribut MAP_PRIVATE de mmap(2), y compris la mémoire allouée sur le tas et les tampons alloués de façon statique). Toutes ces E/S, qu'elles soient soumises par l'intermédiaire d'une interface d'E/S asynchrone ou depuis un autre thread du processus, devraient être achevées avant l'appel de fork(2). En cas d'échec, les conséquences pourraient être une corruption de mémoire ou un comportement imprévisible dans les processus père et fils. Cette restriction ne s'applique pas quand le tampon mémoire pour les E/S O_DIRECT a été créé en utilisant shmat(2) ou mmap(2) avec l'attribut MAP_SHARED. Cette restriction ne s'applique pas non plus quand le tampon mémoire a été configuré comme MADV_DONTFORK avec madvise(2), en s'assurant qu'il ne sera pas disponible au fils après fork(2).
L'attribut O_DIRECT a été introduit par SGI IRIX, qui a des restrictions d'alignement identiques à Linux 2.4. IRIX a aussi un appel fcntl(2) pour obtenir les alignements et tailles appropriés. FreeBSD 4.x a introduit un attribut du même nom, mais sans les restrictions d'alignement.
La gestion de O_DIRECT a été ajoutée dans Linux 2.4.10. Les noyaux Linux plus anciens ignorent simplement cet attribut. Certains systèmes de fichiers peuvent ne pas gérer cet attribut et open() échouera avec l'erreur EINVAL s'il est utilisé.
Les applications devraient éviter de mélanger des entrées-sorties O_DIRECT et normales pour le même fichier, en particulier sur des régions d'un même fichier qui se recouvrent. Même si le système de fichiers gère les problèmes de cohérence dans cette situation, le débit global d'entrées-sorties sera moindre que si un seul mode était utilisé. De la même façon, les applications devraient éviter de mélanger l'utilisation de mmap(2) et d'entrées-sorties directes pour les mêmes fichiers.
Le comportement de O_DIRECT avec NFS diffère des systèmes de fichiers locaux. Les anciens noyaux, ou les noyaux configurés d'une certaine façon, peuvent ne pas gérer cette combinaison. Le protocole NFS ne gère pas le passage de l'attribut au serveur, les entrées-sorties O_DIRECT ne font donc que le cache des pages du client ; le serveur pourra toujours utiliser un cache pour les entrées-sorties. Le client demande au serveur de rendre les entrées-sorties synchrones pour préserver la sémantique synchrone de O_DIRECT. Certains serveurs fonctionnent mal dans ces circonstances, tout particulièrement si les entrées-sorties sont de petite taille. Certains serveurs peuvent aussi être configurés pour mentir aux clients et indiquer que les entrées-sorties ont atteint un espace de stockage stable ; ceci évitera la perte de performance en augmentant les risques pour l'intégrité des données en cas de problème d'alimentation du serveur. Le client NFS Linux n'a pas de restriction d'alignement pour les entrées-sorties O_DIRECT.
En résumé, O_DIRECT est un outil potentiellement puissant qui doit être utilisé avec précaution. Les applications devraient utiliser O_DIRECT comme une option pour améliorer les performances et qui est désactivée par défaut.
Actuellement, il n'est pas possible d'activer les entrées-sorties contrôlées par les signaux en indiquant O_ASYNC lors de l'appel open() ; il faut utiliser fcntl(2) pour activer cet attribut.
Deux codes d’erreur différents – EISDIR et ENOENT — doivent être vérifiés pour essayer de déterminer si le noyau prend en charge la fonctionnalité O_TMPFILE.
Quand O_CREAT et O_DIRECTORY sont indiqués dans flags et que le fichier indiqué par pathname n'existe pas, open() créera un fichier ordinaire (c'est-à-dire que O_DIRECTORY est ignoré).
chmod(2), chown(2), close(2), dup(2), fcntl(2), link(2), lseek(2), mknod(2), mmap(2), mount(2), open_by_handle_at(2), openat2(2), read(2), socket(2), stat(2), umask(2), unlink(2), write(2), fopen(3), acl(5), fifo(7), inode(7), path_resolution(7), symlink(7)
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>, Jean-Philippe MENGUAL <jpmengual@debian.org> et Jean-Pierre Giraud <jean-pierregiraud@neuf.fr>
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 à debian-l10n-french@lists.debian.org.
5 février 2023 | Pages du manuel de Linux 6.03 |