Pregunta

Estoy tratando de escribir un script de Python que obtendrá el MD5SUM de todos los archivos en un directorio (en Linux). Lo que creo que he hecho en el código a continuación.

Quiero poder ejecutar esto para asegurarme de que ningún archivo dentro del directorio haya cambiado, y no se han agregado archivos para eliminar.

El problema es si hago un cambio en un archivo en el directorio pero luego lo cambio. Obtengo un resultado diferente al ejecutar la función a continuación. (Aunque volví a cambiar el archivo modificado.

¿Alguien puede explicar esto? ¿Y avísame si puedes pensar en una solución al trabajo?

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

Editar:Como han respondido estas buenas personas, parece que el alquitrán incluye información de encabezado como la fecha modificada. ¿El uso de zip funcionaría de manera diferente u otro formato?

¿Alguna otra idea para trabajar?

¿Fue útil?

Solución

Como se mencionaron las otras respuestas, dos archivos TAR pueden ser diferentes incluso si los contenidos son los mismos debido a los cambios de metadatos de TAR o a los cambios en el orden. Debe ejecutar la suma de verificación en los datos del archivo directamente, clasificando las listas de directorio para asegurarse de que siempre estén en el mismo orden. Si desea incluir algunos metadatos en la suma de verificación, incluya manualmente.

Ejemplo no probado usando 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()

Otros consejos

Los encabezados del archivo TAR incluyen un campo para la hora modificada del archivo; El acto de cambiar un archivo, incluso si ese cambio se cambia más tarde, significará que los encabezados del archivo TAR serán diferentes, lo que conducirá a diferentes hash.

No necesita hacer el archivo de alquitrán para hacer lo que propone.

Aquí está su algoritmo de solución:

  1. Camine el árbol del directorio;
  2. Tome la firma MD5 de cada archivo;
  3. Ordena las firmas;
  4. Tome la firma MD5 de la cadena de texto de todas las firmas de los archivos individuales.

La firma única resultante será lo que está buscando.

Diablos, ni siquiera necesitas Python. Puedes hacerlo:

find /path/to/dir/ -type f -name *.py -exec md5sum {} + | awk '{print $1}'\
| sort | md5sum

tar Los archivos contienen metadatos más allá del contenido real del archivo, como tiempos de acceso al archivo, tiempos de modificación, etc., incluso si el contenido del archivo no cambia, el tar El archivo será de hecho diferente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top