Mis à jour le 30 janvier 2006
TD 1 : Système de fichiers

TD 1 : Système de fichiers

10 janvier 2006


1  Question de cours

Bob et Alice et Robert sont dans le même groupe de TD. Bob veut montrer son programme (composé de plusieurs fichiers de grosses taille) à Alice sans que Robert (qui peut deviner les noms des fichiers) puisse le lire.

Comment peut-il faire simplement en créant des fichiers et des répertoires avec des droits d'accès bien choisis (Bob peut chuchoter une information à Alice sans que Bob l'entende)?

(Indice)
Attention, il doit prendre une précaution, laquelle?
(Solution)
Donner la liste des commandes, dans l'ordre, exécutées par Bob avant d'envoyer de chuchoter un secret à Alice. (On pourra utiliser les commandes shell mkdir, chmod, cp.)
(Solution)
En fait Bob a fait cd pour se placer dans son répertoire de login ~bob, puis il a fait une fausse manipulation: il a exécuté la commande chmod -x . alors qu'il voulait faire chmod og-x . et s'affole lorsqu'il fait ls -ld et voit le résultat. Essayant de réparer, il fait chmod og+x . mais il panique à la vue du résultat.

Sauriez-vous lui expliquer ce qui s'est passé et l'aider le à réparer?
(Solution)

2  Mise en jambes

