À la recherche des photos perdues...

Comment (en août 2006) j'ai récupéré 1.8 Go de photos effacées sur des «vieux» disques Mac (OS9).

Plantage (du décor)

Un ami à moi a récemment perdu toutes ses photos suite à un vidage de poubelle un peu intempestif.

Après avoir essayé sans succès (mais un peu tard il est vrai) avec divers logiciels dont je tairai ici le nom, il m'a, en désespoir de cause, abandonné sa vieille machine (un Macintosh PowerPC 9500/150).

Plan

Mon idée fut tout de suite d'essayer une solution de (brute de) base à coup de dd et perl...
...mais il me fallait, bien sûr, pour cela (dd) mettre ses disques sous Linux. Or pas question d'installer Linux sur sa machine, parce que :

  1. ça semble être la galère sur un vieux Mac comme ça,
  2. mais surtout, ça aurait définitivement écrasé les possibles traces de fichiers restant sur son disque.

Action

Donc, ni une ni deux : j'attaque au tourne-vis, et sors les (deux) disques de sa machine pour les monter sur une de mes machines (Linux, bien sûr !).

Mais je n'ai que des laptops et deux vieux PC desktops. De plus, grande surprise car je ne savais pas, les disques MachinTosh sont en SCSI :-(...

Qu'à cela ne tienne... l'architecture du PowerPC étant PCI (ça je savais !), je dois bien trouver un intermédiaire quelque part dans le Mac.
Eh oui ! une magnifique (heum...) carte SCSI-PCI (et même pas besoin de tourne-vis car dans les Mac les cartes sont juste enfichées et coincées par du plastic).

Voilà donc mon vieux desktop équipé d'une carte SCSI et de deux nouveaux disques (un peu externes, il est vrai ;-))

Un petit boot sous ma distrib. favorite (Ubuntu Dapper) et...
...super ! Ça marche ! Un superbe /dev/sda est bien présent et fonctionnel.

Il ne reste donc plus qu'à le dumper et le scanner...
mais où ?

En effet, ces deux «nouveaux» disques sont chacun bien plus gros que les disques de mon vieux PC :-(.
Une aide externe s'impose !

Ayant moult place sur un de mes laptops : une petite connexion réseau entre les deux et basta !

Pour résumer, cela donne (sur le vieux PC, un server ssh tournant sur le laptop) :

dd if=/dev/sda bs=4096 | ssh user@laptop 'cat > tmp/disk_image'

Et me voila donc avec, sur mon laptop, une magnifique image (dans $HOME/tmp/disk_image) des disques Mac fautifs.
«Yapuka» scanner cette image à coup de Perl pour trouver les entêtes JPG...

...mais l'Internet est ton ami, et une petite recherche me fait découvrir l'existence de photorec...
...que je me décide donc d'essayer avant de bâcler quelques lignes de Perl.

Note : a posteriori, il y a aussi l'excellente page de Cédric Blancher sur exactement le même sujet...
Comme quoi on doit être plus nombreux qu'on ne le pense à faire ce genre de trucs !

Un petit

photorec /d RescueDir disk_image

et, magnifique !, il me retrouve 2502 images JPG, plus des tonnes de .doc.html, .avi, .mov et autres encore (photorec, version 6.4 (june 2006)).
Ce sont mes amis qui vont être contents !

Finalisation

Rien que pour voir les différents types de fichiers récupérés :

ls RescueDir.[0-9] | cut -d. -f2 | sort | uniq -c | sort -n

Un peu d'ordre ensuite :

mv RescueDir.[0-9]/*.doc Resultat_Final/doc/

et idem pour les autres types de fichiers.

Puis reste à essayer de mettre de l'ordre dans les photos (car les noms produits par photorec ne sont pas très explicites (forcément !))

Suivant l'idée proposée par Cédric Blancher, mais en l'améliorant un petit peu pour éviter les collisions (photos prises en rafales ou avec 2 appareils différents à la même seconde (ou simplement mal configurés !), retouches ou extraits différents d'une même photo, etc...) et traiter aussi les fichiers sans entêtes (e.g. ne venant pas d'appareils photo), voici un petit script donnant un nom basé sur la date :

trash=trash$$
unknown=unknown$$
mkdir $trash
mkdir $unknown
for file in f*.jpg; do
  newname=`exiv2 -p s $file | grep -a timestamp | awk '{ print $4 "-" $5 }' | sed 's/:/-/g'`
  if [ $? -eq 0 -a "x$newname" != "x" ]; then
    if [ ! -f ${newname}.jpg ]; then
      mv $file ${newname}.jpg
    else
      cmp $file ${newname}.jpg
      if [ $? -eq 0 ]; then
        echo "WARN: $file is a duplicate of ${newname}.jpg: moved to $trash"
        mv $file $trash
      else
        echo "ERR: ${newname}.jpg already exists but differs. $file unchanged"
      fi
    fi
  else
      echo "ERR: unable to get info from ${file}: moved to $unknown"
      mv $file $unknown
  fi
done

Notez qu'il faut faire attentions aux doublons qui trouvaient à plusieurs endroits sur le(s) disque(s) d'origine (genre : copie effacée par la suite).
Surtout dans mon cas où j'avais deux disques et où visiblement certains fichiers avaient voyagé de l'un à l'autre.

On peut ensuite aussi les ranger dans des répertoires différents :

for file in [12][0-9][0-9][0-9]-*.jpg; do
 dirname=`echo $file | cut -d- -f1` # ou ${file:0:4} en bash
 if [ ! -d $dirname ]; then
   mkdir $dirname
 fi
 mv $file $dirname
done

Pour la fusion entre les récupérations de disques différents, j'ai aussi trouvé utile de faire :

dir1=Rescue/jpg # repertoire de reference
dir2=Rescue2 # repertoire intermediaire (2nd disque)
year=2001 # par exemple
for file in ${dir2}/${year}/${year}-*.jpg; do
  cmp $file ${dir1}/${year}/`basename $file`
  res=$?
  if [ $res -eq 0 ]; then
    rm $file;
  elif [ $res -eq 2 ]; then # nouveau fichier
    mv $file ${dir1}/${year}
  else
    echo $res; # les 2 fichiers (de meme date) different
  fi;
done

Voilà !
Pour finir, il n'y a plus qu'à graver le tout sur un DVD (mes amis ont depuis acheté une machine plus moderne)[1], remonter les disques dans leur MachineTosh d'origine et aller sonner à leur porte...

Réactions

Vive Linux et les logiciels libres !


[1] J'aurais aussi pu monter un des disques sur mon vieux PC via support HFS et faire une copie par ssh de mon laptop sur ce disque monté :

root@desktop> mount -t hfs /dev/sda /mnt/mac
user@laptop> scp -r Resultat_Final user2@desktop:/mnt/mac

avant de le remettre dans le Mac, mais ils voulaient de toutes façons transférer leur photos sur leur nouvelle machine.

Follow-up

Truc utile pour les .doc

for file in *.doc; do res=`file $file`; a=`echo "$res" | sed 's/,/\n/g' | grep "Author" | cut -d: -f2- | sed 's/ //g'`; b=`echo "$res" | sed 's/,/\n/g' | grep "Last Saved Time/Date" | cut -d: -f2- | perl -lane '$F[3]=~s/://g; print "$F[4]$F[1]$F[2]-$F[3]"'`; mv "$file" "x-$b-$a-$file"; done

Dernière mise à jour le 21 janvier 2010
Last modified: Thu Jan 21, 2010