Table des descripteurs, table des fichiers ouverts, table des inodes en mémoire.
Ouvrir un fichier, lire (cache de blocs de disque), écrire, fermer, rediriger, se déplacer.
Manipuler l'inode.
Manipuler des répertoires, des liens symboliques.
Soit P la partition du cache où I doit figurer. Parcourir P à la recherche de I. Si I n'est pas trouvé dans P allouer la première entrée libre de tim (soit E), (cette entrée contenait l'inode I', de la partition P') si I' est modifié, le copier sur disque, charger l'inode I dans E, initialiser le compteur de références de E à 1, retirer E de la partition P' (le pointeur arrière est utile), ajouter E en tête de la partition P, retirer E de la liste libre. Sinon (I est trouvé en E) Si E est libre (pointeurs de liste libre non nuls) retirer E de la liste libre (le pointeur arrière est utile), initialiser le compteur de références de E à 1. Sinon (I est accédé par un processus) incrémenter le compteur de références de E.
nom ouverture POSIX/C structure accédée open oui p tdf+tfo+tim fopen oui C tdf+tfo+tim creat oui p tdf+tfo+tim close oui p tdf[+tfo[+tim[+blocs]]] fclose oui C tdf[+tfo[+tim[+blocs]]] read oui p tdf+tfo+tim+blocs fread oui C tdf+tfo+tim+blocs write oui p tdf+tfo+tim+blocs fwrite oui C tdf+tfo+tim+blocs lseek oui p tdf+tfo fseek oui C tdf+tfo dup oui p tdf+tfo dup2 oui p tdf+tfo fstat (*) oui p tdf+tfo+tim stat (**) non p tim link non p tim unlink non p tim rename non p tim fchmod oui p tdf+tfo+tim chmod non p tim fchown oui p tdf+tfo+tim chown non p tim opendir oui p tdf+tfo+tim closedir oui p tdf+tfo+tim readdir oui p tdf+tfo+tim+bloc lstat non p tim symlink non p tim+blocs readlink non p tim+blocs fgetc oui C tdf+tfo+tim+bloc fputc oui C tdf+tfo+tim+bloc fgets oui C tdf+tfo+tim+blocs fputs oui C tdf+tfo+tim+blocs fscanf oui C tdf+tfo+tim+blocs fprintf oui C tdf+tfo+tim+blocs (*): fstat sur un lien symbolique accède à tdf+tfo+tim+blocs (**): stat sur un lien symbolique accède à tim+blocs
int open(const char *ref, int mode[, mode_t droits]);La fonction retourne le descripteur alloué par le noyau (numéro de l'entrée allouée dans tdf). Le premier argument est le nom de fichier à ouvrir (référence relative ou absolue). Le second argument est le mode d'ouverture, présenté sous la forme de constantes dont on fait l'union (activation d'une opération à l'ouverture, e.g.
O_WRONLY|O_APPEND). Le troisième argument n'est fourni qu'en création. Il fixe les droits d'accès du fichier pour toutes les catégories d'utilisateurs (S_IRUSR, S_IWUSR, S_IXUSR, S_IRWXU pour le propriétaire, mêmes noms suffixés par GRP et G pour le groupe et par OTH et O pour les autres).
mode ouverture inexistant existant O_RDONLY lecture seule erreur O_WRONLY écriture seule erreur O_WRONLY|O_APPEND écriture en queue erreur O_RDWR lecture+écriture erreur O_WRONLY|O_CREAT|O_TRUNC écriture seule création réinitialisé O_WRONLY|O_CREAT|O_EXCL écriture seule création erreurVoici le travail effectué par le noyau à l'ouverture d'un fichier:
Allocation d'un descripteur dans tdf, Allocation d'une entrée dans tfo, compteur à 0, mode, offset en début de fichier (sauf O_APPEND), Convertir la référence en son numéro d'inode (algorithme namei qui parcourt l'arborescence), Chercher l'inode dans tim, S'il y est et est libre, l'allouer et initialiser le compteur de référence à 1, S'il y est et n'est pas libre, incrémenter le compteur de référence, S'il n'y est pas, allouer une entrée libre de tim, y charger l'inode et initialiser le compteur de référence à 1, Retourner le numéro du descripteur alloué.
int close(int desc);Voici le travail effectué par le noyau à la fermeture d'un fichier:
Libération du descripteur desc de tdf, Décrémenter le compteur de l'entrée de tfo pointée, S'il devient nul, décrémenter le compteur de l'entrée de tim pointée, S'il devient nul et si le compteur de liens de l'inode est nul, Supprimer le fichier (libérer les blocs de données et l'inode).
Soit P la partition du cache où B doit figurer. Parcourir P à la recherche de B. Si B n'est pas trouvé dans P allouer la première entrée libre du cache (soit E), (cette entrée contenait le bloc B', de la partition P') si B' est modifié, le copier sur disque, charger le bloc B dans E, retirer E de la partition P' (le pointeur arrière est utile), ajouter E en tête de la partition P, retirer E de la liste libre. Sinon (B est trouvé en E) Si E est libre (pointeurs de liste libre non nuls) retirer E de la liste libre (le pointeur arrière est utile), Sinon (B est accédé par un processus) attendre que B soit libéré par le processus qui y accède.
ssize_t read(int desc, void *tampon, size_t nb);L'appel lit au plus nb octets à partir de la position courante dans le fichier (champ offset de la table tfo). Les octets sont transférés du cache des blocs de disque dans le tampon pointé (qui doit exister et avoir une taille suffisante). La fonction retourne le nombre d'octets effectivement lus (éventuellement 0).
Accès à tdf[desc] Accès à tfo Vérification du mode d'ouverture Accès à tim Vérification des droits Boucle de lecture (tant que moins de nb octets ont été lus) Convertir l'offset en un numéro d'entrée dans tbf (0 à 12) Accès à tbf dans tim Soit B le numéro du bloc à lire (déterminer B peut nécessiter de lire des blocs d'indirection) Chercher B dans le cache (chargement du disque si B n'est pas dans le cache) Jusqu'à concurrence de nb octets ou de la fin de bloc, copier du cache dans *tampon Avancer l'offset (si nb octets ont été lus ou si l'offset est égal à la taille, sortir) Retourner le nombre d'octets lus
ssize_t write(int desc, void *tampon, size_t nb);L'appel écrit nb octets du tampon dans le cache (l'écriture sur disque est différée. Elle n'intervient que quand l'entrée du cache est réallouée pour un autre bloc). L'écriture se fait à la suite de l'offset dans le fichier. L'algorithme d'écriture est similaire à celui de lecture.
int dup(int desc); /*copie le descripteur desc dans la première entrée libre de tdf*/ int dup2(int d_source, int d_copie); /*duplique d_source dans d_copie*/ /*il y a fermeture de d_copie au préalable si nécessaire*/
off_t lseek(int desc, off_t distance, int origine);L'offset est modifié avec le déplacement distance. L'origine du déplacement est défini par l'argument origine. S'il vaut SEEK_SET, l'origine est le début du fichier (positionnement absolu en distance). S'il vaut SEEK_CUR, l'origine est l'offset (on peut se déplacer vers l'arrière avec une distance négative). S'il vaut SEEK_END, l'origine est la fin de fichier (on peut se déplacer vers l'avant, ce qui étend artificiellement le fichier: les éventuels nouveaux blocs ne sont créés que s'ils sont accédés).
int fstat(int desc, struct stat *pstat);L'inode est copié dans la structure stat pointée par pstat. La structure stat est ainsi définie:
struct stat { dev_t st_dev; /*partition où se trouve le fichier*/ ino_t st_ino; /*numéro d'inode*/ mode_t st_mode; /*type et droits*/ nlink_t st_nlink; /*nombre de liens*/ uid_t st_uid; /*propriétaire*/ gid_t st_gid; /*groupe propriétaire*/ off_t st_size /*taille (ou (majeur, mineur))*/ time_t st_atime; /*dernier accès*/ time_t st_mtime; /*dernière modification du fichier*/ time_t st_ctime; /*dernière modification de l'inode*/ }On peut exploiter le champ st_mode pour déterminer le type d'un fichier avec les macro fonctions suivantes:
S_ISREG(pstat->st_mode) /*fichier régulier*/ S_ISDIR(pstat->st_mode) /*fichier répertoire*/Pour tester les droits d'accès, on emploie un masquage approprié de st_mode:
/*pour tester si accessible en lecture et écriture propriétaire:*/ if (((pstat->st_mode) & S_IRUSR) && ((pstat->st_mode) & S_IWUSR)) {...}L'appel POSIX stat permet d'effectuer la même consultation sans ouvrir le fichier:
int stat(const char *ref, struct stat *pstat);
int link(const char *ancien, const char *nouveau); /*incrémente le compteur de liens de ancien*/ /*et ajoute la référence nouveau dans le répertoire courant*/ /*nouveau et ancien ont le même numéro d'inode*/ int unlink(const char *ref); /*décrémente le compteur de référence du fichier *ref*/ /*supprime la référence *ref du répertoire courant*/ /*si le fichier n'est plus référencé, il est supprimé*/ /*(ses blocs sont libérés)*/ int chmod(const char *ref, mode_t mode); int fchmod(int desc, mode_t mode); /*nouveaux droits pour le fichier*/ int chown(const char *ref, uid_t id_prop, gid_t id_grp); int fchown(int desc, uid_t id_prop, gid_t id_grp); /*nouveaux propriétaires*/
struct dirent { ... char d_name[NAME_MAX]; /*nom de fichier*/ ... ino_t d_ino; /*numéro d'inode*/ ... }On peut chercher un numéro d'inode ou un nom de fichier dans un répertoire avec les appels POSIX suivants (la structure DIR est une structure opaque du système. Elle joue le rôle de descripteur, c'est-à-dire de pointeur sur tdf):
DIR *opendir(const char *ref); /*ouvrir le répertoire*/ struct dirent *readdir(DIR *pdir); /*lire l'entrée suivante et avancer*/ /*la structure retournée en résultat contient l'entrée lue*/ /*NULL en fin de fichier*/ int closedir(DIR *pdir); /*fermer le répertoire*/
FILE *fopen(const char *ref, const char *mode); /*mode: "r" (O_RDONLY), "w" (O_WRONLY|O_CREAT|O_TRUNC), "a" (O_WRONLY|O_CREAT|O_APPEND)*/ /*"r+" (O_RDWR), "w+" (O_RDWR|O_CREAT|O_TRUNC), "a+" (O_RDWR|O_CREAT|O_APPEND)*/ int fclose(FILE *f); int fread(void *tampon, size_t taille_e, size_t nb_e, FILE *f); /*lecture de nb_e éléments de taille taille_e octets*/ int fwrite(void *tampon, size_t taille_e, size_t nb_e, FILE *f); /*écriture de nb_e éléments de taille taille_e octets*/ int fseek(FILE *f, long int offset, int origine); /*origine=SEEK_SET, SEEK_CUR, SEEK_END*/
/*fichiers de caractères*/ int fgetc(FILE *f); /*retourne un entier, négatif en cas d'erreur*/ int fputc(int c, FILE *f); /*fichiers de lignes de caractères*/ char *fgets(char *tampon, int nb, FILE *f); /*lecture d'une ligne d'au plus nb-1 octets*/ /*la ligne lue est terminée par un \0*/ /*le résultat pointe sur la ligne lue*/ /*retourne NULL en cas d'erreur*/ int fputs(char *tampon, FILE *f); /*écrit une chaîne terminée par \0*/ /*le \0 n'est pas écrit*/ /*fichiers de données formatées*/ int fscanf(FILE *f, const char *format, ...); int fprintf(FILE *f, const char *format, ...);
int lstat(const char *ref, struct stat *pstat); /*lit l'inode du lien*/ ssize_t readlink(const char *ref, char *tampon, size_t taille); /*l'argument taille donne le nombre d'octets libres du tampon*/ /*le tampon contient le chemin vers le lié, non terminé par \0*/ int symlink(const char *lié, const char *lien); /*crée un lien symbolique liant lien à lié*/