Programmation

fatcat

FAT: réparez vos fichiers!

0

Chose qui nous est tous déjà arrivée, un disque dur qui crash et qui devient plus ou moins inutilisable. Dans ces cas là, il peut être intéressant d’aller jeter un œil au système de fichier lui-même, éventuellement endommagé et corrompu, qui peut nous permettre d’en apprendre d’avantage sur les données perdues.

C’est pourquoi, il y a peu de temps, je me suis intéressé au FAT32, ayant sous la main un disque de 250Go abîmé sur lequel faire mes tests. J’ai été amené à développer un outil, fatcat, outil qui permet de manipuler des systèmes de fichiers FAT.

Que faire en cas de disque FAT32 endommagé? C’est la question à laquelle je vais essayer de répondre.

1) Sauvez tout!

Première étape, et pas des moindres, il est très important de sauver le disque ailleurs. Certains secteurs étant physiquement inutilisable, le disque ne sera pas réparable sans une copie au préalable. Vous pouvez effectuer cette copie soit vers un disque dur neuf, soit vers un fichier de la machine de rescue.

Pour cela, je vous propose d’utiliser l’utilitaire ddrescue:

$ ddrescue /dev/sdb disk.img rescue.log

Cet outil fera une copie des données de votre disque. Lorsqu’il rencontre des erreurs, en tombant par exemple sur un secteur défectueux, il écrira des 0 dans le fichier cible.

Cette opération peut prendre du temps, surtout lorsque le nombre de secteurs inaccessibles est grand. Dans mon cas, j’ai laissé tourner une bonne nuit avant d’avoir une image complète.

Si vous voulez juste tester, ou vous entraîner, n’hésitez pas à tester l’image de démo « repair.img » que j’ai construite exprès pour le proof-of-concept.

Dans un premier temps, vous pouvez commencer par examiner les données de votre disque en le montant:

mkdir disk
mount disk.img disk/
cd disk
ls -lAh

Et essayer de voir ce qui est sauvé, ce qui manque etc.

Dans les étapes qui suivent, nous allons modifier les tables d’allocation, vous pouvez sauvegarder la table actuelle à l’aide de fatcat:

# Sauvegarde les tables FATs dans un fichier (save.fat)
$ fatcat disk.img -b save.fat
# Restaure les tables FATs depuis un fichier (save.fat)
$ fatcat disk.img -p save.fat

2) Comparez les FATs

FAT signifie « File Allocation Table ». En quelque mots, ce système de fichiers comporte une table d’allocation qui décrit comment les données sont stockées et agencées sur le reste du disque. Dans le cas d’un disque de 250Go, la table FAT pèse environ 60Mo. Si votre disque est physiquement endommagé, il est fortement probable que cette table FAT le soit également. Pour des raisons de sécurité, elle est écrite deux fois sur le disque, vous avez à l’aide de fatcat la possibilité de les comparer:

# Affiche une comparaison des tables FATs
$ fatcat disk.img -2

Cette commande vous montrera la différence entre les deux tables FATs. Sur le disque d’exemple repair.img, vous devriez voir le secteur 0x20 (32) qui est à 0 sur la première table et pas sur l’autre, cela correspond en fait au cluster du dossier fat1_broken à la racine de l’image.

Par la suite, il peut être intéressant de fusionner ces deux tables. Pour cela, fatcat effectue une différence entre les deux puis choisira à chaque fois celle qui fournit le plus d’informations:

# Fusionne les tables FAT en gardant les données allouées
$ fatcat disk.img -m

N’hésitez pas à lire le tutoriel de réparation des tables FATs pour plus d’informations.

3) Réparez les dossiers non alloués

Désormais, nos deux tables sont égales, cependant, il arrive que des dossiers ne soient pas épargnés et soient effacés des deux tables simultanément. Cependant, fatcat arrivera encore à les lire. Si par exemple, le dossier racine (/) dit qu’il existe un dossier sur le cluster 22 et que ce dernier n’est pas marqué comme alloué dans la table d’allocation, fatcat tentera de lire les entrées et de déterminer sa taille, si il y parvient, il essaiera alors de réallouer le dossier dans la table. C’est le cas du dossier unallocated dans l’image d’exemple.

