Commit 7cfed788 authored by bescoto's avatar bescoto

Removed most destructive stepping operations


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@251 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent cf84368c
...@@ -7,6 +7,11 @@ Fixed bug with the --{include|exclude}-globbing-filelist options ...@@ -7,6 +7,11 @@ Fixed bug with the --{include|exclude}-globbing-filelist options
Added --list-changed-since option to list the files changed since the Added --list-changed-since option to list the files changed since the
given date. given date.
Removed --mirror-only and --change-source-perms options.
Removed all "resume" related functionality, like
--checkpoint-interval.
New in v0.11.0 (2002/10/05) New in v0.11.0 (2002/10/05)
--------------------------- ---------------------------
......
...@@ -55,10 +55,6 @@ change_ownership = None ...@@ -55,10 +55,6 @@ change_ownership = None
# permissions). # permissions).
change_mirror_perms = (process_uid != 0) change_mirror_perms = (process_uid != 0)
# If true, temporarily change permissions of unreadable files in
# the source directory to make sure we can read all files.
change_source_perms = None
# If true, try to reset the atimes of the source partition. # If true, try to reset the atimes of the source partition.
preserve_atime = None preserve_atime = None
...@@ -103,24 +99,9 @@ client_conn = None ...@@ -103,24 +99,9 @@ client_conn = None
# list. # list.
changed_settings = [] changed_settings = []
# rdiff-backup will try to checkpoint its state every
# checkpoint_interval seconds. Then when resuming, at most this
# amount of time is lost.
checkpoint_interval = 20
# The RPath of the rdiff-backup-data directory. # The RPath of the rdiff-backup-data directory.
rbdir = None rbdir = None
# Indicates if a resume or a lack of resume is forced. This
# should be None for the default. 0 means don't resume, and 1
# means resume.
resume = None
# If there has been an aborted backup fewer than this many seconds
# ago, attempt to resume it where it left off instead of starting
# a new one.
resume_window = 7200
# This string is used when recognizing and creating time strings. # This string is used when recognizing and creating time strings.
# If the time_separator is ":", then W3 datetime strings like # If the time_separator is ":", then W3 datetime strings like
# 2001-12-07T04:22:01-07:00 are produced. It can be set to "_" to # 2001-12-07T04:22:01-07:00 are produced. It can be set to "_" to
...@@ -265,7 +246,7 @@ def postset_regexp_local(name, re_string, flags): ...@@ -265,7 +246,7 @@ def postset_regexp_local(name, re_string, flags):
if flags: globals()[name] = re.compile(re_string, flags) if flags: globals()[name] = re.compile(re_string, flags)
else: globals()[name] = re.compile(re_string) else: globals()[name] = re.compile(re_string)
def set_select(dsrpath, tuplelist, quote_mode, *filelists): def set_select(source, rpath, tuplelist, quote_mode, *filelists):
"""Initialize select object using tuplelist """Initialize select object using tuplelist
Note that each list in filelists must each be passed as Note that each list in filelists must each be passed as
...@@ -275,12 +256,10 @@ def set_select(dsrpath, tuplelist, quote_mode, *filelists): ...@@ -275,12 +256,10 @@ def set_select(dsrpath, tuplelist, quote_mode, *filelists):
""" """
global select_source, select_mirror global select_source, select_mirror
if dsrpath.source: sel = Select(rpath, quote_mode)
select_source = Select(dsrpath, quote_mode) sel.ParseArgs(tuplelist, filelists)
select_source.ParseArgs(tuplelist, filelists) if source: select_source = sel
else: else: select_mirror = sel
select_mirror = Select(dsrpath, quote_mode)
select_mirror.ParseArgs(tuplelist, filelists)
from rpath import * # kludge to avoid circularity - not needed in this module from rpath import * # kludge to avoid circularity - not needed in this module
......
...@@ -25,7 +25,6 @@ from log import * ...@@ -25,7 +25,6 @@ from log import *
from lazy import * from lazy import *
from connection import * from connection import *
from rpath import * from rpath import *
from destructive_stepping import *
from robust import * from robust import *
from restore import * from restore import *
from highlevel import * from highlevel import *
...@@ -49,21 +48,20 @@ def parse_cmdlineoptions(arglist): ...@@ -49,21 +48,20 @@ def parse_cmdlineoptions(arglist):
except IOError: Log.FatalError("Error opening file %s" % filename) except IOError: Log.FatalError("Error opening file %s" % filename)
try: optlist, args = getopt.getopt(arglist, "blr:sv:V", try: optlist, args = getopt.getopt(arglist, "blr:sv:V",
["backup-mode", "calculate-average", "change-source-perms", ["backup-mode", "calculate-average", "chars-to-quote=",
"chars-to-quote=", "checkpoint-interval=", "current-time=", "current-time=", "exclude=", "exclude-device-files",
"exclude=", "exclude-device-files", "exclude-filelist=", "exclude-filelist=", "exclude-filelist-stdin",
"exclude-filelist-stdin", "exclude-globbing-filelist=", "exclude-globbing-filelist=", "exclude-mirror=",
"exclude-mirror=", "exclude-other-filesystems", "exclude-other-filesystems", "exclude-regexp=",
"exclude-regexp=", "exclude-special-files", "force", "exclude-special-files", "force", "include=",
"include=", "include-filelist=", "include-filelist-stdin", "include-filelist=", "include-filelist-stdin",
"include-globbing-filelist=", "include-regexp=", "include-globbing-filelist=", "include-regexp=",
"list-changed-since=", "list-increments", "no-compression", "list-changed-since=", "list-increments", "no-compression",
"no-compression-regexp=", "no-hard-links", "no-resume", "no-compression-regexp=", "no-hard-links", "null-separator",
"null-separator", "parsable-output", "print-statistics", "parsable-output", "print-statistics", "quoting-char=",
"quoting-char=", "remote-cmd=", "remote-schema=", "remote-cmd=", "remote-schema=", "remove-older-than=",
"remove-older-than=", "restore-as-of=", "restrict=", "restore-as-of=", "restrict=", "restrict-read-only=",
"restrict-read-only=", "restrict-update-only=", "resume", "restrict-update-only=", "server", "sleep-ratio=",
"resume-window=", "server", "sleep-ratio=",
"ssh-no-compression", "terminal-verbosity=", "test-server", "ssh-no-compression", "terminal-verbosity=", "test-server",
"verbosity=", "version", "windows-mode", "verbosity=", "version", "windows-mode",
"windows-time-format"]) "windows-time-format"])
...@@ -73,13 +71,9 @@ def parse_cmdlineoptions(arglist): ...@@ -73,13 +71,9 @@ def parse_cmdlineoptions(arglist):
for opt, arg in optlist: for opt, arg in optlist:
if opt == "-b" or opt == "--backup-mode": action = "backup" if opt == "-b" or opt == "--backup-mode": action = "backup"
elif opt == "--calculate-average": action = "calculate-average" elif opt == "--calculate-average": action = "calculate-average"
elif opt == "--change-source-perms":
Globals.set('change_source_perms', 1)
elif opt == "--chars-to-quote": elif opt == "--chars-to-quote":
Globals.set('chars_to_quote', arg) Globals.set('chars_to_quote', arg)
Globals.set('quoting_enabled', 1) Globals.set('quoting_enabled', 1)
elif opt == "--checkpoint-interval":
Globals.set_integer('checkpoint_interval', arg)
elif opt == "--current-time": elif opt == "--current-time":
Globals.set_integer('current_time', arg) Globals.set_integer('current_time', arg)
elif opt == "--exclude": select_opts.append((opt, arg)) elif opt == "--exclude": select_opts.append((opt, arg))
...@@ -118,7 +112,6 @@ def parse_cmdlineoptions(arglist): ...@@ -118,7 +112,6 @@ def parse_cmdlineoptions(arglist):
elif opt == "--no-compression-regexp": elif opt == "--no-compression-regexp":
Globals.set("no_compression_regexp_string", arg) Globals.set("no_compression_regexp_string", arg)
elif opt == "--no-hard-links": Globals.set('preserve_hardlinks', 0) elif opt == "--no-hard-links": Globals.set('preserve_hardlinks', 0)
elif opt == '--no-resume': Globals.resume = 0
elif opt == "--null-separator": Globals.set("null_separator", 1) elif opt == "--null-separator": Globals.set("null_separator", 1)
elif opt == "--parsable-output": Globals.set('parsable_output', 1) elif opt == "--parsable-output": Globals.set('parsable_output', 1)
elif opt == "--print-statistics": elif opt == "--print-statistics":
...@@ -140,9 +133,6 @@ def parse_cmdlineoptions(arglist): ...@@ -140,9 +133,6 @@ def parse_cmdlineoptions(arglist):
elif opt == "--restrict-update-only": elif opt == "--restrict-update-only":
Globals.security_level = "update-only" Globals.security_level = "update-only"
Globals.restrict_path = arg Globals.restrict_path = arg
elif opt == '--resume': Globals.resume = 1
elif opt == '--resume-window':
Globals.set_integer('resume_window', arg)
elif opt == "-s" or opt == "--server": elif opt == "-s" or opt == "--server":
action = "server" action = "server"
Globals.server = 1 Globals.server = 1
...@@ -263,9 +253,8 @@ def Backup(rpin, rpout): ...@@ -263,9 +253,8 @@ def Backup(rpin, rpout):
def backup_init_select(rpin, rpout): def backup_init_select(rpin, rpout):
"""Create Select objects on source and dest connections""" """Create Select objects on source and dest connections"""
rpin.conn.Globals.set_select(DSRPath(1, rpin), select_opts, rpin.conn.Globals.set_select(1, rpin, select_opts, None, *select_files)
None, *select_files) rpout.conn.Globals.set_select(0, rpout, select_mirror_opts, 1)
rpout.conn.Globals.set_select(DSRPath(None, rpout), select_mirror_opts, 1)
def backup_init_dirs(rpin, rpout): def backup_init_dirs(rpin, rpout):
"""Make sure rpin and rpout are valid, init data dir and logging""" """Make sure rpin and rpout are valid, init data dir and logging"""
...@@ -424,8 +413,8 @@ def restore_init_select(rpin, rpout): ...@@ -424,8 +413,8 @@ def restore_init_select(rpin, rpout):
the restore operation isn't. the restore operation isn't.
""" """
Globals.set_select(DSRPath(1, rpin), select_mirror_opts, None) Globals.set_select(1, rpin, select_mirror_opts, None)
Globals.set_select(DSRPath(None, rpout), select_opts, None, *select_files) Globals.set_select(0, rpout, select_opts, None, *select_files)
def restore_get_root(rpin): def restore_get_root(rpin):
"""Return (mirror root, index) and set the data dir """Return (mirror root, index) and set the data dir
......
...@@ -197,11 +197,6 @@ def BackupInitConnections(reading_conn, writing_conn): ...@@ -197,11 +197,6 @@ def BackupInitConnections(reading_conn, writing_conn):
writing_conn.Globals.set("isbackup_writer", 1) writing_conn.Globals.set("isbackup_writer", 1)
UpdateGlobal("backup_reader", reading_conn) UpdateGlobal("backup_reader", reading_conn)
UpdateGlobal("backup_writer", writing_conn) UpdateGlobal("backup_writer", writing_conn)
if (Globals.change_source_perms and
reading_conn.Globals.get("process_uid") == 0):
Log("Warning: --change_source_perms should usually not be used when\n"
"the reading connection is running as root, because root can\n"
"read all files regardless of their permissions.", 2)
def CloseConnections(): def CloseConnections():
"""Close all connections. Run by client""" """Close all connections. Run by client"""
......
...@@ -547,7 +547,6 @@ from connection import * ...@@ -547,7 +547,6 @@ from connection import *
from rpath import * from rpath import *
from robust import * from robust import *
from rorpiter import * from rorpiter import *
from destructive_stepping import *
from selection import * from selection import *
from statistics import * from statistics import *
from increment import * from increment import *
......
...@@ -87,27 +87,23 @@ class HLSourceStruct: ...@@ -87,27 +87,23 @@ class HLSourceStruct:
"""Return diffs and finalize any dsrp changes remaining """Return diffs and finalize any dsrp changes remaining
Return a rorpiterator with files included of signatures of Return a rorpiterator with files included of signatures of
dissimilar files. This is the last operation run on the local dissimilar files.
filestream, so finalize dsrp writes.
""" """
collated = RORPIter.CollateIterators(cls.initial_dsiter2, sigiter) collated = RORPIter.CollateIterators(cls.initial_dsiter2, sigiter)
finalizer = IterTreeReducer(DestructiveSteppingFinalizer, []) def error_handler(exc, dest_sig, rp):
def error_handler(exc, dest_sig, dsrp):
Log("Error %s producing a diff of %s" % Log("Error %s producing a diff of %s" %
(exc, dsrp and dsrp.path), 2) (exc, rp and rp.path), 2)
return None return None
def diffs(): def diffs():
for dsrp, dest_sig in collated: for rp, dest_sig in collated:
if dest_sig: if dest_sig:
if dest_sig.isplaceholder(): yield dest_sig if dest_sig.isplaceholder(): yield dest_sig
else: else:
diff = Robust.check_common_error( diff = Robust.check_common_error(
error_handler, RORPIter.diffonce, [dest_sig, dsrp]) error_handler, RORPIter.diffonce, [dest_sig, rp])
if diff: yield diff if diff: yield diff
if dsrp: finalizer(dsrp.index, dsrp)
finalizer.Finish()
return diffs() return diffs()
MakeClass(HLSourceStruct) MakeClass(HLSourceStruct)
...@@ -117,7 +113,7 @@ class HLDestinationStruct: ...@@ -117,7 +113,7 @@ class HLDestinationStruct:
"""Hold info used by HL on the destination side""" """Hold info used by HL on the destination side"""
_session_info = None # set to si if resuming _session_info = None # set to si if resuming
def split_initial_dsiter(cls): def split_initial_dsiter(cls):
"""Set initial_dsiters (iteration of all dsrps from rpath)""" """Set initial_dsiters (iteration of all rps from rpath)"""
result, cls.initial_dsiter2 = \ result, cls.initial_dsiter2 = \
Iter.multiplex(Globals.select_mirror.set_iter(), 2) Iter.multiplex(Globals.select_mirror.set_iter(), 2)
return result return result
...@@ -192,10 +188,10 @@ class HLDestinationStruct: ...@@ -192,10 +188,10 @@ class HLDestinationStruct:
return RORPIter.Signatures(dissimilars) return RORPIter.Signatures(dissimilars)
def get_dsrp(cls, dest_rpath, index): def get_dsrp(cls, dest_rpath, index):
"""Return initialized dsrp based on dest_rpath with given index""" """Return initialized rpath based on dest_rpath with given index"""
dsrp = DSRPath(None, dest_rpath.conn, dest_rpath.base, index) rp = RPath(dest_rpath.conn, dest_rpath.base, index)
if Globals.quoting_enabled: dsrp.quote_path() if Globals.quoting_enabled: rp.quote_path()
return dsrp return rp
def get_finalizer(cls): def get_finalizer(cls):
"""Return finalizer, starting from session info if necessary""" """Return finalizer, starting from session info if necessary"""
...@@ -226,8 +222,8 @@ class HLDestinationStruct: ...@@ -226,8 +222,8 @@ class HLDestinationStruct:
def patch_and_finalize(cls, dest_rpath, diffs): def patch_and_finalize(cls, dest_rpath, diffs):
"""Apply diffs and finalize""" """Apply diffs and finalize"""
collated = RORPIter.CollateIterators(diffs, cls.initial_dsiter2) collated = RORPIter.CollateIterators(diffs, cls.initial_dsiter2)
finalizer = cls.get_finalizer() #finalizer = cls.get_finalizer()
diff_rorp, dsrp = None, None diff_rorp, rp = None, None
def patch(diff_rorp, dsrp): def patch(diff_rorp, dsrp):
if not dsrp: dsrp = cls.get_dsrp(dest_rpath, diff_rorp.index) if not dsrp: dsrp = cls.get_dsrp(dest_rpath, diff_rorp.index)
...@@ -244,13 +240,14 @@ class HLDestinationStruct: ...@@ -244,13 +240,14 @@ class HLDestinationStruct:
diff_rorp, dsrp = indexed_tuple diff_rorp, dsrp = indexed_tuple
dsrp = Robust.check_common_error(error_handler, patch, dsrp = Robust.check_common_error(error_handler, patch,
[diff_rorp, dsrp]) [diff_rorp, dsrp])
finalizer(dsrp.index, dsrp) #finalizer(dsrp.index, dsrp)
finalizer.Finish() #finalizer.Finish()
def patch_w_datadir_writes(cls, dest_rpath, diffs, inc_rpath): def patch_w_datadir_writes(cls, dest_rpath, diffs, inc_rpath):
"""Apply diffs and finalize, with checkpointing and statistics""" """Apply diffs and finalize, with checkpointing and statistics"""
collated = RORPIter.CollateIterators(diffs, cls.initial_dsiter2) collated = RORPIter.CollateIterators(diffs, cls.initial_dsiter2)
finalizer, ITR = cls.get_finalizer(), cls.get_MirrorITR(inc_rpath) #finalizer, ITR = cls.get_finalizer(), cls.get_MirrorITR(inc_rpath)
finalizer, ITR = None, cls.get_MirrorITR(inc_rpath)
MiscStats.open_dir_stats_file() MiscStats.open_dir_stats_file()
dsrp, finished_dsrp = None, None dsrp, finished_dsrp = None, None
...@@ -261,10 +258,10 @@ class HLDestinationStruct: ...@@ -261,10 +258,10 @@ class HLDestinationStruct:
if not dsrp: dsrp = cls.get_dsrp(dest_rpath, diff_rorp.index) if not dsrp: dsrp = cls.get_dsrp(dest_rpath, diff_rorp.index)
if diff_rorp and diff_rorp.isplaceholder(): diff_rorp = None if diff_rorp and diff_rorp.isplaceholder(): diff_rorp = None
ITR(dsrp.index, diff_rorp, dsrp) ITR(dsrp.index, diff_rorp, dsrp)
finalizer(dsrp.index, dsrp) #finalizer(dsrp.index, dsrp)
finished_dsrp = dsrp finished_dsrp = dsrp
ITR.Finish() ITR.Finish()
finalizer.Finish() #finalizer.Finish()
except: cls.handle_last_error(finished_dsrp, finalizer, ITR) except: cls.handle_last_error(finished_dsrp, finalizer, ITR)
if Globals.preserve_hardlinks: Hardlink.final_writedata() if Globals.preserve_hardlinks: Hardlink.final_writedata()
...@@ -274,7 +271,8 @@ class HLDestinationStruct: ...@@ -274,7 +271,8 @@ class HLDestinationStruct:
def patch_increment_and_finalize(cls, dest_rpath, diffs, inc_rpath): def patch_increment_and_finalize(cls, dest_rpath, diffs, inc_rpath):
"""Apply diffs, write increment if necessary, and finalize""" """Apply diffs, write increment if necessary, and finalize"""
collated = RORPIter.CollateIterators(diffs, cls.initial_dsiter2) collated = RORPIter.CollateIterators(diffs, cls.initial_dsiter2)
finalizer, ITR = cls.get_finalizer(), cls.get_ITR(inc_rpath) #finalizer, ITR = cls.get_finalizer(), cls.get_ITR(inc_rpath)
finalizer, ITR = None, cls.get_ITR(inc_rpath)
MiscStats.open_dir_stats_file() MiscStats.open_dir_stats_file()
dsrp, finished_dsrp = None, None dsrp, finished_dsrp = None, None
...@@ -286,10 +284,10 @@ class HLDestinationStruct: ...@@ -286,10 +284,10 @@ class HLDestinationStruct:
if not dsrp: dsrp = cls.get_dsrp(dest_rpath, index) if not dsrp: dsrp = cls.get_dsrp(dest_rpath, index)
if diff_rorp and diff_rorp.isplaceholder(): diff_rorp = None if diff_rorp and diff_rorp.isplaceholder(): diff_rorp = None
ITR(index, diff_rorp, dsrp) ITR(index, diff_rorp, dsrp)
finalizer(index, dsrp) #finalizer(index, dsrp)
finished_dsrp = dsrp finished_dsrp = dsrp
ITR.Finish() ITR.Finish()
finalizer.Finish() #finalizer.Finish()
except: cls.handle_last_error(finished_dsrp, finalizer, ITR) except: cls.handle_last_error(finished_dsrp, finalizer, ITR)
if Globals.preserve_hardlinks: Hardlink.final_writedata() if Globals.preserve_hardlinks: Hardlink.final_writedata()
...@@ -311,6 +309,5 @@ from log import * ...@@ -311,6 +309,5 @@ from log import *
from rpath import * from rpath import *
from robust import * from robust import *
from increment import * from increment import *
from destructive_stepping import *
from rorpiter import * from rorpiter import *
import Globals, Hardlink, MiscStats, metadata import Globals, Hardlink, MiscStats, metadata
...@@ -145,8 +145,6 @@ class IncrementITRB(StatsITRB): ...@@ -145,8 +145,6 @@ class IncrementITRB(StatsITRB):
4. Directory -> Normal file: Wait until the end, so we can 4. Directory -> Normal file: Wait until the end, so we can
process all the files in the directory. process all the files in the directory.
Remember this object needs to be pickable.
""" """
# Iff true, mirror file was a directory # Iff true, mirror file was a directory
mirror_isdirectory = None mirror_isdirectory = None
...@@ -299,7 +297,14 @@ class MirrorITRB(StatsITRB): ...@@ -299,7 +297,14 @@ class MirrorITRB(StatsITRB):
def start_process(self, index, diff_rorp, mirror_dsrp): def start_process(self, index, diff_rorp, mirror_dsrp):
"""Initialize statistics and do actual writing to mirror""" """Initialize statistics and do actual writing to mirror"""
self.start_stats(mirror_dsrp) self.start_stats(mirror_dsrp)
if diff_rorp and not diff_rorp.isplaceholder(): if (diff_rorp and diff_rorp.isdir() or
not diff_rorp and mirror_dsrp.isdir()):
# mirror_dsrp will end up as directory, update attribs later
if not diff_rorp: diff_rorp = mirror_dsrp.get_rorpath()
if not mirror_dsrp.isdir():
mirror_dsrp.delete()
mirror_dsrp.mkdir()
elif diff_rorp and not diff_rorp.isplaceholder():
RORPIter.patchonce_action(None, mirror_dsrp, diff_rorp).execute() RORPIter.patchonce_action(None, mirror_dsrp, diff_rorp).execute()
self.incpref = self.inc_rpath.new_index(index) self.incpref = self.inc_rpath.new_index(index)
...@@ -309,6 +314,7 @@ class MirrorITRB(StatsITRB): ...@@ -309,6 +314,7 @@ class MirrorITRB(StatsITRB):
"""Update statistics when leaving""" """Update statistics when leaving"""
self.end_stats(self.diff_rorp, self.mirror_dsrp) self.end_stats(self.diff_rorp, self.mirror_dsrp)
if self.mirror_dsrp.isdir(): if self.mirror_dsrp.isdir():
RPathStatic.copy_attribs(self.diff_rorp, self.mirror_dsrp)
MiscStats.write_dir_stats_line(self, self.mirror_dsrp.index) MiscStats.write_dir_stats_line(self, self.mirror_dsrp.index)
def can_fast_process(self, index, diff_rorp, mirror_dsrp): def can_fast_process(self, index, diff_rorp, mirror_dsrp):
......
...@@ -41,7 +41,6 @@ class Restore: ...@@ -41,7 +41,6 @@ class Restore:
same index as mirror. same index as mirror.
""" """
if not isinstance(mirror, DSRPath): mirror = DSRPath(1, mirror)
if not isinstance(target, DSRPath): target = DSRPath(None, target) if not isinstance(target, DSRPath): target = DSRPath(None, target)
mirror_time = Restore.get_mirror_time() mirror_time = Restore.get_mirror_time()
...@@ -129,18 +128,16 @@ class Restore: ...@@ -129,18 +128,16 @@ class Restore:
"foo/bar". "foo/bar".
""" """
assert isinstance(mirror, DSRPath) and isinstance(target, DSRPath) assert isinstance(target, DSRPath)
assert mirror.index == rid.index assert mirror.index == rid.index
mirror_finalizer = IterTreeReducer(DestructiveSteppingFinalizer, ())
target_finalizer = IterTreeReducer(DestructiveSteppingFinalizer, ()) target_finalizer = IterTreeReducer(DestructiveSteppingFinalizer, ())
for rcd in Restore.yield_rcds(rid.index, mirror, rid, for rcd in Restore.yield_rcds(rid.index, mirror, rid,
target, time, mirror_time): target, time, mirror_time):
rcd.RestoreFile() rcd.RestoreFile()
if rcd.mirror: mirror_finalizer(rcd.index, rcd.mirror) #if rcd.mirror: mirror_finalizer(rcd.index, rcd.mirror)
target_finalizer(rcd.target.index, rcd.target) target_finalizer(rcd.target.index, rcd.target)
target_finalizer.Finish() target_finalizer.Finish()
mirror_finalizer.Finish()
def yield_rcds(index, mirrorrp, rid, target, rest_time, mirror_time): def yield_rcds(index, mirrorrp, rid, target, rest_time, mirror_time):
"""Iterate RestoreCombinedData objects starting with given args """Iterate RestoreCombinedData objects starting with given args
......
...@@ -288,6 +288,8 @@ class RORPath(RPathStatic): ...@@ -288,6 +288,8 @@ class RORPath(RPathStatic):
(not Globals.change_ownership or self.issym())): (not Globals.change_ownership or self.issym())):
# Don't compare gid/uid for symlinks or if not change_ownership # Don't compare gid/uid for symlinks or if not change_ownership
pass pass
elif key == 'mtime':
Log("%s differs only in mtime, skipping" % (self.path,), 2)
elif key == 'atime' and not Globals.preserve_atime: pass elif key == 'atime' and not Globals.preserve_atime: pass
elif key == 'devloc' or key == 'inode' or key == 'nlink': pass elif key == 'devloc' or key == 'inode' or key == 'nlink': pass
elif key == 'size' and not self.isreg(): pass elif key == 'size' and not self.isreg(): pass
...@@ -319,6 +321,10 @@ class RORPath(RPathStatic): ...@@ -319,6 +321,10 @@ class RORPath(RPathStatic):
"""Reproduce RORPath from __getstate__ output""" """Reproduce RORPath from __getstate__ output"""
self.index, self.data = rorp_state self.index, self.data = rorp_state
def get_rorpath(self):
"""Return new rorpath based on self"""
return RORPath(self.index, self.data.copy())
def make_placeholder(self): def make_placeholder(self):
"""Make rorp into a placeholder """Make rorp into a placeholder
...@@ -697,19 +703,15 @@ class RPath(RORPath): ...@@ -697,19 +703,15 @@ class RPath(RORPath):
return self.conn.Globals.get('process_gid') == self.data['gid'] return self.conn.Globals.get('process_gid') == self.data['gid']
def delete(self): def delete(self):
"""Delete file at self.path """Delete file at self.path. Recursively deletes directories."""
The destructive stepping allows this function to delete
directories even if they have files and we lack permissions.
"""
Log("Deleting %s" % self.path, 7) Log("Deleting %s" % self.path, 7)
self.setdata() self.setdata()
if not self.lstat(): return # must have been deleted in meantime if not self.lstat():
Log("Warning: %s does not exist---deleted in meantime?"
% (self.path,), 2)
elif self.isdir(): elif self.isdir():
itm = IterTreeReducer(RpathDeleter, []) itm = IterTreeReducer(RpathDeleter, [])
for dsrp in Select(DSRPath(None, self)).set_iter(): for rp in Select(self).set_iter(): itm(rp.index, rp)
itm(dsrp.index, dsrp)
itm.Finish() itm.Finish()
else: self.conn.os.unlink(self.path) else: self.conn.os.unlink(self.path)
self.setdata() self.setdata()
...@@ -891,18 +893,17 @@ class RPathFileHook: ...@@ -891,18 +893,17 @@ class RPathFileHook:
import FilenameMapping import FilenameMapping
from lazy import * from lazy import *
from selection import * from selection import *
from destructive_stepping import *
from highlevel import * from highlevel import *
class RpathDeleter(ITRBranch): class RpathDeleter(ITRBranch):
"""Delete a directory. Called by RPath.delete()""" """Delete a directory. Called by RPath.delete()"""
def start_process(self, index, dsrp): def start_process(self, index, rp):
self.dsrp = dsrp self.rp = rp
def end_process(self): def end_process(self):
if self.dsrp.isdir(): self.dsrp.rmdir() if self.rp.isdir(): self.rp.rmdir()
else: self.dsrp.delete() else: self.rp.delete()
def can_fast_process(self, index, dsrp): return not dsrp.isdir() def can_fast_process(self, index, rp): return not rp.isdir()
def fast_process(self, index, dsrp): dsrp.delete() def fast_process(self, index, rp): rp.delete()
...@@ -28,7 +28,6 @@ from __future__ import generators ...@@ -28,7 +28,6 @@ from __future__ import generators
import re import re
from log import * from log import *
from robust import * from robust import *
from destructive_stepping import *
import FilenameMapping import FilenameMapping
...@@ -46,7 +45,7 @@ class GlobbingError(SelectError): ...@@ -46,7 +45,7 @@ class GlobbingError(SelectError):
class Select: class Select:
"""Iterate appropriate DSRPaths in given directory """Iterate appropriate RPaths in given directory
This class acts as an iterator on account of its next() method. This class acts as an iterator on account of its next() method.
Basically, it just goes through all the files in a directory in Basically, it just goes through all the files in a directory in
...@@ -66,7 +65,7 @@ class Select: ...@@ -66,7 +65,7 @@ class Select:
file in the directory gets included, so does the directory. file in the directory gets included, so does the directory.
As mentioned above, each test takes the form of a selection As mentioned above, each test takes the form of a selection
function. The selection function takes a dsrp, and returns: function. The selection function takes an rpath, and returns:
None - means the test has nothing to say about the related file None - means the test has nothing to say about the related file
0 - the file is excluded by the test 0 - the file is excluded by the test
...@@ -82,18 +81,18 @@ class Select: ...@@ -82,18 +81,18 @@ class Select:
# This re should not match normal filenames, but usually just globs # This re should not match normal filenames, but usually just globs
glob_re = re.compile("(.*[*?[]|ignorecase\\:)", re.I | re.S) glob_re = re.compile("(.*[*?[]|ignorecase\\:)", re.I | re.S)
def __init__(self, dsrpath, quoted_filenames = None): def __init__(self, rpath, quoted_filenames = None):
"""DSRPIterator initializer. dsrp is the root directory """Select initializer. rpath is the root directory
When files have quoted characters in them, quoted_filenames When files have quoted characters in them, quoted_filenames
should be true. Then RPath's index will be the unquoted should be true. Then RPath's index will be the unquoted
version. version.
""" """
assert isinstance(dsrpath, DSRPath) assert isinstance(rpath, RPath)
self.selection_functions = [] self.selection_functions = []
self.dsrpath = dsrpath self.rpath = rpath
self.prefix = self.dsrpath.path self.prefix = self.rpath.path
self.quoting_on = Globals.quoting_enabled and quoted_filenames self.quoting_on = Globals.quoting_enabled and quoted_filenames
def set_iter(self, starting_index = None, iterate_parents = None, def set_iter(self, starting_index = None, iterate_parents = None,
...@@ -103,19 +102,19 @@ class Select: ...@@ -103,19 +102,19 @@ class Select:
Will iterate indicies greater than starting_index. If Will iterate indicies greater than starting_index. If
iterate_parents is true, will also include parents of iterate_parents is true, will also include parents of
starting_index in iteration. Selection function sel_func is starting_index in iteration. Selection function sel_func is
called on each dsrp and is usually self.Select. Returns self called on each rpath and is usually self.Select. Returns self
just for convenience. just for convenience.
""" """
if not sel_func: sel_func = self.Select if not sel_func: sel_func = self.Select
self.dsrpath.setdata() # this may have changed since Select init self.rpath.setdata() # this may have changed since Select init
if starting_index is not None: if starting_index is not None:
self.starting_index = starting_index self.starting_index = starting_index
self.iter = self.iterate_starting_from(self.dsrpath, self.iter = self.iterate_starting_from(self.rpath,
self.iterate_starting_from, sel_func) self.iterate_starting_from, sel_func)
elif self.quoting_on: elif self.quoting_on:
self.iter = self.Iterate(self.dsrpath, self.Iterate, sel_func) self.iter = self.Iterate(self.rpath, self.Iterate, sel_func)
else: self.iter = self.Iterate_fast(self.dsrpath, sel_func) else: self.iter = self.Iterate_fast(self.rpath, sel_func)
# only iterate parents if we are not starting from beginning # only iterate parents if we are not starting from beginning
self.iterate_parents = starting_index is not None and iterate_parents self.iterate_parents = starting_index is not None and iterate_parents
...@@ -123,7 +122,7 @@ class Select: ...@@ -123,7 +122,7 @@ class Select:
self.__iter__ = lambda: self self.__iter__ = lambda: self
return self return self
def Iterate_fast(self, dsrpath, sel_func): def Iterate_fast(self, rpath, sel_func):
"""Like Iterate, but don't recur, saving time """Like Iterate, but don't recur, saving time
Only handles standard case (quoting off, starting from Only handles standard case (quoting off, starting from
...@@ -131,116 +130,115 @@ class Select: ...@@ -131,116 +130,115 @@ class Select:
""" """
def error_handler(exc, filename): def error_handler(exc, filename):
Log("Error initializing file %s/%s" % (dsrpath.path, filename), 2) Log("Error initializing file %s/%s" % (rpath.path, filename), 2)
return None return None
def diryield(dsrpath): def diryield(rpath):
"""Generate relevant files in directory dsrpath """Generate relevant files in directory rpath
Returns (dsrp, num) where num == 0 means dsrp should be Returns (rpath, num) where num == 0 means rpath should be
generated normally, num == 1 means the dsrp is a directory generated normally, num == 1 means the rpath is a directory
and should be included iff something inside is included. and should be included iff something inside is included.
""" """
for filename in Robust.listrp(dsrpath): for filename in Robust.listrp(rpath):
new_dsrp = Robust.check_common_error(error_handler, new_rpath = Robust.check_common_error(error_handler,
dsrpath.append, (filename,)) rpath.append, (filename,))
if new_dsrp: if new_rpath:
s = sel_func(new_dsrp) s = sel_func(new_rpath)
if s == 1: yield (new_dsrp, 0) if s == 1: yield (new_rpath, 0)
elif s == 2 and new_dsrp.isdir(): yield (new_dsrp, 1) elif s == 2 and new_rpath.isdir(): yield (new_rpath, 1)
yield dsrpath yield rpath
diryield_stack = [diryield(dsrpath)] diryield_stack = [diryield(rpath)]
delayed_dsrp_stack = [] delayed_rp_stack = []
while diryield_stack: while diryield_stack:
try: dsrp, val = diryield_stack[-1].next() try: rpath, val = diryield_stack[-1].next()
except StopIteration: except StopIteration:
diryield_stack.pop() diryield_stack.pop()
if delayed_dsrp_stack: delayed_dsrp_stack.pop() if delayed_rp_stack: delayed_rp_stack.pop()
continue continue
if val == 0: if val == 0:
if delayed_dsrp_stack: if delayed_rp_stack:
for delayed_dsrp in delayed_dsrp_stack: yield delayed_dsrp for delayed_rp in delayed_rp_stack: yield delayed_rp
del delayed_dsrp_stack[:] del delayed_rp_stack[:]
yield dsrp yield rpath
if dsrp.isdir(): diryield_stack.append(diryield(dsrp)) if rpath.isdir(): diryield_stack.append(diryield(rpath))
elif val == 1: elif val == 1:
delayed_dsrp_stack.append(dsrp) delayed_rp_stack.append(rpath)
diryield_stack.append(diryield(dsrp)) diryield_stack.append(diryield(rpath))
def Iterate(self, dsrpath, rec_func, sel_func): def Iterate(self, rpath, rec_func, sel_func):
"""Return iterator yielding dsrps in dsrpath """Return iterator yielding rpaths in rpath
rec_func is usually the same as this function and is what rec_func is usually the same as this function and is what
Iterate uses to find files in subdirectories. It is used in Iterate uses to find files in subdirectories. It is used in
iterate_starting_from. iterate_starting_from.
sel_func is the selection function to use on the dsrps. It is sel_func is the selection function to use on the rpaths. It
usually self.Select. is usually self.Select.
""" """
s = sel_func(dsrpath) s = sel_func(rpath)
if s == 0: return if s == 0: return
elif s == 1: # File is included elif s == 1: # File is included
yield dsrpath yield rpath
if dsrpath.isdir(): if rpath.isdir():
for dsrp in self.iterate_in_dir(dsrpath, rec_func, sel_func): for rp in self.iterate_in_dir(rpath, rec_func, sel_func):
yield dsrp yield rp
elif s == 2: elif s == 2:
if dsrpath.isdir(): # Directory is merely scanned if rpath.isdir(): # Directory is merely scanned
iid = self.iterate_in_dir(dsrpath, rec_func, sel_func) iid = self.iterate_in_dir(rpath, rec_func, sel_func)
try: first = iid.next() try: first = iid.next()
except StopIteration: return # no files inside; skip dsrp except StopIteration: return # no files inside; skip rp
yield dsrpath yield rpath
yield first yield first
for dsrp in iid: yield dsrp for rp in iid: yield rp
else: assert 0, "Invalid selection result %s" % (str(s),) else: assert 0, "Invalid selection result %s" % (str(s),)
def iterate_in_dir(self, dsrpath, rec_func, sel_func): def iterate_in_dir(self, rpath, rec_func, sel_func):
"""Iterate the dsrps in directory dsrpath.""" """Iterate the rpaths in directory rpath."""
def error_handler(exc, filename): def error_handler(exc, filename):
Log("Error initializing file %s/%s" % (dsrpath.path, filename), 2) Log("Error initializing file %s/%s" % (rpath.path, filename), 2)
return None return None
if self.quoting_on: if self.quoting_on:
for subdir in FilenameMapping.get_quoted_dir_children(dsrpath): for subdir in FilenameMapping.get_quoted_dir_children(rpath):
for dsrp in rec_func(subdir, rec_func, sel_func): for rp in rec_func(subdir, rec_func, sel_func):
yield dsrp yield rp
else: else:
for filename in Robust.listrp(dsrpath): for filename in Robust.listrp(rpath):
new_dsrp = Robust.check_common_error( new_rp = Robust.check_common_error(
error_handler, dsrpath.append, [filename]) error_handler, rpath.append, [filename])
if new_dsrp: if new_rp:
for dsrp in rec_func(new_dsrp, rec_func, sel_func): for rp in rec_func(new_rp, rec_func, sel_func):
yield dsrp yield rp
def iterate_starting_from(self, dsrpath, rec_func, sel_func): def iterate_starting_from(self, rpath, rec_func, sel_func):
"""Like Iterate, but only yield indicies > self.starting_index""" """Like Iterate, but only yield indicies > self.starting_index"""
if dsrpath.index > self.starting_index: # past starting_index if rpath.index > self.starting_index: # past starting_index
for dsrp in self.Iterate(dsrpath, self.Iterate, sel_func): for rp in self.Iterate(rpath, self.Iterate, sel_func):
yield dsrp yield rp
elif (dsrpath.index == self.starting_index[:len(dsrpath.index)] elif (rpath.index == self.starting_index[:len(rpath.index)]
and dsrpath.isdir()): and rpath.isdir()):
# May encounter starting index on this branch # May encounter starting index on this branch
if self.iterate_parents: yield dsrpath if self.iterate_parents: yield rpath
for dsrp in self.iterate_in_dir(dsrpath, for rp in self.iterate_in_dir(rpath, self.iterate_starting_from,
self.iterate_starting_from, sel_func): yield rp
sel_func): yield dsrp
# def iterate_with_finalizer(self):
def iterate_with_finalizer(self): # """Like Iterate, but missing some options, and add finalizer"""
"""Like Iterate, but missing some options, and add finalizer""" # finalize = IterTreeReducer(DestructiveSteppingFinalizer, ())
finalize = IterTreeReducer(DestructiveSteppingFinalizer, ()) # for rp in self:
for dsrp in self: # yield rp
yield dsrp # finalize(rp.index, rp))
finalize(dsrp.index, dsrp) # finalize.Finish()
finalize.Finish()
def Select(self, rp):
def Select(self, dsrp):
"""Run through the selection functions and return dominant val 0/1/2""" """Run through the selection functions and return dominant val 0/1/2"""
for sf in self.selection_functions: for sf in self.selection_functions:
result = sf(dsrp) result = sf(rp)
if result is not None: return result if result is not None: return result
return 1 return 1
...@@ -353,11 +351,11 @@ probably isn't what you meant.""" % ...@@ -353,11 +351,11 @@ probably isn't what you meant.""" %
tuple_list.sort() tuple_list.sort()
i = [0] # We have to put index in list because of stupid scoping rules i = [0] # We have to put index in list because of stupid scoping rules
def selection_function(dsrp): def selection_function(rp):
while 1: while 1:
if i[0] >= len(tuple_list): return None if i[0] >= len(tuple_list): return None
include, move_on = \ include, move_on = \
self.filelist_pair_match(dsrp, tuple_list[i[0]]) self.filelist_pair_match(rp, tuple_list[i[0]])
if move_on: if move_on:
i[0] += 1 i[0] += 1
if include is None: continue # later line may match if include is None: continue # later line may match
...@@ -415,12 +413,12 @@ probably isn't what you meant.""" % ...@@ -415,12 +413,12 @@ probably isn't what you meant.""" %
index = tuple(filter(lambda x: x, line.split("/"))) # remove empties index = tuple(filter(lambda x: x, line.split("/"))) # remove empties
return (index, include) return (index, include)
def filelist_pair_match(self, dsrp, pair): def filelist_pair_match(self, rp, pair):
"""Matches a filelist tuple against a dsrp """Matches a filelist tuple against a rpath
Returns a pair (include, move_on). include is None if the Returns a pair (include, move_on). include is None if the
tuple doesn't match either way, and 0/1 if the tuple excludes tuple doesn't match either way, and 0/1 if the tuple excludes
or includes the dsrp. or includes the rpath.
move_on is true if the tuple cannot match a later index, and move_on is true if the tuple cannot match a later index, and
so we should move on to the next tuple in the index. so we should move on to the next tuple in the index.
...@@ -428,16 +426,16 @@ probably isn't what you meant.""" % ...@@ -428,16 +426,16 @@ probably isn't what you meant.""" %
""" """
index, include = pair index, include = pair
if include == 1: if include == 1:
if index < dsrp.index: return (None, 1) if index < rp.index: return (None, 1)
if index == dsrp.index: return (1, 1) if index == rp.index: return (1, 1)
elif index[:len(dsrp.index)] == dsrp.index: elif index[:len(rp.index)] == rp.index:
return (1, None) # /foo/bar implicitly includes /foo return (1, None) # /foo/bar implicitly includes /foo
else: return (None, None) # dsrp greater, not initial sequence else: return (None, None) # rp greater, not initial sequence
elif include == 0: elif include == 0:
if dsrp.index[:len(index)] == index: if rp.index[:len(index)] == index:
return (0, None) # /foo implicitly excludes /foo/bar return (0, None) # /foo implicitly excludes /foo/bar
elif index < dsrp.index: return (None, 1) elif index < rp.index: return (None, 1)
else: return (None, None) # dsrp greater, not initial sequence else: return (None, None) # rp greater, not initial sequence
else: assert 0, "Include is %s, should be 0 or 1" % (include,) else: assert 0, "Include is %s, should be 0 or 1" % (include,)
def filelist_globbing_get_sfs(self, filelist_fp, inc_default, list_name): def filelist_globbing_get_sfs(self, filelist_fp, inc_default, list_name):
...@@ -460,9 +458,9 @@ probably isn't what you meant.""" % ...@@ -460,9 +458,9 @@ probably isn't what you meant.""" %
def other_filesystems_get_sf(self, include): def other_filesystems_get_sf(self, include):
"""Return selection function matching files on other filesystems""" """Return selection function matching files on other filesystems"""
assert include == 0 or include == 1 assert include == 0 or include == 1
root_devloc = self.dsrpath.getdevloc() root_devloc = self.rpath.getdevloc()
def sel_func(dsrp): def sel_func(rp):
if dsrp.getdevloc() == root_devloc: return None if rp.getdevloc() == root_devloc: return None
else: return include else: return include
sel_func.exclude = not include sel_func.exclude = not include
sel_func.name = "Match other filesystems" sel_func.name = "Match other filesystems"
...@@ -476,8 +474,8 @@ probably isn't what you meant.""" % ...@@ -476,8 +474,8 @@ probably isn't what you meant.""" %
Log("Error compiling regular expression %s" % regexp_string, 1) Log("Error compiling regular expression %s" % regexp_string, 1)
raise raise
def sel_func(dsrp): def sel_func(rp):
if regexp.search(dsrp.path): return include if regexp.search(rp.path): return include
else: return None else: return None
sel_func.exclude = not include sel_func.exclude = not include
...@@ -489,8 +487,8 @@ probably isn't what you meant.""" % ...@@ -489,8 +487,8 @@ probably isn't what you meant.""" %
if self.selection_functions: if self.selection_functions:
Log("Warning: exclude-device-files is not the first " Log("Warning: exclude-device-files is not the first "
"selector.\nThis may not be what you intended", 3) "selector.\nThis may not be what you intended", 3)
def sel_func(dsrp): def sel_func(rp):
if dsrp.isdev(): return include if rp.isdev(): return include
else: return None else: return None
sel_func.exclude = not include sel_func.exclude = not include
sel_func.name = (include and "include" or "exclude") + " device files" sel_func.name = (include and "include" or "exclude") + " device files"
...@@ -501,8 +499,8 @@ probably isn't what you meant.""" % ...@@ -501,8 +499,8 @@ probably isn't what you meant.""" %
if self.selection_functions: if self.selection_functions:
Log("Warning: exclude-special-files is not the first " Log("Warning: exclude-special-files is not the first "
"selector.\nThis may not be what you intended", 3) "selector.\nThis may not be what you intended", 3)
def sel_func(dsrp): def sel_func(rp):
if dsrp.issym() or dsrp.issock() or dsrp.isfifo() or dsrp.isdev(): if rp.issym() or rp.issock() or rp.isfifo() or rp.isdev():
return include return include
else: return None else: return None
sel_func.exclude = not include sel_func.exclude = not include
...@@ -512,7 +510,7 @@ probably isn't what you meant.""" % ...@@ -512,7 +510,7 @@ probably isn't what you meant.""" %
def glob_get_sf(self, glob_str, include): def glob_get_sf(self, glob_str, include):
"""Return selection function given by glob string""" """Return selection function given by glob string"""
assert include == 0 or include == 1 assert include == 0 or include == 1
if glob_str == "**": sel_func = lambda dsrp: include if glob_str == "**": sel_func = lambda rp: include
elif not self.glob_re.match(glob_str): # normal file elif not self.glob_re.match(glob_str): # normal file
sel_func = self.glob_get_filename_sf(glob_str, include) sel_func = self.glob_get_filename_sf(glob_str, include)
else: sel_func = self.glob_get_normal_sf(glob_str, include) else: sel_func = self.glob_get_normal_sf(glob_str, include)
...@@ -539,14 +537,14 @@ probably isn't what you meant.""" % ...@@ -539,14 +537,14 @@ probably isn't what you meant.""" %
def glob_get_tuple_sf(self, tuple, include): def glob_get_tuple_sf(self, tuple, include):
"""Return selection function based on tuple""" """Return selection function based on tuple"""
def include_sel_func(dsrp): def include_sel_func(rp):
if (dsrp.index == tuple[:len(dsrp.index)] or if (rp.index == tuple[:len(rp.index)] or
dsrp.index[:len(tuple)] == tuple): rp.index[:len(tuple)] == tuple):
return 1 # /foo/bar implicitly matches /foo, vice-versa return 1 # /foo/bar implicitly matches /foo, vice-versa
else: return None else: return None
def exclude_sel_func(dsrp): def exclude_sel_func(rp):
if dsrp.index[:len(tuple)] == tuple: if rp.index[:len(tuple)] == tuple:
return 0 # /foo excludes /foo/bar, not vice-versa return 0 # /foo excludes /foo/bar, not vice-versa
else: return None else: return None
...@@ -585,17 +583,17 @@ probably isn't what you meant.""" % ...@@ -585,17 +583,17 @@ probably isn't what you meant.""" %
scan_comp_re = re_comp("^(%s)$" % scan_comp_re = re_comp("^(%s)$" %
"|".join(self.glob_get_prefix_res(glob_str))) "|".join(self.glob_get_prefix_res(glob_str)))
def include_sel_func(dsrp): def include_sel_func(rp):
if glob_comp_re.match(dsrp.path): return 1 if glob_comp_re.match(rp.path): return 1
elif scan_comp_re.match(dsrp.path): return 2 elif scan_comp_re.match(rp.path): return 2
else: return None else: return None
def exclude_sel_func(dsrp): def exclude_sel_func(rp):
if glob_comp_re.match(dsrp.path): return 0 if glob_comp_re.match(rp.path): return 0
else: return None else: return None
# Check to make sure prefix is ok # Check to make sure prefix is ok
if not include_sel_func(self.dsrpath): raise FilePrefixError(glob_str) if not include_sel_func(self.rpath): raise FilePrefixError(glob_str)
if include: return include_sel_func if include: return include_sel_func
else: return exclude_sel_func else: return exclude_sel_func
......
...@@ -173,8 +173,7 @@ def CompareRecursive(src_rp, dest_rp, compare_hardlinks = 1, ...@@ -173,8 +173,7 @@ def CompareRecursive(src_rp, dest_rp, compare_hardlinks = 1,
Log("Comparing %s and %s, hardlinks %s" % (src_rp.path, dest_rp.path, Log("Comparing %s and %s, hardlinks %s" % (src_rp.path, dest_rp.path,
compare_hardlinks), 3) compare_hardlinks), 3)
src_select = Select(DSRPath(1, src_rp)) src_select, dest_select = Select(src_rp), Select(dest_rp)
dest_select = Select(DSRPath(None, dest_rp))
if ignore_tmp_files: if ignore_tmp_files:
# Ignoring temp files can be useful when we want to check the # Ignoring temp files can be useful when we want to check the
...@@ -201,13 +200,10 @@ def CompareRecursive(src_rp, dest_rp, compare_hardlinks = 1, ...@@ -201,13 +200,10 @@ def CompareRecursive(src_rp, dest_rp, compare_hardlinks = 1,
dest_select.add_selection_func(dest_select.glob_get_tuple_sf( dest_select.add_selection_func(dest_select.glob_get_tuple_sf(
('rdiff-backup-data',), 0)) ('rdiff-backup-data',), 0))
src_select.set_iter() dsiter1, dsiter2 = src_select.set_iter(), dest_select.set_iter()
dest_select.set_iter()
dsiter1, dsiter2 = src_select.iterate_with_finalizer(), \
dest_select.iterate_with_finalizer()
def hardlink_equal(src_rorp, dest_rorp): def hardlink_equal(src_rorp, dest_rorp):
if src_rorp != dest_rorp: return None if not src_rorp.equal_verbose(dest_rorp): return None
if Hardlink.rorp_eq(src_rorp, dest_rorp): return 1 if Hardlink.rorp_eq(src_rorp, dest_rorp): return 1
Log("%s: %s" % (src_rorp.index, Hardlink.get_indicies(src_rorp, 1)), 3) Log("%s: %s" % (src_rorp.index, Hardlink.get_indicies(src_rorp, 1)), 3)
Log("%s: %s" % (dest_rorp.index, Log("%s: %s" % (dest_rorp.index,
...@@ -229,7 +225,7 @@ def CompareRecursive(src_rp, dest_rp, compare_hardlinks = 1, ...@@ -229,7 +225,7 @@ def CompareRecursive(src_rp, dest_rp, compare_hardlinks = 1,
if dest_rorp.index[-1].endswith('.missing'): return 1 if dest_rorp.index[-1].endswith('.missing'): return 1
if compare_hardlinks: if compare_hardlinks:
if Hardlink.rorp_eq(src_rorp, dest_rorp): return 1 if Hardlink.rorp_eq(src_rorp, dest_rorp): return 1
elif src_rorp == dest_rorp: return 1 elif src_rorp.equal_verbose(dest_rorp): return 1
Log("%s: %s" % (src_rorp.index, Hardlink.get_indicies(src_rorp, 1)), 3) Log("%s: %s" % (src_rorp.index, Hardlink.get_indicies(src_rorp, 1)), 3)
Log("%s: %s" % (dest_rorp.index, Log("%s: %s" % (dest_rorp.index,
Hardlink.get_indicies(dest_rorp, None)), 3) Hardlink.get_indicies(dest_rorp, None)), 3)
......
...@@ -14,7 +14,7 @@ testfiles ...@@ -14,7 +14,7 @@ testfiles
Globals.set('change_source_perms', 1) Globals.set('change_source_perms', 1)
Globals.counter = 0 Globals.counter = 0
Log.setverbosity(3) Log.setverbosity(7)
class Local: class Local:
"""This is just a place to put increments relative to the local """This is just a place to put increments relative to the local
......
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