Introduction
Sous Linux, un fichier n’est pas seulement un nom avec du contenu. Derrière chaque fichier, il existe une organisation beaucoup plus profonde : périphériques, partitions, systèmes de fichiers, inodes, blocs de données, points de montage, VFS, options de montage, etc.
Ce chapitre explique comment Linux organise les fichiers sur disque et comment il donne à l’utilisateur une vision simple :
Code: Select all
/
├── bin
├── boot
├── dev
├── etc
├── home
├── proc
├── sys
├── tmp
└── usr
- ext4 sur la partition principale ;
- tmpfs pour certains répertoires temporaires ;
- procfs pour exposer des informations du noyau ;
- sysfs pour exposer des informations sur les périphériques ;
- vfat, ntfs, iso9660, nfs, etc.
Code: Select all
Programme utilisateur
|
v
open(), read(), write(), stat(), mkdir(), unlink()
|
v
VFS : Virtual File System
|
+--> ext4
+--> xfs
+--> btrfs
+--> tmpfs
+--> procfs
+--> sysfs
+--> nfs
+--> vfat
+--> ntfs
1. Les fichiers spéciaux de périphériques
Sous Linux, beaucoup de périphériques sont visibles sous forme de fichiers spéciaux dans le répertoire :
Code: Select all
/dev
Code: Select all
/dev/sda
/dev/sda1
/dev/null
/dev/zero
/dev/tty
/dev/random
/dev/urandom
Il existe deux grandes familles :
- block devices : périphériques à blocs ;
- character devices : périphériques caractère.
Un périphérique bloc fonctionne par blocs. C’est typiquement le cas des périphériques de stockage.
Exemples :
Code: Select all
/dev/sda
/dev/sda1
/dev/nvme0n1
/dev/nvme0n1p1
Le noyau peut lire ou écrire des blocs de données sur ces périphériques. Ensuite, au-dessus de ces blocs, on peut installer un système de fichiers comme ext4, xfs, btrfs, vfat, etc.
1.2. Périphérique caractère
Un périphérique caractère fonctionne plutôt comme un flux d’octets.
Exemples :
Code: Select all
/dev/tty
/dev/null
/dev/zero
/dev/random
/dev/urandom
1.3. Major number et minor number
Chaque fichier spécial de périphérique est associé à deux numéros :
- major number ;
- minor number.
Le minor number identifie une instance particulière gérée par ce pilote.
Schéma mental :
Code: Select all
major number = quel driver ?
minor number = quelle instance précise ?
Code: Select all
/dev/sda -> disque entier
/dev/sda1 -> première partition
/dev/sda2 -> deuxième partition
2. Disques et partitions
Un disque physique peut être divisé en plusieurs partitions.
Exemple :
Code: Select all
/dev/sda -> disque entier
/dev/sda1 -> première partition
/dev/sda2 -> deuxième partition
/dev/sda3 -> troisième partition
Code: Select all
/dev/nvme0n1 -> disque NVMe entier
/dev/nvme0n1p1 -> première partition
/dev/nvme0n1p2 -> deuxième partition
- un système de fichiers ;
- de l’espace swap ;
- des données brutes ;
- une partition EFI ;
- une partition utilisée par un autre système d’exploitation.
Code: Select all
/dev/sda1 -> ext4
/dev/sda2 -> swap
/dev/sda3 -> vfat
/dev/sda4 -> ntfs
Une partition seule ne suffit pas forcément pour stocker des fichiers de manière organisée.
Pour que Linux puisse voir des fichiers et des répertoires, il faut généralement créer un système de fichiers sur cette partition.
Exemple :
Code: Select all
mkfs.ext4 /dev/sdb1
3. Qu’est-ce qu’un système de fichiers ?
Un système de fichiers définit comment les données sont organisées dans une partition ou dans une zone de stockage.
Il gère :
- les fichiers ;
- les répertoires ;
- les métadonnées ;
- les permissions ;
- les propriétaires ;
- les groupes ;
- les timestamps ;
- les liens physiques ;
- les blocs libres ;
- les blocs utilisés ;
- les inodes libres ;
- les inodes utilisés.
- ext2 ;
- ext3 ;
- ext4 ;
- xfs ;
- btrfs ;
- vfat ;
- ntfs ;
- iso9660 ;
- tmpfs ;
- procfs ;
- sysfs ;
- nfs.
3.1. Systèmes de fichiers sur disque
Un système de fichiers sur disque stocke réellement ses données sur un périphérique de stockage.
Exemples :
Code: Select all
ext4
xfs
btrfs
vfat
ntfs
3.2. Systèmes de fichiers virtuels
Certains systèmes de fichiers ne correspondent pas à des fichiers classiques stockés sur disque.
Exemples :
Code: Select all
/proc
/sys
/dev
/run
/dev/shm
Exemple :
Code: Select all
cat /proc/cpuinfo
cat /proc/mounts
cat /proc/self/status
4. Structure classique d’un système de fichiers
Un système de fichiers classique contient plusieurs zones importantes :
- boot block ;
- superblock ;
- inode table ;
- data blocks.
Code: Select all
+-------------+
| Boot block |
+-------------+
| Superblock |
+-------------+
| Inode table |
+-------------+
| Data blocks |
+-------------+
Le boot block peut contenir du code de démarrage.
Il est surtout important pour les partitions amorçables. Tous les systèmes de fichiers peuvent réserver une zone de ce type, même si elle n’est pas toujours utilisée directement par Linux.
4.2. Superblock
Le superblock contient les informations globales du système de fichiers.
Il peut contenir :
- la taille du système de fichiers ;
- la taille des blocs ;
- le nombre total de blocs ;
- le nombre de blocs libres ;
- le nombre total d’inodes ;
- le nombre d’inodes libres ;
- l’état du système de fichiers ;
- des informations de configuration internes.
4.3. Table des inodes
La table des inodes contient les inodes du système de fichiers.
Chaque inode décrit un fichier, un répertoire, un lien symbolique ou un autre objet du système de fichiers.
Point essentiel :
Code: Select all
L’inode ne contient pas le nom du fichier.
4.4. Blocs de données
Les blocs de données contiennent le contenu réel des fichiers.
Exemple :
Code: Select all
Nom dans un répertoire -> numéro d’inode -> inode -> blocs de données
5. Les inodes
L’inode est l’une des notions les plus importantes du chapitre.
Un inode est une structure qui contient les informations essentielles sur un fichier, sauf son nom.
Un inode contient typiquement :
- le type de fichier ;
- les permissions ;
- l’UID du propriétaire ;
- le GID du groupe ;
- la taille du fichier ;
- le nombre de liens physiques ;
- les timestamps ;
- les pointeurs vers les blocs de données.
Code: Select all
inode = carte d’identité technique du fichier
Code: Select all
inode != contenu du fichier
inode != nom du fichier
5.1. Où est stocké le nom du fichier ?
Le nom du fichier est stocké dans un répertoire.
Un répertoire est lui-même un fichier spécial qui contient des associations :
Code: Select all
nom -> numéro d’inode
Code: Select all
"test.txt" -> inode 12345
"main.c" -> inode 12346
"docs" -> inode 12347
Donc quand tu ouvres :
Code: Select all
/home/jean/test.txt
Code: Select all
/ -> trouve "home"
/home -> trouve "jean"
/home/jean -> trouve "test.txt"
/home/jean/test.txt -> numéro d’inode
5.2. Hard links et inodes
Comme le nom du fichier n’est pas dans l’inode, plusieurs noms peuvent pointer vers le même inode.
C’est le principe du hard link.
Exemple :
Code: Select all
ln fichier.txt autre_nom.txt
Schéma :
Code: Select all
fichier.txt -> inode 5000
autre_nom.txt -> inode 5000
Le nombre de hard links est stocké dans l’inode.
5.3. Différence simple entre nom, inode et contenu
Il faut bien séparer trois niveaux :
Code: Select all
Nom du fichier :
stocké dans un répertoire
Inode :
métadonnées + pointeurs vers les blocs
Blocs de données :
contenu réel du fichier
Code: Select all
/home/jean/cours.txt
|
v
entrée de répertoire : "cours.txt" -> inode 9123
|
v
inode 9123 : taille, permissions, propriétaire, blocs
|
v
blocs de données : contenu texte du fichier
Dans un système comme ext2, l’inode contient des pointeurs vers les blocs de données.
Pour les petits fichiers, il peut utiliser des pointeurs directs.
Pour les gros fichiers, il utilise des niveaux d’indirection.
On trouve généralement :
- des pointeurs directs ;
- un pointeur indirect ;
- un pointeur double indirect ;
- un pointeur triple indirect.
Code: Select all
inode
├── pointeur direct -> bloc de données
├── pointeur direct -> bloc de données
├── pointeur direct -> bloc de données
├── pointeur indirect -> bloc contenant des pointeurs vers des blocs
├── pointeur double indirect
└── pointeur triple indirect
Les petits fichiers doivent être rapides à accéder.
Pour eux, les pointeurs directs suffisent.
Mais un gros fichier peut contenir énormément de blocs. L’inode ne peut pas contenir directement des millions de pointeurs.
On utilise donc des blocs intermédiaires qui contiennent eux-mêmes des pointeurs.
Schéma :
Code: Select all
inode
|
+--> bloc indirect
|
+--> pointeur vers bloc de données
+--> pointeur vers bloc de données
+--> pointeur vers bloc de données
Code: Select all
inode
|
+--> bloc double indirect
|
+--> bloc indirect
|
+--> bloc de données
+--> bloc de données
6.2. Idée à retenir
Le système est conçu pour être efficace pour les petits fichiers tout en permettant de gérer de gros fichiers.
À retenir :
Code: Select all
petit fichier -> pointeurs directs
gros fichier -> pointeurs indirects, double indirects, triple indirects
Le VFS est une couche d’abstraction du noyau Linux.
Son rôle est de fournir une interface commune à tous les systèmes de fichiers.
Un programme utilisateur appelle :
Code: Select all
open()
read()
write()
close()
stat()
mkdir()
rmdir()
unlink()
rename()
Code: Select all
ext4
xfs
btrfs
tmpfs
procfs
sysfs
nfs
vfat
ntfs
7.1. Schéma du VFS
Code: Select all
Application utilisateur
|
v
Appels système :
open(), read(), write(), stat(), unlink()
|
v
VFS
|
+--> driver ext4
+--> driver xfs
+--> driver btrfs
+--> driver tmpfs
+--> driver procfs
+--> driver nfs
Sans VFS, chaque programme devrait connaître les détails de chaque système de fichiers.
Avec VFS, le programme utilise une interface unique.
Exemple :
Code: Select all
int fd = open("fichier.txt", O_RDONLY);
read(fd, buffer, sizeof(buffer));
close(fd);
7.3. Comparaison avec Windows
Sous Windows, une application appelle par exemple :
Code: Select all
CreateFile()
ReadFile()
WriteFile()
CloseHandle()
Sous Linux, l’idée équivalente est :
Code: Select all
open()
read()
write()
close()
|
v
VFS
|
v
système de fichiers réel
Un système de fichiers doit rester cohérent.
Problème : que se passe-t-il si le système plante pendant une écriture ?
Exemple :
- l’inode a été modifié ;
- mais l’entrée de répertoire n’a pas encore été écrite ;
- ou les blocs ont été alloués ;
- mais les métadonnées ne sont pas encore cohérentes.
8.1. Rôle du journal
Un système de fichiers journalisé écrit d’abord dans un journal les opérations qu’il va effectuer.
Principe simplifié :
Code: Select all
1. écrire dans le journal ce qui va être modifié
2. appliquer réellement les modifications
3. marquer l’opération comme terminée
Cela permet une récupération beaucoup plus rapide qu’une vérification complète du disque.
8.2. Exemples
Systèmes non journalisés ou historiquement non journalisés :
Code: Select all
ext2
Code: Select all
ext3
ext4
xfs
btrfs
jfs
reiserfs
Ext4 est plus moderne et apporte d’autres améliorations.
9. Arborescence unique et points de montage
Linux utilise une seule arborescence globale.
Elle commence à :
Code: Select all
/
Code: Select all
C:\
D:\
E:\
Exemple :
Code: Select all
/dev/sda1 -> /
/dev/sda2 -> /home
/dev/sdb1 -> /mnt/usb
tmpfs -> /run
procfs -> /proc
sysfs -> /sys
Un point de montage est un répertoire sur lequel un système de fichiers est attaché.
Exemple :
Code: Select all
mount /dev/sdb1 /mnt/usb
Code: Select all
/mnt/usb
9.2. Contenu masqué par un montage
Si le répertoire utilisé comme point de montage contenait déjà des fichiers, ceux-ci ne sont pas supprimés.
Ils sont simplement masqués tant que le montage est actif.
Exemple :
Code: Select all
/mnt/test contient :
ancien.txt
mount /dev/sdb1 /mnt/test
`ancien.txt` existe toujours, mais il est caché par le montage.
Après démontage :
Code: Select all
umount /mnt/test
10. Monter et démonter un système de fichiers
La commande utilisateur classique pour monter est :
Code: Select all
mount
Code: Select all
mount()
Code: Select all
umount
Code: Select all
umount()
umount2()
Prototype :
Code: Select all
#include <sys/mount.h>
int mount(const char *source,
const char *target,
const char *filesystemtype,
unsigned long mountflags,
const void *data);
- source : périphérique ou source à monter ;
- target : point de montage ;
- filesystemtype : type de système de fichiers ;
- mountflags : options de montage ;
- data : options spécifiques au système de fichiers.
Code: Select all
mount("/dev/sdb1", "/mnt/usb", "ext4", 0, NULL);
Code: Select all
0 -> succès
-1 -> erreur, errno contient la raison
Prototype :
Code: Select all
#include <sys/mount.h>
int umount(const char *target);
Code: Select all
umount("/mnt/usb");
Retour :
Code: Select all
0 -> succès
-1 -> erreur
Prototype :
Code: Select all
#include <sys/mount.h>
int umount2(const char *target, int flags);
Elle permet de préciser des flags.
Flags importants :
Code: Select all
MNT_FORCE
MNT_DETACH
MNT_EXPIRE
`MNT_DETACH` réalise un lazy unmount.
Cela signifie que le montage est détaché immédiatement de l’arborescence, mais les ressources ne sont réellement libérées que plus tard, quand plus aucun processus ne les utilise.
Schéma :
Code: Select all
umount normal :
échoue si le montage est occupé
umount2 + MNT_DETACH :
retire le montage de l’arborescence
libère réellement plus tard
Code: Select all
MNT_DETACH ne tue pas les processus.
10.5. MNT_FORCE
`MNT_FORCE` demande un démontage forcé.
Il est surtout utile pour certains systèmes de fichiers réseau, par exemple dans des cas où un serveur distant ne répond plus.
Attention :
Code: Select all
MNT_FORCE n’est pas un bouton magique.
10.6. MNT_EXPIRE
`MNT_EXPIRE` sert à marquer un montage comme expiré.
C’est principalement utile avec certains mécanismes d’automount.
Principe simplifié :
- un premier appel peut marquer le montage comme expiré ;
- un second appel peut le démonter s’il n’est toujours pas utilisé.
Un démontage peut échouer si le système de fichiers est occupé.
Exemples :
- un processus a un fichier ouvert dans ce système de fichiers ;
- un terminal a son répertoire courant dans ce système de fichiers ;
- un exécutable lancé se trouve sur ce système de fichiers ;
- une bibliothèque utilisée vient de ce montage ;
- un sous-montage existe encore.
Code: Select all
cd /mnt/usb
umount /mnt/usb
12. Fonctions avancées de montage
Linux permet des montages plus avancés que le simple montage d’une partition sur un répertoire.
Le chapitre présente notamment :
- le montage d’un même système de fichiers à plusieurs endroits ;
- l’empilement de montages sur un même point ;
- les flags par point de montage ;
- les bind mounts ;
- les recursive bind mounts.
Linux permet de monter le même système de fichiers sur plusieurs points de montage.
Exemple :
Code: Select all
mount /dev/sda12 /testfs
mount /dev/sda12 /demo
Code: Select all
/testfs
/demo
Si tu crées un fichier via `/testfs`, tu le verras aussi via `/demo`.
Schéma :
Code: Select all
/dev/sda12
|
+--> /testfs
|
+--> /demo
Linux permet de monter plusieurs systèmes de fichiers au même endroit.
Exemple :
Code: Select all
mount /dev/sda12 /testfs
mount /dev/sda13 /testfs
Schéma :
Code: Select all
/testfs -> /dev/sda13 visible
/dev/sda12 caché dessous
C’est une logique de pile :
Code: Select all
haut de pile : montage visible
dessous : montages masqués
Code: Select all
Un montage peut masquer le contenu précédent,
mais il ne le supprime pas.
Certains flags peuvent être liés à un point de montage particulier.
Cela signifie que le même système de fichiers peut être visible à deux endroits avec des options différentes.
Exemple conceptuel :
Code: Select all
mount /dev/sda12 /testfs
mount /dev/sda12 /demo
mount -o remount,noexec /demo
Code: Select all
/testfs -> exécution autorisée
/demo -> exécution interdite avec noexec
13. Options et flags de montage importants
Voici les flags importants à connaître.
13.1. MS_RDONLY
Monte le système de fichiers en lecture seule.
Code: Select all
MS_RDONLY
Code: Select all
Aucune écriture n’est possible.
13.2. MS_NOEXEC
Interdit l’exécution de programmes depuis ce système de fichiers.
Code: Select all
MS_NOEXEC
Code: Select all
Les fichiers ne peuvent pas être exécutés depuis ce montage.
13.3. MS_NOSUID
Ignore les bits set-user-ID et set-group-ID.
Code: Select all
MS_NOSUID
Code: Select all
Les programmes setuid/setgid ne donnent pas d’élévation via ce montage.
13.4. MS_NODEV
Interdit l’interprétation des fichiers spéciaux de périphériques.
Code: Select all
MS_NODEV
Code: Select all
Les fichiers périphériques présents sur ce système de fichiers ne sont pas utilisables comme périphériques.
13.5. MS_NOATIME
Empêche la mise à jour du temps de dernier accès.
Code: Select all
MS_NOATIME
Avec `MS_NOATIME`, cette mise à jour est évitée.
Intérêt :
- moins d’écritures disque ;
- meilleures performances dans certains cas ;
- moins d’usure sur certains supports.
Semblable à `MS_NOATIME`, mais ciblé sur les répertoires.
Code: Select all
MS_NODIRATIME
Code: Select all
Ne met pas à jour l’atime des répertoires.
`MS_RELATIME` est une optimisation intermédiaire.
Au lieu de mettre à jour `atime` à chaque lecture, le noyau le met à jour seulement dans certains cas.
C’est souvent un compromis entre :
- la précision des timestamps ;
- les performances ;
- la réduction des écritures.
Permet de remonter un système de fichiers déjà monté avec de nouvelles options.
Code: Select all
MS_REMOUNT
Code: Select all
MS_REMOUNT ne démonte pas puis remonte complètement.
Exemple conceptuel :
Code: Select all
mount(NULL, "/mnt/test", NULL, MS_REMOUNT | MS_RDONLY, NULL);
Code: Select all
mount -o remount,ro /mnt/test
Permet de créer un bind mount.
Code: Select all
MS_BIND
13.10. MS_REC
Utilisé avec `MS_BIND` pour faire un bind mount récursif.
Code: Select all
MS_BIND | MS_REC
14. Bind mounts
Un bind mount permet de rendre une partie déjà existante de l’arborescence visible à un autre endroit.
Commande :
Code: Select all
mount --bind source target
Code: Select all
mount(source, target, NULL, MS_BIND, NULL);
Code: Select all
mkdir /mnt/projet
mount --bind /home/jean/projet /mnt/projet
Code: Select all
/home/jean/projet
/mnt/projet
14.1. Bind mount : ce que ce n’est pas
Un bind mount n’est pas :
- une copie ;
- un lien symbolique ;
- un nouveau système de fichiers ;
- une duplication des blocs ;
- une duplication d’inodes.
À retenir :
Code: Select all
bind mount = même contenu visible ailleurs
Un lien symbolique est un fichier spécial contenant un chemin texte.
Exemple :
Code: Select all
ln -s /home/jean/projet /mnt/projet
Un bind mount, lui, est géré au niveau du noyau dans la table des montages.
Différence :
Code: Select all
symlink :
chemin texte vers une cible
bind mount :
montage réel d’une partie de l’arborescence ailleurs
Un hard link associe un autre nom au même inode.
Mais les hard links sur répertoire sont généralement interdits pour éviter des incohérences dans l’arborescence.
Le bind mount, lui, peut exposer un répertoire entier ailleurs.
Différence :
Code: Select all
hard link :
autre nom pour le même inode, surtout pour fichiers
bind mount :
expose un fichier ou un répertoire ailleurs dans l’arborescence
Un bind mount peut aussi concerner un fichier.
Exemple conceptuel :
Code: Select all
touch f1
touch f2
mount --bind f1 f2
Le fichier cible devient lui-même un point de montage.
14.5. Utilisations des bind mounts
Les bind mounts sont très utilisés pour :
- les environnements chroot ;
- les containers ;
- l’isolation de systèmes ;
- la réorganisation temporaire de l’arborescence ;
- l’exposition contrôlée de certains répertoires ;
- le montage de `/dev`, `/proc`, `/sys` dans une racine isolée.
Code: Select all
mount --bind /dev /newroot/dev
mount --bind /proc /newroot/proc
mount --bind /sys /newroot/sys
Un bind mount simple ne reprend pas forcément tous les sous-montages présents sous le répertoire source.
Le recursive bind mount permet de reprendre aussi les sous-montages.
Commande :
Code: Select all
mount --rbind source target
Code: Select all
mount(source, target, NULL, MS_BIND | MS_REC, NULL);
Exemple :
Code: Select all
/source
fichier.txt
submount/ -> autre système de fichiers monté ici
Code: Select all
mount --bind /source /target
Avec :
Code: Select all
mount --rbind /source /target
À retenir :
Code: Select all
--bind -> répertoire ou fichier source
--rbind -> source + sous-montages
`tmpfs` est un système de fichiers en mémoire virtuelle.
Il permet de créer un système de fichiers dont les fichiers résident en mémoire, avec possibilité d’utiliser le swap si nécessaire.
Commande :
Code: Select all
mount -t tmpfs tmpfs /mnt/ram
Code: Select all
mkdir /mnt/ram
mount -t tmpfs tmpfs /mnt/ram
16.1. tmpfs et persistance
Un tmpfs n’est pas persistant.
Les données disparaissent :
- au démontage ;
- au redémarrage ;
- si le système de fichiers temporaire est supprimé.
Code: Select all
ext4 sur disque :
données persistantes
tmpfs :
données temporaires en mémoire virtuelle
Même si tmpfs est souvent décrit comme “en RAM”, il utilise en réalité la mémoire virtuelle.
Cela signifie que certaines pages peuvent être déplacées vers le swap si nécessaire.
Donc, phrase précise :
Code: Select all
tmpfs stocke ses données en mémoire virtuelle,
avec possibilité d’utiliser le swap.
`tmpfs` est utilisé pour :
- des fichiers temporaires ;
- des données runtime ;
- certains mécanismes IPC ;
- la mémoire partagée POSIX ;
- des répertoires comme `/run` ou `/dev/shm` selon les systèmes.
Code: Select all
/run
/dev/shm
/tmp
17. stat(), lstat(), fstat()
Ces fonctions servent à obtenir des informations sur un fichier.
Elles remplissent une structure :
Code: Select all
struct stat
Prototype :
Code: Select all
#include <sys/stat.h>
int stat(const char *pathname, struct stat *statbuf);
Exemple :
Code: Select all
struct stat st;
if (stat("test.txt", &st) == -1) {
perror("stat");
}
Prototype :
Code: Select all
int lstat(const char *pathname, struct stat *statbuf);
Différence :
Code: Select all
stat("lien") -> suit le lien symbolique
lstat("lien") -> donne les infos du lien lui-même
Prototype :
Code: Select all
int fstat(int fd, struct stat *statbuf);
Exemple :
Code: Select all
int fd = open("test.txt", O_RDONLY);
struct stat st;
if (fstat(fd, &st) == -1) {
perror("fstat");
}
Code: Select all
stat() -> chemin
lstat() -> chemin, mais ne suit pas le symlink
fstat() -> fd
Exemple simplifié :
Code: Select all
struct stat {
dev_t st_dev;
ino_t st_ino;
mode_t st_mode;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
off_t st_size;
blksize_t st_blksize;
blkcnt_t st_blocks;
time_t st_atime;
time_t st_mtime;
time_t st_ctime;
};
- st_dev : périphérique contenant le fichier ;
- st_ino : numéro d’inode ;
- st_mode : type de fichier + permissions ;
- st_nlink : nombre de liens physiques ;
- st_uid : UID du propriétaire ;
- st_gid : GID du groupe ;
- st_size : taille du fichier ;
- st_blksize : taille de bloc préférée pour les E/S ;
- st_blocks : nombre de blocs alloués ;
- st_atime : dernier accès ;
- st_mtime : dernière modification du contenu ;
- st_ctime : dernier changement de métadonnées.
Code: Select all
ctime ne veut pas dire creation time.
ctime = change time.
Le champ utilisé est :
Code: Select all
st_mode
Code: Select all
S_ISREG(st.st_mode) // fichier régulier
S_ISDIR(st.st_mode) // répertoire
S_ISLNK(st.st_mode) // lien symbolique
S_ISCHR(st.st_mode) // périphérique caractère
S_ISBLK(st.st_mode) // périphérique bloc
S_ISFIFO(st.st_mode) // FIFO
S_ISSOCK(st.st_mode) // socket
Code: Select all
if (S_ISREG(st.st_mode)) {
printf("fichier regulier\n");
}
if (S_ISDIR(st.st_mode)) {
printf("repertoire\n");
}
`stat()`, `lstat()` et `fstat()` donnent des informations sur un fichier.
Mais parfois, on veut des informations sur le système de fichiers lui-même.
Exemples :
- taille des blocs ;
- nombre total de blocs ;
- nombre de blocs libres ;
- nombre d’inodes ;
- longueur maximale d’un nom de fichier ;
- flags du système de fichiers.
Code: Select all
statvfs()
fstatvfs()
Prototype :
Code: Select all
#include <sys/statvfs.h>
int statvfs(const char *pathname, struct statvfs *buf);
Code: Select all
struct statvfs sv;
if (statvfs("/", &sv) == -1) {
perror("statvfs");
}
18.2. API fstatvfs()
Prototype :
Code: Select all
#include <sys/statvfs.h>
int fstatvfs(int fd, struct statvfs *buf);
Comparaison :
Code: Select all
statvfs() -> chemin
fstatvfs() -> fd
Code: Select all
stat() -> chemin
fstat() -> fd
Exemple simplifié :
Code: Select all
struct statvfs {
unsigned long f_bsize;
unsigned long f_frsize;
fsblkcnt_t f_blocks;
fsblkcnt_t f_bfree;
fsblkcnt_t f_bavail;
fsfilcnt_t f_files;
fsfilcnt_t f_ffree;
fsfilcnt_t f_favail;
unsigned long f_fsid;
unsigned long f_flag;
unsigned long f_namemax;
};
- f_bsize : taille de bloc préférée pour les E/S ;
- f_frsize : taille fondamentale des fragments ;
- f_blocks : nombre total de blocs ;
- f_bfree : nombre total de blocs libres ;
- f_bavail : blocs disponibles pour utilisateur non privilégié ;
- f_files : nombre total d’inodes ;
- f_ffree : nombre d’inodes libres ;
- f_favail : inodes disponibles pour utilisateur non privilégié ;
- f_fsid : identifiant du système de fichiers ;
- f_flag : flags ;
- f_namemax : longueur maximale d’un nom de fichier.
Point important :
Code: Select all
f_bfree = blocs libres réels
f_bavail = blocs libres disponibles pour utilisateur non privilégié
Parce qu’un système peut réserver une partie de l’espace pour root ou pour le système.
Donc un utilisateur normal peut voir moins d’espace disponible que le total réellement libre.
18.5. Exemple de code statvfs()
Code: Select all
#include <stdio.h>
#include <sys/statvfs.h>
int main(void)
{
struct statvfs sv;
if (statvfs("/", &sv) == -1) {
perror("statvfs");
return 1;
}
printf("Block size : %lu\n", sv.f_bsize);
printf("Fragment size : %lu\n", sv.f_frsize);
printf("Total blocks : %lu\n", sv.f_blocks);
printf("Free blocks : %lu\n", sv.f_bfree);
printf("Available blocks : %lu\n", sv.f_bavail);
printf("Total inodes : %lu\n", sv.f_files);
printf("Free inodes : %lu\n", sv.f_ffree);
printf("Max filename length : %lu\n", sv.f_namemax);
return 0;
}
Pour obtenir la liste des systèmes de fichiers montés, on peut lire :
Code: Select all
/proc/mounts
/etc/mtab
/etc/fstab
`/proc/mounts` expose les montages actuellement actifs.
Commande :
Code: Select all
cat /proc/mounts
19.2. /etc/fstab
`/etc/fstab` contient la configuration des montages automatiques.
Exemple d’entrée :
Code: Select all
/dev/sda1 / ext4 defaults 0 1
- source ou périphérique ;
- point de montage ;
- type du système de fichiers ;
- options ;
- option dump ;
- ordre fsck.
Historiquement, `/etc/mtab` listait les systèmes de fichiers actuellement montés.
Sur beaucoup de systèmes modernes, il peut être un lien vers `/proc/mounts`.
19.4. API getmntent()
Pour lire les entrées de montage en C, on peut utiliser :
Code: Select all
#include <mntent.h>
FILE *setmntent(const char *filename, const char *type);
struct mntent *getmntent(FILE *stream);
int endmntent(FILE *stream);
Code: Select all
#include <stdio.h>
#include <mntent.h>
int main(void)
{
FILE *fp;
struct mntent *ent;
fp = setmntent("/proc/mounts", "r");
if (fp == NULL) {
perror("setmntent");
return 1;
}
while ((ent = getmntent(fp)) != NULL) {
printf("source : %s\n", ent->mnt_fsname);
printf("target : %s\n", ent->mnt_dir);
printf("type : %s\n", ent->mnt_type);
printf("opts : %s\n\n", ent->mnt_opts);
}
endmntent(fp);
return 0;
}
La structure contient typiquement :
Code: Select all
struct mntent {
char *mnt_fsname;
char *mnt_dir;
char *mnt_type;
char *mnt_opts;
int mnt_freq;
int mnt_passno;
};
- mnt_fsname : source du montage ;
- mnt_dir : point de montage ;
- mnt_type : type de système de fichiers ;
- mnt_opts : options ;
- mnt_freq : champ lié à dump ;
- mnt_passno : ordre de vérification fsck.
Il faut bien distinguer ces structures.
20.1. struct stat
Sert à obtenir les informations sur un fichier.
Utilisée avec :
Code: Select all
stat()
lstat()
fstat()
- type de fichier ;
- permissions ;
- inode ;
- taille ;
- propriétaire ;
- groupe ;
- timestamps ;
- nombre de liens.
Code: Select all
struct stat = infos sur un fichier
Sert à parcourir les entrées d’un répertoire.
Utilisée avec :
Code: Select all
opendir()
readdir()
closedir()
Code: Select all
entry->d_name
Code: Select all
struct dirent = entrée de répertoire
Sert à obtenir des informations sur un système de fichiers.
Utilisée avec :
Code: Select all
statvfs()
fstatvfs()
- taille des blocs ;
- nombre de blocs ;
- blocs libres ;
- inodes libres ;
- flags ;
- taille maximale des noms.
Code: Select all
struct statvfs = infos globales sur le système de fichiers
Sert à lire les entrées de montage depuis `/proc/mounts`, `/etc/mtab` ou `/etc/fstab`.
Utilisée avec :
Code: Select all
setmntent()
getmntent()
endmntent()
- source ;
- point de montage ;
- type ;
- options.
Code: Select all
struct mntent = infos sur les montages
Code: Select all
struct stat
-> infos sur un fichier
struct dirent
-> entrée dans un répertoire
struct statvfs
-> infos sur le système de fichiers
struct mntent
-> infos sur les montages
21.1. Voir les périphériques bloc
Code: Select all
lsblk
Code: Select all
lsblk
lsblk -f
21.2. Voir les UUID
Code: Select all
blkid
21.3. Voir les montages
Code: Select all
mount
findmnt
cat /proc/mounts
Code: Select all
df -h
Code: Select all
mount /dev/sdb1 /mnt/test
mount -t ext4 /dev/sdb1 /mnt/test
Code: Select all
mount -o ro /dev/sdb1 /mnt/test
Code: Select all
mount -o remount,ro /mnt/test
mount -o remount,noexec /mnt/test
Code: Select all
mount --bind /source /target
Code: Select all
mount --rbind /source /target
Code: Select all
mount -t tmpfs tmpfs /mnt/ram
Code: Select all
umount /mnt/test
Code: Select all
umount -l /mnt/test
21.13. Vérifier un système de fichiers
Code: Select all
fsck /dev/sdb1
22. Exemple complet : afficher le type d’un fichier
Code: Select all
#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
struct stat st;
if (argc != 2) {
printf("usage: %s <path>\n", argv[0]);
return 1;
}
if (lstat(argv[1], &st) == -1) {
perror("lstat");
return 1;
}
if (S_ISREG(st.st_mode)) {
printf("fichier regulier\n");
}
else if (S_ISDIR(st.st_mode)) {
printf("repertoire\n");
}
else if (S_ISLNK(st.st_mode)) {
printf("lien symbolique\n");
}
else if (S_ISCHR(st.st_mode)) {
printf("peripherique caractere\n");
}
else if (S_ISBLK(st.st_mode)) {
printf("peripherique bloc\n");
}
else if (S_ISFIFO(st.st_mode)) {
printf("fifo\n");
}
else if (S_ISSOCK(st.st_mode)) {
printf("socket\n");
}
else {
printf("type inconnu\n");
}
printf("inode : %lu\n", (unsigned long)st.st_ino);
printf("taille: %ld\n", (long)st.st_size);
return 0;
}
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
DIR *dir;
struct dirent *entry;
if (argc != 2) {
printf("usage: %s <directory>\n", argv[0]);
return 1;
}
dir = opendir(argv[1]);
if (dir == NULL) {
perror("opendir");
return 1;
}
while ((entry = readdir(dir)) != NULL) {
printf("nom : %s\n", entry->d_name);
printf("inode : %lu\n\n", (unsigned long)entry->d_ino);
}
closedir(dir);
return 0;
}
Code: Select all
#include <stdio.h>
#include <sys/statvfs.h>
int main(int argc, char *argv[])
{
struct statvfs sv;
if (argc != 2) {
printf("usage: %s <path>\n", argv[0]);
return 1;
}
if (statvfs(argv[1], &sv) == -1) {
perror("statvfs");
return 1;
}
printf("Taille bloc E/S : %lu\n", sv.f_bsize);
printf("Taille fragment : %lu\n", sv.f_frsize);
printf("Blocs total : %lu\n", (unsigned long)sv.f_blocks);
printf("Blocs libres : %lu\n", (unsigned long)sv.f_bfree);
printf("Blocs dispo user : %lu\n", (unsigned long)sv.f_bavail);
printf("Inodes total : %lu\n", (unsigned long)sv.f_files);
printf("Inodes libres : %lu\n", (unsigned long)sv.f_ffree);
printf("Nom fichier max : %lu\n", sv.f_namemax);
return 0;
}
Code: Select all
#include <stdio.h>
#include <mntent.h>
int main(void)
{
FILE *fp;
struct mntent *mnt;
fp = setmntent("/proc/mounts", "r");
if (fp == NULL) {
perror("setmntent");
return 1;
}
while ((mnt = getmntent(fp)) != NULL) {
printf("source : %s\n", mnt->mnt_fsname);
printf("target : %s\n", mnt->mnt_dir);
printf("type : %s\n", mnt->mnt_type);
printf("opts : %s\n\n", mnt->mnt_opts);
}
endmntent(fp);
return 0;
}
26.1. L’inode ne contient pas le nom
Erreur fréquente :
Code: Select all
inode = nom + contenu
Code: Select all
répertoire = nom -> inode
inode = métadonnées + pointeurs
blocs = contenu
Erreur fréquente :
Code: Select all
statvfs() sert à récupérer la liste des montages
Code: Select all
statvfs() -> informations sur le système de fichiers contenant un chemin
getmntent() -> lecture des entrées de montage
Erreur fréquente :
Code: Select all
noexec bloque seulement les utilisateurs normaux
Code: Select all
MS_NOEXEC interdit l’exécution depuis ce montage.
Erreur fréquente :
Code: Select all
lecture seule = seul root peut écrire
Code: Select all
MS_RDONLY = montage en lecture seule.
Aucune écriture normale n’est autorisée via ce montage.
Erreur fréquente :
Code: Select all
bind mount = symlink créé par le noyau
Code: Select all
bind mount = montage d’une partie existante de l’arborescence ailleurs.
Erreur fréquente :
Code: Select all
lazy unmount = tuer les processus qui utilisent le montage
Code: Select all
MNT_DETACH détache le montage de l’arborescence.
Les ressources sont libérées quand elles ne sont plus utilisées.
Erreur fréquente :
Code: Select all
remount = umount puis mount
Code: Select all
MS_REMOUNT modifie les options d’un montage existant.
À retenir absolument :
- Linux expose beaucoup de périphériques via `/dev`.
- Les disques sont divisés en partitions.
- Une partition peut contenir un système de fichiers.
- Un système de fichiers organise fichiers, répertoires, inodes, blocs et métadonnées.
- L’inode contient les métadonnées et les pointeurs vers les blocs, mais pas le nom.
- Le nom est stocké dans une entrée de répertoire.
- Un répertoire associe un nom à un numéro d’inode.
- Le VFS uniformise l’accès aux différents systèmes de fichiers.
- Les systèmes journalisés réduisent les problèmes après crash.
- Linux utilise une seule arborescence commençant à `/`.
- Les systèmes de fichiers sont attachés via des points de montage.
- `mount()` monte un système de fichiers.
- `umount()` démonte un système de fichiers.
- `umount2()` permet un démontage avec options.
- `MNT_DETACH` fait un lazy unmount.
- `MNT_FORCE` force certains démontages, surtout utiles sur certains systèmes réseau.
- `MS_RDONLY` monte en lecture seule.
- `MS_NOEXEC` interdit l’exécution depuis le montage.
- `MS_NOSUID` ignore les bits setuid/setgid.
- `MS_NODEV` bloque l’usage des fichiers périphériques.
- `MS_REMOUNT` modifie les options à la volée.
- `MS_BIND` crée un bind mount.
- `MS_REC` permet un bind récursif.
- `tmpfs` est un système de fichiers en mémoire virtuelle.
- `stat()` donne des infos sur un fichier par chemin.
- `lstat()` donne des infos sans suivre les liens symboliques.
- `fstat()` donne des infos sur un fichier via fd.
- `statvfs()` donne des infos sur un système de fichiers via chemin.
- `fstatvfs()` fait pareil via fd.
- `getmntent()` lit les entrées de montage.
Code: Select all
API Rôle
------------------------------------------------------------
mount() Monter un système de fichiers
umount() Démonter simplement un système de fichiers
umount2() Démonter avec flags avancés
stat() Infos sur un fichier depuis un chemin
lstat() Infos sur un chemin sans suivre symlink
fstat() Infos sur un fichier depuis un fd
statvfs() Infos sur le système de fichiers depuis un chemin
fstatvfs() Infos sur le système de fichiers depuis un fd
setmntent() Ouvrir un fichier de table de montage
getmntent() Lire une entrée de montage
endmntent() Fermer la table de montage
opendir() Ouvrir un répertoire
readdir() Lire une entrée de répertoire
closedir() Fermer un répertoire
Code: Select all
Structure Rôle
------------------------------------------------------------
struct stat Informations sur un fichier
struct dirent Entrée de répertoire
struct statvfs Informations globales sur le système de fichiers
struct mntent Entrée de montage
Code: Select all
Flag Rôle
------------------------------------------------------------
MS_RDONLY Montage en lecture seule
MS_NOEXEC Interdit l’exécution depuis le montage
MS_NOSUID Ignore setuid/setgid
MS_NODEV Interdit l’usage des fichiers périphériques
MS_NOATIME Ne met pas à jour atime
MS_NODIRATIME Ne met pas à jour atime des répertoires
MS_RELATIME Mise à jour atime optimisée
MS_REMOUNT Modifie les options d’un montage existant
MS_BIND Bind mount
MS_REC Bind récursif
MNT_DETACH Lazy unmount
MNT_FORCE Démontage forcé dans certains cas
MNT_EXPIRE Expiration de montage
Code: Select all
Linux :
/ comme racine unique
points de montage
/dev pour les périphériques
inodes
VFS
open/read/write
Windows :
C:\, D:\, E:\
lettres de lecteur ou points de montage NTFS
objets de périphériques
MFT pour NTFS
I/O Manager + drivers FS
CreateFile/ReadFile/WriteFile
Code: Select all
Linux inode
proche conceptuellement d’une entrée technique décrivant le fichier,
mais ce n’est pas la même chose que la MFT NTFS.
Linux VFS
comparable à une couche d’abstraction qui uniformise les systèmes de fichiers.
Linux mount point
comparable à l’idée d’attacher un volume à un chemin,
plutôt qu’utiliser seulement des lettres de lecteur.
Ce chapitre est fondamental parce qu’il explique ce qu’il y a derrière les appels simples comme :
Code: Select all
open()
read()
write()
close()
stat()
Après ce chapitre, il faut plutôt penser :
Code: Select all
chemin
|
v
répertoires successifs
|
v
entrée de répertoire
|
v
numéro d’inode
|
v
inode
|
v
blocs de données
Code: Select all
périphérique bloc
|
v
partition
|
v
système de fichiers
|
v
point de montage
|
v
arborescence Linux
|
v
VFS
|
v
appels système utilisateur
