274 lines
9 KiB
Markdown
274 lines
9 KiB
Markdown
---
|
||
title: "Les attributs de fichiers"
|
||
date: 2018-10-16
|
||
categories: ["Programmation système", "Cours"]
|
||
tags: ["fichier", "i-node"]
|
||
---
|
||
|
||
Les attributs de fichiers représentent toutes les informations dont dispose le
|
||
système sur les fichiers et répertoires : propriétaire, groupe permissions,
|
||
taille, horodatage etc.
|
||
|
||
## Système de fichiers
|
||
|
||
Un système de fichiers (ou système de gestion des fichiers) représente la façon
|
||
de stocker les fichiers, leurs informations et les organiser et sur un support
|
||
physique de stockage de masse. Parmi les plus courant on peut citer :
|
||
|
||
- Ext4, système de fichier par défaut sur la plupart des installation
|
||
GNU/Linux
|
||
- NTFS, système de fichiers par défaut de Microsoft Windows
|
||
- YAFFS pour Android
|
||
- APFS pour les machines Apple (MacOS, iOS, et Apple TV)
|
||
- ZFS pour les Unix
|
||
|
||
C'est bien entendu une liste non exhaustive, on pourrait citer des système plus
|
||
ancien comme FAT, UFS, HFS etc. Ou d'autres spécifique comme CEPH (système de
|
||
fichiers pour clusters).
|
||
|
||
## Anatomie d'un stockage de masse
|
||
|
||
Dans les premiers secteurs d'un disque dur, on trouve la table de partitions
|
||
cartographiant le disque. Il en existe deux type principaux : BPT et MBR Du type
|
||
de MBR découlera le nombres de partitions : 4 pour MD-DOS et pas de limites pour
|
||
le GPT par exemple.
|
||
|
||

|
||
|
||
### Gestion des fichiers dans le cas de la FAT
|
||
|
||
Le système de fichier FAT de Microsoft utilise le chainage de blocs : la table
|
||
d'allocation de fichiers contient l'adresse du premier bloc du fichiers. À la
|
||
fin de ce bloc, on obtient l'adresse du suivant. Avec ce système, la lecture
|
||
séquentielle est lente.
|
||
|
||
### Le cas le L'UFS
|
||
|
||
L'UFS pour *Unix File System* utilise, comme la plupart des systèmes de fichiers
|
||
moderne sous les systèmes Unix, utilise les i-nodes. Un numéro unique d'inode
|
||
est attribué à chaque fichier. Chaque fichier a un seul inode mais il peut avoir
|
||
plusieurs nom
|
||
|
||