Pour faire cela, vous pouvez utiliser:

# Répare automatiquement les dossiers et fichiers non alloués que
# fatcat arrive à lire
$ fatcat disk.img -f

4) A la recherche des orphelins

Si votre disque est corrompu, il est parfaitement possible que certains dossiers soient devenus orphelins. Cela signifie qu’ils ne sont plus accessible parce que leurs parents ont par exemple été détruits. Si la référence vers un dossier est brisée, ce dernier restera alloué dans la table FAT mais ne sera plus atteignable à partir de l’arborescence du disque. fatcat dispose d’une option permettant d’explorer les zones allouées mais plus atteignable de votre disque et tentera d’en dégager les dossiers et fichiers:

# Lance la recherche des fichiers et dossiers orphelins
$ fatcat disk.img -o
(...)

There is 1 orphaned elements:
* Directory clusters 33 to 33: 2 elements, 30B

Estimation of orphan files total sizes: 30 (30B)

Listing of found elements with known entry:
In directory with cluster 33:
f 27/10/2013 16:32:54  orphan_file.txt                c=51 s=30 (30B)

Dans cet exemple, fatcat a trouvé un dossier contenant un fichier orphelins. Ce dossier est inatteignable à partir de l’arborescence, il n’a donc pas de nom. Cependant, la liste de ses entrées est accessible, vous pouvez y acceder à l’aide de -L, qui sert à lister les entrées d’un répertoire à partir de son numéro de cluster:

# Liste les entrées du répertoire du cluster 33
$ fatcat disk.img -L 33
Listing cluster 33
Directory cluster: 33
d 27/10/2013 16:32:26  ./                             c=33
d 27/10/2013 16:32:26  ../                            c=0
f 27/10/2013 16:32:54  orphan_file.txt                c=51 s=30 (30B)

Il est également possible de lire le fichier, à l’aide de -R et -s qui permettent de lire un fichier à partir de son numéro de cluster et de sa taille:

# Lis le fichier du cluster 51 et de 30 octets
$ fatcat disk.img -R 51 -s 30
This file is a poor orphaned!

Il est aussi possible d’extraire les fichiers du dossier ainsi retrouvé à l’aide de -x et -c:

# Extrait le dossier du cluster 33 dans le répertoire output/
$ mkdir output/
$ fatcat disk.img -x output/ -c 33
Extracting /orphan_file.txt to output//orphan_file.txt

Pour plus d’informations, consultez le tutoriel des fichiers et dossiers orphelins.

Liens:

mongoose_64x64@2

Serveur web embarqué

0

Déployer une application web, ça n’est pas forcément ouvrir un site qui va accueillir des milliers de personnes et sera disponible sur internet, c’est aussi profiter d’une interface en client léger, et permettre à tous les périphériques du réseau local (ordinateurs, tablettes, téléphones …) d’accéder à votre application.

Cependant, même si de plus en plus de machines permettent de se trimbaler un système d’exploitation, telles que les Raspberry Pi notamment, déployer un serveur Apache et des scripts PHP « classiques » n’est pas toujours une très bonne idée, pour toutes les raisons de performances que l’on peut imaginer.

C’est pour cela qu’il est intéressant de disposer d’un serveur web léger et capable de s’interfacer facilement avec une application bas niveau, par exemple écrite en C++.

C’est en recherchant cela que je suis tombé sur mongoose, un serveur web embarqué qui tient en tout dans un unique fichier C et très léger. Il a d’ailleurs acquis une certaine popularité sur Github. Sur ma machine, il se compile en moins de 2 secondes et ses performances semblent très acceptables. Il supporte également plusieurs features avancés tels que l’upload de fichier ou les websockets.

Seul hic, le développement avec ce mongoose « brut » n’est pas très élégant, car il faut jongler avec des structures de données et une API en C. L’exemple de traitement des requêtes POST donne un peu mal à la tête.

C’est pour cela que j’ai créé un fork de mongoose afin d’y apporter une API C++ permettant d’utiliser beaucoup plus facilement les fonctionnalités du serveur web.

Exemple

Voici un hello world d’exemple, qui répond aux requêtes sur la page /hello?name=Nom en affichant le nom de l’utilisateur echappé:

