Skip to the content.

Link to the English language README page

Precizer — проверка целостности данных для файловых систем любого масштаба

Крошечное, высокопроизводительное приложение для проверки целостности файлов

«По-настоящему хорошая программа всегда поместится на дискету. Есть надежда, что кто-то всё ещё помнит, что это такое… Речь идёт не о дискетах, а о качественных программах!»© :-D

Содержание

Continuous integration and automation

Гибридный интеграционно-системный набор тестов

Test coverage:

Total completed tests
Lines of code covered by tests
Functions covered by tests
Code branches covered by tests

Automated builds:

precizer build & testing

Security:

OpenSSF Best Practices
OpenSSF Scorecard

Bages

precizer badge precizer | AlternativeTo

КРАТКО О ПРОГРАММЕ

Обзор

precizer — крошечное и быстрое консольное приложение, полностью написанное на чистом Си. Предназначено для проверки целостности и сравнения файлов. Особенно полезно для проверки результатов синхронизации. Программа обходит дерево каталогов и создаёт базу данных файлов и их контрольных сумм с последующим быстрым сравнением.

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

Настройки запуска можно сохранять в конфигурационном файле, чтобы при повторных запусках не вводить пути и параметры заново

Простой пример

Допустим, есть две машины, у которых в /mnt1 и /mnt2 соответственно примонтированы диски большого объёма с идентичным содержимым. Стоит задача побайтно проверить, действительно ли содержимое абсолютно идентично или есть различия.

  1. Запустить программу на первой машине с hostname, например «host1»:
precizer --progress /mnt1

В результате работы программы будут исследованы все директории, начиная с /mnt1, и в текущей директории будет создана база данных host1.db. Параметр --progress визуализирует прогресс и покажет объём пространства и количество исследуемых файлов.

  1. Запустить программу на второй машине с hostname, например «host2»:
precizer --progress /mnt2

В результате будет создана база данных host2.db в текущей директории.

  1. Скопировать файлы с базами данных host1.db и host2.db на одну из машин и запустить программу с соответствующими параметрами для сравнения:
precizer --compare host1.db host2.db

На экран будет выведена следующая информация:

Относительные пути в базе данных для сравнения

Следует обратить внимание, что precizer записывает в базу данных только относительные пути. Файл

/mnt1/abc/def/aaa.txt

из приведённого примера будет записан в базу данных как

abc/def/aaa.txt

без /mnt1. То же самое произойдёт с файлом

/mnt2/abc/def/aaa.txt

Смысл в том, что, несмотря на разные точки монтирования и разные источники, файлы можно будет сравнить между собой под одинаковыми именами

abc/def/aaa.txt

и с соответствующими контрольными суммами.

Скачивание/Download

Подходящий пакет определяется по операционной системе и архитектуре процессора.

Linux

64-разрядный процессор Intel или AMD (x86_64)

Скачать precizer для Linux x86_64

Переносимая статически слинкованная сборка для большинства настольных и серверных дистрибутивов Linux. Дополнительные динамические библиотеки не требуются

64-разрядный процессор ARM (ARM64 / AArch64)

Скачать precizer для Linux ARM64

Переносимая статически слинкованная сборка для 64-разрядных ARM-систем. Дополнительные динамические библиотеки не требуются

Windows

Поддержка Windows экспериментальная.

64-разрядный процессор Intel или AMD (x64)

Скачать ZIP-пакет для Windows

Рекомендуемый пакет для Windows. После распаковки архива файлы precizer.exe и msys-2.0.dll должны находиться в одном каталоге

Скачать отдельный EXE-файл для Windows

Самораспаковывающийся исполняемый файл, не требующий отдельных файлов библиотек среды выполнения. Поддержка Windows экспериментальная и исполняемый файл не имеет цифровой подписи, поэтому Defender может показать предупреждение

macOS

Сборки для macOS используют динамические библиотеки. Необходимые для запуска пакеты перечислены в разделе «Системные библиотеки для запуска приложения».

Процессор Apple Silicon (M1 или новее, ARM64)

Скачать precizer для macOS Apple Silicon ARM64

Процессор Intel (x86_64)

Скачать precizer для macOS Intel x86_64

Автоматическое скачивание, распаковка и запуск в Linux и macOS

Этот сценарий определяет операционную систему и архитектуру процессора, скачивает подходящую сборку последнего релиза, распаковывает её и проверяет запуск precizer

# Automation for downloading and unarchiving new versions

# Download
wget -O precizer.zip -q "https://github.com/precizer/precizer/releases/latest/download/precizer_$(uname -s | tr '[:upper:]' '[:lower:]' | sed 's/darwin/macos/')_$(uname -m | sed 's/amd64/x86_64/')$( [ "$(uname -s)" = "Linux" ] && echo '_portable' ).zip"

# Extract the archive
unzip -jqo precizer.zip '*/precizer' -d ./

# Run
./precizer --version

Технические детали portable сборки

ИСТОРИЯ ИЗМЕНЕНИЙ

Список изменений по версиям можно найти в отдельном файле CHANGELOG

ТЕХНИЧЕСКИЕ ПОДРОБНОСТИ АЛГОРИТМОВ РАБОТЫ

Рассмотрим сценарий, когда имеется основное дисковое хранилище и его копия. Например, это может быть хранилище датацентра и его Disaster Recovery‑копия. Периодически происходит синхронизация с основного хранилища на резервное, но по причине огромных объёмов данных, скорее всего, синхронизация происходит не побайтно, а за счёт вычисления изменений среди метаданных файлов на файловой системе. В таких случаях учитывается размер файла и время модификации, но изменившееся содержимое байт за байтом не исследуется. В этом есть смысл, потому что между основным датацентром и резервным Disaster Recovery‑центром, как правило, хорошие каналы связи, но полная побайтовая синхронизация может занять нецелесообразно много времени. Такие инструменты, как rsync, позволяют производить синхронизацию по обеим методикам: как с учётом изменившихся файлов, так и побайтово, но у них есть один серьёзный недостаток — состояние не сохраняется между сессиями. Что это значит, рассмотрим детально:

ВОПРОСЫ И БАГРЕПОРТЫ

УЧАСТИЕ В ПРОЕКТЕ

Участие в развитии проекта приветствуется. Начните с CONTRIBUTING: там описаны рабочий процесс, зависимости, шаги проверки и требования к pull request. Актуальные запросы на усовершенствования можно выбрать в списке Issues по уровню и интересу.

СБОРКА И УСТАНОВКА

Пакетирование для дистрибутивов

Сборка с помощью Docker

Сборка программы уже предусмотрена с использованием Docker. При этом подготовлено несколько тюнингованных платформ, которые могут быть выбраны в качестве дистрибутива для сборки программы. Среди успешно работающих дистрибутивов:

Ознакомиться с подробностями настроек и устанавливаемыми библиотеками можно в соответствующих Docker‑файлах в поддиректории проекта .docker/

Для сборки достаточно указать команду make, ключевое слово docker, дистрибутив debian (например), а затем цель dynamic-production или другой вариант сборки.

Пример сборки в контейнере:

make docker-gentoo-production

Команда соберёт программу в режиме production в контейнере Gentoo и сохранит готовый архив precizer_linux_<архитектура>_production.zip в корне проекта.

Инструменты сборки и библиотеки устанавливаются внутри контейнера; на основной системе достаточно только Docker. Для переносимой сборки лучше всего использовать make docker-gentoo-portable как на наиболее универсальный вариант.

Самостоятельная сборка

Для получения исходного кода требуется Git. Команды сборки выполняются из корня проекта после установки зависимостей для соответствующей операционной системы

git clone --depth=1 https://github.com/precizer/precizer.git
cd precizer

Все цели сборки учитывают переданные через окружение или командную строку переменные CPPFLAGS, CFLAGS и LDFLAGS. Обязательный режим языка -std=gnu2x (C2x с расширениями GNU) добавляется отдельно и не отключается переопределением CFLAGS

При необходимости предыдущие сборки и артефакты удаляются командой:

make purge

Linux

Следующие команды устанавливают компилятор, инструменты и заголовочные файлы библиотек, необходимые для сборки приложения. UPX сжимает копию программы для архива в целях portable, production и dynamic-production; для цели distribution он не нужен

Зависимости для запуска нужны только динамическим сборкам dynamic-production и distribution. Статические сборки portable и production включают необходимые библиотеки в исполняемый файл и не требуют перечисленных ниже пакетов для запуска

Команды установки зависимостей, используемые при автоматической сборке поддерживаемых дистрибутивов, приведены в соответствующих Dockerfile в каталоге .docker/

Arch Linux

Инструменты и библиотеки для сборки:

sudo pacman -S --needed base-devel sqlite pcre2 upx zip unzip

Для запуска динамической сборки:

sudo pacman -S --needed sqlite pcre2
Ubuntu/Debian Linux

Инструменты и библиотеки для сборки:

sudo apt update
sudo apt -y install gcc make libpcre2-dev libsqlite3-dev upx-ucl zip unzip

Для запуска динамической сборки:

sudo apt -y install libpcre2-8-0 libsqlite3-0
Alpine Linux

Инструменты и библиотеки для сборки:

sudo apk add --no-cache build-base pcre2-dev pcre2-static fts-dev sqlite-dev upx zip unzip

Для запуска динамической сборки:

sudo apk add --no-cache pcre2 sqlite-libs fts
AlmaLinux/Rocky/Fedora Linux

Инструменты и библиотеки для сборки:

Набор доступных репозиториев и названия пакетов со статическими библиотеками различаются между выпусками этих дистрибутивов. Для сборки всех вариантов нужны GCC, Make, заголовочные и статические библиотеки glibc, SQLite и PCRE2, а также UPX и ZIP:

sudo dnf -y install gcc make sqlite sqlite-devel glibc-devel pcre2 pcre2-devel upx pcre2-static glibc-static zip unzip

В AlmaLinux и Rocky Linux пакеты pcre2-static и glibc-static могут потребовать предварительного подключения репозиториев CRB, EPEL и репозитория для разработчиков

Подробные команды подключения репозиториев и установки пакетов приведены в Dockerfile соответствующего дистрибутива в каталоге .docker/

Для запуска динамической сборки:

sudo dnf -y install sqlite-libs pcre2
Gentoo Linux

Инструменты и библиотеки для сборки:

echo "dev-libs/libpcre2 static-libs" | sudo tee /etc/portage/package.use/libpcre2
sudo emerge dev-libs/libpcre2 app-arch/upx app-arch/zip app-arch/unzip

Для запуска динамической сборки:

sudo emerge dev-db/sqlite dev-libs/libpcre2
Варианты сборки с помощью Make

Доступны четыре варианта сборки: portable, production, dynamic-production и distribution. Подходящий вариант определяется требованиями к переносимости, производительности и системным библиотекам

Портируемый бинарный файл

make portable

Результатом сборки будет ZIP-архив, содержащий один статически слинкованный, самораспаковывающийся сжатый UPX файл в формате ELF, без каких-либо динамических зависимостей. Этот файл представляет собой всю программу целиком и может быть запущен практически на любом современном дистрибутиве Linux. Файл переносим между системами с той же архитектурой процессора (x64, ARM и другими)

Программа оптимизирована под максимальную переносимость

Особенности компиляции и линковки: -static -O2 -mtune=generic

Альтернатива с использованием Docker:

make docker-gentoo-portable

Вместо -gentoo- может быть указан любой из перечисленных выше дистрибутивов

Единый бинарный файл с оптимизацией под локальный CPU

make production

Архив содержит заточенный под локальный CPU, статически слинкованный, самораспаковывающийся, сжатый UPX файл в формате ELF, не нуждающийся в отдельных библиотеках. Этот файл представляет собой всю программу целиком, может быть запущен на локальном компьютере и будет использовать все возможности CPU по-максимуму

Программа оптимизирована под предельно возможную производительность на локальном железе

Особенности компиляции и линковки: -static -O3 -march=native

Альтернатива с использованием Docker:

make docker-gentoo-production

Вместо -gentoo- может быть указан любой из перечисленных выше дистрибутивов

Исполняемый файл с динамически подгружаемыми библиотеками и оптимизацией под локальный CPU

make dynamic-production

Архив содержит исполняемый файл размером около 50 килобайт в формате ELF. Он будет заточен под локальный CPU, динамически слинкован с установленными в системе библиотеками, самораспаковывающийся, сжатый UPX. Этот файл может быть успешно собран и запущен на локальном компьютере, если в системе были предварительно установлены такие библиотеки, как sqlite3, pcre2 и fts

Файл оптимизирован под максимальную производительность и минимальный размер

При работе программа использует установленные в системе динамические библиотеки. Они могут быть собраны с параметрами оптимизации, отличающимися от параметров сборки precizer, поэтому общая производительность также зависит от этих библиотек

Особенности компиляции: -O3 -march=native

Альтернатива с использованием Docker:

make docker-gentoo-dynamic-production

Вместо -gentoo- может быть указан любой из перечисленных выше дистрибутивов

Исполняемый файл для дистрибутивного пакета

make distribution

Цель distribution предназначена для сборки пакетов Gentoo, Debian, Ubuntu, Fedora и других дистрибутивов. Программа динамически связывается с установленными системными библиотеками

Сборка учитывает стандартные переменные CPPFLAGS, CFLAGS и LDFLAGS, не добавляет настройки для процессора машины, на которой выполняется сборка, не удаляет отладочные символы и не применяет UPX

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

Установка

Для быстрого вызова программы исполняемый файл precizer размещается в одном из каталогов, указанных в $PATH. Сборки создают архив с этим файлом в корне проекта.

macOS

На macOS статическая линковка не поддерживается. Цель macos-zip создаёт архив со сборкой для локального процессора. Сжатие UPX не применяется.

Зависимости для сборки

Для сборки требуются инструменты командной строки Xcode и зависимости из Homebrew. Они устанавливаются следующими командами:

xcode-select --install
brew install llvm sqlite pcre2
Сборка и установка

Для сборки и упаковки без оптимизации под процессор конкретного компьютера используется цель macos-zip:

make macos-zip

Результат находится в корне проекта, в ZIP-архиве. Сборка учитывает CPPFLAGS, CFLAGS и LDFLAGS и не удаляет отладочные символы. Команда make distribution доступна отдельно: она оставляет только бинарник в .builds/distribution/precizer

Для сборки с оптимизацией под локальный процессор доступна цель dynamic-production:

make dynamic-production

В этом случае результат — ./precizer_macos_<архитектура>_dynamic-production.zip

Для вызова программы по имени и без указания пути нужно поместить распакованный файл precizer в один из каталогов, указанных в $PATH

Системные библиотеки для запуска приложения

На macOS все варианты сборки только динамические. Для запуска требуются системные библиотеки из Homebrew:

brew install sqlite pcre2

Windows

Подготовка MSYS2

Для сборки Windows x64 требуется MSYS2. Команды выполняются в терминале MSYS2 MSYS, а не UCRT64 или MINGW64

Перед сборкой выполняется обновление пакетов:

pacman -Syu

Если обновление требует закрытия терминала, после подтверждения терминал MSYS2 MSYS запускается повторно, а команда выполняется ещё раз для завершения обновления. Подробности — в инструкции MSYS2

Зависимости устанавливаются командой:

pacman -S --needed git gcc make libsqlite-devel pcre2-devel zip

Получение исходного кода описано в начале раздела «Самостоятельная сборка». Все следующие команды выполняются из корня проекта в том же терминале

Команда make msys-build собирает программу в .builds/distribution/precizer.exe без упаковки. Обе цели упаковки, windows-zip и windows-exe, автоматически выполняют эту сборку

EXE с DLL рядом

Следующая команда собирает программу и создаёт ZIP-архив с EXE, необходимой DLL, лицензией, историей изменений и обоими README:

make windows-zip

Результат — архив precizer_windows_x64_portable.zip. После распаковки precizer.exe и msys-2.0.dll должны оставаться в одном каталоге. Для запуска на другом компьютере установка MSYS2 не требуется. SQLite, PCRE2 и argp уже включены в EXE

Единый самораспаковывающийся EXE

Следующие команды устанавливают дополнительные инструменты, собирают программу и создают самораспаковывающийся EXE со встроенными программой и DLL. Предварительно выполнять make windows-zip не требуется:

pacman -S --needed mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-binutils mingw-w64-ucrt-x86_64-upx
make windows-exe

Переключать терминал не нужно: сборка сама выбирает UCRT-компилятор. В корне проекта появится precizer_windows_x64_portable.exe. Для переноса и запуска достаточно этого файла: при запуске он самостоятельно извлекает программу и DLL в пользовательский каталог кэша

