Определите, были ли добавлены, удалены или изменены какие-либо файлы в каталоге
Вопрос
Я пытаюсь написать скрипт на Python, который получит md5sum всех файлов в каталоге (в Linux).Что, я полагаю, я и сделал в приведенном ниже коде.
Я хочу иметь возможность запустить это, чтобы убедиться, что никакие файлы в каталоге не изменились, и никакие файлы не были добавлены для удаления.
Проблема в том, что если я внесу изменения в файл в каталоге, но затем изменю его обратно.Я получаю другой результат от запуска функции, приведенной ниже.(Несмотря на то, что я изменил измененный файл обратно.
Кто-нибудь может это объяснить.И дайте мне знать, если сможете придумать обходной путь?
def get_dir_md5(dir_path):
"""Build a tar file of the directory and return its md5 sum"""
temp_tar_path = 'tests.tar'
t = tarfile.TarFile(temp_tar_path,mode='w')
t.add(dir_path)
t.close()
m = hashlib.md5()
m.update(open(temp_tar_path,'rb').read())
ret_str = m.hexdigest()
#delete tar file
os.remove(temp_tar_path)
return ret_str
Редактировать: Как ответили эти замечательные люди, похоже, что tar включает в себя информацию заголовка, такую как дата изменения.Будет ли использование zip работать как-то по-другому или в другом формате?
Есть еще какие-нибудь идеи по обходным путям?
Решение
Как упоминалось в других ответах, два файла tar могут отличаться, даже если содержимое одинаковое либо из-за изменений метаданных tar, либо из-за изменения порядка файлов.Вы должны запускать контрольную сумму непосредственно для данных файла, сортируя списки каталогов, чтобы убедиться, что они всегда находятся в одном и том же порядке.Если вы хотите включить какие-то метаданные в контрольную сумму, включите их вручную.
Непроверенный пример использования os.walk
:
import os
import os.path
def get_dir_md5(dir_root):
"""Build a tar file of the directory and return its md5 sum"""
hash = hashlib.md5()
for dirpath, dirnames, filenames in os.walk(dir_root, topdown=True):
dirnames.sort(key=os.path.normcase)
filenames.sort(key=os.path.normcase)
for filename in filenames:
filepath = os.path.join(dirpath, filename)
# If some metadata is required, add it to the checksum
# 1) filename (good idea)
# hash.update(os.path.normcase(os.path.relpath(filepath, dir_root))
# 2) mtime (possibly a bad idea)
# st = os.stat(filepath)
# hash.update(struct.pack('d', st.st_mtime))
# 3) size (good idea perhaps)
# hash.update(bytes(st.st_size))
f = open(filepath, 'rb')
for chunk in iter(lambda: f.read(65536), b''):
hash.update(chunk)
return hash.hexdigest()
Другие советы
Заголовки файлов TAR включают поле для времени изменения файла;процесс изменения файла, даже если это изменение позже будет изменено обратно, будет означать, что заголовки файлов TAR будут другими, что приведет к разным хэшам.
Вам не нужно создавать TAR-файл, чтобы делать то, что вы предлагаете.
Вот ваш алгоритм обхода:
- Пройдитесь по дереву каталогов;
- Возьмите md5-подпись каждого файла;
- Сортировка подписей;
- Возьмите подпись md5 текстовой строки всех подписей отдельных файлов.
Единственная результирующая подпись будет тем, что вы ищете.
Черт возьми, вам даже не нужен Python.Ты можешь это сделать:
find /path/to/dir/ -type f -name *.py -exec md5sum {} + | awk '{print $1}'\
| sort | md5sum
tar
файлы содержат метаданные, выходящие за рамки фактического содержимого файла, такие как время доступа к файлу, время модификации и т.д.Даже если содержимое файла не изменится, tar
файл на самом деле будет другим.