Як зробити та відновити додаткові знімки жорсткого диска


13

Я багато використовую Virtual Box для цілей дистрибуції / програм.

Одна з особливостей, яку я просто люблю в цьому, - це знімки віртуальних машин, вони зберігають стан віртуальної машини і здатні відновити її колишню славу, якщо щось, що ви зробили, пішло не так без проблем і не витративши весь ваш жорсткий диск.

У моїх живих системах я знаю, як створити зображення файлової системи 1: 1, але всі відомі мені рішення дозволять створити нове зображення цілої файлової системи.

Чи є якісь програми / файлові системи, які здатні зробити знімок поточної файлової системи, зберегти її в іншому місці, але замість створення повного нового зображення вони створюють додаткові резервні копії?

Щоб легко описати те, що я хочу, воно повинно бути у вигляді ddзображень файлової системи, але замість лише повної резервної копії воно також створювало б додаткові.


Я не шукаю клонезілли тощо. Вона повинна працювати в самій системі без (або майже жодної) втручання з боку користувача, але містити всі дані файлових систем. Я також не шукаю duplicityрезервну копію всієї вашої системи, виключаючи сценарій папок +, ddщоб зберегти ваш mbr. Я можу це зробити сам, шукаючи додаткову витонченість.

Я шукаю те, що я можу зробити, перш ніж робити масові зміни в системі, а потім, якщо щось трапилося неправильно, або я спалив жорсткий диск після розливання на нього кави, я можу просто завантажитися з liveCD і відновити робочий знімок на жорсткий диск.

Це не потрібно щодня, навіть графік не потрібен. Просто запустіть раз у раз і дозвольте їй виконувати свою роботу, бажано RAW на основі копіювання файлів.



Отже, ви шукаєте додаток, який може створювати встановлені зображення? Якщо ні, то чому б не віддати перевагу Deja Dup? Якщо ви запитуєте, що програма може створювати встановлені зображення, я хочу знати і цю відповідь. Додавання вибраних.
heartmagic

щойно опублікував відповідь на питання під назвою ... але я бачу, що ви шукаєте більше потенційного способу відновити вашу систему з голого металу замість файлового рівня.
cprofitt

1
Це здається, що ви хочете блоковий рівень, а не файлова система на основі покрокової резервної копії. Крім використання файлової системи, яка підтримує знімки, я не впевнений, чи можливо те, що ви запитуєте. LVM, BTRFS може бути можливим.
cprofitt

@cprofitt thx для виправлення заголовка, це правильніше.
Бруно Перейра

@Bruno - створення хороших назв допомагає зробити це корисним для людей, які приходять пізніше, щоб знайти відповідь.
cprofitt

Відповіді:


14

Пояснити відповідь cprofitt (оскільки його відповідь є поступовим, як я поясню) ...

Спочатку потрібно знати про жорсткі посилання.

Жорсткі посилання вказують на дані, які є насправді на диску (фізичне розташування), і ви можете отримати доступ до даних за допомогою жорсткого посилання. Кожен файл і каталог є міцним посиланням на розташування даних на фізичному диску. Тому якщо є два файли (жорсткі посилання), що вказують на одне і те ж місце, дані зберігаються лише один раз .


Процес, що надається cprofitt, включає:

  1. Оберніть резервні копії, щоб створити місце для нового. ("Резервна копія сьогодні" від вчорашнього дня стає "Резервна копія вчорашнього дня", "Резервна копія вчорашнього дня" з двох днів тому стає "Резервна копія двох днів тому" тощо)

    • Список постійно зростає, доки ви хочете, але в сценарії він містить лише 4 знімки. (Він повторює весь процес знову для наступного рівня (наприклад, тиждень - "резервне копіювання цього тижня") і повертає їх, тому для цього всього 4).
    • Переміщення здійснюється в зворотному порядку, щоб запобігти перезапису
  2. Скопіюйте останній зроблений знімок (наприклад, "Вчорашня резервна копія") на місце нового (наприклад, "Сьогоднішня резервна копія"), зробивши нові жорсткі посилання на існуючі файли, не копіюючи файл. Отже всі файли нового знімка вказують на те саме місце, що і в попередньому .


Ілюстрований приклад