После установки всех перечисленных зависимостей оба пакета можно собрать одной командой. Эти же цели использует GitHub Actions для сборки релизов:

make windows-zip windows-exe

Исполняемый файл автоматически сжимается с помощью UPX. Для отключения сжатия используется команда:

make windows-exe UPX=true

Тестирование

Тестовый набор проверяет отдельные функции, работу приложения через командную строку и результаты обработки файлов из tests/fixtures/.

Для обычной проверки в Linux используется отладочная сборка без санитайзеров:

SLOWTEST=skip make tests-debug

Переменная SLOWTEST=skip пропускает продолжительные сценарии. Полный набор тех же тестов запускается без этой переменной:

make tests-debug

Цель make tests дополнительно включает AddressSanitizer и UndefinedBehaviorSanitizer. Этот режим требует библиотек санитайзеров и llvm-symbolizer:

make tests

Полный перечень системных пакетов и команды их установки приведены в разделе «Системные пакеты для тестирования».

КОНФИГУРАЦИОННЫЙ ФАЙЛ

Конфигурационный файл сохраняет настройки отдельной задачи: какие папки сканировать, где хранить базу и какие файлы исключать. Для разных задач можно подготовить отдельные файлы

Запуск с сохранёнными настройками

Для первого сканирования достаточно сохранить в precizer.conf путь к папке. Например, этот файл также включает отображение прогресса:

path = /mnt/storage
progress = true

Запуск из папки, в которой находится этот файл, не требует аргументов:

precizer

Программа просканирует /mnt/storage и её подпапки. База будет создана в папке запуска под именем компьютера с расширением .db. Для обновления уже существующей базы в файл добавляется update = true. При сканировании хотя бы один path обязателен

Другой конфигурационный файл можно выбрать одной из двух равнозначных команд:

precizer --config=/path/to/task.conf
precizer -g /path/to/task.conf

Относительные пути внутри конфигурации отсчитываются от папки запуска программы, даже если сам файл расположен в другом месте

Готовый precizer.conf в репозитории содержит описания настроек, значения по умолчанию и примеры. Все записи в нём закомментированы: удаление # непосредственно перед именем настройки активирует соответствующую строку

Конфигурация и командная строка

Настройки запуска задаются либо через CLI, либо в конфигурационном файле

Переданные через CLI настройки и пути отключают автоматическое чтение precizer.conf. При явном выборе файла через --config (-g) все настройки задаются в нём; добавление рабочих параметров или путей в командную строку считается ошибкой

Запросы --help, --usage, --version и их короткие формы не читают конфигурацию. Например, precizer --config=task.conf --help показывает справку без открытия файла

Если при запуске без аргументов precizer.conf отсутствует или не содержит настроек, выводится краткая справка. Ошибки в выбранном файле останавливают запуск; отсутствие или недоступность файла, явно указанного через --config, также считается ошибкой

Формат настроек

Имена настроек совпадают с длинными именами CLI-опций без начальных --: например, database, progress, ignore. Имена CLI-опций и ключи конфигурации чувствительны к регистру; дефисы обязательны. Именованные значения (full, machine, always и другие) распознаются без учёта регистра. Регистр путей, имён файлов и регулярных выражений сохраняется. Между именем и значением ставится =; разделитель : также допустим. Параметры help, usage, version и config доступны только в командной строке

Логические настройки принимают все следующие варианты без учёта регистра букв:

Действие Значения
Включить true, yes, on, y, 1
Выключить false, no, off, n, 0

Для настройки с одним значением действует последняя запись: например, после progress = true строка progress = false выключает прогресс. Для списков, таких как ignore и include, записи добавляются. Повтор имени и строки продолжения можно использовать вместе:

ignore = "^cache/"
ignore = "^tmp/"
         "^build/"

Здесь заданы три правила исключения. Непустая строка с отступом, кроме комментария, добавляет ещё одно значение к предыдущему ключу. Новые ключи записываются без отступа

Значение можно заключить в одинаковые одинарные или двойные кавычки. Снимается только внешняя пара; пробелы и обратные слеши внутри сохраняются. Например, ignore = "\.log$" и ignore = \.log$ задают одинаковое правило. Незакрытая кавычка вызывает ошибку с номером строки. Переменные вроде $HOME остаются буквальным текстом

Внутри значения # после пробела или табуляции начинает комментарий, иначе остаётся частью значения. Кавычки это правило не меняют

database = archive.db # комментарий
database = archive#1.db

ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ

Пример 1

Добавить файлы в две базы данных и сравнить их между собой:

precizer --progress --database=database1.db tests/fixtures/diffs/diff1

precizer --progress --database=database2.db tests/fixtures/diffs/diff2

precizer --compare database1.db database2.db
The comparison of database1.db and database2.db databases is starting…
Starting database file database1.db integrity check…
Database database1.db has been verified and is in good condition
Starting database file database2.db integrity check…
Database database2.db has been verified and is in good condition
These files are no longer in database2.db but are still present in database1.db
deleted path2/AAA/ZAW/D/e/f/b_file.txt
These files are present in database2.db but absent from database1.db
added path1/AAA/BCB/CCC/b.txt
The SHA512 checksums of these files do not match between database1.db and database2.db
mismatch 2/AAA/BBB/CZC/a.txt
mismatch 3/AAA/BBB/CCC/a.txt
mismatch 4/AAA/BBB/CCC/a.txt
mismatch path1/AAA/ZAW/D/e/f/b_file.txt
mismatch path2/AAA/BCB/CCC/a.txt
Comparison of database1.db and database2.db databases is complete
Exit status » SUCCESS

Пример 2

Актуализация базы данных

Попробуем использовать предыдущий пример ещё раз. Первая попытка. Сообщение с предупреждением.

precizer --progress --database=database1.db tests/fixtures/diffs/diff1
Primary database file name: database1.db
Starting database file database1.db integrity check…
Database database1.db has been verified and is in good condition
The database database1.db was previously created and already contains data with files and their checksums. Use the --update option only when you are certain that the database needs to be updated and when file information (including changes, deletions, and additions) should be synchronized with the database.
Exit status » WARNING

Должен быть добавлен параметр –update. Этот параметр необходим для защиты базы данных от потери информации из-за случайного запуска.

precizer --update --progress --database=database1.db tests/fixtures/diffs/diff1
Primary database file name: database1.db
Starting database file database1.db integrity check…
Database database1.db has been verified and is in good condition
File system traversal initiated to calculate file count and storage usage
Total traversal size: 48KiB
Total items: 59
Directories: 46
Files: 12
Symlinks: 1
Searching for files that no longer exist on the file system…
Missing file search finished
The database file database1.db has NOT been modified since the program was launched
Exit status » SUCCESS

Внесём некоторые изменения:

# Modify a file
echo -n "  " >> tests/fixtures/diffs/diff1/1/AAA/BCB/CCC/a.txt

# Add a new file
touch tests/fixtures/diffs/diff1/1/AAA/BCB/CCC/c.txt

# Remove a file
rm tests/fixtures/diffs/diff1/path2/AAA/ZAW/D/e/f/b_file.txt

и запустим precizer ещё раз, но уже с параметром --update:

precizer --update --progress --database=database1.db tests/fixtures/diffs/diff1
Primary database file name: database1.db
Starting database file database1.db integrity check…
Database database1.db has been verified and is in good condition
File system traversal initiated to calculate file count and storage usage
Total traversal size: 44KiB
Total items: 59
Directories: 46
Files: 12
Symlinks: 1
Update mode enabled for DB database1.db
File traversal started for tests/fixtures/diffs/diff1
Changes reported during this scan against the DB database1.db:
rehashed 1/AAA/BCB/CCC/a.txt
added as empty 1/AAA/BCB/CCC/c.txt
File traversal complete
Searching for files that no longer exist on the file system…
Dropping DB records for missing or ignored paths in database1.db:
dropped as missing path2/AAA/ZAW/D/e/f/b_file.txt
Missing file search finished
Start vacuuming the primary database…
Primary DB vacuumed: saved 0.00%, elapsed 1ms
The database file database1.db has been modified since the program was launched
Total runtime: 3ms 782μs 866ns
Total traversal size: 44KiB
Total items: 59
Directories: 46
Files: 12
Symlinks: 1
Scan time: 759μs
Scan rate: 10KiB/s
Hashing time: 2μs
Hashing rate: 2MiB/s
Hashed data: 8B
Exit status » SUCCESS

Метки изменений в выводе означают:

