Backup Time Machine своими руками

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

    Помянув сборник софта и архив отсканированных справочников, я задумался над вопросом бекапов. И… Пришел к выводу, что того что мне в самом деле требуется, нет. Точнее конечно же есть, но либо стоит дорого, либо работает не так, как мне бы того хотелось.

    Закончив с пытками гугла на тему: «сделай мне хорошо», решил поступить как истинный Unix`оид, хоть и работающий в форточках. А именно: не выпендривайся, чем проще — лучше.

    Тут я вспомнил презентацию MacOS на которой демонстрировали их Time Machine. Ведь если подумать, очень удобно иметь возможность получить доступ к любому файлу за любой день. Но… Если делать полные копии в виде архивов, то никаких объемов не хватит, чтобы это все хранить. Дальше мысль зацепилась за инкрементные бекапы. То есть в первый раз вы делаете полный архив, а затем архивируете только то, что изменилось.

    И… Этот вариант я тоже отбросил, как не удобный для моего случая. Во-первых, существует необходимость в возможности удалять произвольные «дни». А во-вторых, я очень часто переименовываю свои файлы и время от времени перекладываю из директорию в директорию. А это, в свою очередь, к моему удивлению, срезало почти всех кандидатов в «бекаперы». То есть, софт тупо смотрел на имя файла, дату его изменения и… и все. В итоге бекап разбухал.

    Итак, спасли меня две идеи:
    Во-первых, не важно как называется файл, важно содержание. Таким образом с каждого файла должно сниматься несколько хешей и на основе этой сигнатуры можно достаточно точно судить, что это за файл. В моем случае я ограничился снятием md5 суммы и размером файла. Выбор конечно спорный, но для сканов этого вполне достаточно.
    Во-вторых, если файл не изменился или изменилость только его имя, надо копировать не весь файл, а делать на него жесткую ссылку, благо в NTFS такие есть.

    Если кто не знает, то благодаря команде:
    fsutil hardlink create <ссылка> <файл>
    В windows можно получить настоящую жесткую ссылку.

    В итоге, получился простой алгоритм, который я, не заморачиваясь, оформил на консольном PHP. Теперь бекап происходит при подключении переносного диска к компьютеру, либо (если диск уже подключен) раз в сутки.

    И вот собственно сам «бекапер».
    <?php
    //
    $dir = array();
    $hah = array();
    $hah_new = array();
    $file = array();
    $copy = 0;
    $link = 0;
    include 'conf.php';
    $date = date('Y-m-d');
    
    // выход если бекап на сегодня уже существует
    if(is_dir($date)){
    	exit("Backup already exists\n");
    }
    
    // составляем список существующих файлов
    foreach(glob('*', GLOB_ONLYDIR) as $v){
    	if(is_file($v.'/hah.db')){
    		$hah = array_merge($hah, unserialize(file_get_contents($v.'/hah.db')));
    	}
    }
    
    // создаем дерево директорий
    foreach($dir as $v){
    	$x = explode('/', $v);
    	array_unshift($x, $date);
    	$x[1] = substr($x[1], 0, 1);
    	foreach($x as $k=>$v){
    		$y = implode('/', array_slice($x, 0, $k+1));
    		if(!is_dir($y)){
    			mkdir($y);
    		}
    	}
    }
    
    // получаем список файлов
    while($n = array_pop($dir)){
    	if(!is_dir($date.'/'.substr($n, 0, 1).'/'.substr($n, 3))){
    		mkdir($date.'/'.substr($n, 0, 1).'/'.substr($n, 3));
    	}
    	$dir = array_merge($dir, glob($n.'/*', GLOB_ONLYDIR));
    	$file = array_merge($file, array_diff(glob($n.'/*'), glob($n.'/*', GLOB_ONLYDIR)));
    }
    
    // копируем новые и линкуем старые файлы
    foreach($file as $k=>$v){
    	$x = md5_file($v).filesize($v);
    	if(!$x){
    		continue;
    	}
    	$f = $date.'/'.substr($v, 0, 1).'/'.substr($v, 3);
    	if($hah[$x]){
    		exec('fsutil hardlink create "'.$f.'" "'.$hah[$x].'"');
    		$hah_new[$x] = $f;
    		$link++;
    	}else{
    		copy($v, $f);
    		$hah_new[$x] = $f;
    		$copy++;
    	}
    	print ceil($k*100/count($file))."%\r";
    }
    print "\nLink: ".$link."\n";
    print "Copy: ".$copy."\n";
    
    // сохраняем информацию о файлах
    file_put_contents($date.'/hah.db', serialize($hah_new));
    exit;
    


    Его конфигурация:
    <?php
    date_default_timezone_set('Asia/Novosibirsk');
    
    $dir[] = 'c:/scan'; // сканы
    $dir[] = 'c:/web'; // корень локального сервера
    $dir[] = 'c:/gohsrf'; // приказы
    $dir[] = 'q:'; // флешка
    


    Ну и BAT`ник его запускающий:
    @echo off
    cls
    php backup.php
    pause
    
    Share post

    Comments 47

      +15
      Месье знает толк!
        +8
        Работа с объемными файлами на PHP? Годно.
          +15
          А почему бы просто не купить Acronis True Image? Я понимаю, что это платное ПО, но домашняя версия, к примеру, стоит всего 1000 руб. Совсем не большие деньги за сохранность «нажитого непосильным трудом»
            –4
            Спасибо за минус. Комментарии, чем мой совет настолько плохой будут? :-)
              –3
              Вы заговорили о платном софте, а за это здесь карму рвут в клочья.
                +2
                Да нет, не рвут :-)
                В клочья здесь рвут в основном за велосипеды. А когда для специфической задачи есть софт (хоть и платный), который эту задачу выполняет хорошо — то никто никого не рвёт :-)
                  0
                  Рвут за упоминание «неправославного» платного софта :) Особенно в блогах конкурентов
              +1
              Скорее всего по этой причине
              А во-вторых, я очень часто переименовываю свои файлы и время от времени перекладываю из директорию в директорию. А это, в свою очередь, к моему удивлению, срезало почти всех кандидатов в «бекаперы». То есть, софт тупо смотрел на имя файла, дату его изменения и… и все. В итоге бекап разбухал.

              Акронис при всех его достоинствах — дубли файлов по хэшам не определяет, по крайней мере нам не удалось найти такую настройку.
                0
                Ок, согласен.

                Но лично я как обычный пользователь и программист не могу представить ситуацию, когда в моих бэкапах лежат ОГРОМНЫЕ файлы и я их постоянно переименовываю :-)

                ps: для себя избрал схему с инкрементными бэкапами дважды в неделю и полными раз в 2 месяца
                  0
                  Но лично я как обычный пользователь и программист не могу представить ситуацию, когда в моих бэкапах лежат ОГРОМНЫЕ файлы и я их постоянно переименовываю :-)
                  Не обязательно один огромный, достаточно кучи мелких. Плюс достаточно перемещения, переименование не обязательно.
                  У нас лично отсортированные/отредактированные видео/фото по мере сортировки перемещаются в другие папки, вот Вам и бытовая рядовая ситуация.
                    0
                    Не скажу точно на счет домашней версии. Но у тех версий акрониса которые используем мы, есть великолепный механизм дедупликации данных. По помоему это как раз и есть решение вашей проблемы.
                      +3
                      Нет, мы не будем спрашивать, какой версией вы пользуетесь.
                  0
                  Мне казалось, что блочно-инкрементный бэкап это уже «общее место» для систем резервного копирования сегодня. По крайней мере в последней на сегодня версии TI был замечен режим «непрерывной защиты», и мне показалось, что это именно оно (сохраняются в резервную копию измененные блоки, вне завиимости от названия самого файла)
                  +2
                  Бесплатная Acronis True Image WD Edition.
                    0
                    Тем более :-)
                    0
                    зачем? есть же deja dup… ах да.
                    +6
                    я конечно сам php'шник, но для таких целей помоему лучше юзать на линухе баш скрипты, а на винде какой либо софт.
                      0
                      На винде в Power Shell или VBA можно сделать.
                      +4
                      Плохой заголовок, ждите толпу злых маководов из поисковиков
                        –3
                        Ничего, вот соберусь писать web-интерфейс к «бекаперу», я у них и интерфейс экспроприирую.
                        –6
                        ПХПники… такие велосипедисты…

                        В Windows есть Volume Shadow Copy служба, которая позволяет это делать удобнее и лучше встроенными средствами windows с графическим интерфейсом и версиями файлов.

                        Для того чтобы что-то выкладывать общественности, надо сначала узнать нужно ли это творение.
                          +4
                          На службу теневого копирования Windows надежд мало. Подводила и на server 2003 и на 2008 (на XP,Vista,Seven не пользовался). Если вдруг по какой то причине служба решит, что теневое копирование для тома не включено, все бэкапы тома будут удалены. После исправления ошибки и включения теневого копирования, весь процесс накопления бэкапов начинается заново.
                            0
                            Что значит служба вдруг решит что копирование не включено? Ну и вообще, теневое копирование это лишь механизм для прикладного софта, который используя его делает и управляет резервными копиями. почему то в бизнес-среде (зачастую с очень суровыми требованиями к доступности и наличию резервных копий, включая и юридические требования за рубежом) на эти механизмы полагаются, а вам недостаточно.
                              0
                              Много лет ей пользуюсь сам, проблем не видел (правда службы у меня сами по себе не отключаются).
                                0
                                Прошу прощения, не точно выразился. Данная проблема возникла из за того, что сервер на котором работала служба, был контроллером домена, а после понижения возникла проблема с теневым копированием тома. Задачи по теневому копированию тома не запускались. К сожалению, сейчас не смогу найти ссылку на описание проблемы, остался лишь текст решения:
                                «Заходим: c:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\S-1-5-18\
                                Удаляем.
                                Все задания в планировщике придется внести заново.
                                Включаем расписание теневого копирования.»
                                Тем не менее, после включения расписания теневого копирования, все накопленные бэкапы были потеряны.
                                  0
                                  В настоящее время продолжаю пользоваться теневым копированием, правда уже на Windows Server 2008, проблем не обнаружил. Но неприятный осадок остался. Хотя, конечно, сам виноват — после понижения следовало проверить работоспособность такой важной вещи, как теневое копирование.
                              0
                              Помнится, у NetApp файловая система заточена под такое дело. Читал их занимательные посты примерно год назад. У них и дубликаты и инкрементальные бекапы есть. ИМХО, лучше юзать что-то заточенное профессионалами :)
                                0
                                Да вы прикалываетесь =))) Автор не верит в то, что штатные механизмы бэкапа работают и городит костыли на пхп, а вы сравниваете с системой начинающейся с десятки тысяч долларов :)
                                +16
                                Бэкап файлов под виндой при помощи PHP в стиле MacOS?! Ну нельзя нашим людям давать 10 дней выходных, ну нельзя!
                                  –4
                                  Да уж… Товарисч используй хотя бы Python… Что ле…
                                    0
                                    Why not?

                                    — Винда — основная система

                                    — Пых — основной (и единственный кроме JS) хорошо знакомый ЯП. Плюс который установлен «по дефолту» у пользователей Denwer и т. п. (ну, не считая язык «command.com», который по дефолту без кавычек, хотя, вроде VBScript тоже в винде есть по дефолту, а ещё какой-то PowerShell в новых версиях).

                                    — МакОсь славится своим дружелюбием и удачными решениями, которые не стесняются заимствовать даже лидеры софт-рынка.

                                    Можно, конечно, всё бросить и начать изучать, например, C или Python, его среды трансляции и выполнения (которые во втором случае не совсем «родные» под виндой), библиотеки и т. п. Но зачем это для разовой и не сильно объёмной задачи? Главное, имхо, применяемые алгоритмы, а не язык, если особых требований к скрипту (а это именно скрипт, автоматизирующий рутинную работу) по производительности, поддерживаемости, кроссплатформенности и т. п. нет.

                                    Не, я сам использую иногда Python или Ruby для подобных скриптов и PoC (Django и RoR), но лишь в силу любознательности и наличия большого количества свободного времени (сейчас вот Scala и Lift изучаю для этого, просто интересно, правда время запуска даже «hello world» удручает). Когда нужно что-то срочно заскриптовать, то использую PHP (включая биндинги к GTK+), чтобы не разбираться с незнакомыми глюками нюансами малознакомого ЯП или, тем более, поисками «чёрной кошки в темной комнате» (существующего решения без гарантии, что оно существует), вполне понимая, что PHP менее подходит для этих задач (да и для решаемых ради денег, если честно — не очень, но рынок «визиток» и «бложиков» консервативен, а спрос на пхп-«быдлокодеров» много выше, имхо, всех остальных ЯП вместе взятых на позиции джуниоров), но изучать язык встроенных команд bash, содержание /usr/bin или нестандартные библиотеки C ради конкретной и, как правило, неожиданно возникшей задачи, которую могу решить на PHP, нахожу оверхидом, если подобное решение не попадалось на глаза (и запомнилось) на хабре, стэковерфлоу и т.п.

                                      0
                                      Просто вчера, увидев заголовок статьи в RSS и начав её читать, я подумал что мне самому уже пора лечиться :)
                                      Да нет, я ни сколь не против PHP, благо сам решаю в общем то десктопную задачу при помощи php, но живу с мыслью что это не правильно, хотя да — всё в общем то работает так как надо. Но соглашусь с последними вашими строками — прочитать про нестандартное решение/использование языка тоже в общем то интересно.
                                    0
                                    не сочтите за пиар, я года 2 назад засматривался на аналог вот такого девайся WD My Book Studio Edition II 2TB (WDH2Q20000E). 2 диска в коробке, можно юзать как рэид массив.
                                      +1
                                      <шутка про две категории людей>
                                        0
                                        На самом деле есть три категории.
                                        Из второй понемногу выделяется третья, те, кто после бэкапа проверяют резервную копию на возможность из нее восстановиться (а не просто на читаемость).
                                        +2
                                        Я давно последний раз на PHP что-то делал, поэтому хочу задать вопрос по коду. Вы вроде md5 для всех файлов всегда заново считаете? Не было бы экономнее сначала сравнивать размер, а потом, если он совпал хотя бы с одним файлом из базы, и md5 пересчитывать.
                                          0
                                          Согласен, но от этой практики пришлось отказаться. Очень часто, из-за этого, проскакивали файлы с одинаковыми размерами, но разным содержимым. html-странички в основном. Исправишь что-нибудь, смотришь, а размер тот же получился.
                                            0
                                            Упс… Да вы правы, это я ваш комментарий не правильно понял. :-(
                                            +1
                                            Но в итоге, все-равно придется считать хеш для всех файлов. Если совпадают размеры, надо удостоверится и снять хеш, а если размеры не совпадают со списком… тоже надо сделать хеш, чтобы внести его в список. В итоге, те же яйца, только в профиль.
                                              0
                                              Имхо хеши надо считать только для файлов у которых одинаковый размер. Иначе они все-равно разные. Если в бэкапе нет ни одного с таким же размером, то наш — однозначно надо бэкапить.
                                            0
                                            «Во-первых, не важно как называется файл, важно содержание» было бы еще здорово какой-нибудь музыкальный или видео хэш использовать типа musicbrainz.org/doc/MusicBrainz_Identifier, чтобы mp3 с поправленными тегами не копировались заново. Это особенно важно, так как сортировка новых и старых файлов восстановленных из бэкапа сравнима по трудозатратам с самим редактированием.
                                              0
                                              Для упрощения задачи (только mp3) можно считать хеш не от всего mp3 файла, а только от тела, исключая ID3 теги. Но это на две строчки сложнее. :-) А программист существо ленивое экономное.
                                              0
                                              почему-то не увидел в статье скрипта для восстановления из такого бэкапа
                                                0
                                                Обычным копированием из каталога с заданной датой.
                                                  0
                                                  а… хардлинки же, ну да.
                                                0
                                                Я примерно для этого же использовал git, довольно компактно и легко зеркалировать.
                                                  0
                                                  Так как однажды установил rsync (мануал: Приручаем rsync в Mac OS X ) то и решил его заюзать для бекапа своих документов да бы не лежать ему без дела.

                                                  Создал не большой скрипт, положил в ~/userName/bin/backup

                                                  содержимое:

                                                  #!/bin/bash
                                                  
                                                  # Backup script
                                                  OPT='--progress --stats -lzuogthvr --delete --compress-level=9 --exclude ".D*"'
                                                  
                                                  # Source directory`s
                                                  SRC_DIR=/Volumes/Data/path-to-dir-1
                                                  
                                                  SRC_DIR_2=/Volumes/Data/path-to-dir-2
                                                  SRC_DIR_3=/Volumes/Data/path-to-dir-3
                                                  
                                                  # Destination directory`s
                                                  DES_DIR=/Volumes/Infinite/backup/
                                                  
                                                  /usr/local/bin/rsync --rsync-path="/usr/local/bin/rsync" $OPT $SRC_DIR $DES_DIR
                                                  /usr/local/bin/rsync --rsync-path="/usr/local/bin/rsync" $OPT $SRC_DIR_2 $DES_DIR
                                                  /usr/local/bin/rsync --rsync-path="/usr/local/bin/rsync" $OPT $SRC_DIR_3 $DES_DIR
                                                  


                                                  Работает, правда, в ручном режиме, но мне большего и не требуется на данный момент.
                                                  Пару раз в месяц запустить с терминала скрипт не составляет труда.

                                                  Only users with full accounts can post comments. Log in, please.