На малюнку нижче файли одного кольору, які мають однакове ім'я файлу, є посиланнями на один і той же файл на диску. Тут ми просто маємо справу з двома знімками та кількома файлами, але приклад шкали. (За винятком того, що я рухаю знімки в зворотному напрямку до сценаріїв у відповіді cproffit)

введіть тут опис зображення

Процес такий:

  1. Існує знімок системи.

  2. Знімок - це копії (створення жорстких посилань на існуючі файли)

  3. Rsync запускається для оновлення знімка. При зміні файлів він зберігає новий файл як нову копію на жорсткому диску (тому старіший знімок не змінюється). У цьому прикладі файл B змінено. Примітка. Зараз у нас на жорсткому диску зберігається лише 1 копія файлу A та File C та дві копії File B

  4. Обертайте знімки (у цьому випадку знімок 0 "падає" і видаляється, і я перейменую знімок 1 на знімок 0)

  5. Скопіюйте знімок agin (повторіть крок 2)

  6. Знову Rsync. (Повторіть крок 3). Тепер у нас є 1 копія Файлу А та 2 копії Файлу В та Файлу С


Спрощена версія [першого] сценарію (не запускається, як трамплін):

#!/bin/bash

# Delete the snapshot we don't want (has 'fallen off')
rm -rf /root/snapshot/home/hourly.3 ;

# Rotate the snapshots by shuffling them back
mv /root/snapshot/home/hourly.2 /root/snapshot/home/hourly.3 ;
mv /root/snapshot/home/hourly.1 /root/snapshot/home/hourly.2 ;

# Copy the snapshot (creating hard links to the existing files)
cp -al /root/snapshot/home/hourly.0 /root/snapshot/home/hourly.1 ;

# Do the rsync ...
# step 4: rsync from the system into the latest snapshot (notice that
# rsync behaves like cp --remove-destination by default, so the destination
# is unlinked first.  If it were not so, this would copy over the other
# snapshot(s) too!
rsync -va --delete /home/ /root/snapshot/home/hourly.0 ;