При каждом запуске precizer обходит файловую систему, после этого проверяя, есть ли запись об определённом файле в базе данных или нет. Другими словами, приоритет для программы имеет состояние файловой системы на диске.

Обход каталогов precizer работает очень похоже на работу rsync, поскольку использует похожий алгоритм.

Для обычных файлов с полной SHA512 в базе данных precizer пересчитывает контрольную сумму при изменении размера или mtime. Опция --watch-timestamps дополнительно учитывает любые изменения в метаданных о файле кроме времени последнего доступа (atime).

Любые новые файлы, удалённые файлы или те файлы, которые изменились между запусками приложения, будут обработаны и, соответственно, все изменения будут отражены в базе данных, если указан параметр --update.

Пример 3

Использование режима --silent. При включении этого режима программа ничего не выводит на экран. Это имеет смысл при использовании precizer в скриптах.

Исключение составляет режим --compare: вместе с --silent остаётся только вывод результатов сравнения. Пути с различиями выводятся с префиксами deleted, added или mismatch, без заголовков категорий

Добавим параметр –silent к предыдущему примеру:

precizer --silent --update --progress --database=database1.db tests/fixtures/diffs/diff1

В результате на экране ничего не отобразится.

Пример 4

Дополнительная информация в режиме --verbose может быть полезна для отладки.

Добавим параметр –verbose к предыдущему примеру:

precizer --verbose --update --progress --database=database1.db tests/fixtures/diffs/diff1
2026-10-25 12:05:32:835 src/show_parse_diagnostics.c:241:show_verbose_diagnostics:Configuration: rational_logger_mode=VERBOSE
roots=tests/fixtures/diffs/diff1; database=database1.db; db_file_name=database1.db; verbose=yes; maxdepth=-1; silent=no; quiet-ignored=no; force=no; update=yes; watch-timestamps=no; rehash-locked=no; progress=yes; compare=no, db-drop-ignored=no, db-drop-inaccessible=no, dry-run=no, one-file-system=no, check-level=FULL, rational_logger_mode=VERBOSE, color=auto
2026-10-25 12:05:32:835 src/parse_arguments.c:837:parse_arguments:Argument parsing is finished
2026-10-25 12:05:32:835 src/paths_detect.c:036:paths_detect:Checking directory paths provided as arguments
2026-10-25 12:05:32:835 src/file_availability.c:029:file_availability:Verify that the path tests/fixtures/diffs/diff1 exists
2026-10-25 12:05:32:835 src/file_availability.c:048:file_availability:The path tests/fixtures/diffs/diff1 is exists and it is a directory
2026-10-25 12:05:32:835 src/paths_detect.c:060:paths_detect:Path detection is finished
2026-10-25 12:05:32:835 src/init_signals.c:033:init_signals:Set signal SIGUSR2 OK:pid:664206
2026-10-25 12:05:32:835 src/init_signals.c:042:init_signals:Set signal SIGINT OK:pid:664206
2026-10-25 12:05:32:835 src/init_signals.c:051:init_signals:Set signal SIGTERM OK:pid:664206
2026-10-25 12:05:32:835 src/init_signals.c:062:init_signals:Signals initialized
2026-10-25 12:05:32:835 src/db_determine_name.c:084:db_determine_name:Primary database file name: database1.db
2026-10-25 12:05:32:835 src/db_determine_name.c:087:db_determine_name:Primary database file path: database1.db
2026-10-25 12:05:32:835 src/db_determine_name.c:090:db_determine_name:Finished determining database name
2026-10-25 12:05:32:835 src/file_availability.c:029:file_availability:Verify that the path . exists
2026-10-25 12:05:32:835 src/file_availability.c:048:file_availability:The path . is exists and it is a directory
2026-10-25 12:05:32:835 src/file_availability.c:029:file_availability:Verify that the path database1.db exists
2026-10-25 12:05:32:836 src/file_availability.c:040:file_availability:The path database1.db is exists and it is a file
2026-10-25 12:05:32:836 src/db_determine_mode.c:146:db_determine_mode:Final value for config->sqlite_open_flag: SQLITE_OPEN_READWRITE
2026-10-25 12:05:32:836 src/db_determine_mode.c:147:db_determine_mode:Final value for config->db_initialize_tables: false
2026-10-25 12:05:32:836 src/db_determine_mode.c:149:db_determine_mode:DB mode determined
2026-10-25 12:05:32:836 src/db_integrity_check.c:055:db_integrity_check:Starting database file database1.db integrity check…
2026-10-25 12:05:32:836 src/db_integrity_check.c:077:db_integrity_check:The database verification level has been set to FULL
2026-10-25 12:05:32:836 src/db_integrity_check.c:116:db_integrity_check:Database database1.db has been verified and is in good condition
2026-10-25 12:05:32:837 src/db_retrieve_version.c:093:db_retrieve_version:Version number 4 found in database
2026-10-25 12:05:32:837 src/db_check_version.c:052:db_check_version:The database1.db database file is version 4
2026-10-25 12:05:32:837 src/db_check_version.c:075:db_check_version:The database database1.db is on version 4 and does not require any upgrades
2026-10-25 12:05:32:837 src/db_init.c:040:db_init:Successfully opened database database1.db
2026-10-25 12:05:32:837 src/db_init.c:142:db_init:The primary database and tables do not require initialization
2026-10-25 12:05:32:837 src/db_init.c:176:db_init:The primary database named database1.db is ready for operations
2026-10-25 12:05:32:837 src/db_init.c:208:db_init:The TEMP table the_path_id_does_not_exists is ready for runtime checks
2026-10-25 12:05:32:837 src/db_init.c:216:db_init:Database initialization process completed
2026-10-25 12:05:32:837 src/db_compare.c:316:db_compare:Database comparison mode is not enabled. Skipping comparison
2026-10-25 12:05:32:837 src/db_contains_data.c:092:db_contains_data:The database database1.db has already been created previously
2026-10-25 12:05:32:837 src/db_validate_paths.c:278:db_validate_paths:The paths written against the database and the paths passed as arguments are completely identical
2026-10-25 12:05:32:837 src/file_list.c:154:file_list:File system traversal initiated to calculate file count and storage usage
2026-10-25 12:05:32:838 src/show_statistics.c:093:show_statistics:Total traversal size: 44KiB
2026-10-25 12:05:32:838 src/show_statistics.c:094:show_statistics:Total items: 59
2026-10-25 12:05:32:838 src/show_statistics.c:095:show_statistics:Directories: 46
2026-10-25 12:05:32:838 src/show_statistics.c:096:show_statistics:Files: 12
2026-10-25 12:05:32:838 src/show_statistics.c:097:show_statistics:Symlinks: 1
2026-10-25 12:05:32:839 src/db_delete_missing_metadata.c:203:db_delete_missing_metadata:Searching for files that no longer exist on the file system…
2026-10-25 12:05:32:839 src/db_delete_missing_metadata.c:629:db_delete_missing_metadata:Missing file search finished
2026-10-25 12:05:32:839 src/db_close.c:077:db_close:The database connection has been closed
2026-10-25 12:05:32:839 src/db_primary_consider_vacuum.c:033:db_primary_consider_vacuum:No changes were made. The primary database doesn't require vacuuming
2026-10-25 12:05:32:839 src/db_check_changes.c:073:db_check_changes:The database file database1.db has NOT been modified since the program was launched
2026-10-25 12:05:32:839 src/exit_status.c:030:exit_status:The precizer completed as expected
2026-10-25 12:05:32:839 src/exit_status.c:032:exit_status:Exit status » SUCCESS
2026-10-25 12:05:32:839 src/exit_status.c:033:exit_status:Enjoy your life!

Пример 5

Исследование без рекурсии с помощью параметра --maxdepth

tree tests/fixtures/4

tests/fixtures/4
├── AAA
│   ├── BBB
│   │   ├── CCC
│   │   │   └── a.txt
│   │   └── uuu.txt
│   └── tttt.txt
└── sss.txt

4 directories, 4 files

Параметр --maxdepth со значением =0 полностью отключает рекурсию.

