Linux: calculer un seul hachage pour un dossier et un contenu donnés?
Il doit Sûrement y avoir un moyen de le faire facilement!
J'ai essayé les applications de ligne de commande linux sha1sum & md5sum mais elles semblent seulement capables de calculer les hachages de fichiers individuels et de produire une liste de valeurs de hachage, une pour chaque fichier.
J'ai besoin de générer un seul hachage pour l'ensemble du contenu d'un dossier (pas seulement les noms de fichiers).
Je voudrais faire quelque chose comme
sha1sum /folder/of/stuff > singlehashvalue
Edit: pour clarifier, mes fichiers sont à plusieurs niveaux dans l'arborescence des répertoires, ils ne sont pas tous dans le même dossier racine.
14 réponses
Une façon possible serait:
sha1sum path/to/folder/* | sha1sum
S'il y a toute une arborescence de répertoires, il vaut probablement mieux utiliser find et xargs. Une commande possible serait
find path/to/folder -type f -print0 | xargs -0 sha1sum | sha1sum
Edit: Bon point, c'est probablement une bonne chose pour trier la liste des fichiers, donc:
find path/to/folder -type f -print0 | sort -z | xargs -0 sha1sum | sha1sum
Et, enfin, si vous devez également tenir compte des autorisations et des répertoires vides:
(find path/to/folder -type f -print0 | sort -z | xargs -0 sha1sum;
find path/to/folder \( -type f -o -type d \) -print0 | sort -z | \
xargs -0 stat -c '%n %a') \
| sha1sum
Les arguments de {[4] } lui feront imprimer le nom du fichier, suivi de ses autorisations octales. Le deux trouvailles s'exécuteront l'une après l'autre, provoquant le double de la quantité d'E / S du disque, la première trouvant tous les noms de fichiers et la somme de contrôle du contenu, la seconde trouvant tous les noms de fichiers et de répertoires, le nom et le mode d'impression. La liste des "noms de fichiers et sommes de contrôle", suivie de "noms et répertoires, avec des autorisations" sera alors checksumed, pour une somme de contrôle plus petite.
Validez le répertoire dans git, utilisez le hachage de validation. Voir metastore pour un moyen de contrôler également les autorisations.
Utilisez un outil de détection d'intrusion de système de fichiers comme aide .
-
Hachez une boule de goudron du répertoire:
tar cvf - /path/to/folder | sha1sum
-
Code quelque chose vous-même, comme oneliner de vatine :
find /path/to/folder -type f -print0 | sort -z | xargs -0 sha1sum | sha1sum
Si vous voulez juste vérifier si quelque chose dans le dossier a changé, je recommanderais celui-ci:
ls -alR --full-time /folder/of/stuff | sha1sum
Il vous donnera juste un hachage de la sortie ls, qui contient des dossiers, des sous-dossiers, leurs fichiers, leur horodatage, leur taille et leurs autorisations. À peu près tout ce dont vous auriez besoin pour déterminer si quelque chose a changé.
Veuillez noter que cette commande ne générera pas de hachage pour chaque fichier, mais c'est pourquoi elle devrait être plus rapide que l'utilisation de find.
Si vous voulez juste hacher le contenu des fichiers, en ignorant les noms de fichiers, vous pouvez utiliser
cat $FILES | md5sum
Assurez-vous que vous avez les fichiers dans le même ordre lors du calcul du hachage:
cat $(echo $FILES | sort) | md5sum
Mais vous ne pouvez pas avoir de répertoires dans votre liste de fichiers.
Il y a un script python pour cela:
Http://code.activestate.com/recipes/576973-getting-the-sha-1-or-md5-hash-of-a-directory/
Si vous modifiez les noms d'un fichier sans modifier leur ordre alphabétique, le script de hachage ne le détectera pas. Mais, si vous modifiez l'ordre des fichiers ou le contenu d'un fichier, l'exécution du script vous donnera un hachage différent qu'avant.
Je dirigerais les résultats pour les fichiers individuels via sort
(pour empêcher une simple réorganisation des fichiers pour changer le hachage) en md5sum
ou sha1sum
, selon votre choix.
Un Autre outil pour y parvenir:
Http://md5deep.sourceforge.net/
Tel quel sonne: comme md5sum mais aussi récursif, plus d'autres fonctionnalités.
J'ai écrit un script Groovy pour faire ceci:
import java.security.MessageDigest
public static String generateDigest(File file, String digest, int paddedLength){
MessageDigest md = MessageDigest.getInstance(digest)
md.reset()
def files = []
def directories = []
if(file.isDirectory()){
file.eachFileRecurse(){sf ->
if(sf.isFile()){
files.add(sf)
}
else{
directories.add(file.toURI().relativize(sf.toURI()).toString())
}
}
}
else if(file.isFile()){
files.add(file)
}
files.sort({a, b -> return a.getAbsolutePath() <=> b.getAbsolutePath()})
directories.sort()
files.each(){f ->
println file.toURI().relativize(f.toURI()).toString()
f.withInputStream(){is ->
byte[] buffer = new byte[8192]
int read = 0
while((read = is.read(buffer)) > 0){
md.update(buffer, 0, read)
}
}
}
directories.each(){d ->
println d
md.update(d.getBytes())
}
byte[] digestBytes = md.digest()
BigInteger bigInt = new BigInteger(1, digestBytes)
return bigInt.toString(16).padLeft(paddedLength, '0')
}
println "\n${generateDigest(new File(args[0]), 'SHA-256', 64)}"
Vous pouvez personnaliser l'utilisation pour éviter d'imprimer chaque fichier, modifier le résumé des messages, supprimer le hachage de répertoire, etc. Je l'ai testé contre les données de test du NIST et cela fonctionne comme prévu. http://www.nsrl.nist.gov/testdata/
gary-macbook:Scripts garypaduana$ groovy dirHash.groovy /Users/garypaduana/.config
.DS_Store
configstore/bower-github.yml
configstore/insight-bower.json
configstore/update-notifier-bower.json
filezilla/filezilla.xml
filezilla/layout.xml
filezilla/lockfile
filezilla/queue.sqlite3
filezilla/recentservers.xml
filezilla/sitemanager.xml
gtk-2.0/gtkfilechooser.ini
a/
configstore/
filezilla/
gtk-2.0/
lftp/
menus/
menus/applications-merged/
79de5e583734ca40ff651a3d9a54d106b52e94f1f8c2cd7133ca3bbddc0c6758
Essayer de le faire en deux étapes:
- créez un fichier avec des hachages pour tous les fichiers d'un dossier
- hachez ce fichier
Comme ça:
# for FILE in `find /folder/of/stuff -type f | sort`; do sha1sum $FILE >> hashes; done
# sha1sum hashes
Ou tout faire en même temps:
# cat `find /folder/of/stuff -type f | sort` | sha1sum
Vous pouvez sha1sum
pour générer la liste des valeurs de hachage, puis sha1sum
cette liste à nouveau, cela dépend exactement de ce que vous voulez accomplir.
Une approche robuste et propre
- tout d'Abord, ne pas monopoliser la mémoire disponible! Hachez un fichier en morceaux plutôt que d'alimenter le fichier entier.
- différentes approches pour différents besoins / objectifs (tous les ci-dessous ou choisir ce qui s'applique):
- Hash uniquement le nom d'entrée de toutes les entrées de l'arborescence des répertoires
- hachez le contenu du fichier de toutes les entrées (en laissant le meta like, le numéro d'inode, ctime, atime, mtime, size,etc., vous obtenez le idée)
- pour un lien symbolique, son contenu est le nom référent. Hachez-le ou choisissez de sauter
- suivre ou ne pas suivre (nom résolu) le lien symbolique tout en hachant le contenu de l'entrée
- Si c'est un répertoire, son contenu ne sont que des entrées de répertoire. En traversant récursivement, ils seront hachés éventuellement, mais les noms d'entrée de répertoire de ce niveau devraient-ils être hachés pour marquer ce répertoire? Utile dans les cas d'utilisation où le hachage est nécessaire pour identifier un changement rapide sans avoir à traverser profondément pour hacher le contenu. Un exemple serait les changements de nom d'un fichier mais le reste du contenu reste le même et ce sont tous des fichiers assez volumineux
- gérez bien les fichiers volumineux (encore une fois, attention à la RAM)
- gère les arborescences de répertoires très profondes (attention aux descripteurs de fichiers ouverts)
- Gérer les noms de fichiers non standard
- Comment procéder avec les fichiers qui sont prises, pipes/Fifo, les périphériques de bloc, char appareils? Doit les hacher aussi?
- Ne pas mettre à jour l'accès temps de toute entrée en traversant parce que ce sera un effet secondaire et contre-productif (intuitif? pour certains cas d'utilisation.
C'est ce que j'ai sur la tête, quiconque a passé du temps à travailler sur cela aurait pratiquement attrapé d'autres pièges et des cas de coin.
Voici un outil, très léger sur la mémoire, qui répond à la plupart des cas, peut être un peu rugueux sur les bords, mais a été très utile.
Un exemple d'utilisation et sortie de dtreetrawl
.
Usage: dtreetrawl [OPTION...] "/trawl/me" [path2,...] Help Options: -h, --help Show help options Application Options: -t, --terse Produce a terse output; parsable. -j, --json Output as JSON -d, --delim=: Character or string delimiter/separator for terse output(default ':') -l, --max-level=N Do not traverse tree beyond N level(s) --hash Enable hashing(default is MD5). -c, --checksum=md5 Valid hashing algorithms: md5, sha1, sha256, sha512. -R, --only-root-hash Output only the root hash. Blank line if --hash is not set -N, --no-name-hash Exclude path name while calculating the root checksum -F, --no-content-hash Do not hash the contents of the file -s, --hash-symlink Include symbolic links' referent name while calculating the root checksum -e, --hash-dirent Include hash of directory entries while calculating root checksum
Un extrait de l'homme amicale sortie:
... ... //clipped ... /home/lab/linux-4.14-rc8/CREDITS Base name : CREDITS Level : 1 Type : regular file Referent name : File size : 98443 bytes I-node number : 290850 No. directory entries : 0 Permission (octal) : 0644 Link count : 1 Ownership : UID=0, GID=0 Preferred I/O block size : 4096 bytes Blocks allocated : 200 Last status change : Tue, 21 Nov 17 21:28:18 +0530 Last file access : Thu, 28 Dec 17 00:53:27 +0530 Last file modification : Tue, 21 Nov 17 21:28:18 +0530 Hash : 9f0312d130016d103aa5fc9d16a2437e Stats for /home/lab/linux-4.14-rc8: Elapsed time : 1.305767 s Start time : Sun, 07 Jan 18 03:42:39 +0530 Root hash : 434e93111ad6f9335bb4954bc8f4eca4 Hash type : md5 Depth : 8 Total, size : 66850916 bytes entries : 12484 directories : 763 regular files : 11715 symlinks : 6 block devices : 0 char devices : 0 sockets : 0 FIFOs/pipes : 0
J'ai dû vérifier dans un répertoire entier pour les changements de fichiers.
, Mais avec l'exclusion, l'horodatage, répertoire de la propriété.
Le but est d'obtenir une somme identique n'importe où, si les fichiers sont identiques.
Y compris hébergé dans d'autres machines, indépendamment de tout sauf les fichiers, ou un changement en eux.
md5sum * | md5sum | cut -d' ' -f1
Il génère une liste de hachage par fichier, puis concatène ces hachages en un seul.
C'est beaucoup plus rapide que la méthode tar.
Pour un plus fort confidentialité dans nos tables de hachage, nous pouvons utiliser sha512sum sur la même recette.
sha512sum * | sha512sum | cut -d' ' -f1
Les hachages sont également identiques n'importe où en utilisant sha512sum mais il n'y a aucun moyen connu de l'Inverser.
Voici une variante simple et courte en Python 3 qui fonctionne bien pour les fichiers de petite taille (par exemple une arborescence source ou quelque chose, où chaque fichier peut facilement s'intégrer dans la RAM), en ignorant les répertoires vides, en fonction des idées des autres solutions:
import os, hashlib
def hash_for_directory(path, hashfunc=hashlib.sha1):
filenames = sorted(os.path.join(dp, fn) for dp, _, fns in os.walk(path) for fn in fns)
index = '\n'.join('{}={}'.format(os.path.relpath(fn, path), hashfunc(open(fn, 'rb').read()).hexdigest()) for fn in filenames)
return hashfunc(index.encode('utf-8')).hexdigest()
Cela fonctionne comme ceci:
- trouve tous les fichiers dans le répertoire récursivement et les trie par nom
- calculez le hachage (par défaut: SHA-1) de chaque fichier (lit le fichier entier en mémoire)
- créer un texte index avec "filename=hash" lignes
- encodez cet index dans une chaîne d'octets UTF-8 et hachez-le
Vous pouvez passer une fonction de hachage différente comme deuxième paramètre si SHA-1 n'est pas votre tasse de thé.