Écrire des commandes mon_true et mon_false comparables aux commandes true et false du système (tester man true et man false) qui ne font rien et dont les valeurs de retour sont respectivement toujours 0 et toujours 1. Pour préciser la valeur de retour, on utilisera la fonction exit du module Pervasives. Ce module est ouvert par défaut, il n'est donc pas nécessaire de préfixer cette fonction par le nom du module, ni d'ouvrir le module (open Pervasives). Pour afficher la valeur de retour d'une commande qui vient d'être exécutée par l'interpréteur de commandes on utilisera la commande echo $?. (Testez vos programmes!)
(corrigé)
Écrire une commande bonjour qui affiche la chaîne de caractères "Bonjour monde !" suivie d'un retour à la ligne sur la sortie standard et qui a toujours pour valeur de retour 0. Pour réaliser l'affichage d'une chaîne de caractères suivie d'un retour à la ligne, on utilisera la fonction print_endline du module Pervasives.
(corrigé)
Écrire une commande mon_echo qui affiche les chaînes de caractères passées en argument sur la sortie standard séparées par un espace (pas d'espace à la fin !) et a pour valeur de retour 0. Les arguments de la ligne de commande sont placés dans le tableau argv du module Sys dont l'élément d'indice i est récupéré par Sys.argv.(i). La longueur d'un tableau est retournée par la fonction Array.length. L'affichage d'une chaîne de caractères sans retour à la ligne se fait par la fonction print_string du module Pervasives.
(corrigé)

3  L'environnement d'exécution

Écrire une commande mon_printenv qui affiche des informations sur les variables d'environnement et qui a le même comportement que la commande printenv du système (man):

Lorsque la commande est appelée sans argument, elle affiche l'ensemble des variables d'environnement et retourne 0 lorsque tout s'est bien passé. Pour cela, on utilisera la fonction Unix.environment de type unit -> string array qui retourne l'ensemble des variables d'environnement sous la forme d'un tableau et la fonction Array.iter de type ('a -> unit) -> 'a array -> unit qui permet d'itérer une fonction passée en premier argument sur les éléments d'un tableau passé en second argument.

Lorsque la commande est appelée avec au moins un argument, elle affiche (sur des lignes séparées) les valeurs des variables d'environnement dont les noms sont passés en arguments. Si un nom ne correspond pas à une variable d'environnement valide, la commande n'affiche rien pour cet argument, mais essaye d'afficher les valeurs des arguments suivants. Si au moins un des arguments n'est pas le nom d'une variable d'environnement valide la commande retourne 1, sinon elle retourne 0. Pour récupérer la valeur d'une variable d'environnement en fonction de son nom, on utilisera la fonction Sys.getenv. Cette dernière lève une exception Not_found lorsque le nom passé en argument ne correspond pas à une variable d'environnement valide.
(corrigé)

4  Répertoire de travail courant

Le but de l'exercice est d'écrire une commande mon_pwd qui affiche le répertoire courant équivalente à la commande /bin/pwd du système.

Faire cela en une ligne avec la fonction Unix.getcwd.
(corrigé)
On a utilisé ici la fonction Unix.handle_unix_error de type ('a -> 'b) -> 'a -> 'b pour récupérer et afficher les éventuelles formes de l'exception Unix_error levées dans le module Unix lors des appels système.

La commande Unix.getcwd n'est pas toujours directement un appel système mais simplement une fonction écrite en C (qui elle-même fait des appels système). On se propose donc de réécrire la fonction getcwd en OCaml. Cette fonction doit pouvoir être utilisée comme fonction de librairie : elle ne doit donc pas modifier les variables globales du programme ni créer une fuite de mémoire. Cette fonction remonte récursivement dans la hiérarchie jusqu'à la racine du système en recherchant à chaque étape le répertoire courant « . » dans le répertoire supérieur « .. ». Décrire le schéma général du programme.
(corrigé)
Écrire une fonction equal_node de type stats -> stats -> bool qui teste si deux noeuds de la hiérarchie de fichiers sont identiques. Deux noeuds sont identiques si et seulement si leurs numéros de noeuds et leurs numéros de partition sont égaux.

(corrigé)
Écrire une commande try_finally qui prend quatre arguments f, x, finally et y et qui effectue le calcul f x, puis, avant de retourner le résultat, exécute finally y, y compris lorsque le résultat est une exception.
(corrigé)
Écrire une fonction dir_find qui prend en arguments un prédicat f string -> bool et un nom de répertoire et recherche dans celui-ci le nom d'un fichier qui satisfait le prédicat f. Si la fonction trouve le fichier elle retourne son nom, sinon elle lève l'exception Not_found. Pour écrire cette fonction, on utilisera les fonctions Unix.opendir, Unix.readdir et Unix.closedir. Pour ne pas créer une fuite de mémoire, on fera bien attention à refermer le répertoire ouvert, y compris lorsqu'une exception est levée, avant de rendre le résultat ou de relever une exception.
(corrigé)
Écrire une fonction mon_getcwd qui se comporte comme Unix.getcwd. L'algorithme manipule des chemins et des noeuds. Les informations sur les noeuds, indispensables à la comparaison de noeuds, sont obtenues par l'appel système Unix.lstat qui prend en argument un chemin (on n'utilise pas Unix.stat ici car on recherche un chemin directe issu de la racine qui ne traverse pas de liens symboliques). Pour être portable, on utilisera les fonctions concat, current_dir_name (.) et parent_dir_name (..) du module Filename pour manipuler les chemins. On évitera l'utilisation de chdir qui affecterait alors le reste du programme.
(corrigé)
Terminer le programme. On n'oubliera pas d'appeler handle_unix_error pour reporter les messages d'erreurs éventuels qui peuvent se produire pendant le parcours de la hiérarchie.
(corrigé)

5  Parcours de l'arborescence

On désire écrire une commande mon_find qui permet d'effectuer diverses recherches dans le système de fichiers. On se limite ici à un sous-ensemble des possibilités de la commande find du système.

1) Donner des exemples de requêtes avec la commande find d'Unix (man find) permettant d'exécuter les opérations suivantes: 2) Écrire une première commande mon_find0 équivalente à find . -maxdepth 1.
(corrigé)


3) Écrire une seconde version mon_find1 qui prend en argument une profondeur p et affiche la liste des chemins accessibles depuis le répertoire courant avec une profondeur inférieure à p.
(corrigé)


4) Implanter les comportements équivalents aux options : Pour réaliser cette commande, on pourra utiliser le module Arg pour récupérer les arguments de la ligne de commande et le module Str (dont la librairie str.cma est à charger explicitement pour compiler) pour manipuler les expressions régulières.
(corrigé)



Ce document a été traduit de LATEX par HEVEA