Назад | Перейти на главную страницу

Архивирование папки для создания файла tgz

У меня есть папка, в которой я хочу создать файл tgz и вычислить его sha256:

Папка преобразуется в tgz с помощью следующей команды

 "tar -c -C #{Shellwords.escape dir} #{Shellwords.escape basename} " \
        "--owner=0 --group=0 --mtime='2000-01-01 00:00:00' | gzip -n > #{Shellwords.escape file}"

Теперь я выполнил описанный выше процесс, используя 2 отдельных пользователя, и получил 2 файла: 1 и 2.

Оба файла tgz различаются по размеру:

-rw-r--r--@ 1 myuser  \Domain Users  9024 Jul 31 14:28 1.tgz
-rw-r--r--@ 1 myuser  \Domain Users  9037 Jul 31 14:29 2.tgz

Если я пытаюсь вычислить разницу между файлами, я не вижу никакого diff.Diff было получено с помощью следующей команды.

diff  <(tar -tvf 1.tgz | sort) <(tar -tvf 2.tgz | sort)

Если я вычисляю sha256, используя ruby ​​из этих двух файлов, то он будет другим.

Возникает вопрос: почему я получаю разницу в файлах tgz при запуске от разных пользователей.

РЕДАКТИРОВАТЬ: после прочтения комментариев и некоторых поисковых запросов я обнаружил, что порядок, в котором файлы добавляются, не фиксируется каждый раз.

посмотри это https://reproducible-builds.org/docs/archives/#file-ordering.

Я попробую это и добавлю подробностей.

TL; DR: Да, как вы уже догадались, разница в размерах получаемых файлов, скорее всего, связана с различиями в User ID.

Вот определение формата файла tar в структурах C:

https://www.gnu.org/software/tar/manual/html_node/Standard.html

Вы можете заметить, что даже в этом «определении» есть аргументы о деталях заголовков tar-файлов и информации о метаданных, о том, что именно хранится и где. Но, несмотря на то, что существуют разные реализации формата файла tar, есть, по крайней мере, согласие, что действительно есть информация метаданных, хранящаяся о каждом файле или объекте в файле tar, хранящаяся в выделенном блоке заголовка перед содержимым файла. Для вашего варианта использования важно, чтобы два элемента, которые хранятся в блоках метаданных tar, - это владельцы файлов и каталогов пользователя и группы.

Более подробную информацию также можно найти на странице руководства проекта FreeBSD в tar:

https://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5&manpath=FreeBSD+8-current

Tar имеет долгую, извилистую историю, которая следует за многими поворотами в развитии последовательных запоминающих устройств без произвольного доступа в вычислительной технике с 1970-х годов. Требования обратной совместимости могут вызывать подобные вещи. :)

Совет: Для сравнения каталогов с использованием хэшей ваш ответ - md5deep. http://md5deep.sourceforge.net/ :)

Это могло произойти по многим причинам.

  • Метаданные, хранящиеся в tar (а также метаданные, хранящиеся в gzip, которые могут включать время модификации архива tar). Я вижу, что вы используете некоторые параметры tar GNU, которые потенциально могут сбросить некоторые части этих метаданных, но я готов поспорить, что параметры не исчерпывают все атрибуты переменных.

  • Порядок файлов. Когда вы извлекаете файлы в файловую систему, порядок не имеет значения для большинства приложений (хотя каждая запись каталога обычно идет до или после любой другой записи в том же директории в базовой файловой системе). Однако порядок файлов в tar-архиве не гарантируется.

  • Сжатие gzip. Формат файла гарантирует, что сжатые файлы будут распакованы до оригиналов, однако не всегда гарантируется, что их сжатая форма должна быть идентична. Более того, если входные данные различаются по содержанию (даже если они остаются того же размера), то аналогично вы увидите, что два архива могут даже быть настолько разными, что имеют разный размер файла.

Таким образом, если вы пытаетесь определить, одинаково ли содержимое двух папок, использование архивов .tgz, вероятно, не лучший способ сделать это.

Что делать, если вы не сортируете tar при запуске команды diff? Возможно, он просто добавил файлы в другом порядке, а затем gzip просто заархивировал их по-другому.

Как только способ справиться с этим, будет добавление файлов в определенном порядке: (при условии, что GNU tar и оболочка на основе Борна) (здесь используется find для получения списка файлов, а затем сортировки его в определенной локали)

d="dir1";bn="basename";( cd "$d" && find "$bn" -type f -print0 | \
LC_ALL=C sort -z | \
tar --null -T - --owner=0 --group=0 --mtime='2000-01-01 00:00:00' \
--no-acls --no-xattrs --no-selinux -c | \
gzip -n; ) > out1.tgz

Список --no--stuff необходимо будет обновить, поскольку в tar и файловые системы добавляется больше функций ...

В большинстве случаев, если все, что вас интересует, это имена файлов и их содержимое, diff -r может быть более подходящим ... Для более чем одной пары сравнения sha256sum из sha256sum список всех файлов может быть более надежным.

Я не уверен, что tar - лучший способ сделать это. Слишком много переменных под капотом, и они на самом деле не используют их так, как кажется, для использования. Тем более со сжатием.

В зависимости от структуры каталогов и доступного времени это может оказаться невозможным, но рассматривали ли вы возможность хеширования каждого файла, а затем хеширования этого списка?

Одна из таких схем может быть следующей: список всех файлов, детерминированная сортировка, хеширование каждого отдельного файла, затем хеширование вывода этой комбинации хеш / имя файла.

Этот метод игнорирует все метаданные и имеет дело исключительно с содержимым файла и его именем.

Вот пример команды (я пройдусь по отдельным частям ниже)

find -L `pwd` 2> /dev/null | sort | awk '{ print "\""$0"\""}' | xargs md5sum 2> /dev/null > /tmp/out; md5sum /tmp/out | awk '{print $1}'; rm -rf /tmp/out &> /dev/null;
  • find -L \pwd` 2> / dev / null` - Находит список всех файлов, игнорируя ошибки
  • sort - Сортировка списка файлов по имени позволяет избежать проблем с разницей в порядке возврата файловой системы.
  • awk '{ print "\""$0"\""}' - Добавляет кавычки вокруг каждой строки. Не обязательно, но если на вашем пути есть пробелы или специальные символы, у вас будут проблемы.
  • xargs md5sum 2> /dev/null > /tmp/out - Фактически вычисляет хеш каждой строки, возвращает хеш в файл.
  • md5sum /tmp/out | awk '{print $1}' - Хеширует окончательный список хешей. Awk не является обязательным, но немного очищает вывод.
  • rm -rf /tmp/out &> /dev/null - Очистка временных файлов

Насколько я могу судить, это приведет к "хешу" для дерева каталогов.

Согласно моему тестированию, он вернул тот же хэш для нетронутого дерева каталогов (даже после того, как прошло некоторое время), но изменил хеш при изменении любого из отдельных файлов или даже при создании нового пустого файла. Затем хеш возвращается к исходному при удалении новых файлов и отмене изменений.

YMMV.