V. Quelques informations▲
V-A. La segmentation en blocks pour les blocks device▲
Comme je l'ai laissé entendre, sans jamais développer le sujet, les données d'un fichier (ou répertoire) sont souvent fragmentées sur le disque. Cela dépend de la topologie du filesystem, mais il est bien souvent plus simple de prendre le premier block libre que l'on trouve que de déplacer d'importantes masses de données sous prétexte que l'on se refuse à fragmenter un fichier.
Dans le cas de minix, la partition est divisée comme ceci :
Les deux premiers éléments dressent une liste des inodes disponibles sur la partition, puis des blocks disponibles (c'est à dire l'espace de la partition en octets divisé par la taille d'un block, elle aussi en octets. Le superblock est alors le premier block de cette liste).
Suit la table des inodes, qui est l'espace réservé aux inodes. Ainsi, le nombre d'inodes maximum sur une partition est défini lors du formatage de celle-ci.
Pour un système type ext2, on retrouvera une structure similaire, qui se répète à plusieurs reprises sur la partition, et dispose donc de copies du superblock en cas de corruption.
V-B. Lookup▲
Je n'ai fait que mentionner le nom de cette fonction, pourtant cruciale.
Lookup est la fonction qui permet de résoudre un path (chemin) vers un fichier/répertoire, et donc d'obtenir la dentry de cette élément.
Concrètement, la résolution de « /dir/subdir/file » produira les appels suivants :
- dir_dentry = lookup(root_dentry, « dir »)
- subdir_dentry = lookup(dir_dentry, « subdir »)
- file_dentry = lookup(subdir_dentry, « file »)
Nous disposons de la dentry associée au point de montage grâce au super_block. Par la suite, on parcourt l'arbre (si bien sûr les nœuds existent).
Cette fonction est implémentée par le filesystem. Elle a un comportement similaire à readdir, puisqu'il lui faut lire le contenu d'un dossier pour obtenir l'inode du nœud suivant, et créer/récupérer la dentry associée.
V-C. Readdir▲
Cette fonction est chargée de lister le contenu d'un répertoire, en fournissant des paires (<nom de fichier>,<inode id>).
Dans un filesystem type minix, un dossier est simplement un fichier subdivisé en structure contenant ces paires. Ajouter un lien physique revient alors simplement à ajouter une structure pointant sur une inode existante. De même, supprimer un lien vers un fichier, c'est simplement supprimer cette structure (si l'inode du fichier considéré se retrouve avec un i_nlink de 0, c'est qu'elle doit être supprimée).
On comprend alors pourquoi le nom d'un fichier ne figure pas dans une inode, mais bien dans chaque dossier lié à cette inode.
Voici un exemple de ce à quoi peut ressembler cette fonction :
//Dans cette exemple, la taille d'une structure élémentaire représentant une paire n'est pas fixe.
static
int
yfs_readdir
(
struct
file *
file, void
*
dirent, filldir_t filldir)
{
//Get page index
unsigned
long
pidx =
file->
f_pos >>
PAGE_CACHE_SHIFT;
//Get data offset
unsigned
long
offset =
file->
f_pos &
~
PAGE_CACHE_MASK;
//File's inode
struct
inode*
inode =
file->
f_dentry->
d_inode;
//Parent directory
struct
inode*
parent =
file->
f_dentry->
d_parent->
d_inode;
//How much pages in this file?
unsigned
long
cnt_pages =
yfs_count_pages
(
inode);
//Page used
struct
page *
page =
NULL
;
//yfs directory entry
struct
yfs_dirent*
dent;
//Page address
char
*
kaddr;
//Len name
int
len;
//Page doesn't exist!
if
(
file->
f_pos >
inode->
i_size +
IDX_ADD)
goto
done;
//On each page
for
(
;pidx <
cnt_pages; pidx++
)
{
//Get page or next page
page =
yfs_get_page
(
inode, pidx);
if
(
IS_ERR
(
page))
continue
;
//Lock page
lock_page
(
page);
//End is ino = 0 (An entry can't be broken into 2 pages!)
kaddr =
(
void
*
)page_address
(
page);
dent =
(
void
*
)kaddr +
offset;
while
(
dent->
d_ino)
{
len =
strlen
(
dent->
d_name);
offset =
(
char
*
)dent -
kaddr;
//Fill file (unknow type, fs will know by checking inode latter)
if
(
filldir
(
dirent, dent->
d_name, len,
file->
f_pos =
((
pidx <<
PAGE_CACHE_SHIFT) |
offset),
dent->
d_ino, DT_UNKNOWN))
{
//Unlock the page
unlock_page
(
page);
//filldir error
yfs_put_page
(
page);
goto
out;
}
dent =
yfs_next_dentry
(
dent, len);
}
//Unlock and put page
unlock_page
(
page);
yfs_put_page
(
page);
offset =
0
;
}
//. and .. are special directory
if
(
offset ==
0
&&
filldir
(
dirent, "
.
"
, 1
, file->
f_pos =
((
pidx <<
PAGE_CACHE_SHIFT) |
offset), inode->
i_ino, DT_DIR))
goto
out;
offset =
1
;
filldir
(
dirent, "
..
"
, 2
,
file->
f_pos =
((
pidx <<
PAGE_CACHE_SHIFT) |
offset),
parent->
i_ino, DT_DIR);
//Finish, . .. and others writed.
done
:
file->
f_pos =
inode->
i_size +
IDX_ADD +
1
;
return
1
;
//Out, all dirent aren't already writed
out
:
return
0
;
}