Grimoire-
Command
.es

GNU+Linux command memo

After photorec

1. version : en

1.1. Lost files

At the last Repair Café of Pougne-Hérisson a friend came to me with an USB hard drive of 1TB he claimed it would not mount itself on Linux…

Dead hardware ? I plug it, it mounts.

Ah… the friend though it tested it on Linux, but the drive only fails to mount on Windows.

OK, the hardware is still here.

I show the content of the drive, 3 empty folders with unknown names to the friend (data, storage, work).

I point out the creation date of those empty folders : last Friday at 18h43. Can you remember whet you were doing that evening ?

Ah, memories came back : the family wanted to record a movie on TV, with their paying TV service Canal+ and its dedicated box, which needs an external hard drive to record things. It appears the box just formats any new disk (to Ext4) without enough disclaimer and warnings.

So the disk was not recognized by Windows anymore… and the files were lost.

After a Testdisk check, I was left with Photorec. It took 22h and got back 432GB of data, 150 159 files in 238 folders.

A lot more than what the friend was aware he created.

PS: This post can be looked at as the second episode after : Saving data from lost partition on a hard drive

1.2. And now what ?

I would like to reduce this file number to help the friend exploring it. I know he is most interested in recent files (has he have other backups).

First, lets check what ncdu can tell us :

 53.9 GiB [#############] /recup_dir.233
 50.1 GiB [############ ] /recup_dir.232
 21.2 GiB [#####        ] /recup_dir.2
 16.7 GiB [####         ] /recup_dir.234
 15.9 GiB [###          ] /recup_dir.1
 13.7 GiB [###          ] /recup_dir.229
  8.1 GiB [#            ] /recup_dir.182
  8.1 GiB [#            ] /recup_dir.205
  6.6 GiB [#            ] /recup_dir.180
  6.3 GiB [#            ] /recup_dir.237
  6.1 GiB [#            ] /recup_dir.228
  5.9 GiB [#            ] /recup_dir.227
  5.2 GiB [#            ] /recup_dir.204
  5.2 GiB [#            ] /recup_dir.179
  5.0 GiB [#            ] /recup_dir.224
  4.9 GiB [#            ] /recup_dir.187
  4.7 GiB [#            ] /recup_dir.4
  4.5 GiB [#            ] /recup_dir.3
  4.2 GiB [#            ] /recup_dir.186
  4.1 GiB [             ] /recup_dir.222
  4.0 GiB [             ] /recup_dir.215
[…]
Total disk usage: 431.7 GiB  Apparent size: 428.6 GiB  Items: 150 159

I can confirm the file number with :

$ rg -uuu --files --iglob * | wc -l
149682
$ python -c 'print(149682+(238*2))'  # adding folders
150158 (1)
1 Seem folders are counting for 2 items as per ncdu count, and we’re still missing 1 item…

1.3. Removing programming files

Exploring some folders I sees C and Python programming files. Let’s count them :

$ rg -uuu --files --iglob "*.c" Recup | wc -l (1)
21348

# Nombre de fichiers Pythons :
$ rg -uuu --files --iglob "*.py" Recup | wc -l
4363
1 I told photorec to write things in a Recup folder

So I can create a folder "poubelle" and move those files out of the way :

$ mkdir poubelle
$ for a in `seq 238`; do mkdir "poubelle/recup_dir.$a"; done; (1)
$ rg -uuu --files --iglob "**py" . | xargs -I {} mv {} poubelle/{} (2)
1 Creating 238 subfolders in the "poubelle" folder.
2 Moving the Python files there.

But how many other programming languages are represented ?

$ for a in `rg --type-list | cut -f 1 -d ':'`; do echo "$a: `rg --files -t $a | wc -l`"; done; (1)
1 For each file type known by rg (currently 169) print the number of files of this type rg can count
fortran: 14 (1)
h: 1642
html: 292
java: 219
config: 3
pdf: 14536
perl: 12
php: 9
sh: 11
svg: 377
txt: 8645
1 I kept here only the non-empty results.

Well, it shows PDF files but I’m missing the ODT ones for instance and exact file extensions are not listed.

1.4. Counting files by type

Let’s create a better content summary, sorted by file extensions, as photorec saved them.

$ rg -uuu --files --iglob "*" Recup > 122552_filenames.txt  (1)
1 I was still with 122552 files at that stage. The command took around 15s.

1.4.1. Counting files with recovered names

$ rg '.{42,}' 122552_filenames.txt > liste_fichiers_avec_nom.txt
$ wc -l liste_fichiers_avec_nom.txt
4566 (1)
1 This represents 3,7% of the 122k files we still have.

Example of long names to skip :

  • Recup/recup_dir.10/f136265448.sqlite

  • Recup/recup_dir.194/f936769224_ftyp.mov

  • Recup/recup_dir.36/f179430256_PAY18E.pdf


Let’s list all the file’s mime-types :

$ file --mime-type -f 122552_filenames.txt > 122552_file_mime-types.txt (1)
$ sed -r 's/\s+/ /g' ../122552_file_mime-types.txt | cut -f 3,4,5,6,7 -d '.' | sort | uniq -c | sort -r -n > ../122552_file_ext_mime-type_summary.txt (2)
1 Takes 2h with a modern plates hard drive
2 This remove some spaces in the file, removes the beginning of the lines (two 1st dotted parts), then sort by file extension and count how many of each we have, finally sorting the biggest count firsts
  72429 jpg: image/jpeg
  14544 pdf: application/pdf
   7513 txt: text/plain
   6576 png: image/png
   5198 odt: application/vnd.oasis.opendocument.text
   3430 mpg: video/mpeg
   1795 avi: video/x-msvideo
   1369 elf: application/x-sharedlib
   1219 mp3: audio/mpeg
   1199 apple: application/octet-stream
    739 txt: application/octet-stream
    […] (1)
1 There were still 77 file types (after I removed already C, H, Python, Java and some other programming language files

We can move elf and so called apple files, but the big deal is about jpg.

1.4.2. Sorting files by extension

A friend used this post to recover files and decided to stop here, sorting his 10k files by extention using the following script :

#!/bin/bash

# Utilisation du premier argument comme répertoire source
source_dir="$1"

if [ -z "$source_dir" ]; then
    echo "Usage: $0 <source_directory>"
    exit 1
fi

# Fonction récursive pour traiter les fichiers d'un répertoire
process_directory() {
    local dir="$1"

    for ext in $(find "$dir" -type f | sed -n 's/.*\.\(.*\)/\1/p' | sort -u); do
        ext_dir="${ext}_files"
        # Création du répertoire d'extension s'il n'existe pas déjà
        mkdir -p "$ext_dir"

        # Déplacer les fichiers de l'extension vers le répertoire d'extension
        find "$dir" -type f -wholename "*.$ext" -exec mv {} "$ext_dir" \;
    done
}

# Appel initial pour le répertoire source
process_directory "$source_dir"

1.5. Removing JPEG thumbnails

Lets explore a random folder for it’s images :

$ find . -name "*.jpg" | wc -l
89
find . -name "*.jpg" -size -35k | wc -l
68
find . -name "*.jpg" -size -50k | wc -l
69
find . -name "*.jpg" -size -100k | wc -l
71
find . -name "*.jpg" -size -150k | wc -l
78
find . -name "*.jpg" -size -1500k | wc -l
78
find . -name "*.jpg" -size -1800k | wc -l
79

We can see that there is a lot of small pictures, mainly thumbnails of real photos, created by various software (file explorer, photo viewer…) on various operating systems.

We can also see that there is a large no man’s land between 150 and 1500ko. Bigger files might be real photos. I decided to cat at 300ko :

find Recup -name "*.jpg" -size -300k | wc -l
43414
find Recup -name "*.jpg" -size -300k | xargs -I {} mv {} poubelle/{} (1)
1 Took around 1 minute

Here we can count 72635 files left and 414 GO so 50% of the file number for 96% of the size.

1.6. fclones to find redundant files

I decided to try fclones to find duplicates in remaining files.

$ fclones group --cache /tmp > /tmp/fclones.group.txt  (1) (2)
fclones:  info: Found 48416 (149.9 GB) redundant files
$ fclones move poubelle < /tmp/fclones.group.txt
Deduplicating 17252 groups
fclones:  info: Processed 48416 files and reclaimed 149.9 GB space (3)
1 The cache option saves the file hashes on the filesystem to eventually reuse them (if you miss-spelled something in the way) keeping what’s long to compute
2 It took 2h38
3 Took 10 minutes

We’re now at 24220 files and 273 GO. It 16% of the initial file number and 63% of the size.

1.7. Removing empty folders

Easy part :

$ rmdir Recup/*
$ exa -l | wc -l
199 (1)
1 So 39 folders less (16%)

1.8. Find the recent files

Unfortunately photorec is only able to restore file creation date and times for some photos and office documents. Around a third of the initial documents.

We can find the recent documents among all the ones which date were not recovered via :

$ find . -newermt $(date +%Y-%m-%d -d '4 months ago') -type f -print > recent_file_list.txt  (1) (2)
1 To get the file that are not older than 4 months
2 Here we get ~100k file names

We can remove from the list the files dating from the recovery via photorec :

$ find . -newermt $(date +%Y-%m-%d -d '4 months ago') ! -newermt $(date +%Y-%m-%d -d '1 week ago') -type f -print > liste_incomplete_fichiers_recents.txt (1)
1 Here we get 453 files ; 4 ODT ; 0 with a recovered name

To get the existing files (after our big cleanup) :

$ for a in `cat ~/liste_des_fichiers_recents.txt` ; do if test -f $a; then echo $a >> ~/liste_des_fichiers_recents_existants.txt ; fi; done

We get 17 122 files, 144 DOC, 76 ODT…

1.9. Conclusion

photorec is a great tool but it’s not easy to do something with the numerous files it retrieves from a storage.

In this post, we walked from 150k to 17k recent recovered files.

We seen that photorec might get your precious report out of a dying drive, but it might get it several times and also all it’s previous or deleted versions… it will save your photos, but also their thumbnails and even with all the hints detailed in this post you will still have a huge amount work to do to get familiar with all those "unsorted" files.

1.10. After thoughs

I should have created a disk image via the dd command and worked on it, to allow recovering from mistakes.

2. version : fr

2.1. Fichiers perdus

Lors du dernier Repair Café de Pougne-Hérisson un ami est venu m’apporter un disque dur USB d'1TO en m’expliquant que ce dernier n’était plus reconnu par ces ordinateurs, Windows ou Linux.

Matériel défectueux ? Je le branche, il se monte.

Ah… l’ami pensait l’avoir testé aussi sous Linux, mais le disque n’échoue à se monter que sous Windows du coup.

Bon, bah au moins c’est pas matériel.

Je lui montre alors le contenu du disque, il y a 3 dossiers vides (data, storage, work) que l’ami ne reconnait pas.

Je lui précise la date de création des dossiers : vendredi dernier à 18h43. Que faisait-il dans la nuit du vendredi en début de soirée ?

La mémoire lui revient, la famille voulait enregistrer un film via la nouvelle Box Canal+, or cette dernière réclamait un disque dur pour pouvoir enregistrer quelque chose. Il semble bien que la Box en question a juste formaté le disque qu’on lui présentait (en Ext4) sans prévenir suffisamment explicitement que les données seraient perdues.

Le disque n’était donc plus reconnus par les ordinateurs tournant sous Windows… et les fichiers furent joyeusement supprimés par la Box.

Bon, après une vérification via testdisk je me retrouvais à lancer photorec. Ça a pris 22h et je me suis retrouvé avec 432 GO de données, en 150 159 fichiers répartis en 238 dossiers.

Bien plus que ce que l’ami imaginais avoir comme données.

PS: Ce billet peut être vu comme un second épisode après le sauvetage précédent : Saving data from lost partition on a hard drive

2.2. Et maintenant ?

Rendu là, j’aimerai réduire cette masse de fichiers pour aider mon ami à l’explorer et y retrouver son travail récent. (il a d’autres sauvegardes, mais plus anciennes)

Lançons tout d’abord un ncdu pour voir ce qu’il peut nous en dire :

53.9 GiB [#############] /recup_dir.233
50.1 GiB [############ ] /recup_dir.232
21.2 GiB [#####        ] /recup_dir.2
16.7 GiB [####         ] /recup_dir.234
15.9 GiB [###          ] /recup_dir.1
13.7 GiB [###          ] /recup_dir.229
 8.1 GiB [#            ] /recup_dir.182
 8.1 GiB [#            ] /recup_dir.205
 6.6 GiB [#            ] /recup_dir.180
 6.3 GiB [#            ] /recup_dir.237
 6.1 GiB [#            ] /recup_dir.228
 5.9 GiB [#            ] /recup_dir.227
 5.2 GiB [#            ] /recup_dir.204
 5.2 GiB [#            ] /recup_dir.179
 5.0 GiB [#            ] /recup_dir.224
 4.9 GiB [#            ] /recup_dir.187
 4.7 GiB [#            ] /recup_dir.4
 4.5 GiB [#            ] /recup_dir.3
 4.2 GiB [#            ] /recup_dir.186
 4.1 GiB [             ] /recup_dir.222
 4.0 GiB [             ] /recup_dir.215
 […]
Total disk usage: 431.7 GiB  Apparent size: 428.6 GiB  Items: 150 159

Je peux confirmer ce nombre de fichiers via :

$ rg -uuu --files --iglob * | wc -l
149682
$ python -c 'print(149682+(238*2))'  # adding folders
150158 (1)
1 Il semble que chaque dossier compte pour 2 items (tels que les compte ncdu), et encore il en manque toujours 1…

2.3. Retirer les fichiers de programmation

En explorant quelques dossiers, je constate qu’il y a beaucoup de fichiers C et Python parmi les fichiers récupérés. Combien exactement ?

$ rg -uuu --files --iglob "*.c" Recup | wc -l (1)
21348

# Nombre de fichiers Pythons :
$ rg -uuu --files --iglob "*.py" Recup | wc -l
4363
1 photorec était configuré pour écrire dans le dossier Recup

Bon, alors je peux créer un dossier "poubelle" et y déclarer ces fichiers, mon amis n’est pas un programmeur.

$ mkdir poubelle
$ for a in `seq 238`; do mkdir "poubelle/recup_dir.$a"; done; (1)
$ rg -uuu --files --iglob "**py" . | xargs -I {} mv {} poubelle/{} (2)
1 Création de 238 sous dossiers dans "poubelle" folder.
2 Déplacement des fichiers Python.

Mais combien y a-t-il de langages de programmation représentés ?

$ for a in `rg --type-list | cut -f 1 -d ':'`; do echo "$a: `rg --files -t $a | wc -l`"; done; (1)
1 Pour chaque type de fichier reconnu par rg (169 en l’occurrence) afficher le nombre de fichier qu’rg peut en compter
fortran: 14 (1)
h: 1642
html: 292
java: 219
config: 3
pdf: 14536
perl: 12
php: 9
sh: 11
svg: 377
txt: 8645
1 Je n’ai gardé là que les types effectivement présents

Tiens, ça liste également des PDF mais pas d’ODT et puis on a pas les extensions fichiers exactes pour chaque type…

2.4. Compter les fichiers par type

Lançons nous dans un meilleur aperçu de la répartition des fichiers par type, en comptant les fichiers par type mime et par extension (du moins celle que photorec a attribué aux fichiers).

$ rg -uuu --files --iglob "*" Recup > 122552_filenames.txt  (1)
1 J’en étais encore à 122552 fichiers. La commande dura 15s.

2.4.1. Compter les fichiers dont le noms a été retrouvé

$ rg '.{42,}' 122552_filenames.txt > liste_fichiers_avec_nom.txt
$ wc -l liste_fichiers_avec_nom.txt
4566 (1)
1 Cela représente 3,7% des 122k fichiers restant

Voici quelques exemples de long nom de fichier à éviter quand même :

  • Recup/recup_dir.10/f136265448.sqlite

  • Recup/recup_dir.194/f936769224_ftyp.mov

  • Recup/recup_dir.36/f179430256_PAY18E.pdf


Listons maintenant tous les fichiers par type mime et par extension :

$ file --mime-type -f 122552_filenames.txt > 122552_file_mime-types.txt (1)
$ sed -r 's/\s+/ /g' ../122552_file_mime-types.txt | cut -f 3,4,5,6,7 -d '.' | sort | uniq -c | sort -r -n > ../122552_file_ext_mime-type_summary.txt (2)
1 Bon là ça prend 2h sur ce disque dur à plateau d’une grande marque et relativement moderne
2 Cette ligne retire des espaces dans chaque ligne, puis retire le début de chaque ligne (jusqu’au 2e point), puis tri le fichier et compte les lignes identiques avant de les trier par nombre d’occurrences.
  72429 jpg: image/jpeg
  14544 pdf: application/pdf
   7513 txt: text/plain
   6576 png: image/png
   5198 odt: application/vnd.oasis.opendocument.text
   3430 mpg: video/mpeg
   1795 avi: video/x-msvideo
   1369 elf: application/x-sharedlib
   1219 mp3: audio/mpeg
   1199 apple: application/octet-stream
    739 txt: application/octet-stream
    […] (1)
1 Il y avait encore 77 types de fichiers à ce moment là (après le retrait des fichiers C, H, Python, Java et quelques autres).

On note qu’il est intéressant de retirer les fichiers elf et apple mais que le gros morceau reste les jpg.

2.4.2. Ranger les fichiers par extension

Un ami a utilisé ce billet de blog pour récupérer des fichiers perdus dans un Windows 11 sur support de stockage NVME. Il a décidé de s’arrêter à cette étape, après avoir rangé les 10k fichiers par extension. Voilà le script qu’il a utilisé :

#!/bin/bash

# Utilisation du premier argument comme répertoire source
source_dir="$1"

if [ -z "$source_dir" ]; then
    echo "Usage: $0 <source_directory>"
    exit 1
fi

# Fonction récursive pour traiter les fichiers d'un répertoire
process_directory() {
    local dir="$1"

    for ext in $(find "$dir" -type f | sed -n 's/.*\.\(.*\)/\1/p' | sort -u); do
        ext_dir="${ext}_files"
        # Création du répertoire d'extension s'il n'existe pas déjà
        mkdir -p "$ext_dir"

        # Déplacer les fichiers de l'extension vers le répertoire d'extension
        find "$dir" -type f -wholename "*.$ext" -exec mv {} "$ext_dir" \;
    done
}

# Appel initial pour le répertoire source
process_directory "$source_dir"

2.5. supprimer les miniatures JPEG

Explorer un dossier au hasard pour voir ce qu’il contient comme images :

$ find . -name "*.jpg" | wc -l
89
find . -name "*.jpg" -size -35k | wc -l
68
find . -name "*.jpg" -size -50k | wc -l
69
find . -name "*.jpg" -size -100k | wc -l
71
find . -name "*.jpg" -size -150k | wc -l
78
find . -name "*.jpg" -size -1500k | wc -l
78
find . -name "*.jpg" -size -1800k | wc -l
79

On constate qu’il y a plein de petites images, principalement des miniatures de vraies photos, créées par divers logiciels (explorateur de fichier, visionneur de photo…) sur divers systèmes d’exploitation.

On remarque également qu’il y a un grand trou dans la répartition des images entre 150ko et 1500ko. Les photos plus grosses auront toutes les chances d’être des vraies. Pour ma part j’ai décidé de couper à 300ko :

find Recup -name "*.jpg" -size -300k | wc -l
43414
find Recup -name "*.jpg" -size -300k | xargs -I {} mv {} poubelle/{} (1)
1 Cela prend environ 1 minute

Arrivé là on en est à 72635 fichiers et 414 GO soit 50% du nombre de fichiers du départ mais toujours 96% de l’occupation disque.

2.6. fclones pour trouver les fichiers redondants

J’ai alors décidé d’essayer fclones pour tenter de trouver des fichiers qui seraient présents en plusieurs exemplaires parmi les fichiers restants.

$ fclones group --cache /tmp > /tmp/fclones.group.txt  (1) (2)
fclones:  info: Found 48416 (149.9 GB) redundant files
$ fclones move poubelle < /tmp/fclones.group.txt
Deduplicating 17252 groups
fclones:  info: Processed 48416 files and reclaimed 149.9 GB space  (3) (4)
1 L’option --cache permet de sauver l’index des hash de fichier sur le disque dur (ici rangé dans le dossier /tmp), cela permettrait de le réutiliser si on avait à relancer la commande rapidement suite à une erreur, sans avoir à recalculer tous les hash
2 L’execution a pris 2h38
3 Cette dernière phase a pris 10 min
4 Il aurait probablement été préférable de faire des liens symboliques avant de déplacer les fichiers redondants

Nous voilà rendus à 24220 fichiers et 273 GO soit 16% du nombre initial de fichiers et 63% de la taille considérée.

2.7. Retrait des dossiers vides

Une partie rapide :

$ rmdir Recup/*
$ exa -l | wc -l
199 (1)
1 Donc 39 dossiers vides retirés (16%)

2.8. Retrouver les fichiers récents

Malheureusement photorec ne sait pas restaurer toutes les dates de création de fichier (mais, comme pour les noms, seulement celles retrouvables dans les métadonnées internes d’un fichier). Quand la date est inconnue, c’est la date du jour qui est utilisée.

Un tiers des documents ont pu être éliminés comme étant trop vieux (plus de 4 mois).

Voici la commande utilisée pour retrouver les fichiers récents :

$ find . -newermt $(date +%Y-%m-%d -d '4 months ago') -type f -print > recent_file_list.txt  (1) (2)
1 Retrouver les fichiers qui ont moins de 4 mois
2 Environ 100k fichiers furent trouvés par les 150k du départ

On peut retirer de cette liste les fichiers datant du jour de la récupération pour une liste plus courte (et donc plus facile à consulter) :

$ find . -newermt $(date +%Y-%m-%d -d '4 months ago') ! -newermt $(date +%Y-%m-%d -d '1 week ago') -type f -print > liste_incomplete_fichiers_recents.txt (1)
1 Là on tombe à 453 fichiers ; 4 ODT ; 0 avec son nom d’origine

Vu que je suis reparti de la liste intégrale des fichiers, on peut en retirer tous les fichiers éliminés ou dédoublonnés :

$ for a in `cat ~/liste_des_fichiers_recents.txt` ; do if test -f $a; then echo $a >> ~/liste_des_fichiers_recents_existants.txt ; fi; done

On en arrive à 17 122 fichiers, dont 144 DOC, 76 ODT…

2.9. Conclusion

photorec est un outil très précieux mais il n’est pas facile de s’y retrouver dans tous les fichiers qu’il retrouve.

Dans ce billet, nous sommes passés de 150k à 17k fichiers récents et uniques retrouvés.

Nous avons vu que photorec peut vous aider à retrouver votre précieux rapport perdu sur un support mourant, mais il risque de le retrouver plusieurs fois, accompagné de toutes ses versions précédentes et/ou supprimées… vos photos serons sauvées, mais également leurs miniatures et même avec toutes les techniques illustrées ici pour raffiner les données récupérées, il vous faudra encore beaucoup de travail pour vous réapproprier cette montagne de fichiers

2.10. Pensées pour la prochaine fois

J’aurais pu commencer par faire une copie bit à bit du support via dd pour pouvoir éventuellement revenir à une étape précédente en cas de fausse manip.