precizer --maxdepth=0 tests/fixtures/4
Primary database file name: myhost.db
The path myhost.db doesn't exist or it is not a file
The primary DB file not yet exists. Brand new database will be created
Recursion depth limited to: 0
File traversal started for tests/fixtures/4
Items reported during this traversal against the DB myhost.db:
added sss.txt
File traversal complete
Start vacuuming the primary database…
Primary DB vacuumed: saved -11.11%, elapsed 895μs
The brand-new primary database file myhost.db was created and modified since the program started (files were added, removed, or updated)
Total runtime: 2ms 288μs 525ns
Total traversal size: 4KiB
Total items: 3
Directories: 2
Files: 1
Symlinks: 0
Scan time: 248μs
Scan rate: 7KiB/s
Hashing time: 1μs
Hashing rate: 1MiB/s
Hashed data: 2B
Exit status » SUCCESS

Пример 6

Пример пути, который следует игнорировать. Для указания шаблона игнорирования файлов или каталогов можно использовать регулярные выражения PCRE2. Внимание! Все пути в регулярном выражении должны быть указаны как относительные.

Чтобы проверить и протестировать регулярные выражения PCRE2, можно использовать ресурс https://regex101.com

Для понимания, как выглядит относительный путь, достаточно запустить сканирование директорий без опции --ignore и посмотреть, как терминал будет отображать относительные пути, записываемые в базу данных:

% tree -L 3 tests/fixtures/diffs

tests/fixtures/diffs
├── diff1
│   ├── 1
│   │   └── AAA
│   ├── 2
│   │   └── AAA
│   ├── 3
│   │   └── AAA
│   ├── 4
│   │   └── AAA
│   ├── path1
│   │   └── AAA
│   └── path2
│       └── AAA
└── diff2
    ├── 1
    │   └── AAA
    ├── 2
    │   └── AAA
    ├── 3
    │   └── AAA
    ├── 4
    │   └── AAA
    ├── path1
    │   └── AAA
    └── path2
        └── AAA

27 directories, 0 files
precizer --ignore="^diff1/1/.*" tests/fixtures/diffs

