Fichier détruit par inadvertance sur un système de fichiers ext2 ?
Lire le HOWTO intitulé "Ext2-undeletion"
Laurent Foucher résume cela (mots-clés : restaurer, undelete) :
voici les manip à faire pour récupérer un fichier (ici : sur hda2)
echo lsdel | debugfs /dev/hda2 > liste.txt
cela permet de connaitre les inodes des fichiers perdus.
puis lancer debugfs /dev/hda2 et dans la ligne de commande de debugfs, lancer :
dump ((No_inode)) /mnt/recovered.000
Cette section concerne surtout les disques IDE et, dans une certaine mesure, SCSI. Lire aussi le Guide du rootard Linux
Changer de cordon d'alimentation (à l'intérieur de la machine : cordon issu du bloc d'alimentation et connecté au disque lui-même), débrancher temporairement les autres équipements, en particulier les ventilateurs, et tester.
Essayer après avoir changé de nappe.
Ne pas utiliser de « déboubleur en Y » d'alimentation (mais plutôt un connecteur unique).
L. Delépine conseille (dans le cas de certains disques) d'appuyer assez fort sur le connecteur.
En cas de dégâts graves D. Seigneur conseille, afin de tenter de lire une dernière fois afin de récupérer autant de données que possible, de laisser le disque au congélateur puis de le reconnecter rapidement et de tenter de lire.
Note : tout cela est en fait beaucoup plus compliqué, bien entendu, mais je suis pas spécialiste de la question et ne souhaite pas trop digresser.
Certaines pannes découlent d'un accident mécanique majeur (chute, contact avec un liquide ...) mais d'autres paraissent plus difficilement explicables.
Des blocs (zones du disque allouables aux données) qui furent longtemps corrects deviennent inutilisables car l'étanchéité du carter laisse à désirer (de petites poussières pénètrent dans l'enceinte des plateaux) ou bien parce que les têtes entrent en contact avec les supports à cause de chocs ou de vibrations.
Il faut, pour en comprendre la raison, savoir que les blocs défectueux sont automatiquement détectés lors des tentatives d'écriture. La logique interne (les programmes embarqués, le fameux "firmware") du disque dresse au fur et à mesure liste de ces blocs afin de ne plus essayer de les employer. Elle effectue cela de façon transparente, même le système d'exploitation n'est pas tenu informé.
Tôt ou tard la table de « relocation » ("remapping"), un cylindre réservé du disque, sera saturée. Il ne sera dès lors plus possible d'y écrire de façon fiable. Note : l'utilisateur ne peut (et ne doit) d'ordinaire PAS accéder à cette zone mais il peut tenter de réutiliser le disque après un reformatage qui s'avère rarement possible).
Dans l'immense majorité des cas ces problèmes découlent de conditions thermiques défavorables : essayer d'utiliser la machine ouverte en laissant un gros ventilateur braqué sur ses entrailles.
Voici une liste d'autres causes fréquentes :
PIO,
DMA, UDMA ... trop élevé) inadéquat. Lire la page de man
de hdparm afin de bien utiliser les paramètres '-u', '-c', '-d',
'-p', '-X' voire '-S')
RZ1000 ou CMD640),Tout cela, pour une oreille exercée, s'entend parfois : certaines écritures paraissent anormalement lentes, le disque émet des bruits périodiques ('recalibrate' (retour en piste 0) après 'recalibrate') puis reprend une activité normale.
Des messages assez explicites apparaissent dans le fichier de trace
principal, souvent /var/log/messages.
Exemples :
hdQUELQUECHOSE: write_intr: { Error}
hdQUELQUECHOSE: write_intr: error=0x10 {SectorIdNotFound }, CHS=QUELQUECHOSE, sector=QUELQUECHOSE
hdQUELQUECHOSE: status error=0x10: status=0x59 { DriveReady SeekComplete DataRequest Error }
hdQUELQUECHOSE: status error=0x0: { }
hdQUELQUECHOSE: no DRQ after issuing WRITE
ideQUELQUECHOSE: reset: succes
(ou bien "read_intr" à la place de "write_intr")
hdQUELQUECHOSE: read_intr: error=0x40 {UnrecoverableError} LBAsect=QUELQUECHOSE, sector=QUELQUECHOSE
end_request: I/O error, dev QUELQUECHOSE:QUELQUECHOSE, sector QUELQUECHOSE
(le plus souvent après un contact d'une tête avec la surface d'un disque,
vraisemblablement après un choc mécanique)
En cas d'erreur :
set_multmode: status=0x51 { DriveReady SeekComplete Error }
set_multmode: error=0x04 { DriveStatusError }
utiliser un noyau très récent (avec patch IDE), le recompiler
avec l'option 'CONFIG_IDEDISK_MULTI_MODE'
Sitôt les problèmes constatés mieux vaut, s'il ne s'agit pas du disque
racine, passer le disque en mode "lecture seule". Utiliser l'argument "-o
ro" de mount, ou le "-r" de hdparm (cas d'un disque IDE).
Puis réaliser une copie physique ("dumper") des données en péril dans un
fichier stocké sur un autre support. On pourra pour cela utiliser le
programme dd et le fichier produit permettra d'essayer par la
suite d'"aller à la pèche" (vaste panoplie de possibilités, de "strings" à
"debugfs") en cas d'échec complet des tentatives de réparation.
Exemple :
cd Un_répertoire_sur_un_autre_support_de_données
dd if=/dev/NOM_DU_DEVICE_ASSOCIÉ_AU_DISQUE_DÉFECTUEUX of=sauvegarde.dump
De toutes façons il FAUT SAUVEGARDER AU MOINS LES DONNÉES, SINON TOUT LE SYSTÈME, si possible EN PLUSIEURS EXEMPLAIRES et SUR AUTANT DE SUPPORTS PHYSIQUES DISTINCTS DE NATURES DIFFÉRENTES que possible, puis tenter de restaurer sur une autre machine et s'assurer que tous les fichiers sont bien présents et utilisables. Ne pas conserver ensuite tous ces supports au même endroit et les « protéger contre l'écriture ».
On peut aussi acheter un autre disque afin d'y vidanger tout le contenu du support défectueux (attention : pas d'erreur lors de l'installation ou du formatage) ou utiliser (quitte à l'emprunter) un périphérique de sauvegarde et réaliser au moins une sauvegarde totale sur un support qui ne sera jamais utilisé directement.
Vérifier que le paramètrage du disque et de l'interface, dans le SETUP du BIOS, sont adéquats. En cas de doute restaurer les éléments de configuration livrés par défaut.
Certains disques ou programmes des circuits d'interface présentent des défauts pris en charge par le constructeur ("patch", modification du firmware, échange ...). Explorer au moins le site Web du constructeur de la carte mère et du disque.
Rechercher ensuite des informations pertinentes grâce aux robots de recherche de l'Internet. Utiliser, en guise de mots-clés, le nom du constructeur, le type de disque, le messages d'erreur ...
Si tout semble en ordre monter le disque dans une autre machine (pas en tant que disque contenant la partition racine, bien entendu, car il ne faut pas risquer d'utiliser des binaires endommagés). Changer aussi de carte d'interface et de nappe.
Chercher et corriger les incohérences de la table des partitions. au préalable : consigner les paramètres en vigueur et la sauvegarder.
Voici comment obtenir la liste des noms de fichiers situés sur des zones (monter la partition à vérifier en mode « lecture seule ») : endommagées :
find /mnt/partition-endommagée -type f |
xargs -iNIMPORTEQUOIXYZ cp NIMPORTEQUOIXYZ /dev/null >&
~/mnt/autre-disque/noms-fichiers-endommages.txt
(tout cela doit naturellement tenir sur une seule ligne).
Il faudra ensuite supprimer ces fichiers, redémarrer le système sans monter
la partition endommagée, utiliser e2fsck -c afin d'interdire à
Linux d'utiliser les secteurs défecteux, puis de restaurer grâce aux plus
récentes sauvegardes les fichiers perdus.
Installer le plus récent fsck correspondant au type de système de
fichiers.
Le système de fichiers e2fs recopie le superbloc tous les 8192 blocs. Employer par conséquent "e2fsck -fb 8193 /dev/nom_de_la_partition", puis "e2fsck -fb 16385 ...", puis "e2fsck -fb 24577 ..." ...
Si tout échoue essayer d'employer l'option "-S" de mke2fs.
Le remplacement intempestif du contenu de la table des partitions rend la restauration des paritions logiques (« étendues ») très difficile.
L. Prylli offre une solution :
Récupérer correctement l'emplacement de la partition primaire contenant les partitions logiques. Mettre ensuite le type de la partition sur extended (code 05 ou 85) et les partitions logiques devraient réapparaître automatiquement.
Pour changer ainsi le type de la partition à 05 ou 85, on peut récupérer le
contenu du secteur de boot dans un fichier (par exemple grâce à
dd), puis l'éditer avec beav ou un autre éditeur
hexadécimal (mode hexl-mode sous emacs) avant de le réécrire.
Ne pas tenter de recréer les partitions logiques l'une après l'autre car toute création remet à zéro les champs qui contenaient les informatons sur les partitions logiques qui se trouvaient déjà déclarées.
On peut aussi essayer trouver l'emplacement des systèmes de fichiers
ext2 grâce à ce petit programme, puis recréer les partitions en
utilisant les numéros de secteurs trouvés (difficile) !
/* author: Loic Prylli, lprylli@graville.fdn.fr, Public domain */
/*
search ext2 filesystems with 1 Ko block size on a device
Utilisation : rediriger l'entrée standard sur le fichier spécial adéquat.
Exemple : "searchext2 < /dev/hda"
Utiliser "-start" pour reprendre la recherche à partir d'un certain
point (multiple d'1 Ko)
Exemple : "searchext2 -start 150000 < /dev/hda"
(pour rechercher après les 150 premiers Mo)
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#undef NDEBUG
#include <assert.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
char buf[BLOCK_SIZE];
int die(const char *s)
{
fprintf(stderr,"system error in %s:abort\n",s);
exit(1);
}
/* basic check to avoid false magic number, (probability for random
data is 1 every 65Mo with just the magic field ) */
int look_like_ext2sb(struct ext2_super_block *es,int block)
{
if (es->s_magic != EXT2_SUPER_MAGIC)
return 0;
printf("ext2 magic found at %u\n",block);
if (es->s_blocks_per_group % 8 != 0 || es->s_blocks_per_group == 0)
return 0;
if (es->s_rev_level > EXT2_GOOD_OLD_REV
&& (es->s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPP))
return 0;
if (es->s_r_blocks_count >= es->s_blocks_count ||
es->s_free_blocks_count >= es->s_blocks_count ||
es->s_free_inodes_count >= es->s_inodes_count ||
es->s_frags_per_group != es->s_blocks_per_group ||
es->s_log_block_size != es->s_log_frag_size ||
es->s_first_data_block >= es->s_blocks_count )
return 0;
/* limitation to 1k block size for now */
if (es->s_log_block_size != 0)
return 0;
return 1;
}
int ext2_identical(struct ext2_super_block*ori,struct ext2_super_block *new)
{
new->s_free_inodes_count = ori->s_free_inodes_count;
new->s_free_blocks_count = ori->s_free_blocks_count;
new->s_mtime = ori->s_mtime;
new->s_wtime = ori->s_wtime;
new->s_mnt_count = ori->s_mnt_count;
new->s_state = ori->s_state;
new->s_block_group_nr = ori->s_block_group_nr;
return memcmp(ori,new,sizeof(struct ext2_super_block)) == 0;
}
/* find the first superblock of the filesystem in case the search does not begin at the first block */
int search_firstsb(struct ext2_super_block *es,unsigned block)
{
static char buf[BLOCK_SIZE];
struct ext2_super_block *new=(struct ext2_super_block *)buf;
unsigned current=block;
if (es->s_rev_level >= EXT2_DYNAMIC_REV)
return block - es->s_block_group_nr*es->s_blocks_per_group;
while (current > es->s_blocks_per_group) {
if (lseek(0,-BLOCK_SIZE*(es->s_blocks_per_group+1),1) == -1)
die("lseek");
current -= es->s_blocks_per_group;
if (read(0,buf,BLOCK_SIZE) != BLOCK_SIZE)
die ("reading block");
if (!ext2_identical(es,new)) {
if (lseek(0,(block-current)*BLOCK_SIZE,1) == -1)
die("lseek");
return current+es->s_blocks_per_group;
}
}
if (lseek(0,(block-current)*BLOCK_SIZE,1) == -1)
die("lseek");
return current;
}
int check_last(struct ext2_super_block *es,unsigned block)
{
static char buf[BLOCK_SIZE];
struct ext2_super_block *new=(struct ext2_super_block *)buf;
if (lseek(0,(block-1)*BLOCK_SIZE,1) == -1)
die("lseek");
if (read(0,buf,BLOCK_SIZE) != BLOCK_SIZE)
die ("reading block");
if (lseek(0,-block*BLOCK_SIZE,1) == -1)
die("lseek");
return ext2_identical(es,new);
}
int main(int argc,char *argv[])
{
unsigned block = 0;
int i;
for (i=1;i<argc;i++) {
if (strcmp(argv[i],"-start")==0) {
block = atoi(argv[i+1]);
if (lseek(0,block*BLOCK_SIZE,1) == -1)
die ("lseek");
i += 1;
} else {
printf("usage:searchext2 [-start startblock] < device\n"
"used to search ext2 device with 1k block size on a device\n");
exit(1);
}
}
while (read(0,buf,BLOCK_SIZE) == BLOCK_SIZE) {
struct ext2_super_block *es = (struct ext2_super_block *)buf;
if (look_like_ext2sb((struct ext2_super_block *)buf,block)) {
int first,start;
unsigned nbgroup;
first = search_firstsb((struct ext2_super_block *)buf,block);
start = first - es->s_first_data_block;
nbgroup = (es->s_blocks_count-es->s_first_data_block-1)/es->s_blocks_per_group+1;
printf("found something like an ext2 superblock with %d groups starting at %u\n",nbgroup,start);
if (check_last(es,(nbgroup-1)*es->s_blocks_per_group-(block-first))) {
printf("ext2 filesystem starting at 512b-sector %u(%uk),len=%u sectors(%uk)\n",
start*2,start,es->s_blocks_count*2,es->s_blocks_count);
if (lseek(0,(es->s_blocks_count-(block-start)-1)*BLOCK_SIZE,1) == -1)
die("lseek");
block += es->s_blocks_count-(block-start)-1;
} else {
printf("false guess\n");
}
}
block += 1;
}
return 0;
}
L. PICOULEAU offre la solution de la dernière chance :
En observant la structure des partitions logiques grâce au mode expert de
fdisk sous Linux, j'ai appris que le chaînage des partitions
logiques se "faisait" dans le secteur 0 tête 0 du premier cylindre de
chaque partition (logique ou étendue).
Armé de cette info, un éditeur de secteurs physiques m'a permis en regardant les secteurs 0 tête 0 des cylindres de mon disque de retrouver ma partition étendue. De là, il est facile de suivre la liste chaînée des partitions logiques. J'ai ensuite recréé sous Linux les partitions étendues et logiques à leurs emplacement antérieurs.