КДПВ, ради хайпа, а не флейма.
Моя попытка облегчить муки в процессе резервного копирования хотя бы на чуть-чуть. Какие требования были мной выдвинуты и как я их реализовал.
Скажу сразу, статья не про системы контроля версий. Кто из вас кладет чертежи из САПРа в 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