|
||
|
||
Un inode peut aussi contenir d'autres informations comme le créateurs, les accès
|
||
etc.
|
||
|
||
## Appels Systèmes
|
||
|
||
La lecture des attributs de fichiers se fait par un appel système `stat()`.
|
||
|
||
```c
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <unistd.h>
|
||
|
||
int stat(const char *pathname, struct stat *statbuf);
|
||
```
|
||
|
||
Récupère les informations du fichiers pointé par `*pathname` et rempli la
|
||
structure `*statbuf`. En cas de succès renvoie 0 sinon -1 et positionne `errno`.
|
||
|
||
Il est aussi possible d'utiliser `fstat()`, variante de `stat()` mais utilisant
|
||
un descripteur de fichier.
|
||
|
||
```c
|
||
int fstat(int fd, struct stat *statbuf);
|
||
```
|
||
|
||
`lstat()` est utiliser dans le cas de lien symbolique, cet appel est utiliser
|
||
afin de récupérer les informations sur le lien lui-même et non le fichier
|
||
pointé.
|
||
|
||
```c
|
||
int lstat(const char *pathname, struct stat *statbuf);
|
||
```
|
||
|
||
### La structure stat
|
||
|
||
Voici les informations contenues dans la structure de type `stat`.
|
||
|
||
```c
|
||
struct stat {
|
||
dev_t st_dev; /* Périphérique */
|
||
ino_t st_ino; /* numéro d'inode */
|
||
mode_t st_mode; /* protection */
|
||
nlink_t st_nlink; /* nombres de lien physiques */
|
||
uid_t st_uid ; /* UID du propriétaire */
|
||
gui_t st_gid; /* UID du groupe */
|
||
dev_t st_rdev; /* type de périphérique */
|
||
off_t st_size; /* taille totale en octets */
|
||
blksize_t st_blksize; /* taille de bloc pou E/S */
|
||
blkcnt_t st_blocks; /* nombres de blocks de 512o alloués */
|
||
struct timespec st_atim; /* heure du dernier accès */
|
||
struct timespec st_mtim; /* heure de la dernière modification */
|
||
struct timespec st_ctim; /* heure du dernier changemet d'état */
|
||
}
|
||
```
|
||
|
||
`st_rdev`, `st_blksize`, et `st_blocks` ne sont pas requises par POSIX.1 mais
|
||
définies comme extensions dans SUS.
|
||
|
||
- `st_mode` : Permissions d’accès au fichier ainsi que le type de ce dernier
|
||
(répertoire, socket, fichier normal, etc.)
|
||
- `st_ino` :Numéro de référence du fichier (SUSv4), identifiant unique
|
||
d’accès au contenu du fichier, plus communément sous UNIX : numéro
|
||
d’i-inœud
|
||
- `st_dev` : Numéro du périphérique qui contient le système de fichier auquel
|
||
se rapporte le numéro d’i-inœud
|
||
- `st_nlink` : Nombre de liens physiques sur i-inœud (un fichier peut avoir
|
||
plusieurs noms). L’appel système `unlink()` décrémente cette valeur
|
||
jusqu'à 0 alors le fichier sera réellement supprimé.
|
||
- `st_size` : Taille du fichier mesurée en octets (uniquement utile pour les
|
||
fichiers normaux)
|
||
|
||
### tests sur les types de fichiers
|
||
|
||
Ces extraits de codes permettent de tester les types de fichiers. `statbuf`
|
||
étant le retour de `stat()` ou de ses dérivées.
|
||
|
||
```c
|
||
if (S_ISREG(statbuf.st_mode)) {
|
||
printf "Regular file";
|
||
}
|
||
if (S_ISDIR(statbuf.st_mode)) {
|
||
printf "Directory file";
|
||
}
|
||
if (S_ISCHR(statbuf.st_mode)) {
|
||
printf "Character special file";
|
||
}
|
||
if (S_ISBLK(statbuf.st_mode)) {
|
||
printf "Block special file";
|
||
}
|
||
if (S_ISFIFO(statbuf.st_mode)) {
|
||
printf "Pipe or Fifo";
|
||
}
|
||
if (S_ISLNK(statbuf.st_mode)) {
|
||
printf "Symbolic link";
|
||
}
|
||
if (S_ISSOCK(statbuf.st_mode)) {
|
||
printf "Socket";
|
||
}
|
||
```
|
||
|
||
#### Exemple de code
|
||
|
||
```c
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <unistd.h>
|
||
int main(int argc, char *argv[]) {
|
||
int i;
|
||
struct stat statbuf;
|
||
for (i = 1; i < argc; i++) {
|
||
printf("%s: ", argv[i]);
|
||
if (lstat(argv[i], &statbuf) < 0) {
|
||
perror("Unable to get stats");
|
||
continue;
|
||
}
|
||
if (S_ISREG(statbuf.st_mode)) {
|
||
printf("regular\n");
|
||
}
|
||
else if (S_ISDIR(statbuf.st_mode)) {
|
||
printf("directory\n");
|
||
}
|
||
else if (S_ISCHR(statbuf.st_mode)) {
|
||
printf("character special\n");
|
||
}
|
||
else if (S_ISBLK(statbuf.st_mode)) {
|
||
printf("block special\n");
|
||
}
|
||
else if (S_ISFIFO(statbuf.st_mode)) {
|
||
printf("fifo\n");
|
||
}
|
||
else if (S_ISLNK(statbuf.st_mode)) {
|
||
printf("symbolic link\n");
|
||
}
|
||
else if (S_ISSOCK(statbuf.st_mode)) {
|
||
printf("socket\n");
|
||
}
|
||
else {
|
||
printf("*unknown*\n");
|
||
}
|
||
}
|
||
exit(EXIT_SUCCESS);
|
||
}
|
||
```
|
||
|
||
##### Exécution
|
||
|
||
```shell
|
||
$ ./stat-file /etc /etc/passwd /dev/null /dev/sda
|
||
/etc: directory
|
||
/etc/passwd: regular
|
||
/dev/null: character special
|
||
/dev/sda: block special
|
||
```
|
||
|
||
### Tests sur les permissions de fichiers
|
||
|
||
Les extraits de codes suivant permettent des tester les permissisons sur les
|
||
fichiers et répertoires.
|
||
|
||
```c
|
||
if (statbuf.st_mode & S_IRUSR) { printf "User can read"; }
|
||
if (statbuf.st_mode & S_IWUSR) { printf "User can write"; }
|
||
if (statbuf.st_mode & S_IXUSR) { printf "User can execute"; }
|
||
if (statbuf.st_mode & S_IRGRP) { printf "Group can read"; }
|
||
if (statbuf.st_mode & S_IWGRP) { printf "Group can write"; }
|
||
if (statbuf.st_mode & S_IXGRP) { printf "Group can execute"; }
|
||
if (statbuf.st_mode & S_IROTH) { printf "Others can read"; }
|
||
if (statbuf.st_mode & S_IWOTH) { printf "Others can write"; }
|
||
if (statbuf.st_mode & S_IXOTH) { printf "Others can execute";}
|
||
```
|
||
|
||
### changer les permissions sur un fichier
|
||
|
||
```c
|
||
#include <sys/stat.h>
|
||
int chmod(const char *pathname, mode_t mode);
|
||
```
|
||
|
||
Modifie les permissions du fichier référencé par `*pathname`
|
||
|
||
```c
|
||
in fchmod(int fd, mode_t mode);
|
||
```
|
||
|
||
Modifie les permissions tout comme `chmod()` mais prend un descripteur de
|
||
fichier en paramètre.
|
||
|
||
Dans les deux cas, `mode` est un masquage de bits avec les paramètres suivants :
|
||
|
||
| mode | octal | utilisation |
|
||
|---------|-------|--------------------------------------------------------
|
||
| S_IRWXU | 00700 | Le propriétaire a le droit de lire, écrire, exécuter |
|
||
| S_IRUSR | 00400 | L’utilisateur a le droit de lire |
|
||
| S IWUSR | 00200 | L'utilisateur a le droit d'écrire |
|
||
| S IXUSR | 00100 | L'utilisateur a le droit d'exécuter |
|
||
| S_IRWXG | 00070 | Le groupe a le droit de lire, écrire, exécuter |
|
||
| S_IRGRP | 00040 | Le groupe a le droit de lire |
|
||
| S IWGRP | 00020 | Le groupe a le droit d'écrire |
|
||
| S IXGRP | 00010 | Le groupe a le droit d'exécuter |
|
||
| S_IRWXO | 00007 | Le propriétaire a le droit de lire, écrire, exécuter |
|
||
| S_IROTH | 00004 | Les autres ont le droit de lire |
|
||
| S IWOTH | 00002 | Les autres onr le droit d'écrire |
|
||
| S IXOTH | 00001 | Les autres ont le droit d'exécuter |
|
||
| | | S_ISUID, S_ISGID, S_ISVTX, cf. man 2 chmod
|
||
|
||
En cas de succès, retourne 0, sinon -1 et positionne `errno`
|
||
|
||
### Modifier l'appartenance d'un fichier
|
||
|
||
```c
|
||
#include <unistd.h>
|
||
int chown(const char *path, uid_t owner, gid_t group);
|
||
```
|
||
|
||
Modifie l'appartenance d'un fichier pointé par `*path`. comme pour `stat()`, il
|
||
existe un variante avec un descripteur de fichiers : `fchown()` et une pour les
|
||
lien symboliques `lchmod()`.
|
||
|
||
En cas de succès, retourne 0, sinon -1 et positionne `errno`
|