В этом примере начальный путь сканирования — ./tests/fixtures/diffs, а сформированный путь для игнорирования — ./tests/fixtures/diffs/diff1/1/ со всеми подкаталогами (/*).

Primary database file name: myhost.db
The path myhost.db doesn't exist or it is not a file
The primary DB file not yet exists. Brand new database will be created
File traversal started for tests/fixtures/diffs
Items reported during this traversal against the DB myhost.db:
ignored directory diff1/1/AAA
added diff1/2/AAA/BBB/CZC/a.txt
added diff1/3/AAA/BBB/CCC/a.txt
added diff1/4/AAA/BBB/CCC/a.txt
added diff1/path1/AAA/BCB/CCC/a.txt
added diff1/path1/AAA/ZAW/A/b/c/a_file.txt
added diff1/path1/AAA/ZAW/D/e/f/b_file.txt
added diff1/path2/AAA/BCB/CCC/a.txt
added diff1/path2/AAA/ZAW/A/b/c/a_file.txt
added diff1/path2/AAA/ZAW/D/e/f/b_file.txt
added diff2/1/AAA/BCB/CCC/a.txt
added diff2/1/AAA/ZAW/A/b/c/a_file.txt
added diff2/1/AAA/ZAW/D/e/f/b_file.txt
added diff2/2/AAA/BBB/CZC/a.txt
added diff2/3/AAA/BBB/CCC/a.txt
added diff2/4/AAA/BBB/CCC/a.txt
added diff2/path1/AAA/BCB/CCC/a.txt
added diff2/path1/AAA/BCB/CCC/b.txt
added diff2/path1/AAA/ZAW/A/b/c/a_file.txt
added diff2/path1/AAA/ZAW/D/e/f/b_file.txt
added diff2/path2/AAA/BCB/CCC/a.txt
added diff2/path2/AAA/ZAW/A/b/c/a_file.txt
File traversal complete
Start vacuuming the primary database…
Primary DB vacuumed: saved -11.11%, elapsed 1ms
The brand-new primary database file myhost.db was created and modified since the program started (files were added, removed, or updated)
Total runtime: 4ms 444μs 867ns
Total traversal size: 84KiB
Total items: 103
Directories: 81
Files: 21
Symlinks: 1
Scan time: 1ms
Scan rate: 48KiB/s
Hashing time: 28μs
Hashing rate: 2MiB/s
Hashed data: 86B
Exit status » SUCCESS

Повторим тот же пример, но без опции --ignore, чтобы добавить три ранее проигнорированных файла:

precizer --update tests/fixtures/diffs
Primary database file name: myhost.db
Starting database file myhost.db integrity check…
Database myhost.db has been verified and is in good condition
Update mode enabled for DB myhost.db
File traversal started for tests/fixtures/diffs
Changes reported during this scan against the DB myhost.db:
added diff1/1/AAA/BCB/CCC/a.txt
added diff1/1/AAA/ZAW/A/b/c/a_file.txt
added diff1/1/AAA/ZAW/D/e/f/b_file.txt
File traversal complete
Searching for files that no longer exist on the file system…
Missing file search finished
Start vacuuming the primary database…
Primary DB vacuumed: saved 0.00%, elapsed 729μs
The database file myhost.db has been modified since the program was launched
Total runtime: 2ms 756μs 88ns
Total traversal size: 96KiB
Total items: 115
Directories: 90
Files: 24
Symlinks: 1
Scan time: 912μs
Scan rate: 11KiB/s
Hashing time: 4μs
Hashing rate: 2MiB/s
Hashed data: 11B
Exit status » SUCCESS

Пример 7

Продолжение предыдущего примера Пример 6.

Несколько регулярных выражений для игнорирования можно указать одновременно, повторив опцию --ignore несколько раз.

База данных будет очищена от упоминаний файлов, соответствующих регулярным выражениям из аргументов --ignore: “diff1/1/.*” и “diff2/1/.*”

Параметр --db-drop-ignored должен быть указан дополнительно, чтобы удалить из базы данных упоминание файлов, соответствующих регулярным выражениям, переданным через опции --ignore.

На файловой системе не было изменений, но игнорируемые файлы будут удалены из БД.

# Обновить базу данных, удалив информацию о тех файлах, которые были указаны как игнорируемые:

precizer \
    --update \
    --db-drop-ignored \
    --ignore="^diff1/1/.*" \
    --ignore="^diff2/1/.*" \
    tests/fixtures/diffs
Primary database file name: myhost.db
Starting database file myhost.db integrity check…
Database myhost.db has been verified and is in good condition
Update mode enabled for DB myhost.db
File traversal started for tests/fixtures/diffs
Changes reported during this scan against the DB myhost.db:
ignored directory diff1/1/AAA
ignored directory diff2/1/AAA
File traversal complete
Searching for files that no longer exist on the file system…
Dropping DB records for missing or ignored paths in myhost.db:
dropped as ignored diff1/1/AAA/BCB/CCC/a.txt
dropped as ignored diff1/1/AAA/ZAW/A/b/c/a_file.txt
dropped as ignored diff1/1/AAA/ZAW/D/e/f/b_file.txt
dropped as ignored diff2/1/AAA/BCB/CCC/a.txt
dropped as ignored diff2/1/AAA/ZAW/A/b/c/a_file.txt
dropped as ignored diff2/1/AAA/ZAW/D/e/f/b_file.txt
Missing file search finished
Start vacuuming the primary database…
Primary DB vacuumed: saved 16.67%, elapsed 671μs
The database file myhost.db has been modified since the program was launched
Total runtime: 2ms 713μs 359ns
Total traversal size: 72KiB
Total items: 91
Directories: 72
Files: 18
Symlinks: 1
Scan time: 660μs
Scan rate: n/a
Hashing time: 0ns
Hashing rate: n/a
Hashed data: 0B
Exit status » SUCCESS

Пример 8

Использование параметров --ignore вместе с --include


# Удалим старую базу данных и создадим новую, наполним её данными:

rm -i "${HOST}.db"

precizer tests/fixtures/diffs

Усложним задачу с использованием регулярных выражений.

Регулярные выражения PCRE2 для относительных путей, которые необходимо включить. Включаем указанные относительные пути, даже если они были исключены с помощью одного или нескольких параметров --ignore. Несколько регулярных выражений могут быть указаны с помощью --include

Чтобы проверить и протестировать регулярные выражения PCRE2, можно использовать ресурс https://regex101.com

DB будет очищена от упоминаний файлов, соответствующих регулярным выражениям из аргументов --ignore: “^.*/path2/.*” и “diff2/.*”, но опция --include оставит в базе данных пути, соответствующие заданным шаблонам.

Параметр --db-drop-ignored должен быть указан дополнительно, чтобы удалить из базы данных упоминание файлов, соответствующих регулярным выражениям, переданным через опции --ignore.


# Обновить базу данных, удалив информацию о тех файлах, которые были указаны как игнорируемые за исключением шаблонов путей из --include

precizer --update \
	--progress \
	--ignore="^.*/path2/.*" \
	--ignore="^diff2/.*" \
	--include="^diff2/1/AAA/ZAW/A/b/c/.*" \
	--include="^diff2/path1/AAA/ZAW/.*" \
	--include="^diff1/path2/AAA/ZAW/A/b/c/a_file\..*" \
	--db-drop-ignored \
	tests/fixtures/diffs
Primary database file name: myhost.db
Starting database file myhost.db integrity check…
Database myhost.db has been verified and is in good condition
File system traversal initiated to calculate file count and storage usage
Total traversal size: 96KiB
Total items: 115
Directories: 90
Files: 24
Symlinks: 1
Update mode enabled for DB myhost.db
File traversal started for tests/fixtures/diffs
Changes reported during this scan against the DB myhost.db:
ignored directory diff1/path2/AAA
ignored directory diff1/path2/AAA/BCB
ignored directory diff1/path2/AAA/BCB/CCC
ignored directory diff1/path2/AAA/ZAW
ignored directory diff1/path2/AAA/ZAW/A
ignored directory diff1/path2/AAA/ZAW/A/b
ignored directory diff1/path2/AAA/ZAW/A/b/c
ignored directory diff1/path2/AAA/ZAW/D
ignored directory diff1/path2/AAA/ZAW/D/e
ignored directory diff1/path2/AAA/ZAW/D/e/f
ignored directory diff2/1
ignored directory diff2/1/AAA
ignored directory diff2/1/AAA/BCB
ignored directory diff2/1/AAA/BCB/CCC
ignored directory diff2/1/AAA/ZAW
ignored directory diff2/1/AAA/ZAW/A
ignored directory diff2/1/AAA/ZAW/A/b
ignored directory diff2/1/AAA/ZAW/A/b/c
ignored directory diff2/1/AAA/ZAW/D
ignored directory diff2/1/AAA/ZAW/D/e
ignored directory diff2/1/AAA/ZAW/D/e/f
ignored directory diff2/2
ignored directory diff2/2/AAA
ignored directory diff2/2/AAA/BBB
ignored directory diff2/2/AAA/BBB/CZC
ignored directory diff2/3
ignored directory diff2/3/AAA
ignored directory diff2/3/AAA/BBB
ignored directory diff2/3/AAA/BBB/CCC
ignored directory diff2/4
ignored directory diff2/4/AAA
ignored directory diff2/4/AAA/BBB
ignored directory diff2/4/AAA/BBB/CCC
ignored directory diff2/path1
ignored directory diff2/path1/AAA
ignored directory diff2/path1/AAA/BCB
ignored directory diff2/path1/AAA/BCB/CCC
ignored directory diff2/path1/AAA/ZAW
included directory diff2/path1/AAA/ZAW/A
included directory diff2/path1/AAA/ZAW/A/b
included directory diff2/path1/AAA/ZAW/A/b/c
included directory diff2/path1/AAA/ZAW/D
included directory diff2/path1/AAA/ZAW/D/e
included directory diff2/path1/AAA/ZAW/D/e/f
ignored directory diff2/path2
ignored directory diff2/path2/AAA
ignored directory diff2/path2/AAA/BCB
ignored directory diff2/path2/AAA/BCB/CCC
ignored directory diff2/path2/AAA/ZAW
ignored directory diff2/path2/AAA/ZAW/A
ignored directory diff2/path2/AAA/ZAW/A/b
ignored directory diff2/path2/AAA/ZAW/A/b/c
File traversal complete
Searching for files that no longer exist on the file system…
Dropping DB records for missing or ignored paths in myhost.db:
dropped as ignored diff1/path2/AAA/BCB/CCC/a.txt
dropped as ignored diff1/path2/AAA/ZAW/D/e/f/b_file.txt
dropped as ignored diff2/1/AAA/BCB/CCC/a.txt
dropped as ignored diff2/1/AAA/ZAW/D/e/f/b_file.txt
dropped as ignored diff2/2/AAA/BBB/CZC/a.txt
dropped as ignored diff2/3/AAA/BBB/CCC/a.txt
dropped as ignored diff2/4/AAA/BBB/CCC/a.txt
dropped as ignored diff2/path1/AAA/BCB/CCC/a.txt
dropped as ignored diff2/path1/AAA/BCB/CCC/b.txt
dropped as ignored diff2/path2/AAA/BCB/CCC/a.txt
dropped as ignored diff2/path2/AAA/ZAW/A/b/c/a_file.txt
Missing file search finished
Warnings and errors encountered:
dropped as ignored diff1/path2/AAA/BCB/CCC/a.txt
dropped as ignored diff1/path2/AAA/ZAW/D/e/f/b_file.txt
dropped as ignored diff2/1/AAA/BCB/CCC/a.txt
dropped as ignored diff2/1/AAA/ZAW/D/e/f/b_file.txt
dropped as ignored diff2/2/AAA/BBB/CZC/a.txt
dropped as ignored diff2/3/AAA/BBB/CCC/a.txt
dropped as ignored diff2/4/AAA/BBB/CCC/a.txt
dropped as ignored diff2/path1/AAA/BCB/CCC/a.txt
dropped as ignored diff2/path1/AAA/BCB/CCC/b.txt
dropped as ignored diff2/path2/AAA/BCB/CCC/a.txt
dropped as ignored diff2/path2/AAA/ZAW/A/b/c/a_file.txt
Start vacuuming the primary database…
Primary DB vacuumed: saved 16.67%, elapsed 658μs
The database file myhost.db has been modified since the program was launched
Total runtime: 3ms 656μs 611ns
Total traversal size: 96KiB
Total items: 115
Directories: 90
Files: 24
Symlinks: 1
Scan time: 1ms
Scan rate: n/a
Hashing time: 0ns
Hashing rate: n/a
Hashed data: 0B
Exit status » SUCCESS

Те же фильтры в режиме --compare

Та же комбинация --ignore и --include работает и при сравнении двух баз данных. Фильтры определяют не только то, какие строки будут напечатаны, но и то, какая часть относительных путей считается входящей в отчёт сравнения. Поэтому итоговые сводки и сообщения об идентичности относятся только к этой отфильтрованной области

# Продолжая Пример 1, вернём в отчёт только один путь из скрытой группы различий

precizer --compare \
	--ignore="^(?:2|3|4)/.*" \
	--ignore="^path1/.*" \
	--ignore="^path2/.*" \
	--include="^2/AAA/BBB/CZC/a\.txt$" \
	database1.db database2.db
The comparison of database1.db and database2.db databases is starting…
Starting database file database1.db integrity check…
Database database1.db has been verified and is in good condition
Starting database file database2.db integrity check…
Database database2.db has been verified and is in good condition
The SHA512 checksums of these files do not match between database1.db and database2.db
mismatch 2/AAA/BBB/CZC/a.txt
Comparison of database1.db and database2.db databases is complete
Exit status » SUCCESS

В этом примере все различия из путей 2/, 3/, 4/, path1/ и path2/ сначала выводятся из области отчёта сравнения, а затем --include возвращает обратно только 2/AAA/BBB/CZC/a.txt. В результате в отчёте снова появится именно этот путь, а остальные скрытые различия останутся вне итоговых списков и сводок

Пример 9

Защита неизменяемых архивов с помощью --lock-checksum

Опция --lock-checksum нужна для архивных каталогов или файлов, содержимое которых не должно переписываться. Она принимает регулярные выражения PCRE2 для относительных путей (тот же формат, что и у --ignore). Пути, совпавшие с любым шаблоном, записываются в БД один раз. После этого их контрольные суммы не пересчитываются даже при --update. Любое дальнейшее изменение размера или временных меток (при использовании режима --watch-timestamps), исчезновение файла с диска, потеря доступа на чтение или неожиданный сбой проверки доступа считается порчей данных и выводится соответствующее сообщение об ошибке вместо обновления записи. Для исчезнувшего или недоступного заблокированного файла запись в БД сохраняется, чтобы нарушение не терялось между последующими запусками. Защита заблокированного пути имеет приоритет над --ignore, --db-drop-ignored и --db-drop-inaccessible: совпадение с этими фильтрами не должно молча удалять такую запись из БД. Та же защита сохраняется и в ситуации, когда --include возвращает только часть ранее скрытого поддерева. Несколько шаблонов могут быть указаны повторением добавления опции --lock-checksum:

precizer \
  --lock-checksum="^archive/2024/.*" \
  --lock-checksum="^snapshots/monthly/.*" \
  /mnt/storage

В последующих запусках необходимо сохранять те же шаблоны блокировки при актуализации базы:

precizer \
  --update \
  --lock-checksum="^archive/2024/.*" \
  --lock-checksum="^snapshots/monthly/.*" \
  /mnt/storage

Файлы вне шаблонов обновляются в обычном порядке. Для заблокированных через --lock-checksum записей любое расхождение сразу становится заметным и код возврата при завершении precizer будет больше нуля и это можно использовать в скриптах.

Пример 10

Глубокая проверка заблокированных данных с помощью --rehash-locked

Опция --rehash-locked используется только вместе с --lock-checksum. При её включении каждый файл, попавший под шаблон блокировки и уже присутствующий в базе данных, перечитывается побайтно при каждой актуализации базы данных через --update. Для такого файла заново вычисляется контрольная сумма SHA512 и выполняется сравнение с сохранённым значением. Это позволяет выполнить дополнительный аудит неизменяемых архивов ценой увеличенного дискового ввода-вывода. Наличие или отсутствие параметра --watch-timestamps не влияет на работу --rehash-locked. Если пересчитанная сумма и размер совпадают с записью в БД, файл считается консистентным; если при этом на диске отличаются ctime/mtime, новые значения сохраняются в базе данных. Если заблокированный путь одновременно совпадает с --ignore, параметр --rehash-locked всё равно обязан пройти по этому пути и выполнить проверку, а не пропустить её.

precizer --update \
  --lock-checksum="^archive/2024/.*" \
  --rehash-locked \
  /mnt/storage

Чтобы увидеть взаимодействие параметров командной строки --lock-checksum, --watch-timestamps и --rehash-locked, рассмотрим несколько случаев:

  1. Размер файла отличается Если размер, записанный в базе, не совпадает с размером на диске, файл будет помечен как «нарушение заблокированной контрольной суммы» вне зависимости от --watch-timestamps и --rehash-locked. Пересчитывать контрольную сумму бессмысленно: при изменившемся размере она всё равно не совпадёт.
  2. Совпадает размер файла, не указаны ни --watch-timestamps, ни --rehash-locked поэтому остальные значения, такие как SHA512 и временные метки не учитываются и файл считается полностью консистентным, программа завершится со статусом SUCCESS.
  3. Совпадают размер и временные метки; указана --watch-timestamps и не указана опция --rehash-locked Файл считается полностью консистентным, он не появится в выводе, а статус завершения программы будет SUCCESS.
  4. Размер совпадает, временные метки различаются; указана --watch-timestamps и не указана --rehash-locked Файл будет отмечен как «нарушение заблокированной контрольной суммы» только из-за различающихся временных меток, и программа завершится со статусом WARNING.
  5. Размер совпадает, указан параметр --rehash-locked Для проверки учитываются только контрольная сумма и размер, записанные в базе данных. Если они совпадают, файл считается консистентным. Если на диске изменились временные метки, то новые значения ctime/mtime будут сохранены в базе данных независимо от того был ли указан --watch-timestamps или нет.

Подробные примеры поведения в сложных ситуациях собраны в тесте №30 (tests/src/test0030.c). Там проверяются удаления заблокированных файлов, потеря доступа, сбои проверки доступа и взаимодействие с --ignore, --include, --db-drop-ignored и --db-drop-inaccessible.

Практический сценарий: выполнять ежедневное быстрое сканирование без --rehash-locked (и при необходимости без --watch-timestamps), чтобы поддерживать БД в актуальном состоянии, а реже запускать углублённый аудит с --rehash-locked, который гарантированно сверяет контрольные суммы «замороженных» данных.

Пример 11

Сброс записей о недоступных файлах с помощью --db-drop-inaccessible

По умолчанию, если файл недоступен из-за прав доступа, его запись в базе данных сохраняется при --update, чтобы избежать случайной потери данных. Для удаления таких записей используется дополнительный параметр командной строки --db-drop-inaccessible:

precizer --update --db-drop-inaccessible /mnt/storage
dropped as inaccessible archive/secret.bin

Важно: --db-drop-inaccessible относится не к удалённым файлам, а к файлам, которые сейчас нельзя прочитать или для которых не удалось надёжно проверить доступ. Например, могли измениться права, владелец, ACL, или файловая система временно вернула ошибку доступа. По умолчанию такие записи остаются в БД, чтобы временная проблема с доступом не стёрла полезную историю. Если вы уверены, что такие записи больше не нужны, добавьте --db-drop-inaccessible.

Если же файл или один из каталогов в его пути вообще не виден в файловой системе, precizer считает удалённой обычную запись, не защищённую через --lock-checksum, и при --update удалит её из БД без дополнительных опций. Программа не может сама отличить настоящее удаление от ситуации, когда точка монтирования существует, но нужный том не подключился и поэтому каталог выглядит пустым. Перед обновлением БД для внешних, сетевых или съёмных томов сначала убедитесь, что нужный том действительно смонтирован. Для важных архивных путей используйте --lock-checksum: тогда исчезнувший или недоступный файл будет показан как предупреждение, а запись в БД сохранится.

ОСНОВНЫЕ ПАРАМЕТРЫ КОМАНДНОЙ СТРОКИ

Ниже описаны основные опции для повседневной работы. В режиме сканирования после опций указывают исходные каталоги, а с --compare — два файла баз данных. Полный список опций и подробную справку можно получить командой:

precizer --help

Сканирование и обновление базы

--update не означает полный пересчёт всех контрольных сумм. Для обычных файлов с уже сохранённой полной SHA512 пересчёт запускается при изменении размера или mtime. С --watch-timestamps также учитываются изменения ctime и количества занятых блоков на диске. Правила защиты архивных файлов через --lock-checksum описаны в примере 9, а их принудительная проверка — в примере 10

Сравнение баз

Выбор баз для сравнения

Параметр --compare (-c) сравнивает две базы по относительным путям и контрольным суммам. В CLI после него указываются пути к двум файлам баз данных:

precizer --compare database1.db database2.db

В precizer.conf каждый путь задаётся отдельной записью compare:

compare = database1.db
compare = database2.db

Второй путь также можно записать на следующей строке с отступом:

compare = database1.db
    database2.db

Имена файлов могут содержать пробелы, например: compare = my database.db

Фильтрация категорий отчёта сравнения

По умолчанию сравнение показывает все три категории различий. Параметр compare-filter позволяет выбрать нужные: checksum-mismatch — файлы с одинаковыми относительными путями, но разными контрольными суммами; first-source — файлы, присутствующие в первой базе и отсутствующие во второй; second-source — присутствующие во второй и отсутствующие в первой. Параметр можно указывать несколько раз в любых сочетаниях: в отчёт попадут все выбранные категории. Используется в режиме сравнения

В CLI значение передаётся через --compare-filter=TYPE или -F TYPE:

precizer --compare --compare-filter=checksum-mismatch database1.db database2.db

precizer --compare --compare-filter=first-source database1.db database2.db

precizer --compare \
	--compare-filter=first-source \
	--compare-filter=second-source \
	database1.db database2.db

В последнем примере выводятся только пути, присутствующие в одной базе и отсутствующие в другой, а различия SHA512 для общих путей не показываются

В режиме --compare параметры --ignore и --include ограничивают ту область относительных путей, по которой строится отчёт сравнения. Если фильтры скрывают часть различий, итоговые сообщения об идентичности относятся только к оставшейся отфильтрованной области. Пути, возвращённые через --include, снова участвуют и в списках различий, и в итоговых сводках

Выбор файлов и глубина обхода

Шаблоны --ignore и --include задаются для относительных путей от исходного каталога. Обе опции можно повторять. В режиме --compare эти фильтры ограничивают и списки различий, и область, для которой выводятся итоговые сообщения об идентичности. Исключение через --ignore само по себе не удаляет существующие записи из базы; управление таким удалением описано в примере 7

Форматы вывода

Параметр --output (-O) выбирает формат вывода:

В режимах full и compact вывод в терминале дополнительно расцвечивается для лучшего визуального восприятия. Режим machine предназначен для разбора скриптами, которому подсветка не нужна, поэтому по умолчанию выводится простой текст без цвета

Пример формирования компактного отчёта:

precizer --output=compact --database=files.db /data

Примеры строк при сканировании в compact и machine:

added [as new] notes/report.txt
rehashed [file] notes/archive.txt
ignored [not added] cache/session.tmp

В режиме machine вывод имеет вид: действие [пояснение] путь. После слова-действия и после закрывающей квадратной скобки стоит один пробел. Вся оставшаяся чать строки это путь к файлу, включая содержащиеся в нём пробелы, скобки и любые другие символы. Текст в квадратных скобках имеет второстепенное значение и специально заключён в них, чтобы его можно было легко отфильтровать с помощью регулярных выражений.

Пример разбора с помощью awk: $1 — действие, $2 — пояснение без скобок, $3 — весь путь.

precizer --output=machine /data |
	awk -F ' \\[|\\] ' '
		/^[^ ]+ \[[^]]*\] / {
			$3 = substr($0, length($1) + length($2) + 5)
			print $1, $2, $3
		}
	'