#include <stdlib.h>
#include <signal.h>
#include <mongoose/Server.h>
#include <mongoose/WebController.h>

using namespace std;
using namespace Mongoose;

class MyController : public WebController
{
    public:
        void hello(Request &request, StreamResponse &response)
        {
            response << "Hello " << htmlEntities(request.get("name", "... what's your name ?")) << endl;
        }

        void setup()
        {
            addRoute("GET", "/hello", MyController, hello);
        }
};

int main()
{
    MyController myController;
    Server server(8080);
    server.registerController(&myController);

    server.start();

    while (1) {
        sleep(10);
    }
}

Dans cet exemple, un serveur web est créé, et sert par défaut les fichiers statiques du dossier www/ à partir du dossier d’exécution du serveur, sur le port 8080.

De plus, grâce à un système de contrôleur enregistré auprès du serveur, il répondra également aux requêtes GET sur l’URL /hello, en appelant la méthode hello du contrôleur.

La réponse hérite en fait ici de ostringstream, ce qui permet de lui ajouter des données simplement avec l’opérateur « << ».

Comme vous le voyez, accéder aux paramètres GET de la requête est aussi très facile à l’aide de request.get().

Comme on peut le voir dans un autre exemple plus complet, mon API permet également de manipuler des variables de sessions, les variables POST, et aussi de changer les en-têtes de la réponse.

Il est également possible de modifier le type de la réponse utilisée par les routes, et de créer ainsi par exemple un serveur web supportant une API JSON.

Application

Ce système peut permettre d’embarquer facilement un serveur web dans n’importe quelle application « lourde » C++. Et ce indépendamment de toute grosse bibliothèque qui pourrait exister (pour ne pas citer Qt ou boost par exemple).

C’est donc en effet approprié pour une utilisation dans l’embarqué comme par exemple une exécution à bord d’un petit ordinateur tel que la Raspberry Pi ou d’un MK802. Il pourrait être utilisé pour piloter un robot ou un appareil (routeur, télévision, serveur divers…).

Conclusions

Comme je risque de m’en servir dans de futurs projets, je compte continuer de maintenir mongoose-cpp et de merger mongoose de temps en temps pour rester à jour. J’aimerais aussi y ajouter une manière simple d’utiliser les websockets, comme cela est permis par mongoose.

Ce qui est assez remarquable, c’est l’intérêt de cette architecture qui utilise un outil très léger entièrement écrit en C pour y ajouter une fine couche d’ingénieurie logiciel, ce qui fait au final un outil à la fois performant et facile à utiliser. Implémenter un serveur web intégralement en C++ avec un génie logiciel au cordeau aurait sans doute donné une application nettement plus longue à compiler et moins performante.

Liens

Guide de conception PHP

2

Comme chacun le sait, il existe plusieurs PHP, du très bon au très mauvais. On trouve aujourd’hui sur internet de très (trop) nombreuses sources pour apprendre le PHP, des cours, leçons et tutoriels.

Je donne moi-même un cours de PHP à des étudiants de licence professionnelle, et aborder cet enseignement s’avère assez compliqué, car les étudiants parviennent en général à réaliser quelque chose de fonctionnel, en laissant malheureusement de nombreuses bonnes pratiques de coté, ou en utilisant des fonctionnalités obsolètes de PHP.

PHP est historiquement un langage très répandu et facile à utiliser, et les cours, tutoriels ou exemple que l’on trouve sur internet sont souvent préférés par les gens pour leur facilité de prise en main que pour leur qualités techniques.

Par exemple, le tutoriel numéro 1 de developpez.com sur le PHP (cf http://php.developpez.com/cours/) date de 2009, nous propose d’utiliser les obselètes fonctions mysql_connect & co, et de construire des requêtes non échappées par concaténation. Les cours du Site du Zéro ont l’air quant à eux de bien meilleure facture.

Suite aux projets de l’année dernière, j’ai pu lister quelques uns des problèmes les plus fréquents, et j’ai produit un guide de conception que l’on peut trouver ici:

http://gregwar.com/php/guide-de-conception.html

Ce guide a pour but d’imposer des règles relativement strictes pour essayer de respecter les concepts modernes du développement en PHP.

Toutes les remarques à ce sujet seront les bienvenues !

Haut de page