Тепер повний ( -ла) скрипт (и) містить повне пояснення тут (як cprofitt, пов'язане з), і воно є більш ретельним, але в основному, як вище. Другий сценарій призначений для групування знімків, а інша частина відповіді cprofitt розповідає про автоматичний процес (з використанням cron) та перевірку того, що резервне копіювання було успішним.

Ви можете змінити імена, тому замість каталогів називатись "погодинно ..." вони називаються чимось іншим, а сценарій запускається вручну.


Щоб відновити всю партію, скопіюйте останній знімок (або попередній) назад у каталог, у який ви робили резервні копії.

Щоб відновити один файл, який все ще знаходиться на знімку, перейдіть до знімка та скопіюйте його туди, куди він належить.

Носій для резервного копіювання може бути зовнішнім жорстким диском (повинен бути ext2 / ext3 / ext4). Якщо ви резервне копіювання /( в основному /boot, /home, /etc /rootі /usr) , то сказати ...

  1. Ви змонтуєте зовнішній диск, виконайте резервну копію та створіть останній знімок.

  2. Відключіть привід.

  3. Пам'ятайте, що ви видалили файл (навіть із кошика), який ви хотіли.

  4. Підключіть зовнішній диск і витягніть файл.

  5. Зробіть резервну копію (просто щоб бути впевненою)

  6. Відключіть привід і вирушайте в подорож ...

  7. Зрозумійте, що ноутбук та лава не змішуються.

  8. На новому ноутбуці працює живий компакт-диск, відформатуйте внутрішній диск, змонтуйте зовнішній диск, а потім cp -a /media/external/snapshot-0/* /media/internal-drive(припустимо, що знімок-0 - це останній знімок)

  9. Встановіть grub в MBR (так, це повинно бути окремим) - або використовуйте ddдля резервного копіювання mbr, як сказав cprofitt внизу своєї відповіді.

  10. Перезавантажте.

Сценарій потрібно вдосконалити (щоб отримати лише потрібні речі), а процедура aove передбачає, що у вас немає /homeрозділу. Якщо ви (або мали), створіть новий на диску та встановіть його на місце mount /dev/sdxy /media/external/homeперед копіюванням.


Знімки на 100 дд коштуватимуть 100 x <average size of snapshot> місця на диску. 100 з них коштуватимуть <size of snapshot> + <size of changed files>. Я використовував це, щоб поставити кілька знімків / home (~ 400 ГБ) на диск об'ємом 500 ГБ.
Portablejim

Ви можете змонтувати зображення віртуального диска у вашій файловій системі, а потім зробити резервні копії цього. Дивіться superuser.com/questions/158908/… та посилання
Portablejim

Як сказано, це для моїх працюючих комп’ютерів, а не для віртуальної коробки, vbox був лише прикладом.
Бруно Перейра

Оновлене запитання (наприкінці замість додавання коментаря).
Portablejim

@Portablejim: Ви пишете, що cp "зберігає жорсткі посилання". Я думаю, що ця фраза є заплутаною. cp -alстворює жорсткі посилання на вихідні файли замість копіювання вихідних файлів. Ваші малюнки також повинні це відображати, наприклад, показуючи, що A-файли на рисунку 2 є тим самим файлом.
daniel kullmann

7

Ви можете використовувати rsync.

Listing one: make_snapshot.sh

#!/bin/bash
# ----------------------------------------------------------------------
# mikes handy rotating-filesystem-snapshot utility
# ----------------------------------------------------------------------
# this needs to be a lot more general, but the basic idea is it makes
# rotating backup-snapshots of /home whenever called
# ----------------------------------------------------------------------

unset PATH  # suggestion from H. Milz: avoid accidental use of $PATH

# ------------- system commands used by this script --------------------
ID=/usr/bin/id;
ECHO=/bin/echo;

MOUNT=/bin/mount;
RM=/bin/rm;
MV=/bin/mv;
CP=/bin/cp;
TOUCH=/bin/touch;

RSYNC=/usr/bin/rsync;


# ------------- file locations -----------------------------------------

MOUNT_DEVICE=/dev/hdb1;
SNAPSHOT_RW=/root/snapshot;
EXCLUDES=/usr/local/etc/backup_exclude;


# ------------- the script itself --------------------------------------

# make sure we're running as root
if (( `$ID -u` != 0 )); then { $ECHO "Sorry, must be root.  Exiting..."; exit; } fi

# attempt to remount the RW mount point as RW; else abort
$MOUNT -o remount,rw $MOUNT_DEVICE $SNAPSHOT_RW ;
if (( $? )); then
{
    $ECHO "snapshot: could not remount $SNAPSHOT_RW readwrite";
    exit;
}
fi;


# rotating snapshots of /home (fixme: this should be more general)

# step 1: delete the oldest snapshot, if it exists:
if [ -d $SNAPSHOT_RW/home/hourly.3 ] ; then         \
$RM -rf $SNAPSHOT_RW/home/hourly.3 ;                \
fi ;

# step 2: shift the middle snapshots(s) back by one, if they exist
if [ -d $SNAPSHOT_RW/home/hourly.2 ] ; then         \
$MV $SNAPSHOT_RW/home/hourly.2 $SNAPSHOT_RW/home/hourly.3 ; \
fi;
if [ -d $SNAPSHOT_RW/home/hourly.1 ] ; then         \
$MV $SNAPSHOT_RW/home/hourly.1 $SNAPSHOT_RW/home/hourly.2 ; \
fi;

# step 3: make a hard-link-only (except for dirs) copy of the latest snapshot,
# if that exists
if [ -d $SNAPSHOT_RW/home/hourly.0 ] ; then         \
$CP -al $SNAPSHOT_RW/home/hourly.0 $SNAPSHOT_RW/home/hourly.1 ; \
fi;

# step 4: rsync from the system into the latest snapshot (notice that
# rsync behaves like cp --remove-destination by default, so the destination
# is unlinked first.  If it were not so, this would copy over the other
# snapshot(s) too!
$RSYNC                              \
    -va --delete --delete-excluded              \
    --exclude-from="$EXCLUDES"              \
    /home/ $SNAPSHOT_RW/home/hourly.0 ;

# step 5: update the mtime of hourly.0 to reflect the snapshot time
$TOUCH $SNAPSHOT_RW/home/hourly.0 ;

# and thats it for home.

# now remount the RW snapshot mountpoint as readonly

$MOUNT -o remount,ro $MOUNT_DEVICE $SNAPSHOT_RW ;
if (( $? )); then
{
    $ECHO "snapshot: could not remount $SNAPSHOT_RW readonly";
    exit;
} fi;

і друге:

Listing two: daily_snapshot_rotate.sh

#!/bin/bash
# ----------------------------------------------------------------------
# mikes handy rotating-filesystem-snapshot utility: daily snapshots
# ----------------------------------------------------------------------
# intended to be run daily as a cron job when hourly.3 contains the
# midnight (or whenever you want) snapshot; say, 13:00 for 4-hour snapshots.
# ----------------------------------------------------------------------

unset PATH

# ------------- system commands used by this script --------------------
ID=/usr/bin/id;
ECHO=/bin/echo;

MOUNT=/bin/mount;
RM=/bin/rm;
MV=/bin/mv;
CP=/bin/cp;

# ------------- file locations -----------------------------------------

MOUNT_DEVICE=/dev/hdb1;
SNAPSHOT_RW=/root/snapshot;

# ------------- the script itself --------------------------------------

# make sure we're running as root
if (( `$ID -u` != 0 )); then { $ECHO "Sorry, must be root.  Exiting..."; exit; } fi

# attempt to remount the RW mount point as RW; else abort
$MOUNT -o remount,rw $MOUNT_DEVICE $SNAPSHOT_RW ;
if (( $? )); then
{
    $ECHO "snapshot: could not remount $SNAPSHOT_RW readwrite";
    exit;
}
fi;


# step 1: delete the oldest snapshot, if it exists:
if [ -d $SNAPSHOT_RW/home/daily.2 ] ; then          \
$RM -rf $SNAPSHOT_RW/home/daily.2 ;             \
fi ;

# step 2: shift the middle snapshots(s) back by one, if they exist
if [ -d $SNAPSHOT_RW/home/daily.1 ] ; then          \
$MV $SNAPSHOT_RW/home/daily.1 $SNAPSHOT_RW/home/daily.2 ;   \
fi;
if [ -d $SNAPSHOT_RW/home/daily.0 ] ; then          \
$MV $SNAPSHOT_RW/home/daily.0 $SNAPSHOT_RW/home/daily.1;    \
fi;

# step 3: make a hard-link-only (except for dirs) copy of
# hourly.3, assuming that exists, into daily.0
if [ -d $SNAPSHOT_RW/home/hourly.3 ] ; then         \
$CP -al $SNAPSHOT_RW/home/hourly.3 $SNAPSHOT_RW/home/daily.0 ;  \
fi;

# note: do *not* update the mtime of daily.0; it will reflect
# when hourly.3 was made, which should be correct.

# now remount the RW snapshot mountpoint as readonly

$MOUNT -o remount,ro $MOUNT_DEVICE $SNAPSHOT_RW ;
if (( $? )); then
{
    $ECHO "snapshot: could not remount $SNAPSHOT_RW readonly";
    exit;
} fi;

Після створення сценарію для ваших потреб додайте його до завдань cron.

кронтаб -е

додати наступне:

0 * / 4 * * * /usr/local/bin/make_snapshot.sh

0 13 * * * /usr/local/bin/daily_snapshot_rotate.sh

Вони змушують запускати make_snapshot.sh кожні чотири години на годину, а daily_snapshot_rotate.sh запускати щодня о 13:00 (тобто до 13:00).

джерело: http://www.mikerubel.org/computers/rsync_snapshots/

* * * * * command to be executed
- - - - -
| | | | |
| | | | ----- Day of week (0 - 7) (Sunday=0 or 7)
| | | ------- Month (1 - 12)
| | --------- Day of month (1 - 31)
| ----------- Hour (0 - 23)
------------- Minute (0 - 59)

Якщо ви хочете, щоб він працював щогодини, ви додасте завдання cron за кожну годину.

Інший можливий варіант - використання rsnapshot

  1. Встановіть rsnapshot (доступний у центрі програмного забезпечення)

  2. Налаштуйте rsnapshot та вкажіть Каталог джерел резервного копіювання

Відкрийте /etc/rsnapshot.conf і відмініть коментарі до наступних рядків.

# nano /etc/rsnapshot.conf

cmd_cp          /bin/cp
cmd_ssh /usr/bin/ssh
cmd_du          /usr/bin/du
cmd_rsnapshot_diff      /usr/local/bin/rsnapshot-diff
logfile /var/log/rsnapshot
  1. Визначте каталоги резервного копіювання призначення у /etc/rsnapshot.conf, як показано нижче. У цьому прикладі

    / home - вихідний каталог, який повинен бути резервним довідником localhost / - призначення, де буде зберігатися резервна копія. Зауважте, що цей каталог буде створений в /.snapshots/{internal.nkvi/ директорії, як показано на останньому кроці.

    nano /etc/rsnapshot.conf

    резервне копіювання / Головна / localhost /

  2. Перевірте конфігурацію rsnapshot

Виконайте тест на конфігурацію, щоб переконатися, що rsnapshot налаштований належним чином і готовий виконати резервне копіювання Linux rsync.

# rsnapshot configtest
Syntax OK
  1. Перевірте конфігурацію резервного копіювання на годиннику rsnapshot

Ви можете створювати резервні копії Linux-каталогів або файлів через різні проміжки часу. За замовчуванням налаштовуються погодинні та щоденні резервні копії.

Перевірте конфігурацію погодинного резервного копіювання.

# rsnapshot -t hourly
echo 6490 > /var/run/rsnapshot.pid
mkdir -m 0700 -p /.snapshots/
mkdir -m 0755 -p /.snapshots/hourly.0/
/usr/bin/rsync -a --delete --numeric-ids --relative --delete-excluded /home \
/.snapshots/hourly.0/localhost/
mkdir -m 0755 -p /.snapshots/hourly.0/
/usr/bin/rsync -a --delete --numeric-ids --relative --delete-excluded /etc \
/.snapshots/hourly.0/localhost/
mkdir -m 0755 -p /.snapshots/hourly.0/
/usr/bin/rsync -a --delete --numeric-ids --relative --delete-excluded \
/usr/local /.snapshots/hourly.0/localhost/
touch /.snapshots/hourly.0/
  1. Перевірте конфігурацію щоденного резервного копіювання rsnapshot

Переконайтеся, що щоденний процес резервного копіювання rsnapshot cwrsync налаштований належним чином.

# rsnapshot -t daily
echo 6493 > /var/run/rsnapshot.pid
mkdir -m 0700 -p /.snapshots/
/.snapshots/hourly.5 not present (yet), nothing to copy
  1. Додати запис Crontab для rsnapshot

Після того, як ви переконалися, що конфігурації резервного копіювання rsync щодня і щодня налаштовані належним чином в утиліті rsnapshot cwrsync, настав час встановити цього цуценя на кробди, як показано нижче.

# crontab -e
0 */4 * * * /usr/local/bin/rsnapshot hourly
30 23 * * * /usr/local/bin/rsnapshot daily

джерело: http://www.thegeekstuff.com/2009/08/tutorial-backup-linux-using-rsnapshot-rsync-utility/

---- Відновлення голих металів

Я б використав дд та дьогтю для відновлення бареметалу.

Резервне копіювання важливих метаданих:

# dd if-/dev/hda of=/backups/mbr bs=512 count=1

Резервне копіювання операційної системи:

# mkdir /backups
# mount nfsserver:/backups/<servername> /backups


# cd /
# tar cfz /backups/system.tar.gz --exclude /mnt --exclude /proc --exclude /backups

Я особисто схилявся б виводити свою систему в режим офлайн, якби я хотів зробити файл відновлення бареметалу.


2
Уся ваша відповідь виглядає дуже добре, проблем немає, і все, окрім того, що я не прошу, жоден із методів не відновить MBR і ddне є поступовим. Нічого цього не запитую. Останні 10% можуть бути цікавими для пошуку, але вся решта інформаційного сміття насправді ні.
Бруно Перейра

Вище описані деталі стосуються файлової системи (як файлової системи), і я додав процес dd для боротьби з MBR.
cprofitt

3

Є два способи зробити додаткове резервне копіювання на основі блоку

  • Знімки на основі файлової системи
  • Знімки на основі програми

Знімки на основі файлової системи

І ZFS, і BTRFS забезпечують покрокові знімки на основі блоку ( BTRFS , ZFS (стор. 25) ). Ви можете мати привід, який ви rsync - це ZFS або BTRFS та знімок.

Існують також знімки LVM (згадані cprofitt), які забезпечують той самий блок на основі покрокових знімків.

Знімки на основі програми

Існує декілька програм резервного копіювання , проте кілька дотримуються цієї мети:

Я знаю, що ви спеціально згадали, що ви не шукаєте чогось на кшталт подвійності, проте я подумав, що можу згадати деякі особливості.

Однак ці програми вимагають встановити їх для відновлення. Краса чогось на зразок rsync полягає в тому, що майже кожна установка Linux має rsync (наприклад, у крихітного ядра (10 МБ дистрибутива) цього немає).

Подвійність

Він просто зберігає diff (рівень блоку), а потім стискає і шифрує їх. Це призводить до ще меншого обсягу пам’яті, ніж метод rsync, однак (принаймні так, як я це бачу) файлову систему потрібно буде реконструювати, що потребує часу (якщо ви використовуєте додаткові резервні копії з нею, і це залежить від часу з остання повна резервна копія)

Сторінка man пояснює, як це працює.

Rdiff-резервне копіювання

Програма клієнт-сервер, яка створює, як і дублікат, рівень блоку, відрізняється, проте вона зберігає зміни з точки останнього відновлення, тому останній знімок найшвидше відновити. Якщо повернутися назад у часі (не найновіший знімок), потрібно проаналізувати більше розбіжностей, і тому це повільніше.

Деякі люди порівнюють rdiff-резервне копіювання з rsnapshot (здається, більш автоматичний спосіб ментоду rsync). Практично всі технічні завдання зосереджуються на використанні rdiff через мережу, проте я знайшов той, який згадує, як це зробити на localhost .


ОК, мені подобається це, подбайте, щоб описати, як зробити цю роботу з відновленням розділу? тобто, якщо я зламаю диск, як би я відновив повну систему зі знімка з необхідністю самостійно робити розділи і т. д., це не має бути дуже детальним і не включає сценарії, лише деякі назви команд і те, що вони будуть робити.
Бруно Перейра

Я не мав досвіду роботи з цими системами, я лише виявив це, коли я провів деякі дослідження за допомогою Google (отже, чому вони є лише посиланнями). наприклад, я дізнався, що duplicityнасправді є.
Portablejim

3

Слід подивитися на ddar ( домашня сторінка ).

Це поступово в сенсі не перенесення однакових частин знімка. У класичному значенні цього слова він не збільшується, оскільки має справу зі знімками.

Примітка: я сам цього не пробував (але довіряю автору). Це може не зробити те, що ви хотіли б досягти поза межами коробки, але все ж на сторінці є більше подібних рішень (наприклад, ZFS ), тож як відправна точка це може виявитися корисним.


1
Я автор ddar (дякую за згадку!). Якщо я правильно розумію питання, передавати ddar серію знімків LVM буде точно так, як вимагається. Як ви кажете, це стосується знімків, а не поступових знімків, але знімки матимуть такий самий ефект із тим перевагою, що старі знімки можна видалити за бажанням, не впливаючи на новіші.
Робі Басак

@robie Мені б хотілося побачити, як це буде працювати, чи можете ви зробити для мене або будь-якого користувача дуже маленьке керівництво, яке може шукати подібне рішення?
Бруно Перейра

1

Я думаю, що ви можете зробити це з єдиним теоретичним для LVM, і це витратить більшу кількість жорсткого диска. Моя теорія полягає в тому, що ви можете отримати свою кореневу систему на логічному томі, тоді, якщо ви хочете зробити тест, ви можете створити знімок і перезапустити машину, використовуючи новий том.

Знімки LVM для роботи потрібні оригінальному обсягу. Це тому, що новий том містить різницю між знімком і реальною файловою системою.

Якщо ви залишите систему в такому стані, ви почнете витрачати дисковий простір по мірі зміни нової файлової системи. Я не знаю, чи існує спосіб консолідувати знімок та остаточний файл файлів. Звичайно, ви можете додати інший логічний том, але для цього вам знадобиться вдвічі більше місця вашої файлової системи плюс різниця між вашою "точкою відновлення" та поточним станом.

І все це вимагає перезавантаження та далеко не автоматичне.

Також передбачається, що декілька сучасних файлових систем йдуть цим шляхом, як zfs в системах solaris або експериментальних btrfs.


1

Це трохи над головою, але це звучить як частина того, що ви хочете зробити - це зробити часткові резервні копії бінарних файлів (як файли зображень розділів). Є пакет, призначений для цього (я щойно читав про це - не пробував).

Погляньте на буп.

https://github.com/apenwarr/bup

Це може дати вам кілька ідей.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.