В этих форматах --verbose добавляет сведения об изменившихся метаданных:

rehashed [changed: lsize was:1KiB, now:2KiB] notes/report.txt

При сравнении БД строки имеют вид:

deleted notes/old.txt
added notes/new.txt
mismatch notes/report.txt

Типы вывода

Цвет и оформление текста

Параметр --color=auto|always|never управляет цветом и выделением текста, например полужирным шрифтом, в сообщениях программы. Значение обязательно: используйте, например, --color=never или короткую форму -S never

В режиме auto наличие переменной окружения NO_COLOR, даже с пустым значением, или значение TERM=dumb отключает оформление. Это правило действует и при явном --color=auto. Режимы always и never имеют приоритет над этими переменными

Проверяется именно поток, в который выводится сообщение. Например, при перенаправлении stdout в файл сообщения в этом потоке остаются без оформления в режиме auto, даже если stderr всё ещё подключён к терминалу. Режим auto определяет подключение к терминалу, но не проверяет, какие цвета и эффекты он поддерживает

Примеры для двух уже существующих баз данных first.db и second.db:

# Автоматически включать оформление при выводе в интерактивный терминал
precizer --compare --color=auto first.db second.db

# Сохранить отчёт сравнения без оформления в режиме auto по умолчанию
precizer --compare first.db second.db > comparison.txt

