Commit 39465b29 authored by Marco Mariani's avatar Marco Mariani

incremental restore hack

parent 36171d3b
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
"""Invoke rdiff utility to make signatures, deltas, or patch""" """Invoke rdiff utility to make signatures, deltas, or patch"""
import os, librsync import os, librsync
import Globals, log, static, TempFile, rpath, hash import connection, Globals, log, static, TempFile, rpath, hash
def get_signature(rp, blocksize = None): def get_signature(rp, blocksize = None):
...@@ -30,6 +30,13 @@ def get_signature(rp, blocksize = None): ...@@ -30,6 +30,13 @@ def get_signature(rp, blocksize = None):
(rp.get_indexpath(), blocksize), 7) (rp.get_indexpath(), blocksize), 7)
return librsync.SigFile(rp.open("rb"), blocksize) return librsync.SigFile(rp.open("rb"), blocksize)
def get_signature_vf(rorp):
size = os.path.getsize(rorp.path)
file2 = open(rorp.path, 'rb')
signature_fp = librsync.SigFile(file2, find_blocksize(size))
vf = connection.VirtualFile.new(signature_fp)
return vf
def find_blocksize(file_len): def find_blocksize(file_len):
"""Return a reasonable block size to use on files of length file_len """Return a reasonable block size to use on files of length file_len
......
...@@ -134,7 +134,8 @@ def set_allowed_requests(sec_level): ...@@ -134,7 +134,8 @@ def set_allowed_requests(sec_level):
"Log.log_to_file", "FilenameMapping.set_init_quote_vals_local", "Log.log_to_file", "FilenameMapping.set_init_quote_vals_local",
"FilenameMapping.set_init_quote_vals", "Time.setcurtime_local", "FilenameMapping.set_init_quote_vals", "Time.setcurtime_local",
"SetConnections.add_redirected_conn", "RedirectedRun", "SetConnections.add_redirected_conn", "RedirectedRun",
"sys.stdout.write", "robust.install_signal_handlers"] "sys.stdout.write", "robust.install_signal_handlers",
"Rdiff.get_signature_vf"]
if (sec_level == "read-only" or sec_level == "update-only" or if (sec_level == "read-only" or sec_level == "update-only" or
sec_level == "all"): sec_level == "all"):
l.extend(["rpath.make_file_dict", "os.listdir", "rpath.ea_get", l.extend(["rpath.make_file_dict", "os.listdir", "rpath.ea_get",
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
from __future__ import generators from __future__ import generators
import tempfile, os, cStringIO import tempfile, os, cStringIO
import static, rorpiter, FilenameMapping import static, rorpiter, FilenameMapping, connection
class RestoreError(Exception): pass class RestoreError(Exception): pass
...@@ -32,7 +32,9 @@ def Restore(mirror_rp, inc_rpath, target, restore_to_time): ...@@ -32,7 +32,9 @@ def Restore(mirror_rp, inc_rpath, target, restore_to_time):
MirrorS.set_mirror_and_rest_times(restore_to_time) MirrorS.set_mirror_and_rest_times(restore_to_time)
MirrorS.initialize_rf_cache(mirror_rp, inc_rpath) MirrorS.initialize_rf_cache(mirror_rp, inc_rpath)
target_iter = TargetS.get_initial_iter(target) # we run this locally to retrieve RPath instead of RORPath objects
# target_iter = TargetS.get_initial_iter(target)
target_iter = selection.Select(target).set_iter()
diff_iter = MirrorS.get_diffs(target_iter) diff_iter = MirrorS.get_diffs(target_iter)
TargetS.patch(target, diff_iter) TargetS.patch(target, diff_iter)
MirrorS.close_rf_cache() MirrorS.close_rf_cache()
...@@ -252,14 +254,28 @@ class MirrorStruct: ...@@ -252,14 +254,28 @@ class MirrorStruct:
def get_diff(cls, mir_rorp, target_rorp): def get_diff(cls, mir_rorp, target_rorp):
"""Get a diff for mir_rorp at time""" """Get a diff for mir_rorp at time"""
delta_fp = None
if not mir_rorp: mir_rorp = rpath.RORPath(target_rorp.index) if not mir_rorp: mir_rorp = rpath.RORPath(target_rorp.index)
elif Globals.preserve_hardlinks and Hardlink.islinked(mir_rorp): elif Globals.preserve_hardlinks and Hardlink.islinked(mir_rorp):
mir_rorp.flaglinked(Hardlink.get_link_index(mir_rorp)) mir_rorp.flaglinked(Hardlink.get_link_index(mir_rorp))
elif mir_rorp.isreg(): elif mir_rorp.isreg():
expanded_index = cls.mirror_base.index + mir_rorp.index expanded_index = cls.mirror_base.index + mir_rorp.index
file_fp = cls.rf_cache.get_fp(expanded_index, mir_rorp) file_fp = cls.rf_cache.get_fp(expanded_index, mir_rorp)
mir_rorp.setfile(hash.FileWrapper(file_fp)) if (target_rorp):
# a file is already there, we can create a diff
signature_vf = target_rorp.conn.Rdiff.get_signature_vf(target_rorp)
target_signature = connection.VirtualFile(target_rorp.conn, signature_vf)
delta_fp = mir_rorp.get_delta(target_signature, open(file_fp.name, 'rb'))
mir_rorp.setfile(delta_fp)
else:
# standard rdiff-backup behavior, transfer everything
mir_rorp.setfile(hash.FileWrapper(file_fp))
mir_rorp.set_attached_filetype('snapshot') mir_rorp.set_attached_filetype('snapshot')
if delta_fp:
mir_rorp.set_attached_filetype('diff')
return mir_rorp return mir_rorp
static.MakeClass(MirrorStruct) static.MakeClass(MirrorStruct)
...@@ -464,7 +480,8 @@ class RestoreFile: ...@@ -464,7 +480,8 @@ class RestoreFile:
log.Log("Applying patch %s" % (inc_diff.get_indexpath(),), 7) log.Log("Applying patch %s" % (inc_diff.get_indexpath(),), 7)
assert inc_diff.getinctype() == 'diff' assert inc_diff.getinctype() == 'diff'
delta_fp = inc_diff.open("rb", inc_diff.isinccompressed()) delta_fp = inc_diff.open("rb", inc_diff.isinccompressed())
new_fp = tempfile.TemporaryFile() # the temporary file must be named to provide a second file handler later
new_fp = tempfile.NamedTemporaryFile()
Rdiff.write_patched_fp(current_fp, delta_fp, new_fp) Rdiff.write_patched_fp(current_fp, delta_fp, new_fp)
new_fp.seek(0) new_fp.seek(0)
current_fp = new_fp current_fp = new_fp
...@@ -494,7 +511,8 @@ rdiff-backup destination directory, or a bug in rdiff-backup""" % ...@@ -494,7 +511,8 @@ rdiff-backup destination directory, or a bug in rdiff-backup""" %
if not first_inc.isinccompressed(): return first_inc.open("rb") if not first_inc.isinccompressed(): return first_inc.open("rb")
# current_fp must be a real (uncompressed) file # current_fp must be a real (uncompressed) file
current_fp = tempfile.TemporaryFile() # the temporary file must be named to provide a second file handler later
current_fp = tempfile.NamedTemporaryFile()
fp = first_inc.open("rb", compress = 1) fp = first_inc.open("rb", compress = 1)
rpath.copyfileobj(fp, current_fp) rpath.copyfileobj(fp, current_fp)
assert not fp.close() assert not fp.close()
......
...@@ -36,7 +36,10 @@ are dealing with are local or remote. ...@@ -36,7 +36,10 @@ are dealing with are local or remote.
""" """
import os, stat, re, sys, shutil, gzip, socket, time, errno import os, stat, re, sys, shutil, gzip, socket, time, errno
import Globals, Time, static, log, user_group, C import Globals, Time, static, log, user_group, C, hash
import librsync
try: try:
import win32file, winnt import win32file, winnt
...@@ -408,6 +411,7 @@ class RORPath: ...@@ -408,6 +411,7 @@ class RORPath:
""" """
def __init__(self, index, data = None): def __init__(self, index, data = None):
self.index = index self.index = index
# signature can be read only once
if data: self.data = data if data: self.data = data
else: self.data = {'type':None} # signify empty file else: self.data = {'type':None} # signify empty file
self.file = None self.file = None
...@@ -708,6 +712,11 @@ class RORPath: ...@@ -708,6 +712,11 @@ class RORPath:
"""Set the type of the attached file""" """Set the type of the attached file"""
self.data['filetype'] = type self.data['filetype'] = type
def get_delta(self, signature_fp, new_fp):
delta = librsync.DeltaFile(signature_fp,
hash.FileWrapper(new_fp))
return delta
def isflaglinked(self): def isflaglinked(self):
"""True if rorp is a signature/diff for a hardlink file """True if rorp is a signature/diff for a hardlink file
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment