--- 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. ![Schéma de fonctionnement d'un systeme de fichier](images/schema_hdd.svg) ### 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 ![Schéma de fonctionnement des inodes](images/schema_inodes.svg) 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 #include #include 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 #include #include #include #include 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 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 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`