# Сохранить оформление при передаче отчёта другой программе через pipe
precizer --compare --color=always first.db second.db | cat

# Отключить оформление даже при выводе в интерактивный терминал
precizer --compare -S never first.db second.db

# Отключить автоматическое оформление через переменную окружения
NO_COLOR=1 precizer --compare first.db second.db

УСТРАНЕНИЕ НЕПОЛАДОК (ТРАБЛШУТИНГ)

Антивирус замедляет работу под Windows

Антивирусная защита в реальном времени может значительно замедлять обход файлов и расчёт контрольных сумм, в отдельных случаях — на один-два порядка. Причина в том, что антивирус проверяет каждый файл при обращении. Для ускорения работы обрабатываемые каталоги рекомендуется добавить в исключения проверки в реальном времени.

precizer считывает каждый байт всех файлов в указанной директории для расчёта контрольной суммы, но НЕ запускает файлы и НЕ исполняет их содержимого. Для самого расчёта контрольных сумм антивирус не требуется.

Медленный проход по файлам, медленный расчёт контрольных сумм, медленная запись в БД. Или решение проблемы под названием «ВСЁ МЕДЛЕННО»

Чтобы выяснить причину, попробуйте запустить precizer в режиме --dry-run или --dry-run=with-checksums.

--dry-run рекурсивно проходит по Файловой Системе. В этом режиме, кроме обхода дерева файлов, больше ничего не выполняется. Можно добавить --progress — тогда добавится подсчёт занимаемого файлами места и количества файлов, но записи в БД не будет. В этом режиме можно проверить доступность ФС и частично — аппаратные возможности. Если медленно даже с --dry-run, то маловероятно, что причина в самой программе precizer.

Режим --dry-run=with-checksums отличается от --dry-run только тем, что каждый встреченный файл будет полностью (побайтово) считан с диска, и для него будет рассчитана контрольная сумма. Это значительно более ресурсоёмкий процесс, практически идентичный реальной работе программы. Режим полностью раскрывает аппаратный потенциал, но при этом не делает записей в БД. Если при этом указать --progress, то после прохода по файловой системе будет показан статус: количество байт, которые прошли через хеширование, а так же средняя скорость хеширования в B/s Показатель скорости хеширования можно сравнивать с результатами сторонних бенчмарков для поиска «бутылочного горлышка».

Возможна ситуация, когда даже с --dry-run=with-checksums программа работает очень быстро, но в режиме реальной работы (без Dry-Run) наблюдается заметная деградация производительности, особенно при массовых добавлениях или изменениях в БД. В этой ситуации нужно проверить ФС, на которой расположен файл базы данных. Именно там может скрываться причина.

База данных SQLite открывается программой precizer с такими параметрами, чтобы максимально сохранить уже записанное и всеми силами противостоять повреждению файла БД. Однако это предполагает больше дисковых I/O-операций и больше синхронизаций ФС с блочным устройством. На практике SQLite действительно очень быстрая БД и обычно не является «слабым звеном». Но если ФС с компрессией, сетевая или просто медленная, это может ощутимо отразиться на производительности программы в целом.

Например, при массовых добавлениях precizer ждёт, когда информация о файле будет записана в БД и транзакция будет завершена, и только потом переходит к следующему файлу. В такой ситуации для решения проблем производительности имеет смысл попробовать временно разместить файл .db, например, на tmpfs, — это может значительно увеличить общую производительность и понять где именно кроется проблема.

Если по-прежнему всё медленно в любых режимах, то имеет смысл проверить:

Целостность файловой системы

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

Аппаратные возможности:

Скорость диска

Файлы считываются полностью и побайтово. Производительность дисковой подсистемы прямо пропорциональна скорости работы precizer. Программа работает поверх ФС как с более высоким слоем абстракции, а не с блочными устройствами напрямую. Любые логические ошибки ФС имеют значение.

Падение производительности может сильно зависеть от выбранной ФС. Например, скорость обработки файлов из смонтированной точки NFS может упираться в производительность сети и заметно отличаться от скорости доступа к ФС с отключённым atime на локальном диске NVMe (atime — access time, метка «время последнего доступа» к файлу). Используйте сторонние утилиты для проверки производительности файловой подсистемы.

Производительность CPU

Расчёт контрольных сумм — это чистая математика и достаточно трудоёмкий процесс. Современные процессоры справляются с этим незаметно быстро, но имеет смысл убедиться, что производительность не деградирует из-за разделяемых ресурсов виртуальных CPU в случае контейнеризации или виртуализации. Используйте сторонние системы мониторинга и бенчмарки для проверки производительности CPU.

Матрица диагностики узких мест

Шаг Режим/команда Что проверяем Если здесь медленно Что делать дальше
1 precizer –dry-run Доступность ФС, скорость обхода дерева файлов, базовая скорость I/O Вероятнее всего проблема вне precizer: ФС/диск/сеть/нагрузка Проверить ФС и подсистему хранения, состояние монтирования, нагрузку системы
2 precizer –dry-run=with-checksums Реальную скорость чтения файлов + вычисления checksum (без БД) Узкое место: чтение данных (диск/сеть/ФС) или CPU (реже) Проверить скорость диска/сети, параметры ФС, ограничение ресурсов CPU (виртуализация/контейнеры)
3 Реальный режим (без Dry-Run) Влияние записи в БД (SQLite) и транзакций Часто проблема в ФС, где лежит .db (медленная/сетевая/компрессия) Проверить ФС под .db, попробовать временно перенести .db на быстрый носитель или tmpfs

АЛЬТЕРНАТИВЫ

Инструменты с открытым исходным кодом для проверки целостности, сравнения файлов и резервного копирования. Другие программы: alternativeto.net

АВТОР

Автор приложения Денис Владимирович Разумовский

COPYING

This program is distributed under the GNU General Public License v3.0 (GPLv3) as provided in the top-level COPYING file. The author is not responsible for any use of the source code or the entire program. Anyone who uses the code or the program uses it at their own risk and responsibility

Ограничение использования на территории рашистского террористического геообразования, захваченного оккупировавшей власть авторитарной диктатурой