Бэкап с сохранением старых версий файлов и папок
Для Windows есть много разных программ для "зеркалирования" - создания точной резервной копии папки.
Но эти программы удаляют и перезаписывают старые версии файлов в бэкапе. А мне нужно было во время синхронизации не удалять старые версии файлов, а сохранять (например в заданную третью папку).
Когда просматривал разные известные программы для бэкапа, обнаружил, что обычно в них идея "третьей папки" вообще отсутствует. Есть две - исходная (откуда) и целевая (куда - "зеркальная"), а так, чтобы результат сравнения этих двух папок (отличающиеся старые или уже удаленные файлы) сохранялся в третью папку - такого вообщем-то нет.
Или почти нет.
Содержание
- "Третья папка" в программе CopyMik
- Другие варианты
- Robocopy - сохранение старых версий файлов [Решено]
- Интересные ключи Robocopy
- Некоторые особенности жестких ссылок Windows
- Дополнительный бэкап на другой компьютер
"Третья папка" в программе CopyMik
На самом деле есть такая программа. Называется - CopyMik.
Это своего рода расширенный вариант, более функциональная альтернатива известной Robocopy.
В CopyMik предварительное сохранение старых копий выглядит примерно так:
copymik.exe c:\откуда d:\куда /MIR /BEMPTY /BDEL d:\устаревшие /BREPL d:\устаревшие
c:\откуда
- исходная папка-источникd:\куда
- целевая папка-приемник (бэкап-зеркало)d:\устаревшие
- "третья папка".
Ключи:
/BDEL
/BREPL
/BEMPTY
* В названии "третьей папки" можно использовать переменные, например - {DATE} - текущая дата, {DATETIME} - текущие дата и время и др.
КСТАТИ! Эта программа может сразу "на лету" копируемые файлы сжимать и даже шифровать. Ключи: /CO
- сжатие/CR
- шифрование/B
- сжатие с шифрованием/CRPASS
- пароль для шифрования
ВАЖНО! Есть здесь пара настораживающих моментов. Во-первых функция предварительного сохранения удаляемых и измененных файлов и папок в данный момент присутствует только в последней альфа-версии (v2_20_9_alpha) (дополнение: уже в бэтте v2.21b2 - см. комментарий автора программы под этой статьей). Во-вторых несколько настораживает то, что программа хотя и бесплатная, но полностью закрытая (исходников нет) и мало что известно об ее авторе. Если Вас например это не смущает, то можно пользоваться этой программой - в ней именно то что нужно.
Другие варианты
Я очень долго (хотя может быть все-же недостаточно) искал другие варианты. Начиная от готовых решений до написания сложных скриптов на PowerShell.
По разным причинам мне ни одно из решений не понравилось. Либо оно было платным, либо громоздким, либо недостаточно функциональным (например не копирует атрибуты и права NTFS), либо непроверенным, ненадежным или даже подозрительным.
Вообще очень странно, что нет простого решения. Та же Robocopy - прекрасная программа, но в ней вообще нет идеи "третьей папки", а есть только две папки (исходная и целевая), и нет никаких возможностей перехвата, которые могли бы позволить например выполнить скрипт перед удалением отсутствующего или измененного файла в "зеркальной" (целевой) папке.
В результате принял решение использовать комбинацию Robocopy и vbs-скриптов.
Robocopy - сохранение старых версий файлов [Решено]
Рассмотренные скрипты проверялись только на последних версиях Windows. На XP и Vista необходима дополнительная проверка их работоспособности и некоторые корректировки (см. ниже).
ВАЖНО! Здесь рассматривается в основном частный случай того, что принято называть "бэкап" - т.е. только сохранение старых версий файлов и сохранение тех, которые были удалены. Полноценный бэкап - это когда данные сохраняются с дублированием, на отдельное физической устройство и производится еще много дополнительных действий.
Robocopy, .bat, .vbs и жесткие ссылки Windows
Следующий скрипт (его нужно сохранить в текстовом файле с расширением .bat) запускается от имени Администратора.
Для корректной работы с кириллицей можно использовать например редактор "WordPad" в котором при сохранении выбрать
ВАЖНО! Для того, чтобы создавались жесткие ссылки, необходимо чтобы папки "куда" и "устаревшие" находились на одном логическом диске. Кавычки обязательны именно там (и только там) где они указаны ниже.
Запускать так (в консоли):
"C:\_ПУТЬ_\backup.bat" "C:\откуда" "D:\куда" "D:\устаревшие" "D:\папка_скриптов"
В бэкапе участвуют три скрипта и программа Robocopy.
Скрипты hlinkch.vbs и dellink.vbs должны находится в папке D:\папка_скриптов
Скрипт backup.bat в папке указанной в командной строке выше - C:\_ПУТЬ_\backup.bat
backup.bat
@echo off rem chcp 866>nul Set srcFolder=%1 Set destFolder=%2 Set saveFolder=%3 Set pathRunScript=%~4 echo -^> Source path %srcFolder% echo -^> Destination path %destFolder% echo -^> Save date Parent path %saveFolder% echo. echo Create hardlinks in new 'save date' folder (...Save_date_Parent_path\yyy_mm_dd): for /f "tokens=*" %%i in ('cscript //Nologo "%pathRunScript%\hlinkch.vbs" /src:%srcFolder% /dest:%destFolder% /save:%saveFolder% /day:-2') ^ do set saveDateFolder=%%i echo -^> 'Save Date' path - [%saveDateFolder%] echo. rem if save date folder not created - skip 'save date' folder IF NOT EXIST %saveDateFolder% GOTO SKIP echo. echo Fix attributes, time stamps, ntfs acl, owner, auditing for new hardlinks in: echo -^> %saveDateFolder% rem for old Windows --->>> robocopy %destFolder% %saveDateFolder% /E /COPY:ATSOU /XX /XL /IS /IT /ZB /R:3 /W:5 robocopy %destFolder% %saveDateFolder% /E /COPY:ATSOU /DCOPY:T /XX /XL /IS /IT /ZB /R:3 /W:5 echo. echo Delete previous hardlink in destination folder: for /f "tokens=*" %%i in ('cscript //Nologo "%pathRunScript%\dellink.vbs" /dest:%destFolder% /save:%saveDateFolder%') ^ do set countfiles=%%i echo %countfiles% files deleted in destination - %destFolder% GOTO MIR :SKIP echo. echo Skip "save date" - folder name empty! :MIR echo. echo Update (mirror) all from source to destination folder: rem for old Windows --->>> robocopy.exe %srcFolder% %destFolder% /ZB /COPYALL /MIR /R:3 /W:5 /NP /LOG:"%saveFolder:~1%\backup.log" robocopy.exe %srcFolder% %destFolder% /ZB /COPYALL /MIR /DCOPY:T /R:3 /W:5 /NP /UNILOG:"%saveFolder:~1%\backup.log" echo.
hlinkch.vbs
Option Explicit On Error Resume Next Dim FSO, WshShell, testMode Dim srcPath, destPath, savePath, savePathDate, saveDate, cmdMklink Dim countChFolders, countChFiles srcPath = Wscript.Arguments.Named.Item("src") destPath = Wscript.Arguments.Named.Item("dest") savePath = Wscript.Arguments.Named.Item("save") saveDate = Now() + Wscript.Arguments.Named.Item("day") If (Wscript.Arguments.Named.Exists("testmode")) Then testMode = True Else testMode = False End If countChFolders = 0 countChFiles = 0 'cmdMklink = "fsutil hardlink create " ' for old Windows cmdMklink = "mklink /h " savePathDate = "" Set WshShell = WScript.CreateObject("WScript.Shell") 'WshShell.Exec "cmd /c chcp 866" Set FSO = CreateObject("Scripting.FileSystemObject") If ((FSO.FolderExists(srcPath)) And (FSO.FolderExists(destPath)) _ And (FSO.FolderExists(savePath))) Then savePathDate = NewDirBackup(Array(savePath, saveDate)) If (Len(savePathDate) > 0) Then MirrorDirFilesHlink(Array(srcPath, destPath, savePathDate, "")) If ((countChFolders + countChFiles) > 0) Then ' ... Else If (testMode = False) Then FSO.DeleteFolder savePathDate, True End If savePathDate = "" End If If (testMode = True) Then Wscript.Echo vbCrLf & "Foders: " & countChFolders & ", Files: " & countChFiles Wscript.Echo "Return 'save date' name new foder:" End If End If Else If (testMode = True) Then Wscript.Echo "Folder SOURCE or DESTINATION or SAVE not exist!!!" Wscript.Echo "SOURCE -" & vbTab & srcPath Wscript.Echo "DESTINATION - " & destPath Wscript.Echo "SAVE -" & vbTab & vbTab & savePath End If End If If (testMode = True) Then Else Wscript.Echo Chr(34) & savePathDate & Chr(34) End If Function NewDirBackup(dirNameArr) Dim fsoF, fsoFB Dim parentPath, saveDate, fldSaveDate parentPath = dirNameArr(0) saveDate = dirNameArr(1) Set fsoF = CreateObject("Scripting.FileSystemObject") If fsoF.FolderExists(parentPath) Then If (testMode = True) Then Wscript.Echo parentPath & " <-- EXIST 'save' folder" End If Else If (testMode = True) Then Wscript.Echo parentPath & " <-- NOT EXIST 'save' folder!!! Stopped!" End If WScript.Quit End If fldSaveDate = parentPath & "\" & _ Year(saveDate) & "_" & Right("0" & Month(saveDate),2) & "_" & _ Right("0" & Day(saveDate),2) If fsoF.FolderExists(fldSaveDate) Then Set fsoFB = fsoF.GetFolder(fldSaveDate) if (fsoFB.SubFolders.Count > 0) Or (fsoFB.Files.Count > 0) Then If (testMode = True) Then Wscript.Echo fldSaveDate & " <-- 'save data' folder NOT EMPTY!!! Stopped!" End If NewDirBackup = "" Else If (testMode = True) Then Wscript.Echo fldSaveDate & " <-- 'save data' folder EXIST and EMPTY" & vbCrLf End If NewDirBackup = fldSaveDate End If Else If (testMode = True) Then Wscript.Echo fldSaveDate & " <-- 'save date' folder CREATE!!!" & vbCrLf Else fsoF.CreateFolder(fldSaveDate) End If NewDirBackup = fldSaveDate End If End Function Function MirrorDirFilesHlink(pDirArr) ' Out: testMode, countChFolders, countChFiles Dim srcP, destP, savPD, chldP Dim FSOmir, FSOmirDest Dim dstFolders, dstFolder, dstFiles, dstFile Dim srcPathFile, dstPathFile, savPathFile Dim childPath, childPathFile srcP = pDirArr(0) destP = pDirArr(1) savPD = pDirArr(2) chldP = pDirArr(3) Set FSOmir = CreateObject("Scripting.FileSystemObject") Set FSOmirDest = FSOmir.GetFolder(destP) Set dstFolders = FSOmirDest.SubFolders For Each dstFolder In dstFolders If (Len(chldP) > 0) Then childPath = chldP & "\" & dstFolder.Name Else childPath = dstFolder.Name End If If FSOmir.FolderExists(srcP & "\" & childPath) Then If (compareFolders(Array(srcP & "\" & childPath, dstFolder.Path)) = True) Then If (testMode = True) Then Wscript.Echo vbCrLf & "Skip Folder - " & srcP & "\" & childPath Wscript.Echo "-> (i) EQUAL Folder: " & srcP & "\" & childPath & _ " = " & dstFolder.Path End If Else createPathFolder(Array(savPD, Split(childPath, "\"))) countChFolders = countChFolders + 1 If (testMode = True) Then Wscript.Echo "-> (i) DIFFERENT Folder in source: " & srcP & "\" & childPath End If End If Else createPathFolder(Array(savPD, Split(childPath, "\"))) countChFolders = countChFolders + 1 If (testMode = True) Then Wscript.Echo "-> (i) MISSING Folder in source: " & dstFolder.Path End If End If MirrorDirFilesHlink(Array(srcP, destP & "\" & dstFolder.Name, savPD, childPath)) Next Wscript.Echo "" Set dstFiles = FSOmirDest.Files For Each dstFile In dstFiles if (Len(chldP) > 0) Then childPathFile = chldP & "\" & dstFile.Name Else childPathFile = dstFile.Name End If srcPathFile = srcP & "\" & childPathFile dstPathFile = dstFile.Path savPathFile = savPD & "\" & childPathFile If FSOmir.FileExists(srcPathFile) Then If (compareFiles(Array(srcPathFile, dstPathFile)) = True) Then If (testMode = True) Then Wscript.Echo vbCrLf & "Skip FILE - " & dstPathFile Wscript.Echo "->> (i) EQUAL FILE: " & srcPathFile & " = " & dstPathFile End If Else createPathFolder(Array(savPD, Split(chldP, "\"))) ' maybe not exist save path folders? countChFiles = countChFiles + 1 If (testMode = True) Then Wscript.Echo "mklink " & savPathFile & " ==> " & dstPathFile Wscript.Echo "->> (i) DIFFERENT FILE in source: " & srcPathFile Else WshShell.Exec "cmd /c " & cmdMklink & Chr(34) & savPathFile & Chr(34) & _ " " & Chr(34) & dstPathFile & Chr(34) End If End If Else createPathFolder(Array(savPD, Split(chldP, "\"))) ' maybe not exist save path folders? countChFiles = countChFiles + 1 If (testMode = True) Then Wscript.Echo "mklink " & savPathFile & " ==> " & dstPathFile Wscript.Echo "->> (i) MISSING FILE in source: " & srcPathFile Else WshShell.Exec "cmd /c " & cmdMklink & Chr(34) & savPathFile & Chr(34) & _ " " & Chr(34) & dstPathFile & Chr(34) End If End If Next End Function Function createPathFolder(pathArr) Dim FSOp Dim parentPath, childPathArr Dim childPath, childPathSum parentPath = pathArr(0) childPathArr = pathArr(1) Set FSOp = CreateObject("Scripting.FileSystemObject") childPathSum = "" For Each childPath In childPathArr If (Len(childPath) > 0) Then If (Len(childPathSum) = 0) Then childPathSum = childPath Else childPathSum = childPathSum & "\" & childPath End If If FSOp.FolderExists(parentPath & "\" & childPathSum) Then If (testMode = True) Then Wscript.Echo vbCrLf & "Folder exist - " & parentPath & "\" & childPathSum End If Else If (testMode = True) Then Wscript.Echo vbCrLf & "Create New Folder - " & parentPath & "\" & childPathSum Else FSOp.CreateFolder(parentPath & "\" & childPathSum) End If End If End If Next End Function Function compareFolders(foldersArr) Dim pathA, pathB Dim FSOc, getA, getB pathA = foldersArr(0) pathB = foldersArr(1) Set FSOc = CreateObject("Scripting.FileSystemObject") Set getA = FSOc.GetFolder(pathA) Set getB = FSOc.GetFolder(pathB) If ((getA.Attributes <> getB.Attributes) Or (getA.DateLastModified <> getB.DateLastModified)) Then compareFolders = False Else compareFolders = True End If End Function Function compareFiles(filesArr) Dim pathA, pathB Dim FSOf, getA, getB pathA = filesArr(0) pathB = filesArr(1) Set FSOf = CreateObject("Scripting.FileSystemObject") Set getA = FSOf.GetFile(pathA) Set getB = FSOf.GetFile(pathB) If ((getA.Size <> getB.Size) Or (getA.Attributes <> getB.Attributes) Or _ (getA.DateLastModified <> getB.DateLastModified)) Then compareFiles = False Else compareFiles = True End If End Function
dellink.vbs
Option Explicit On Error Resume Next Dim FSO, WshShell, testMode Dim destPath, savePathDate Dim countFiles destPath = Wscript.Arguments.Named.Item("dest") savePathDate = Wscript.Arguments.Named.Item("save") If (Wscript.Arguments.Named.Exists("testmode")) Then testMode = True Else testMode = False End If countFiles = 0 Set WshShell = WScript.CreateObject("WScript.Shell") 'WshShell.Exec "cmd /c chcp 866" Set FSO = CreateObject("Scripting.FileSystemObject") If (FSO.FolderExists(savePathDate)) Then Wscript.Echo DeleteFilesR(Array(destPath, savePathDate, "")) End If Function DeleteFilesR(pDirArr) ' Out: testMode, countFiles Dim destP, savPD, chldP Dim FSOs, FSOsf Dim savFolders, savFolder, savFiles, savFile, delFile Dim childPath, dstPathFile destP = pDirArr(0) savPD = pDirArr(1) chldP = pDirArr(2) Set FSOs = CreateObject("Scripting.FileSystemObject") Set FSOsf = FSOs.GetFolder(savPD) Set savFolders = FSOsf.SubFolders For Each savFolder In savFolders If (Len(chldP) > 0) Then childPath = chldP & "\" & savFolder.Name Else childPath = savFolder.Name End If DeleteFilesR(Array(destP, savPD & "\" & savFolder.Name, childPath)) Next If (testMode = True) Then Wscript.Echo vbCrLf & "-> " & savPD End If Set savFiles = FSOsf.Files For Each savFile In savFiles if (Len(chldP) > 0) Then dstPathFile = destP & "\" & chldP & "\" & savFile.Name Else dstPathFile = destP & "\" & savFile.Name End If If (testMode = True) Then Wscript.Echo "->> " & savFile.Path End If If FSOs.FileExists(dstPathFile) Then If (testMode = True) Then Wscript.Echo "DEL " & dstPathFile Else Set delFile = FSOs.GetFile(dstPathFile) delFile.Delete(True) End If countFiles = countFiles + 1 End If Next If (testMode = True) Then DeleteFilesR = vbCrLf & "Deleted files - " & countFiles Else DeleteFilesR = countFiles End If End Function
Пояснения к скриптам
- Для версий Windows более старых чем Vista программу Robocopy можно взять здесь. К сожалению, в этой старой версии отсутствует возможность зеркалирования меток времени для папок (
).... /DCOPY:T
После установки программу нужно найти здесь"C:\Program Files\Windows Resource Kits\Tools" и скопировать в"C:\Windows\System32" - Для версий Windows более старых чем Vista необходимо раскомментировать строку использующую
и закомментировать строку использующуюfsutil hardlink create ...
в начале файла hlinkch.vbs.mklink /h ...
- При отслеживании изменений папок учитываются только папки которые были удалены (из откуда), папки у которых отличается время изменения и папки с изменившимися атрибутами. Изменения: NTFS ACL, владельца и аудита не отслеживаются.
- У файлов отслеживается их удаление (из откуда), время изменения, размер (но не содержимое), атрибуты. Изменения NTFS ACL, владелец и аудит - не отслеживаются. Если изменилось содержимое файла, но не изменился размер (а такое бывает), дата и атрибуты, то файл будет проигнорирован!
- Жесткие ссылки здесь задействованы для того, чтобы не копировать целиком "удаленные" в процессе сравнения (в .vbs), поскольку в какой-то момент (после сохранения копии в устаревшие, перед удалением из куда) они займут двойное пространство на диске (а если не копировать, а сразу перемещать, то теряются свойства файлов).
- Все три папки: "c:\откуда" "d:\куда" "d:\устаревшие" должны присутствовать заранее!
- Файл hlinkch.vbs можно запускать самостоятельно с такими параметрами:
- установить позавчерашнюю дату в имени конечной папки,/day:-2
- сегодняшняя дата/day:0
формат имени конечной папки будет -"d:\устаревшие\yyyy_mm_dd\" - имитация действий с выводом предполагаемых результатов в консоль/testmode
отсутствие этого параметра - обычный рабочий режим с применением реальных изменений- В путях должны быть кавычки, в остальных параметрах их не должно быть!
- Если папки "d:\устаревшие\yyyy_mm_dd\" нет, то она будет создана, а если она есть, то должна быть пустой
- Если в откуда не было измененных и удаленных, то даже если там появились новые, папка
"\yyy_mm_dd\" не будет создана (будет удалена после временного создания)! - Файл dellink.vbs можно запускать самостоятельно с такими параметрами:
cscript hlinkch.vbs /src:"c:\откуда" /dest:"d:\куда" /save:"d:\устаревшие" /day:-2 /testmode
При таком самостоятельном запуске (без задействования Robocopy и "backup.bat"), в
Скрипт возвращает имя папки
cscript dellink.vbs /dest:"d:\куда" /save:"d:\устаревшие" /testmode
Этот скрипт удаляет из папки
Таким образом, поскольку каждая такая "совпадающая" (по имени и относительному пути) пара имен файлов, является парой жестких ссылок на один и тот же файл, то просто разрывается жесткая ссылка (hardlink) на этот файл из папки
Использование параметров (в т.ч. /testmode
Скрипт возвращает количество разорванных (удаленных) ссылок в папке
Интересные ключи Robocopy
robocopy c:\откуда d:\куда ...[параметры]
Некоторые полезные и малопонятные параметры (ключи):
/XO
- если старее окажется файл в папке куда, то он будет в ней перезаписан - все как обычно
- если файл в папке куда вдруг окажется новее, то он останется нетронутым
Т.е. если в момент сравнения файла источника (откуда) и файла назначения (куда) окажется, что в папке источника (откуда) более старый файл - этот файл просто пропускается и ничего с ним не происходит вообще.
ВАЖНО! Файл будет перезаписан (в первом случае), или не затронут (во втором случае) независимо того какой у него размер или атрибуты. Кроме того, если у обрабатываемых файлов есть посторонние внешние жесткие ссылки, то обрабатываемые файлы могут быть неверно прочитаны Robocopy - см. об этом здесь ниже в разделе о жестких ссылках.
/XN
- если новее вдруг окажется файл в папке куда, то он будет в ней перезаписан
- если файл в папке куда окажется старее, то он останется нетронутым
Т.е. если в момент сравнения файла источника (откуда) и файла назначения (куда) окажется, что в папке источника (откуда) более новый файл - этот файл просто пропускается и ничего с ним не происходит вообще.
ВАЖНО! Файл будет перезаписан (в первом случае), или не затронут (во втором случае) независимо того какой у него размер или атрибуты. Кроме того, если у обрабатываемых файлов есть посторонние внешние жесткие ссылки, то обрабатываемые файлы могут быть неверно прочитаны Robocopy - см. об этом здесь ниже в разделе о жестких ссылках.
/XС
- только одинаковое время (!) и разный размер означают, что файлы "changed"
- если файлы имеют одинаковое время и разный размер - файл в папке куда останется нетронутым (будет исключен из обработки)
- если файлы имеют разное время то даже разный размер не будет иметь значения, - файл в папке куда НЕ будет считаться "changed" и НЕ будет исключен из обработки (а будет видимо перезаписан).
- атрибуты файлов для этого ключа вообще не важны
Т.е. если в момент сравнения файла источника (откуда) и файла назначения (куда) окажется, что у файлов одинаковые метки времени, то только тогда сравнивается размер файлов, и если размер отличается, то только тогда файлы считаются "changed" и будут исключены из обработки (проигнорированы). Если метки времени разные, то независимо от их разного размера - файлы НЕ попадут в класс "changed" (и НЕ будут обрабатываться этим ключом), - т.е. НЕ будут исключены (НЕ будут проигнорированы программой), а будут перезаписаны!
ВАЖНО! Если одноименные файлы в папках откуда и куда имеют одинаковые метки времени, одинаковый размер (!), но разное содержимое (а такое тоже бывает), то Robocopy этого к сожалению не увидит - в этом случае его будет интересовать только размер файлов.
Так же надо учитывать что посторонние жесткие ссылки на обрабатываемые файлы могут сильно повлиять на достоверность результата, поскольку информация о новом размере файла может отсутствовать (даже если размер был изменен - см. ниже о жестких ссылках).
/XX
/XL
/IS
/IT
File Exists In Exists In Source/Dest Source/Dest Source/Dest Class Source Destination File Times File Sizes Attributes =========== =========== ================ =============== ============= ============ Lonely Yes No n/a n/a n/a Tweaked Yes Yes Equal Equal Different Same Yes Yes Equal Equal Equal Changed Yes Yes Equal Different n/a Newer Yes Yes Source > Dest n/a n/a Older Yes Yes Source < Dest n/a n/a Extra No Yes n/a n/a n/a Mismatched Yes (file) Yes (directory) n/a n/a n/a
Некоторые особенности жестких ссылок Windows
Изучая свойства жестких ссылок в Windows, обнаружил следующее:
- Изменения в правах доступа к файлу видны сразу во всех жестких ссылках на этот файл, а время изменения файла - не сразу во всех.
- Когда изменяем содержимое файла, то время изменений обновляется сразу только у той жесткой ссылки из которой эти изменения производились.
- Измененные атрибуты файла ведут себя так же как и время изменения файла (см. выше).
- Если изменить содержимое файла (например находящегося в папке "куда"), используя внешнюю жесткую ссылку на этот файл, то программа Robocopy в некоторых случаях может этого не увидеть, т.к. например время изменения файла обновилось только в той внешней ссылке, через которую он был изменен.
- Если измененный через внешнюю жесткую ссылку файл просто открыть или просто просмотреть его свойства через не затронутую ранее ссылку (например из папки "куда"), то "замороженное" время изменений и атрибуты у этой не затронутой ссылки обновятся. Если просматривая в браузере список файлов в виде таблицы добавить столбец "Владелец", то "замороженная" не затронутся ранее ссылка будет обновляться сразу (и ее время и атрибуты).
* Все вышеперечисленное касается точно только последних версий Windows. В устаревших (например XP или Vista) все может быть иначе - это нужно проверять отдельно.
ВЫВОД из вышесказанного может быть видимо следующим, - если Robocopy будет обрабатывать файл, у которого есть дополнительные используемые где-то еще жесткие ссылки, то Robocopy может не заметить, что у файла могут быть уже другие: атрибуты, время изменения, и судя по всему даже размер. И все это видимо до тех пор, пока каким-либо образом не будут запрошены права доступа к файлу, когда само чтение этих NTFS-прав автоматически обновит и сделает "читабельной" реальную дополнительную информацию (атрибуты, время и размер).
Дополнительный бэкап на другой компьютер
Выше был рассмотрен "версионный" бэкап, который сохраняет старые версии, на случай ошибки пользователя или сбоя программ.
Бывает еще бэкап предназначенный для сохранения файлов на случай поломки оборудования (дисков) или атаки вируса.
Такой бэкап лучше всего делать на отдельный физический компьютер.
Почему FTP
У бэкапа на FTP есть свои плюсы и свои минусы.
Один из очевидных плюсов - пользователь FTP не является пользователем операционной системы, как в случае сетевых папок или SSH.
Т.е. даже если вирус или злоумышленник получит полный доступ к рабочей системе и узнает все пароли, то в случае с логином и паролем FTP, возможен достаточно простой вариант, при котором это ничем не грозит.
Инициатива извне - FTP сервер на рабочем компьютере
Максимально параноидальный вариант - когда компьютер "внешнего" бекапа сам является инициатором операции резервирования - он сам по расписанию подключается к FTP серверу рабочего компьютера и копирует к себе все нужные данные.
В этом случае у внешнего компьютера могут быть закрыты все сетевые папки, и даже сам сетевой доступ, а так же все порты для входящих. Т.е. доступа к нему нет вообще, и даже нет возможности его пинговать. Кроме того из всех протоколов и служб в настройке сетевого подключения ему достаточно оставить один пункт (протокол TCP/IP v4). Тогда даже он сам не сможет иметь доступ к сетевым папкам.
Единственное что у него есть - это логин и пароль на FTP доступ к рабочему компьютеру. А поскольку пользователь FTP может быть полностью изолирован от операционной системы (чего не скажешь о пользователях сетевых папок например), то достигается максимальная защита.
Бесплатный, простой и легкий FTP-сервер для Windows можно взять например здесь - FileZilla server и установить его на рабочий компьютер. После этого нужно завести в нем пользователя и дать доступ к папке с данными (достаточно доступа только на чтение).
Для того чтобы внешний компьютер мог бэкапить к себе данные по расписанию, ему нужна программа с поддержкой командной строки. Были перепробованы разные программы (ncftp-ncftpget, aria2c, wget для windows и пр.) и единственная из них кто имеет достаточную гибкость и не имеет в Windows проблем с кириллицей в именах файлов и папок оказалась WinSCP (качать проще всего сразу версию Portable).
full_backup.bat
@echo off rem chcp 65001 set spath=D:\BACKUP\%date:~-4%-%date:~3,2%-%date:~0,2% rem set spath=D:\BACKUP "D:\Winscp_portable\winscp.com" /command "option batch continue" "open ftp://ftpUSER:ftpPASSWORD@192.168.0.2:21/" ^ "get ""/Work"" ""%spath%""" "exit"
ВАЖНО! Здесь запускается файл с расширением .com из Portable версии WinSCP. Из пути при желании можно убрать создание папки с текущей датой. IP адрес рабочего компьютера нужно подставить свой (на нем должен быть установлен FileZilla-server - см. выше). Так же надо подставить в этот скрипт свой логин и пароль FTP вместо "ftpUSER" и "ftpPASSWORD".
Папка "/Work" в контексте этой статьи, это видимо будет папка куда на рабочем компьютере (хотя конечно можно настроить FTP-сервер так чтобы он сразу давал к ней доступ как корневой для FTP).
Количество двойных кавычек ("" ... """) должно быть точно таким как указано в скрипте!
Инициатива изнутри - FTP сервер на внешнем компьютере
Чуть менее параноидальным вариантом "внешнего" бэкапа будет вариант когда рабочий компьютер не ждет когда к нему подключатся извне, а сам копирует данные на внешний FTP - по своей инициативе, и своему расписанию. В этом случае рабочий компьютер все же имеет минимальный доступ на внешний компьютер бэкапов - доступ по FTP.
В этом варианте все наоборот - на внешний компьютер необходимо установить FTP-сервер, например FileZilla-server (см. чуть выше ссылку), а на рабочий компьютер ту же программу WinSCP (ссылку на Partable см. чуть выше), и закачивать данные на внешний компьютер по расписанию так же с ее помощью.
full_backup.bat
@echo off chcp 1251 set spath=D:\Work "D:\Winscp_portable\winscp.com" /command "option batch continue" "open ftp://ftpUSER:ftpPASSWORD@192.168.0.2:21/" ^ "synchronize remote -mirror -delete ""%spath%"" ""/BACKUP/Work""" "exit"
ВАЖНО! chcp 1251
chcp 1251
D:\Work
/BACKUP
.../Work
"option batch continue"
synchronize remote -mirror ...
... -delete
Здесь запускается файл с расширением .com из Portable версии WinSCP. IP адрес внешнего компьютера нужно подставить свой (на нем должен быть установлен FileZilla-server - см. выше). Так же надо подставить в этот скрипт свой логин и пароль FTP вместо "ftpUSER" и "ftpPASSWORD".
Количество двойных кавычек ("" ... """) должно быть точно таким как указано в скрипте!
Некоторые замечания по FileZilla Server
В FileZilla Server странно реализованы виртуальные каталоги.
Во-первых нужно указать реальный корневой каталог, - например пустую папку. Во-вторых для добавления других папок так, чтобы они были видны одним списком при доступе по FTP, нужно после добавления любой дополнительной папки (только после того как была добавлена пустая корневая) указать у этой дополнительной папки путь стандартно, а после этого навести мышь напротив строки где была добавлена эта папка и одновременно по вертикали напротив столбца "Aliases" и дважды кликнуть. После чего можно будет указать имя виртуального каталога в формате
Последняя версия FileZilla Server не работает на XP. Можно попробовать легкий
Чтобы административный интерфейс FileZilla Server не стартовал при старте Windows (сам сервер будет запускаться как служба в любом случае, если это было указано при установке), нужно удалить ссылку на автостарт интерфейса в двух местах:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run\
См. так же заметку посвященную ротации файлов бэкапа: Ротация файлов бэкапа
2017-09-01 в 16:58:11
По поводу CopyMik
>ВАЖНО! Есть здесь пара настораживающих моментов. Во-первых функция предварительного сохранения удаляемых и измененных файлов и папок в данный >момент присутствует только в последней альфа-версии (v2_20_9_alpha). Во-вторых несколько настораживает то, что программа хотя и бесплатная, но >полностью закрытая (исходников нет) и мало что известно об ее авторе. Если Вас например это не смущает, то можно пользоваться этой программой - >в ней именно то что нужно.
Альфа переведена в бэту v2.21b2
Исходники планируется опубликовать (просто пока не было времени их причесать (написать комментариев итп)
Автор конечно не Алла Пугачёва но например тут
https://www.xing.com/profile/Mikhail_Tchervonenko
или тут
https://habrahabr.ru/users/rusmikle/
а ещё всякие фейсбуки и одноклассники итп информацию нарыть можно при желании.
Короче лошадка я не очеь тёмная ;)
Спасибо за упоминание в статье :)
2017-09-01 в 18:11:36
Михаил Червоненко
И Вам спасибо за комментарий. :)
На самом деле консольных программ с "третьей папкой" я больше вообще не нашел.
Ваша программа похоже уникальна в этом.
2018-08-02 в 16:01:20
Подскажите что будет в моей ситуации?
имеем папки и файлы снимаю зеркальную копию на внешний_диск_1
через какое-то время делаю новый бекап зеркальной копии на внешний_диск_2
что будет потом если я по очереди буду подсовывать диск_1 и диск_2???
в результате я хочу получить два бекапа последних актуальных файлов на двух разных внешних дисках.
2018-08-02 в 23:31:22
Sergey
Если Вы имеете в виду актуальный последний и предпоследний бэкапы, то Вам видимо надо делать так - сначала копировать все с диска 1 на диск 2, а потом сразу делать бэкап зеркала на диск 1. И делать все в одно время, хотя по очереди конечно и именно в таком в порядке - сначала с диска 1 на диск 2, потом с зеркала на диск 1. Тогда будете иметь на внешних дисках последний и предпоследний бэкапы.
2018-08-02 в 23:38:57
Спасибо за ответ, расскажу сценарий, что бы мы говорили об одном и том же.
Есть файлы, и есть два внешних диска. В наличии на руках только один.
Цель делать зеркальный бекап по очереди.
Сегодня на один диск, завтра на второй, послезавтра опять на первый, потом на второй.
2018-08-03 в 04:28:40
Sergey
По такой схеме могут быть проблемы. Зависит от того какой вид бэкапа Вы делаете.
Если каждый раз полный бэкап без сравнения - проблем нет. Если со сравнением то каждый раз Вы сравниваете не с последней копией а с предыдущей - предпоследней, что может быть источником ошибок.
2018-08-03 в 10:09:41
во-во, полный бекап не вариант, у нас тут порядка 6-7 ТБ и 2млн файлов, хочется дописывать только то что изменилосьв режиме "зеркала".
Я вот тоже понимаю, что будут проблемы, так как оно не будет сравнивать с последней версией. Поэтому я и нашел этот сайт и обратился к продвинутым в этой теме, как бы выйти из ситуации малой кровью?
Робокопи была выбрана из-за простоты и самое главное поддержка длинных путей (более 260символов)
2018-08-03 в 19:01:40
Sergey
Ага и насколько я понял задача усложняется тем что каждый день у Вас только один из двух дисков? Т.е. два одновременно, чтобы делать бэкап с 1 на 2, а потом с зеркала на 1-й не получится?
Тогда Вам нужно где-то хранить "скелет" системы из предыдущего дня. Возможно тут имеет смысл задействовать жесткие ссылки, но по ним можно отследить только те файлы которые были удалены или добавлены. Те которые были изменены так отслеживать проблематично (речь о правах доступа - см. ниже).
При таком количестве файлов возможно имеет смысл создать базу данных и в ней хранить "скелет" системы с именами файлов и атрибутами - размером, временными метками, скрытый, архивный и пр. Я бы пожалуй сделал именно так.
Робокопи Вам тут не поможет точно, т.к. в ней нет возможности перехватывать обработку каждого файла - указывать что делать можно только для всех сразу и эти возможности там ограничены. Жесткие ссылки могут быть вариантом т.к. по ним можно отследить удаленные-добавленные, и если не трогать (не запрашивать) права доступа то и измененные. Т.е. если Вам не нужно отслеживать в сравнении изменения в правах доступа то можно попробовать поиграться с сохранением "скелета" системы в виде жестких ссылок в отдельной папке за каждый предыдущий день.
2018-08-03 в 22:28:03
Боюсь ошибиться, но кажется Робокопи при сравнении обновляет жесткие ссылки и устаревшая информация в них теряется.
А если отслеживать скриптом не запрашивая права доступа то можно узнать устаревшую информацию и сравнить с текущей.
Кстати открытие папки со ссылками в проводнике (в том случае если это табличный режим и там видны права доступа) или просмотр свойств жесткой ссылки по правому клику мыши может обновить информацию о файле в жесткой ссылке и возможность для сравнения изменений будет утрачена.
2018-09-06 в 15:42:03
При запуске батник не отрабатывает,выдаёт ошибку:
-> Source path E:\Obmen
-> Destination path D:\backup
-> Save date Parent path D:\oldbackup
Create hardlinks in new 'save date' folder (...Save_date_Parent_path\yyy_mm_dd):
-> 'Save Date' path - [""]
Skip "save date" - folder name empty!
Update (mirror) all from source to destination folder:
2018/09/06 15:19:58 ОШИБКА 123 (0x0000007B) Открытие файла журнала C:\file_backu
p.bat\:\oldbackup\backup.log
Синтаксическая ошибка в имени файла, имени папки или метке тома.
-------------------------------------------------------------------------------
ROBOCOPY :: Robust File Copy for Windows
-------------------------------------------------------------------------------
Начало: Thu Sep 06 15:19:58 2018
Источник - E:\Obmen\
Назначение - D:\backup\
Файлы:
Параметры: /S /E /COPYALL /DCOPY:T /PURGE /MIR /ZB /NP /R:3 /W:5
------------------------------------------------------------------------------
ОШИБКА: Недопустимый параметр #10 : "/UNILOG::\oldbackup\backup.log"
Простое использование :: ROBOCOPY источник назначение /MIR
Источник:: Исходная папка (диск:\путь или \\сервер\общий ресурс\пут
ь).
Назначение :: Папка назначения (диск:\путь или \\сервер\общий ресурс\пут
ь).
/MIR :: Создать зеркало всего дерева папок.
Для получения информации об использовании выполните команду ROBOCOPY /?
**** /MIR может не только скопировать файлы, но и УДАЛИТЬ их!
2018-09-06 в 18:00:41
Evgeniy
Возможно Ваша версия Robocopy не поддерживает команду /UNILOG
Запустите Robocopy отдельно с параметром /? и посмотрите есть ли там /UNILOG
2018-09-06 в 18:16:12
короче решил в свою проблему так:
всего будет 3 набора дисков,
на 1. все сливается в режиме зеркала, дописывая только то что изменилось.
2 и 3 диски - периодически будет вне офиса и поэтому буду делать полные бекапы с первого диска.
Данных будет близко к 10ТБ, наверно перед сливом буду форматировать винты, чтобы по времени было не так долго ждать.
Как по мне эта вся схема максимально простая и надежная. Форматиться винты будут раз в 2 месяца, это ж не сильно печально для них, как считаете?
2018-09-06 в 18:44:02
Sergey
Не совсем понимаю зачем форматировать винты, хотя ничего печального конечно в этом нет. :)
2019-06-24 в 17:41:50
ну на чистый винт делаем обычное копирование всего с .. на...делает быстро и все подряд.
а если там будут уже файлы, то будет тратиться время на сравнение и при этом оно все равно все файлы перезатирает. Даже если файл и не именял.
по ходу оно делает какие-то метки свои, когда бекапишь командой robocopy
я проводил эксперимент, был позапрошлый бекап и запуская новый, оно все-все файлы перезаписало. Это хорошо было видно на архивах большого объема
2019-06-24 в 23:33:53
Sergey
Насколько я проверял - без нужды не перезаписывает. Иначе не справлялся бы с большими объемами так быстро