TD 3 : Représentation des fichiers sur le disque dur |

module type DISKPARAMS = sig val block_size : int val block_nb : int end module type DISKDATA = sig include DISKPARAMS val blocks : int array array end |
Empty :
module Empty (P : DISKPARAMS) : DISKDATA |
block_size) et nombre de blocs (block_nb), construit un tableau
de blocs vides (blocks) correspondant à ces caractéristiques.Fromfile suivant au fichier
disk.mli et écrire son implantation dans le fichier disk.ml.
module type FILENAME = sig val name : string end module Fromfile (F : FILENAME) : DISKDATA |
Fromfile initialise les paramètres du
disque et son contenu avec les données d'un fichier dont le nom est
passé en argument. Le fichier commence par les valeurs block_size et
block_nb, stockées en binaire, suivies des blocs d'entiers écrits
les uns derrière les autres. Pour lire les entiers stockés dans le
fichier en binaire, utiliser input_binary_int.read et write et la fonction dump qui
sauve dans un fichier la totalité du disque au format utilisé par
Fromfile. Pour cela, ajouter au fichier d'interface disk.mli le
foncteur Makedisk suivant :
module type DISK = sig include DISKDATA val read : int -> int array -> int -> unit val write : int -> int array -> int -> unit val dump : string -> unit end module Makedisk (P : DISKDATA) : DISK |
disk.ml son implantation. La fonction
read i buffer offset permet de placer les données du bloc d'indice i
dans le tampon buffer à partir de la position offset. La fonction
write effectue l'opération inverse. On supposera à chaque fois qu'il
y a suffisamment de place dans le tampon à partir de la position
offset pour lire (resp. recevoir) la totalité d'un bloc. On
utilisera une assertion pour vérifier cette propriété.100 blocs vides de taille 256.
100 blocs de taille 256.
simplefs.mli et
simplefs.ml.Filesystem pour le programmeur du système de fichiers et l'autre
externe UserFs, plus restreinte, pour l'utilisateur. Les
interfaces de départ auxquelles nous ajouterons au fur et à mesure
les fonctions et les types nécessaires pour la manipulation des
fichiers sont les suivantes
module type UserFs = sig exception File_system_exception of string exception File_system_error of string end module type Filesystem = sig (* fonctions externes *) include UserFs end |
module Mount : functor (D : Disk.DISK) -> Filesystem |
0 représente le type de l'inode
(0 = S_REG, 1 = S_DIR et 2 = S_LNK); l'entier à l'indice
1 contient le nombre de liens vers cet inode; l'entier à l'indice
2 contient la taille du fichier et les autres entiers correspondent
à la table des blocs. Il n'y a pas d'indirection dans la table des
blocs. La taille maximale d'un fichier est donc : D.block_size * (D.block_size - 3)
read_inode qui lit sur le
disque l'inode dont le numéro de bloc est passé en argument et
retourne son contenu sous la forme d'un type inode.file_kind et stats dans le module
UserFs.
type file_kind = S_REG | S_DIR | S_LNK type stats = { st_dev : int; st_ino : int; st_kind : file_kind; st_nlink : int; mutable st_size : int} |
Filesystem.
type inode = { mutable reference_number : int; stats : stats; blocktbl : int array } (* identificateur d'un bloc *) type bid = int (* lit un inode depuis un bloc disque *) val read_inode : bid -> inode |
reference_number contient le nombre de descripteurs
ouverts sur cet inode, il sera initialisé à 0. Le champs stats
contient les différentes informations lues sur disque, dans lequel le
numéro de partition (st_dev) est toujours égal à 0. Enfin, le
tableau blocktbl contient la table des blocs.
1. Lire son contenu sur le
disque est le stocker dans une référence de nom root_inode.Filesystem une fonction namei qui retourne
l'inode du fichier dont le nom est passé en argument.
(* retourne l'inode associé à un chemin *) (* nous nous restreignons ici à la racine *) val namei : path -> inode |
File_system_exception lorsque le nom passé en argument est
différent de / et retourne systématiquement root_inode.
UserFs une fonction stat ui retourne les
informations sur le fichier dont le nom est passé en argument (pour
l'instant toujours /).
val stat : string -> stats |
stat et la tester avec l'inode
de la racine.
file_descr qui contient
un inode, une position dans le fichier et un mode d'ouverture
(O_RDONLY, O_WRONLY, etc.). Pour se simplifier, on pourra
décomposer la position courante en un numéro de bloc et une position
relative au bloc, puis définir une fonction desc_offset qui retourne
la position absolue.openfile qui retourne un descripteur ouvert sur
le fichier dont le nom est passé en argument (/ pour nous). On
n'utilisera pas les drapeaux O_CREAT et O_EXCL qui ne s'appliquent
pas dans notre cas. Dans un premier temps on ignorera les options et
on ouvrira systématiauement le fichier en lecture.
close qui ferme un descripteur de fichier.read qui a le même comportement que celle du
module Unix. Dans un premier temps on ignorera les blocs vides qui
peuvent être représentés par le bloc 0.write_super_block qui écrit le super-bloc sur le disque.
alloc_block qui retourne le numéro du premier
bloc libre et met à jour la liste des blocs libres comme vu en cours. S'il n'y a plus de blocs libres, la fonction lève une exception File_system_exception.free_block qui libère le bloc dont le numéro est
passé en argument.
write_inode qui écrit un inode sur le disque.
newfs qui initialise le disque comme un système de fichier vide.
openfile.
lseek qui permet de changer la position courante du
descripteur de fichier. Lorsque lseek déplace le descripteur au delà de la
fin du fichier, la taille du fichier n'est pas modifiée. En revanche, dès
qu'une écriture aura lieu celle-ci augmentera la taille du fichier. Les
blocs intermédiaires ne sont pas alloués, un 0 est laissé dans la table des
blocs de l'inode.
write.
umount qui écrit le contenu du système de fichiers dans un fichier. On prendra soin de bien synchroniser les données représentées comme des structures en mémoire avec celles de notre « disque ».
This document was translated from LATEX by HEVEA and HACHA.