Sunflat のブログ

ソフトウェア開発についての話題が多いかも

Acronis True Image の増分バックアップを回転

Windowsマシンの自動バックアップ用に、Acronis True Image Home 11 を買ってみた。(True Image 9は前から使ってたけど)

True ImageはHDDパーティションやファイルの増分バックアップ差分バックアップ)が取れるバックアップソフト。

バックアップローケーションという機能があって、古いバックアップファイルを自動的に消してくれる。しかし、古いファイルを消すときにかなり時間がかかるっぽい…。完全バックアップと増分バックアップをマージしているみたいで、これに時間がかかってるのかな。


というわけで、バックアップローケーション機能を使うのはあきらめて、増分バックアップ前に、バックアップファイル数が一定数に達したら自動的に別ディレクトリへバックアップファイルを移動(古い世代から順次削除)するRubyスクリプトを作ってみた。

完全バックアップファイルが無い状態で増分バックアップをかけると、完全バックアップを取ってくれるみたいなので、これで完全+増分バックアップを一定世代数保存できる。


バックアップ開始時に、"trueimage_rotate.bat D:\backup_dir MyBackup 2 4" のようなコマンドを実行させる。この例の場合、D:\backup_dir\MyBackup*.tib の数を数えて、増分バックアップが4つ以上になったら、別ディレクトリへ移動(最大2世代まで保存)する。

trueimage_rotate.bat

ruby trueimage_rotate.rb %* > %1\trueimage_rotate.log 2>&1


trueimage_rotate.rb

#!ruby -Ks
# TrueImageの増分バックアップが一定数に達したら、別ディレクトリへ移動
# 古いディレクトリは削除

if ARGV.length<4
  puts "Usage: #{$0} (バックアップディレクトリ) (バックアップファイル名(連番,拡張子無し)) (完全バックアップ保持数) (増分バックアップ保持数)"
  exit 1
end

def error(msg)
  STDERR.puts(msg)
  exit 1
end

backdir=ARGV[0]
basename=ARGV[1]
maxbasenum=ARGV[2].to_i
maxznum=ARGV[3].to_i
$olddirbase='_old_'+basename+'_'

error("not dir: #{backdir}") if !FileTest.directory?(backdir)
error("maxbasenum<1") if maxbasenum<1

regexp_files=Regexp.new('^'+Regexp.escape(basename)+'(\d*)\.tib$',Regexp::IGNORECASE)

hasbase=false
znum=0
backfiles=[]
Dir.foreach(backdir) do |file|
  if regexp_files =~ file
    # backup files
    zindex=$~[1].to_i
    puts "file: #{file},#{zindex}\n"
    if zindex<=1
      hasbase=true
    else
      znum+=1
    end
    backfiles << file
  end
end

puts "znum:#{znum}"

exit unless hasbase && znum>=maxznum

# rotate!
puts "rotate!"

#Umm
$backdir=backdir
$maxbasenum=maxbasenum
$regexp_files=regexp_files
$regexp_tib=/\.tib$/i

def olddirname(index)
  $backdir+"/"+$olddirbase+index.to_s
end

# index番目のolddirを後ろにずらして空にする
def rotate(index)
  dir=olddirname(index)
  if FileTest.directory?(dir)
    if index>=$maxbasenum
      # delete oldest dir
      print "delete #{dir}\n"
      Dir.foreach(dir) do |file|
        File.delete(dir+"/"+file) if $regexp_tib =~ file
      end
      Dir.rmdir(dir)
      sleep(1) # 待たないと次の名前変更がPermission Errorになる???
    elsif
      # rotate to next
      rotate(index+1)
      print "rename #{dir} to #{olddirname(index+1)}\n"
      File.rename(dir,olddirname(index+1))
      sleep(0.1) # 念のため
    end
  end
  true
end

# 最新のものを移動
rotate(1)
olddir=olddirname(1)
error("olddir #{olddir} already exists")if FileTest.directory?(olddir)
workdir=olddirname(0)
Dir.mkdir(workdir) unless FileTest.directory?(workdir)

Dir.foreach($backdir) do |file|
  File.rename($backdir+'/' + file, workdir +'/'+ file) if regexp_files =~ file
end
File.rename(workdir,olddir)

※ファイル削除処理等が含まれているので、万が一使いたい場合は、十分動作確認してからお願いします。

  • -

追記:どうも、この方法で増分バックアップをとると、パスワードの設定や暗号化が無効になってしまうっぽい...。うむむ