Вечерний backup. Делаем все проще и понятней

в 16:16, , рубрики: backup, c++, windows, резервное копирование
image

КДПВ, ради хайпа, а не флейма.

Моя попытка облегчить муки в процессе резервного копирования хотя бы на чуть-чуть. Какие требования были мной выдвинуты и как я их реализовал.

Скажу сразу, статья не про системы контроля версий. Кто из вас кладет чертежи из САПРа в Git? А стомегабайтные графические файлы? Ежедневно? И не про облачные хранилища. Статья про реализацию конкретной потребности, которая была озвучена не раз знакомыми и коллегами, пользующихся обычной MS Windows, создающих что-то дома или в офисе.

Однажды осознаешь, что не стоило неделю назад удалять страницу в чертеже, или объединять слои в скетче. Допустим, бэкапы делались, даже инкрементальные. В этот момент меньше всего хочется разбираться, как достать файлы из контейнера, гуглить ключи командной строки и все это самое. Хочется самого простого — любым файловым менеджером найти свежайшую версию файла, или недельной давности, лучше по имени, а не хешу содержимого. Не тот файл? Может нужен двухнедельной давности?

Так появилась моя разработка. Назвал ее BURO. Никак не расшифровывается.

Вдохновителем была утилита rdiff-backup, но у нее был «фатальный недостаток». Написана она на python и хранит данные в текстовых пожатых файлах. Ждать по 20 минут, когда она отработает в конце рабочего дня, или готовясь отойти ко сну, для меня было не приемлемо. Не может оперировать очень длинными именами. Даже страшно подумать, как мне из резерва «отмотать» нужный файл на n правок/дней назад.

Для примера, покажу как сделать резервную копию папки:

buro --backup --srcdir="путь к резервируемой папке" --dstdir="куда будем резервировать"

В папке, указанной как dstdir, будет создан файл buro.db и папка mirror, которая будет полной копией папки srcdir. В следующий раз, когда мы запустим ту же самую команду, в папке dstdir будет создана подпапка, названная меткой времени запуска резервирования, в которую будут перемещены модифицированные или удаленные файлы, по сравнению с предыдущим запуском. Выглядит это примерно так:

<2017-06-14T00-01-34.771>
  <Отчеты о практике>
    Отчет1.doc
<2017-06-15T00-57-35.858>
  Список покупок.xls
<mirror>
  <Отчеты о практике>
    Отчет1.doc
    Отчет2.doc
  <Для мамы>
    Vivaldi.mp3
  Список покупок.xls
buro.db

Как видно, сохранилась возможность достать файловым менеджером любой файл и его предыдущие версии. Имена и пути сохранились. Ура!

Восстанавливаются файлы из резерва командой:

buro --restore --srcdir="откуда восстанавливаем" --dstdir="куда восстанавливаем"

Тут все просто. Если нужно состояние папки на определенную дату, то добавляем аргумент —timestamp и указываем дату в формате «YYYY-MM-DD HH:mm:SS.SSS», например:

buro --restore --srcdir="z:backup" --dstdir="d:documents" --timestamp=”2017-06-15 00:00:00.000”

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

Инкременты стали занимать много места? Руками удалять не нужно, есть команда purge. Пример:

buro --purge --srcdir="где лежит бэкап" --older="P30D"

Аргументом older указываем конкретную дату, либо период времени в формате ISO 8601 (P1Y2M3DT4H5M6S, в примере выше выбран период 30 дней).

Но ведь даже та самая Visual Studio каждый раз генерирует служебных файлов на многие мегабайты. Место не бесплатное. Настраивать маски файлов и папки для исключения? Пффф… Есть опция сжатия файлов! Команде --backup добавляем аргумент --compress и каждый файл будет преобразован в архив bzip2. К имени файлов также будет добавлено расширение ".bz2" Степень сжатия задается числом от 1 до 9 (по-умолчанию 5). Пример:

buro --backup --srcdir="d:myprojects" --dstdir="g:backup" --compress=9

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

Мой типичный сценарий бэкапа, под который и разрабатывалось Buro, это сохранение на съемный носитель или сетевой диск. Данные переносятся в слабо контролируемую среду, секретность не помешает. Шифрование съемных носителей, и тем более сетевых дисков, это всегда немножко грустная тема, особенно если с файлами планируется продолжить работу в другом месте. Но и тут есть решение! Встроенное шифрование. К команде --backup добавляется опция --password. К имени файлов добавляется расширение ".encrypted" Можно одновременно использовать сжатие и шифрование, расширение все равно будет ".encrypted"

Предположим, на предприятии неадекватная СБ, у которой могут возникнуть вопросы к происхождению файла «Зарплатная ведомость руководства.xls.encrypted». Для этого реализована опция шифрования имен --encodenames.

Пример. Каталог с файлами

<.github>
<doc>
<fmt>
<support>
<test>
.gitignore
.travis.yml
Android.mk
ChangeLog.rst
CMakeLists.txt
CONTRIBUTING.rst
LICENSE.rst
README.rst

Превращается в:

<3kOFykh>
<aqFkiIL7WrQu>
<fInOJigKGsSu>
<QCvcAkh>
<WmT4cT0A>
Au!U33x!41SS(8Ir
BuN0kVhe85aPkQh2$
fS1twqYhBCWCagGr
IKNW$LFo3$x9Mgb!rQd
nzSFA6G3RGfKkFA~XaXDZ
pWWMxno894zDuu0L!s3WY
rHtwmdKLrYxkWN~)NtKCuxH4Q
UiJ~)YM0zu01O8g52x~iAPIk

Если кому-то интересны технические детали реализации шифрования:

При использовании опции защиты паролем файл «buro.db» также шифруется. Движок БД — Berkeley DB, шифрует данные алгоритмом AES CBC 128bit, ключ получается из SHA1(пароль + соль). Моя утилита пропускает пароль пользователя через функцию Argon2, получает на выходе 256 бит данных, преобразует в текстовую строку, которая служит паролем к БД. Для шифрования файлов и имен используется алгоритм ChaCha20. Ключи генерируются случайно и сохраняются БД. Я поленился для каждого файла заводить свой ключ, пользуюсь одним. Чтобы нельзя было наложить друг на друга разные версии одного файла, для каждого генерируется свой NONCE, записываю его как первые 8 байт шифрованного файла. Имена файлов перед шифрованием сжимаются простым LZ-подобным алгоритмом, чтобы было труднее угадать длину исходного имени. Поправьте меня, если в чем-то ошибся.

Скучные подробности:

  • Информационные сообщения выводятся в stdout, сообщения об ошибках в stderr;
  • Чтобы видеть подробную информацию, что куда копируется и перемещается, используйте опцию --verbose;
  • Чтобы добавить к сообщениям метку времени, используйте опцию --printtimestamp. Чтобы отобразить уровень логгирования, используйте --printloglevel;

Не стал добавлять контроль целостности данных контрольной суммой, ИМХО в процессе передачи данных и так идет контроль на многих уровнях. Если очень хочется, используйте опцию сжатия, там контроль есть, я так и делаю.

Для заинтересовавшихся ссылка на исходные коды и бинарники.

p.s. В процессе разработки Buro у меня скончался SSD. Какая ирония.

Автор: tandzan

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js