Quelque part, maintenant, un job de sauvegarde est « vert » tout en omettant silencieusement des fichiers. Une autre équipe expédie une release construite à partir d’un dossier qui « devrait correspondre à la prod ». Et quelqu’un s’apprête à copier un téraoctet deux fois parce qu’il ne fait pas confiance à la première copie.
Comparer deux dossiers semble une tâche basique. En production, c’est un piège. La bonne méthode dépend de ce que vous essayez de prouver : présence, identité octet-par-octet, ou « suffisamment proche » pour un déploiement. Se tromper et vous obtenez soit une confiance erronée, soit une réponse lente et coûteuse qui arrive après l’incident.
Ce que vous prouvez réellement (et pourquoi c’est important)
« Comparer deux dossiers » n’est pas un seul problème. C’en est au moins cinq. Si vous ne dites pas lequel vous mean, vous tomberez par défaut sur quelque chose de lent (hasher tout) ou trompeur (faire confiance aux tailles de fichier). Voici la taxonomie que j’utilise en astreinte.
1) Existence : tous les fichiers attendus sont-ils présents ?
C’est le problème des « fichiers manquants » : une copie partielle, une sauvegarde ratée, une synchronisation d’artefacts incomplète. Vous vous souciez des noms de fichiers, et peut-être de la structure des répertoires. En général vous ne vous souciez pas encore du contenu des fichiers.
Bonnes outils : rsync --dry-run, comm sur des listes de fichiers triées, manifestes find.
2) Égalité des métadonnées : horodatages, permissions, propriétaires correspondent-ils ?
Cela compte quand vous restaurez des systèmes, migrez des répertoires personnels, ou déplacez des données entre serveurs NFS où les modes et propriétaires sont les « données réelles ». Si les permissions diffèrent, votre appli échoue de façon à ressembler à des « interruptions aléatoires ». Elles ne le sont pas.
Bonnes outils : rsync -a --dry-run, stat, getfacl si les ACL importent.
3) Égalité de contenu : les octets sont-ils identiques ?
C’est la vérification d’intégrité. Vous prouvez que deux fichiers sont les mêmes, même si les horodatages ou noms mentent. C’est plus lent, mais c’est la seule chose qui ferme les débats après une restauration.
Bonnes outils : checksums (SHA-256), rsync --checksum (avec précaution), échantillonnage de contenu quand vous êtes limité dans le temps.
4) Égalité logique : produisent-ils le même résultat ?
Pour les builds, conteneurs et jeux de données, vous pouvez ne pas vous préoccuper de l’égalité octet-par-octet. Vous voulez que l’application se comporte de la même manière. C’est une preuve différente. La comparaison de dossiers peut aider, mais ne confondez pas « ça ressemble » et « c’est identique ».
5) Cohérence sous changement : comparez-vous une cible mouvante ?
Comparer un dossier pendant que des fichiers sont écrits, c’est comme mesurer un poisson pendant qu’il s’échappe. Parfois vous pouvez le faire (snapshots, quiescing, builds immuables). Parfois non, et la bonne réponse est « arrêtez le monde, puis comparez ».
Une citation opérationnelle à garder :
Idée paraphrasée — Gene Kim : les opérations performantes raccourcissent les boucles de rétroaction et rendent le travail visible, de sorte que les problèmes apparaissent avant de devenir incidents.
La comparaison de dossiers, c’est de la visibilité. Pas glamour. Mais c’est la différence entre « on pense que ça a copié » et « on peut le prouver ».
Méthodes rapides d’abord : choisir le bon outil
Règle n°1 : ne hashez pas un pétaoctet parce que vous êtes nerveux
Les checksums sont la référence, mais ils imposent aussi la « taxe lire chaque octet ». Si votre seule question est « avons-nous raté quelque chose ? », hasher est de l’automutilation. Commencez par un manifeste de chemins relatifs et tailles ; puis escaladez.
Règle n°2 : rsync --dry-run est l’outil « comparer dossiers » le plus utile sur Terre
Il parle le langage des opérations : « Que changerait la synchronisation ? » C’est un diff avec conséquences. Utilisez-le localement, via SSH, entre points de montage. Sous pression, il vous donne une liste actionnable.
Règle n°3 : les horodatages mentent souvent
Les outils de copie préservent parfois les mtimes, parfois non. Les systèmes de fichiers arrondissent les mtimes différemment. Les changements de fuseau horaire et la dérive d’horloge arrivent. Si vous comparez les mtimes, considérez les résultats comme un indice, pas un verdict.
Règle n°4 : permissions et ACL sont des données
Si vous restaurez un service, une mauvaise propriété est une « perte de données » mieux emballée. Si votre comparaison ignore les ACL, vous livrerez un problème en l’appelant une restauration réussie.
Règle n°5 : si le dataset est actif, utilisez des snapshots (ou acceptez l’incertitude)
Sur ZFS, les snapshots rendent cela simple. Sur LVM, c’est possible aussi. Sur le stockage objet cloud, vous aurez besoin de manifestes versionnés. Sans vue stable à un instant T, votre comparaison montrera des changements qui ne sont que des écritures du jour.
Blague n°1 : hasher tout « pour être sûr » revient à peser votre voiture chaque matin pour vérifier le niveau de carburant. Exact, oui. Nécessaire, non.
Tâches pratiques (commandes, sorties, décisions)
Ci‑dessous des tâches adaptées à la production. Chacune inclut une commande, un extrait de sortie réaliste, et la décision que vous en tirez. Exécutez-les avec un but clair : trouver des fichiers manquants, modifiés, dérive de métadonnées, ou problèmes d’intégrité.
Task 1: Fast missing-file detection with rsync (local-to-local)
cr0x@server:~$ rsync -a --dry-run --itemize-changes /data/src/ /data/dst/
sending incremental file list
*deleting old/unused.log
>f+++++++++ reports/2026-01.csv
>f..t...... images/logo.png
sent 1,204 bytes received 88 bytes 2,584.00 bytes/sec
total size is 9,812,441,102 speedup is 7,589,904.72 (DRY RUN)
Ce que ça signifie : >f+++++++++ est un fichier qui serait créé dans la destination (manquant là-bas). >f..t...... signifie que le timestamp diffère (le contenu peut ou non différer). *deleting indique que la destination a des fichiers en plus par rapport à la source (affiché uniquement si vous ajoutez les flags de suppression ; voir la tâche suivante).
Décision : Si vous vérifiez une copie, les fichiers manquants (+++++++++) sont un arrêt de ligne. Les seules différences de timestamp nécessitent des vérifications supplémentaires (taille/hash) selon votre tolérance au risque.
Task 2: Detect extras in destination (safely) with rsync
cr0x@server:~$ rsync -a --dry-run --delete --itemize-changes /data/src/ /data/dst/
sending incremental file list
*deleting tmp/debug.dump
*deleting cache/.DS_Store
sent 1,112 bytes received 64 bytes 2,352.00 bytes/sec
total size is 9,812,441,102 speedup is 8,342,119.31 (DRY RUN)
Ce que ça signifie : Avec --delete, rsync proposera de supprimer les fichiers dans la destination qui ne sont pas dans la source. En dry-run, il se contente de rapporter.
Décision : Si la destination doit être un miroir (sauvegardes, répliques), ces extras sont une dérive. Si la destination est une archive, vous ne voudrez probablement pas la sémantique delete.
Task 3: Compare two directories quickly with diff -rq
cr0x@server:~$ diff -rq /data/src /data/dst | head
Only in /data/src/reports: 2026-01.csv
Files /data/src/images/logo.png and /data/dst/images/logo.png differ
Only in /data/dst/tmp: debug.dump
Ce que ça signifie : Fichiers manquants et lignes « differ ». diff compare le contenu, mais lit les fichiers ; sur des arbres énormes, il peut être plus lent que la détection basée sur les métadonnées de rsync.
Décision : Utilisez ceci quand vous avez besoin d’un rapport direct « même/différent » et que le dataset est modéré. Si c’est multi-téraoctets, préférez les manifestes rsync et le hachage ciblé.
Task 4: Build a stable manifest of paths and sizes (cheap, usually enough)
cr0x@server:~$ cd /data/src
cr0x@server:~$ find . -type f -printf '%P\t%s\n' | sort > /tmp/src.pathsizes
cr0x@server:~$ wc -l /tmp/src.pathsizes
84217 /tmp/src.pathsizes
Ce que ça signifie : Une ligne par fichier : chemin relatif et taille. Le tri le rend comparable.
Décision : Si les manifestes src et dst correspondent exactement, vous avez prouvé « mêmes fichiers, mêmes tailles ». Pas identique octet-par-octet, mais une preuve solide pour des copies où la corruption est peu probable et le temps serré.
Task 5: Compare manifests with comm to find missing files
cr0x@server:~$ cd /data/dst
cr0x@server:~$ find . -type f -printf '%P\t%s\n' | sort > /tmp/dst.pathsizes
cr0x@server:~$ comm -3 /tmp/src.pathsizes /tmp/dst.pathsizes | head
reports/2026-01.csv 12044
tmp/debug.dump 4096
Ce que ça signifie : Les lignes préfixées par une tab existent seulement dans le second fichier ; les lignes sans tab existent seulement dans le premier. Ici : report manquant dans dst ; debug.dump en extra dans dst.
Décision : Fichiers manquants : recopier ou resynchroniser. Fichiers en extra : décider si dst doit être un miroir exact ; si oui, supprimer ou reconstruire dst depuis la source de vérité.
Task 6: Identify “same path, different size” quickly
cr0x@server:~$ join -t $'\t' -j 1 \
<(cut -f1,2 /tmp/src.pathsizes) \
<(cut -f1,2 /tmp/dst.pathsizes) | awk -F'\t' '$2 != $3 {print $1, $2, $3}' | head
images/logo.png 18432 18312
db/seed.sql 901122 901114
Ce que ça signifie : Le même chemin relatif existe dans les deux, mais les tailles diffèrent.
Décision : Traitez ça comme du contenu modifié. Si ça doit être identique, resynchronisez ces chemins puis hashez-les pour confirmation.
Task 7: Targeted hashing of only suspicious files (fast escalation)
cr0x@server:~$ sha256sum /data/src/images/logo.png /data/dst/images/logo.png
a1c3d2d19c9f7f0c2a2a0ddc7f6d4b2e9f1b2d3c4a5b6c7d8e9f001122334455 /data/src/images/logo.png
b88f2bd42a9e0f1c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c /data/dst/images/logo.png
Ce que ça signifie : Hashs différents : octets différents, point final.
Décision : Si dst est une sauvegarde/réplica, enquêtez sur une corruption de transfert/stockage ou une mise à jour non synchronisée. Si c’est un artefact de déploiement, arrêtez et reconstruisez depuis une source de vérité unique.
Task 8: Full-tree checksum manifest (slow, definitive)
cr0x@server:~$ cd /data/src
cr0x@server:~$ find . -type f -print0 | sort -z | xargs -0 sha256sum > /tmp/src.sha256
cr0x@server:~$ head -3 /tmp/src.sha256
9f2a... ./bin/app
44c1... ./conf/app.yaml
e11b... ./images/logo.png
Ce que ça signifie : Manifeste de checksum trié et stable pour tout l’arbre. Le tri avec séparateurs nuls évite les problèmes de chemins et de dérive d’ordre.
Décision : Utilisez ceci quand vous avez besoin d’une preuve de type juridictionnelle (restaurations, conformité, promotion d’artefacts). Acceptez que ce soit coûteux en E/S ; planifiez-le, ne surprenez pas la prod.
Task 9: Verify destination matches a checksum manifest
cr0x@server:~$ cd /data/dst
cr0x@server:~$ sha256sum -c /tmp/src.sha256 | head
./bin/app: OK
./conf/app.yaml: OK
./images/logo.png: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
Ce que ça signifie : OK signifie correspondance exacte. FAILED signifie que le contenu diffère. Si le message indique « No such file », le fichier manque.
Décision : Tout FAILED ou fichier manquant est une défaillance sévère pour la vérification de sauvegarde. Recopiez ces fichiers ; si les échecs persistent, suspectez un problème de stockage/média ou une corruption silencieuse.
Task 10: Compare folders over SSH with rsync (dry-run)
cr0x@server:~$ rsync -a --dry-run --itemize-changes -e ssh /data/src/ backup01:/data/dst/
sending incremental file list
>f+++++++++ reports/2026-01.csv
>f..t...... images/logo.png
sent 1,882 bytes received 112 bytes 3,988.00 bytes/sec
total size is 9,812,441,102 speedup is 4,920,184.83 (DRY RUN)
Ce que ça signifie : Mêmes sémantiques, mais vous validez maintenant l’état distant. Note : rsync compare par défaut les métadonnées, pas les checksums.
Décision : Utilisez comme audit distant en première passe. Si quelque chose de surprenant apparaît, faites du hachage ciblé via SSH pour les fichiers suspects (ou générez un manifeste de chaque côté).
Task 11: Catch permission drift (the “it exists but doesn’t work” class)
cr0x@server:~$ stat -c '%a %U:%G %n' /data/src/conf/app.yaml /data/dst/conf/app.yaml
640 app:app /data/src/conf/app.yaml
600 app:app /data/dst/conf/app.yaml
Ce que ça signifie : Même propriétaire, modes différents. Ça peut casser les lectures, écritures ou attentes de gestion de configuration.
Décision : Si les permissions doivent correspondre, corrigez votre méthode de copie : rsync -a (et exécutez en root quand la propriété compte), ou préservez ACLs/xattrs si votre environnement les utilise.
Task 12: Compare extended attributes (xattrs) when they matter
cr0x@server:~$ getfattr -d -m - /data/src/bin/app 2>/dev/null
# file: data/src/bin/app
security.capability=0sAQAAAgAgAAAAAAAAAAAAAAAAAAA=
cr0x@server:~$ getfattr -d -m - /data/dst/bin/app 2>/dev/null
# file: data/dst/bin/app
Ce que ça signifie : La source a un xattr de capacité Linux ; la destination n’en a pas. Le binaire peut échouer à binder des ports bas ou se comporter différemment.
Décision : Utilisez rsync -aX (xattrs) et possiblement -A (ACLs). Si vous êtes sur des systèmes de fichiers qui perdent les xattrs, cessez de faire comme si c’était une copie fidèle.
Task 13: Find files that changed recently (triage during an incident)
cr0x@server:~$ find /data/src -type f -mmin -60 -printf '%TY-%Tm-%Td %TH:%TM %p\n' | head
2026-02-05 09:12 /data/src/reports/2026-02.csv
2026-02-05 09:21 /data/src/tmp/run.log
Ce que ça signifie : Fichiers modifiés dans la dernière heure. Idéal pour « pourquoi la comparaison continue de changer ?».
Décision : Si votre arbre change activement, arrêtez de le comparer en direct. Utilisez des snapshots, figez les écritures, ou comparez seulement des sous-arbres immuables (comme des artefacts de release).
Task 14: Quick “are these directories on different filesystems with different semantics?” check
cr0x@server:~$ df -T /data/src /data/dst
Filesystem Type 1K-blocks Used Available Use% Mounted on
tank/data zfs 9767548928 512334112 9255214816 6% /data/src
backup:/data nfs4 9767548928 515220480 9252328448 6% /data/dst
Ce que ça signifie : La source est ZFS ; la destination est NFS. Attendez-vous à une précision d’horodatage différente, des bizarreries de mappage de propriétaires, et du caching d’attributs.
Décision : Si les résultats de comparaison sont « bruyants », validez avec des checksums pour les fichiers critiques et ajustez les options de montage NFS si nécessaire. Aussi : n’assumez pas que les fonctionnalités POSIX se comportent identiquement.
Task 15: Measure the cost of your compare method (don’t guess)
cr0x@server:~$ /usr/bin/time -v rsync -a --dry-run /data/src/ /data/dst/ >/dev/null
Command being timed: "rsync -a --dry-run /data/src/ /data/dst/"
User time (seconds): 0.82
System time (seconds): 4.11
Percent of CPU this job got: 62%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:07.96
File system inputs: 126544
File system outputs: 0
Ce que ça signifie : Beaucoup d’entrées système de fichiers même pour un dry-run. C’est de l’I/O métadonnée. Sur caches froids, cela peut bombarder votre stockage.
Décision : Si les scans de métadonnées saturent la prod, planifiez-les hors pic, réchauffez les caches avec précaution, ou gardez un manifeste roulant mis à jour de façon incrémentale.
Task 16: When you absolutely need byte-level compare for a single huge file
cr0x@server:~$ cmp -n 1048576 /data/src/big.img /data/dst/big.img && echo "first 1MiB matches"
first 1MiB matches
Ce que ça signifie : Les premiers 1 MiB correspondent. Ce n’est pas une vérification complète, mais c’est un test de fumée rapide quand vous faites du triage.
Décision : Utilisez comme contrôle rapide, puis suivez avec des checksums complets si le fichier est critique.
Blague n°2 : rien ne crée l’unité d’équipe comme un fichier manquant découvert cinq minutes avant une démo.
Playbook de diagnostic rapide
Quand « la comparaison de dossiers est lente » ou « les résultats n’ont pas de sens », n’allez pas dans tous les sens. Diagnosez comme un SRE : isolez le goulot, puis choisissez la correction la moins invasive.
Premier : confirmez le type de problème
- Fichiers manquants ? Utilisez
rsync -a --dry-runou des manifestes de chemins. Ne hashez pas encore. - Contenu changé ? Vérifiez les deltas taille/mtime, puis hashez seulement l’ensemble delta.
- Problèmes de permissions/ACL ? Comparez les métadonnées ; le hachage n’aidera pas.
- Churn en direct ? Arrêtez de comparer des cibles mouvantes : snapshots ou figez les écritures.
Second : identifiez ce qui est lent (CPU, I/O métadonnées, réseau ou disque)
cr0x@server:~$ iostat -xz 1 3
Linux 6.5.0 (server) 02/05/2026 _x86_64_ (16 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
3.11 0.00 9.44 41.02 0.00 46.43
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s w_await aqu-sz %util
nvme0n1 821.0 66240.0 0.0 0.00 47.20 80.70 2.0 64.0 1.50 38.80 99.20
Interprétation : %iowait élevé et %util proche de 100 % : le stockage est le goulot. Les scans de répertoire punissent vos disques.
Action : Arrêtez de faire des scans complets en heures de pointe. Utilisez snapshots/manifestes, ou lancez les comparaisons sur une réplique/secondaire.
cr0x@server:~$ sar -n DEV 1 3 | tail -n +4
Average: IFACE rxpck/s txpck/s rxkB/s txkB/s %ifutil
Average: eth0 120.11 115.88 9821.33 9012.47 82.50
Interprétation : Le réseau est occupé ; les comparaisons distantes peuvent être contraintes par l’utilisation de lien ou la latence.
Action : Préférez la génération de manifestes côté distant et comparez de petits fichiers texte. Évitez de lire des fichiers entiers sur le réseau sauf si nécessaire.
Troisième : vérifiez les sémantiques du système de fichiers et du montage
- Le caching d’attributs NFS peut rendre les mtimes temporairement « incorrects ».
- SMB/CIFS peut normaliser la casse ; les copies macOS peuvent créer des fichiers AppleDouble.
- La précision d’horodatage différente peut produire des signaux « modifié » constants.
cr0x@server:~$ mount | grep -E ' /data/dst | /data/src '
tank/data on /data/src type zfs (rw,xattr,noacl)
backup:/data on /data/dst type nfs4 (rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2)
Interprétation : Plateformes différentes. Attendez-vous à des cas limites métadonnées.
Action : Si l’objectif est l’intégrité, ne discutez pas avec les mtimes. Utilisez des manifestes de checksum pour les sous-ensembles critiques.
Quatrième : réduisez la portée intelligemment
- Comparez seulement des répertoires immuables (releases, snapshots, partitions journalières).
- Excluez caches et dossiers temporaires ; ce sont des générateurs d’entropie.
- Commencez par des comparaisons « liste seulement » puis escaladez.
cr0x@server:~$ rsync -a --dry-run --itemize-changes --exclude='tmp/' --exclude='cache/' /data/src/ /data/dst/ | head
sending incremental file list
>f+++++++++ reports/2026-01.csv
Interprétation : Le rapport signal/bruit s’améliore immédiatement.
Action : Intégrez des exclusions dans vos scripts de comparaison standards, mais documentez-les pour ne pas cacher de vrais problèmes.
Trois mini-récits d’entreprise (avec douleur)
Incident causé par une mauvaise hypothèse : « taille identique = contenu identique »
Une équipe a migré une grande archive de rapports entre deux NAS. Ils ont utilisé une vérification rapide : nombre de fichiers et total d’octets. Tout correspondait. Ils ont déclaré victoire et mis hors service l’ancien système.
Des semaines plus tard, des auditeurs ont demandé un ensemble précis de rapports mensuels. Une poignée était illisible : les PDF s’ouvraient avec des erreurs. Les noms existaient, les tailles correspondaient. C’est ce qui a rendu la situation pénible ; personne ne suspectait de la corruption.
La cause racine était un chemin réseau défectueux lors de la copie initiale. L’outil de copie a relancé et « achevé », mais quelques fichiers ont été silencieusement tronqués puis rembourrés par une application qui a touché les métadonnées. Même taille. Octets différents. Le contrôle par compte ne l’a pas détecté ; le contrôle de taille non plus ; les horodatages non plus.
La correction a été ennuyeuse : générer un manifeste SHA-256 sur la source, le vérifier sur la destination, puis seulement supprimer l’ancien dataset. Ils ont réhydraté les fichiers corrompus à partir de sauvegardes plus anciennes et mis en place la vérification par checksum pour les futures migrations.
Leçon : si vous retirez la source de vérité, effectuez au moins une passe de vérification basée sur le contenu. Pas forcément pour tout quotidiennement, mais pour les migrations, toujours.
Optimisation qui s’est retournée contre eux : « utilisons --checksum partout »
Un groupe plateforme en avait assez de débattre si deux répertoires étaient « vraiment » identiques. Ils ont emballé rsync dans un script et utilisé --checksum par défaut. Sur le papier, ça résolvait le problème de confiance : rsync hacherait chaque fichier et comparerait les hashs.
En réalité, ça a déplacé le coût de « parfois on recopie trop » à « on lit tout le dataset à chaque exécution ». Sur un cluster de stockage avec une forte pression métadonnées et des disques occupés, la tâche de comparaison est devenue une attaque par déni de service contre leur propre infrastructure. La latence a grimpé. Les fenêtres de sauvegarde ont glissé. Quelques services ont commencé à timeouter contre le stockage partagé.
Le plus agaçant : le script tournait en cron. Donc l’impact était périodique et confus, comme une maison hantée mais avec des graphes. Ils ont d’abord blâmé le réseau. Puis le fournisseur de stockage. Puis quelqu’un a finalement lancé iostat pendant l’événement et a vu la saturation en lecture.
La correction finale a été une vérification en couches : utiliser la comparaison de métadonnées rsync pour les contrôles quotidiens, et exécuter un manifeste de checksum hebdomadaire (ou à la demande après incidents). Ils ont aussi ajouté un contrôle de portée : ne hasher que les artefacts de release immuables et les répertoires critiques pour la conformité.
Leçon : « correct » peut être opérationnellement faux quand on l’applique sans discernement. La vérité déterministe, c’est bien ; des interruptions déterministes, non.
Pratique ennuyeuse mais correcte qui a sauvé la mise : snapshot + manifeste
Une équipe data engineering devait répliquer chaque nuit un dataset vers un site de disaster recovery. Le dataset était volumineux et changeait constamment en heures ouvrées. Les premières tentatives de comparaison de répertoires en direct produisaient des résultats incohérents : des fichiers apparaissaient et disparaissaient en plein scan, et les diffs étaient bruyants.
Ils ont adopté une pratique stricte : à 01:00, prendre un snapshot du dataset source, répliquer ce snapshot, puis comparer le contenu du snapshot au snapshot répliqué. Pas de comparaisons « live ». Pas de discussions sur le churn.
Un mardi au hasard, la réplication a « réussi » mais des jobs downstream ont commencé à échouer en DR. Leur pipeline de comparaison a signalé un petit nombre de fichiers manquants dans une partition. Parce que la comparaison portait sur un snapshot, c’était sans équivoque : les fichiers manquaient de la vue répliquée, pas « encore en écriture ».
Ils ont rapidement trouvé le coupable : un pattern d’exclusion mal configuré dans le job de réplication qui filtrait un nom de répertoire utilisé seulement par un client. Il avait été introduit lors d’un nettoyage. Le pipeline de comparaison l’a détecté immédiatement, avant qu’un désastre ne les force à compter sur la DR.
Leçon : les snapshots transforment la comparaison d’opinion en mathématiques. La pratique est ennuyeuse. C’est pour ça que ça marche.
Faits intéressants et histoire utile
- L’idée de « delta transfer » de rsync date du milieu des années 1990 et a rendu la synchronisation distante pratique sur des liens lents en n’envoyant pas les blocs inchangés.
- Unix
diffprédate la plupart des systèmes de fichiers modernes. Il a été conçu pour du texte, mais son mode récursif est devenu un instrument brut pour les arbres de répertoires. - MD5 était courant pour les vérifications d’intégrité, mais les attaques par collision en ont fait un mauvais choix en contextes adverses. Pour la vérification ops, SHA-256 est le défaut raisonnable.
- La précision des horodatages varie : ext4 supporte les nanosecondes ; certains systèmes réseau arrondissent à 1 seconde (ou pire). Votre signal « modifié » peut être du bruit d’arrondi.
- La sensibilité à la casse diffère : les systèmes Linux sont généralement sensibles à la casse ; beaucoup de Windows et macOS par défaut sont insensibles. Deux fichiers différents peuvent se fusionner pendant une copie.
- Les hard links compliquent le « compte de fichiers » : un même inode peut avoir plusieurs entrées de répertoire. Certains outils dupliquent les données au lieu de préserver les liens sauf si configurés.
- Les attributs étendus et ACLs sont devenus largement utilisés à mesure que les systèmes se sécurisaient ; les perdre peut changer le comportement d’exécution et d’accès sans modifier le contenu des fichiers.
- La corruption silencieuse existe : les systèmes modernes s’appuient sur des vérifications end-to-end (systèmes de fichiers comme ZFS, checksums applicatifs, ou vérification par manifeste) parce que disques, contrôleurs et RAM peuvent mentir occasionnellement.
- « Sauvegarde réussie » signifie rarement « restauration vérifiée » : la maturité opérationnelle se manifeste souvent par des vérifications routinières, pas par des tableaux de bord plus jolis.
Erreurs fréquentes : symptômes → cause → correction
1) Symptom: compare shows thousands of “changed” files every run
Cause racine : mismatch de précision d’horodatage (ext4 local vs NFS/SMB), dérive d’horloge, ou un outil de copie qui ne préserve pas les mtimes.
Correction : Cessez de faire confiance aux mtimes comme signal principal. Utilisez d’abord les manifestes de taille ; puis hashez les deltas. Si vous avez besoin de fidélité métadonnée, utilisez rsync -a et assurez-vous que les deux côtés le supportent.
2) Symptom: files exist on destination but app fails with “permission denied”
Cause racine : propriété/mode/ACL/xattr non préservés ; restauration effectuée en non-root ; ACLs supprimées par le système de fichiers.
Correction : Utilisez rsync -aAX quand approprié. Validez avec stat, getfacl, getfattr. Si la destination ne peut pas stocker ACLs/xattrs, changez la destination ou adaptez le modèle de sécurité volontairement.
3) Symptom: “Only in source” files come and go during the scan
Cause racine : comparaison d’un répertoire live qui est écrit, roté, ou nettoyé.
Correction : Comparez des snapshots ou arrêtez les écritures pendant la comparaison. Pour les logs et chemins temporaires, excluez-les du périmètre de comparaison.
4) Symptom: rsync shows differences, but hashing shows files are identical
Cause racine : différences de métadonnées (mtime, perms) ou arrondi d’horodatage ; rsync dit la vérité sur les métadonnées, pas sur le contenu.
Correction : Décidez ce que « identique » signifie pour ce workflow. Pour l’intégrité de sauvegarde, le contenu importe le plus ; pour les restaurations système, les métadonnées aussi. Configurez la comparaison en conséquence.
5) Symptom: checksum verification is unbearably slow and impacts production
Cause racine : lecture complète de grands datasets, caches froids, contention avec I/O utilisateur ; exécution en pic.
Correction : Planifiez les scans de checksum hors‑pic. Hashez seulement les sous‑ensembles immuables ou à haute valeur. Maintenez des manifestes roulants par partition/jour plutôt que de scanner tout l’arbre.
6) Symptom: destination has extra dotfiles and “weird” metadata files
Cause racine : copie depuis macOS (AppleDouble ._ files), métadonnées Windows, ou artefacts d’outils de sauvegarde.
Correction : Excluez intentionnellement les patterns de junk connus, mais documentez les exclusions. Mieux : séparez les « données » des « artefacts OS client » à la source.
7) Symptom: compare results differ depending on who runs it
Cause racine : différences de permissions affectent ce que find peut voir ; certains fichiers sont illisibles pour les non-root. Aussi, le root-squash NFS peut masquer la réalité de propriété.
Correction : Exécutez les comparaisons avec des privilèges cohérents. Pour les restaurations système, faites-les en root des deux côtés (avec précaution). Capturez les erreurs de find et traitez-les comme des échecs, pas du bruit.
8) Symptom: a file with the same name overwrote another during copy
Cause racine : système de fichiers destination insensible à la casse ; Readme et README entrent en collision.
Correction : Ne copiez pas d’arbres sensibles à la casse vers des volumes insensibles à la casse sauf si vous avez une politique de nommage et une validation. Détectez les collisions en normalisant la casse dans les manifestes avant migration.
Checklists / plan pas à pas
Checklist A : « Je dois juste savoir ce qui manque » (rapide, faible risque)
- Confirmez le périmètre : choisissez les racines et assurez-vous que les slashs finaux sont corrects pour rsync (
/src/vs/src). - Lancez rsync en dry-run avec l’itemize:
cr0x@server:~$ rsync -a --dry-run --itemize-changes /data/src/ /data/dst/ | head -50 sending incremental file list >f+++++++++ reports/2026-01.csv - Si vous devez détecter les extras dans la destination, ajoutez
--delete(toujours en dry-run) et examinez les lignes*deleting. - Décidez : si l’objectif est un miroir, corrigez en synchronisant ; si l’objectif est « la sauvegarde conserve plus », ne supprimez pas.
Checklist B : « Je dois prouver l’intégrité » (plus lent, défendable)
- Stabilisez le dataset : snapshot ou pause des écritures. Si vous ne pouvez pas, soyez honnête sur l’incertitude.
- Générez un manifeste SHA-256 trié sur la source:
cr0x@server:~$ cd /data/src cr0x@server:~$ find . -type f -print0 | sort -z | xargs -0 sha256sum > /tmp/src.sha256 cr0x@server:~$ tail -1 /tmp/src.sha256 3d4c... ./reports/2026-01.csv - Copiez le manifeste vers la destination (ou générez-le aussi là-bas) et vérifiez:
cr0x@server:~$ cd /data/dst cr0x@server:~$ sha256sum -c /tmp/src.sha256 | tail -3 ./images/logo.png: OK ./reports/2026-01.csv: OK - Tout
FAILEDou « No such file » est une défaillance sévère. Resynchronisez et revérifiez. - Décidez : si les échecs persistent, stoppez et enquêtez sur corruption stockage/réseau, RAM défectueuse, problèmes de contrôleur, ou une application qui modifie les fichiers après copie.
Checklist C : « La restauration doit fonctionner » (permissions, ACLs, xattrs)
- Choisissez un échantillon représentatif de fichiers : configs, exécutables, secrets, et répertoires qui imposent des permissions.
- Comparez les métadonnées:
cr0x@server:~$ stat -c '%a %U:%G %n' /data/src/bin/app /data/dst/bin/app 755 root:root /data/src/bin/app 755 root:root /data/dst/bin/app - Si votre environnement utilise ACLs/xattrs, vérifiez-les explicitement (
getfacl,getfattr). - Corrigez la méthode de copie (
rsync -aAX) et relancez la validation.
Checklist D : « Grand dataset, temps limité » (triage)
- Exécutez une comparaison manifeste chemins+tailles (bon marché) pour trouver les fichiers manquants et ceux dont la taille diffère.
- Hashez seulement les fichiers dont la taille diffère et un échantillon aléatoire de fichiers « même taille ».
- Si l’échantillon aléatoire échoue, étendez le hachage. S’il passe, avancez avec une confiance prudente et documentez vos actions.
FAQ
1) What’s the fastest way to compare two folders on Linux?
Pour l’usage opérationnel, rsync -a --dry-run --itemize-changes est généralement le moyen le plus rapide et actionnable. Il lit principalement des métadonnées, pas le contenu complet, donc il scale mieux que le hachage.
2) Does diff -rq verify file contents?
Oui, il peut lire et comparer le contenu des fichiers, ce qui le rend plus définitif que les comparaisons mtime/taille. Il peut aussi être beaucoup plus lent sur de grands arbres et bruyant sur des datasets majoritairement binaires.
3) When should I use checksums?
Utilisez les checksums quand vous avez besoin de preuve : migrations où vous supprimerez la source, vérification de conformité, tests de restauration, ou quand vous suspectez une corruption. Utilisez manifestes et rsync pour la détection quotidienne de dérive.
4) Is rsync --checksum the same as a checksum manifest?
Pas exactement. --checksum force rsync à calculer des checksums pour décider des transferts. Il nécessite encore la lecture de tout le contenu des fichiers, et ce n’est pas un artefact durable sauf si vous capturez séparément les résultats. Un manifeste est un enregistrement autonome que vous pouvez re-vérifier ultérieurement.
5) Why do I see changes even when nobody touched the files?
Causes communes : arrondis d’horodatage, dérive de fuseau/horloge, mises à jour métadonnées par antivirus/indexeurs, caching d’attributs NFS, ou outils qui réécrivent des fichiers en place (même si le contenu est logiquement identique).
6) How do I compare folders over SSH without pulling all data across the network?
Générez de petits manifestes de chaque côté (chemins+tailles, ou checksums si nécessaire) et comparez les sorties texte. Ou utilisez rsync dry-run sur SSH, qui ne transfère que métadonnées et listes de fichiers.
7) What about symlinks and hard links?
Les symlinks peuvent être comparés en tant que liens ou en tant que cibles déréférencées, selon l’outil et les flags. Les hard links exigent un traitement spécial si vous voulez préserver les relations de lien ; sinon les copies peuvent dupliquer les données tout en « ayant l’air correctes » par le contenu des fichiers.
8) How do I handle filenames with spaces and weird characters in manifests?
Utilisez des pipelines terminés par null : find ... -print0 avec sort -z et xargs -0. Évitez le parsing naïf ligne-par-ligne quand les chemins peuvent contenir des tabs ou des nouvelles lignes.
9) Can I trust file size comparisons for integrity?
Les correspondances de taille sont utiles pour le triage rapide et détecter les truncations évidentes, mais elles ne prouvent pas l’identité du contenu. Si les enjeux sont élevés, la taille est un indice, pas une preuve.
10) How do I compare only a subset (exclude caches, temp, logs)?
Utilisez les exclusions rsync (ou la taille/pruning via find) explicitement et de façon cohérente. Gardez la liste d’exclusions sous contrôle de version, car les « exclusions temporaires » ont tendance à devenir des angles morts permanents.
Étapes suivantes à réaliser aujourd’hui
- Choisissez une norme pour votre organisation : rsync dry-run pour les comparaisons quotidiennes, manifestes de checksum pour les migrations et la vérification des restaurations.
- Notez ce que « identique » signifie pour chaque workflow : existence seulement, fidélité des métadonnées, ou identité octet-par-octet. Mettez-le dans le runbook pour que vous à 3 h du matin n’improvisiez pas.
- Créez un script de manifeste réutilisable qui soit safe pour les nuls et trié, et stockez les manifestes à côté des sauvegardes/snapshots.
- Planifiez les vérifications lourdes (hachage complet d’arbre) hors-pic et mesurez l’impact avec
iostatet des timings. Ne devinez pas. - Entraînez la vérification de restauration sur un sous‑ensemble petit mais représentatif chaque semaine. Pas parce que vous aimez la paperasse. Parce que les incidents aiment les surprises.
Si vous retenez une chose : commencez petit, escaladez seulement quand les preuves le dictent, et ne comparez jamais une cible mouvante à moins d’aimer débattre philosophiquement avec votre array de stockage.