summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rdiff-backup/CHANGELOG4
-rw-r--r--rdiff-backup/TODO2
-rw-r--r--rdiff-backup/rdiff-backup.114
-rw-r--r--rdiff-backup/rdiff_backup/FilenameMapping.py64
-rw-r--r--rdiff-backup/rdiff_backup/Globals.py9
-rw-r--r--rdiff-backup/rdiff_backup/Main.py38
-rw-r--r--rdiff-backup/rdiff_backup/Time.py14
-rw-r--r--rdiff-backup/rdiff_backup/increment.py11
-rw-r--r--rdiff-backup/rdiff_backup/restore.py36
-rw-r--r--rdiff-backup/rdiff_backup/rpath.py12
-rw-r--r--rdiff-backup/rdiff_backup/selection.py55
-rw-r--r--rdiff-backup/testing/FilenameMappingtest.py31
-rw-r--r--rdiff-backup/testing/commontest.py2
-rw-r--r--rdiff-backup/testing/finaltest.py53
14 files changed, 188 insertions, 157 deletions
diff --git a/rdiff-backup/CHANGELOG b/rdiff-backup/CHANGELOG
index ba822a1..f9a4cd1 100644
--- a/rdiff-backup/CHANGELOG
+++ b/rdiff-backup/CHANGELOG
@@ -1,9 +1,11 @@
-New in v0.11.2 (2003/??/??)
+New in v0.11.2 (2003/02/07)
---------------------------
Fixed seg fault bug reported by a couple sparc/openbsd users. Thanks
to Dave Steinberg for giving me an account on his system for testing.
+Re-enabled --windows-mode and filename quoting.
+
New in v0.11.1 (2002/12/31)
---------------------------
diff --git a/rdiff-backup/TODO b/rdiff-backup/TODO
index f7d2aa8..17c689f 100644
--- a/rdiff-backup/TODO
+++ b/rdiff-backup/TODO
@@ -1,3 +1,5 @@
+Look at Kent Borg's suggestion for restore options and digests.
+
Write some better selection test cases to test new Iterate_fast func.
Work on killtest code - avoid returning a failure when a file is
diff --git a/rdiff-backup/rdiff-backup.1 b/rdiff-backup/rdiff-backup.1
index cb565b7..377351a 100644
--- a/rdiff-backup/rdiff-backup.1
+++ b/rdiff-backup/rdiff-backup.1
@@ -362,18 +362,8 @@ This option is short for "--chars to quote A-Z: --windows-time-format
--no-hard-links --exclude-special-files" and is appropriate when
backing a normal unix file system to one that doesn't allow colons in
filenames, is not case sensitive, and cannot store special files or
-hard links. --windows-mode should not be necessary when backing up
-one windows file system to another, although --windows-time-format
-would still be required. If this switch is used for backing up, it
-must also be used when restoring, listing increments, etc.
-.TP
-.B --windows-time-format
-If this option is present, use underscores instead of colons in
-increment files, so 2001-07-15T04:09:38-07:00 becomes
-2001-07-15T04_09_38-07_00. This option may be useful under various
-Microsoft file systems, which prohibit colons in filenames. If this
-switch is used for backing up, it must also be used when restoring,
-listing increments, etc.
+hard links. If this switch is used for backing up, it must also be
+used when restoring, listing increments, etc.
.SH EXAMPLES
Simplest case---backup directory foo to directory bar, with increments
diff --git a/rdiff-backup/rdiff_backup/FilenameMapping.py b/rdiff-backup/rdiff_backup/FilenameMapping.py
index e305f68..fdcd017 100644
--- a/rdiff-backup/rdiff_backup/FilenameMapping.py
+++ b/rdiff-backup/rdiff_backup/FilenameMapping.py
@@ -20,14 +20,17 @@
"""Coordinate corresponding files with different names
For instance, some source filenames may contain characters not allowed
-on the mirror end. Also, if a source filename is very long (say 240
-characters), the extra characters added to related increments may put
-them over the usual 255 character limit.
+on the mirror end. These files must be called something different on
+the mirror end, so we escape the offending characters with semicolons.
+
+One problem/complication is that all this escaping may put files over
+the 256 or whatever limit on the length of file names. (We just don't
+handle that error.)
"""
import re
-import Globals, log
+import Globals, log, rpath
max_filename_length = 255
@@ -43,6 +46,8 @@ unquoting_regexp = None
quoting_char = None
+class QuotingException(Exception): pass
+
def set_init_quote_vals():
"""Set quoting value from Globals on all conns"""
for conn in Globals.connections:
@@ -90,7 +95,54 @@ def unquote(path):
def unquote_single(match):
"""Unquote a single quoted character"""
- assert len(match.group()) == 4
- return chr(int(match.group()[1:]))
+ if not len(match.group()) == 4:
+ raise QuotingException("Quoted group wrong size: " + match.group())
+ try: return chr(int(match.group()[1:]))
+ except ValueError:
+ raise QuotingException("Quoted out of range: " + match.group())
+
+class QuotedRPath(rpath.RPath):
+ """RPath where the filename is quoted version of index
+ We use QuotedRPaths so we don't need to remember to quote RPaths
+ derived from this one (via append or new_index). Note that only
+ the index is quoted, not the base.
+
+ """
+ def __init__(self, connection, base, index = (), data = None):
+ """Make new QuotedRPath"""
+ quoted_index = tuple(map(quote, index))
+ rpath.RPath.__init__(self, connection, base, quoted_index, data)
+ self.index = index
+
+ def listdir(self):
+ """Return list of unquoted filenames in current directory
+
+ We want them unquoted so that the results can be sorted
+ correctly and append()ed to the currect QuotedRPath.
+
+ """
+ return map(unquote, self.conn.os.listdir(self.path))
+
+ def __str__(self):
+ return "QuotedPath: %s\nIndex: %s\nData: %s" % \
+ (self.path, self.index, self.data)
+
+ def isincfile(self):
+ """Return true if path indicates increment, sets various variables"""
+ result = rpath.RPath.isincfile(self)
+ if result: self.inc_basestr = unquote(self.inc_basestr)
+ return result
+
+def get_quotedrpath(rp, separate_basename = 0):
+ """Return quoted version of rpath rp"""
+ assert not rp.index # Why would we starting quoting "in the middle"?
+ if separate_basename:
+ dirname, basename = rp.dirsplit()
+ return QuotedRPath(rp.conn, dirname, (unquote(basename),), rp.data)
+ else: return QuotedRPath(rp.conn, rp.base, (), rp.data)
+
+def get_quoted_sep_base(filename):
+ """Get QuotedRPath from filename assuming last bit is quoted"""
+ return get_quotedrpath(rpath.RPath(Globals.local_connection, filename), 1)
diff --git a/rdiff-backup/rdiff_backup/Globals.py b/rdiff-backup/rdiff_backup/Globals.py
index bb4195c..a06e246 100644
--- a/rdiff-backup/rdiff_backup/Globals.py
+++ b/rdiff-backup/rdiff_backup/Globals.py
@@ -102,19 +102,12 @@ changed_settings = []
# The RPath of the rdiff-backup-data directory.
rbdir = None
-# This string is used when recognizing and creating time strings.
-# 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
-# make filenames that don't contain colons, which aren't allowed
-# under MS windows NT.
-time_separator = ":"
-
# quoting_enabled is true if we should quote certain characters in
# filenames on the source side (see FilenameMapping for more
# info). chars_to_quote is a string whose characters should be
# quoted, and quoting_char is the character to quote with.
quoting_enabled = None
-chars_to_quote = ""
+chars_to_quote = "A-Z:"
quoting_char = ';'
# If true, emit output intended to be easily readable by a
diff --git a/rdiff-backup/rdiff_backup/Main.py b/rdiff-backup/rdiff_backup/Main.py
index 3921c73..bfcc906 100644
--- a/rdiff-backup/rdiff_backup/Main.py
+++ b/rdiff-backup/rdiff_backup/Main.py
@@ -1,4 +1,3 @@
-
# Copyright 2002 Ben Escoto
#
# This file is part of rdiff-backup.
@@ -142,16 +141,21 @@ def parse_cmdlineoptions(arglist):
sys.exit(0)
elif opt == "-v" or opt == "--verbosity": Log.setverbosity(arg)
elif opt == "--windows-mode":
- Globals.set('time_separator', "_")
Globals.set('chars_to_quote', "A-Z:")
Globals.set('quoting_enabled', 1)
Globals.set('preserve_hardlinks', 0)
- select_opts.append(("--exclude-special-files", None))
- assert 0, "Windows mode doesn't work in this version!"
- elif opt == '--windows-time-format':
- Globals.set('time_separator', "_")
else: Log.FatalError("Unknown option %s" % opt)
+def isincfilename(path):
+ """Return true if path is of a (possibly quoted) increment file"""
+ rp = rpath.RPath(Globals.local_connection, path)
+ if Globals.quoting_enabled:
+ if not FilenameMapping.quoting_char:
+ FilenameMapping.set_init_quote_vals()
+ rp = FilenameMapping.get_quotedrpath(rp, separate_basename = 1)
+ result = rp.isincfile()
+ return result
+
def set_action():
"""Check arguments and try to set action"""
global action
@@ -160,8 +164,7 @@ def set_action():
if l == 0: commandline_error("No arguments given")
elif l == 1: action = "restore"
elif l == 2:
- if rpath.RPath(Globals.local_connection, args[0]).isincfile():
- action = "restore"
+ if isincfilename(args[0]): action = "restore"
else: action = "backup"
else: commandline_error("Too many arguments given")
@@ -230,6 +233,8 @@ def Main(arglist):
def Backup(rpin, rpout):
"""Backup, possibly incrementally, src_path to dest_path."""
+ if Globals.quoting_enabled:
+ rpout = FilenameMapping.get_quotedrpath(rpout)
SetConnections.BackupInitConnections(rpin.conn, rpout.conn)
backup_set_select(rpin)
backup_init_dirs(rpin, rpout)
@@ -259,9 +264,9 @@ def backup_init_dirs(rpin, rpout):
elif not rpin.isdir():
Log.FatalError("Source %s is not a directory" % rpin.path)
- datadir = rpout.append("rdiff-backup-data")
+ datadir = rpout.append_path("rdiff-backup-data")
SetConnections.UpdateGlobal('rbdir', datadir)
- incdir = rpath.RPath(rpout.conn, os.path.join(datadir.path, "increments"))
+ incdir = datadir.append_path("increments")
prevtime = backup_get_mirrortime()
if rpout.lstat():
@@ -351,7 +356,7 @@ def RestoreAsOf(rpin, target):
target - RPath of place to put restored file
"""
- restore_check_paths(rpin, target, 1)
+ rpin, rpout = restore_check_paths(rpin, target, 1)
try: time = Time.genstrtotime(restore_timestr)
except Time.TimeException, exc: Log.FatalError(str(exc))
restore_common(rpin, target, time)
@@ -384,7 +389,9 @@ def restore_check_paths(rpin, rpout, restoreasof = None):
if not restoreasof:
if not rpin.lstat():
Log.FatalError("Source file %s does not exist" % rpin.path)
- elif not rpin.isincfile():
+ if Globals.quoting_enabled:
+ rpin = FilenameMapping.get_quotedrpath(rpin, 1)
+ if not rpin.isincfile():
Log.FatalError("""File %s does not look like an increment file.
Try restoring from an increment file (the filenames look like
@@ -438,7 +445,8 @@ def restore_get_root(rpin):
i = i-1
else: Log.FatalError("Unable to find rdiff-backup-data directory")
- rootrp = parent_dir
+ if not Globals.quoting_enabled: rootrp = parent_dir
+ else: rootrp = FilenameMapping.get_quotedrpath(parent_dir)
Log("Using mirror root directory %s" % rootrp.path, 6)
datadir = rootrp.append_path("rdiff-backup-data")
@@ -476,7 +484,7 @@ def CalculateAverage(rps):
def RemoveOlderThan(rootrp):
"""Remove all increment files older than a certain time"""
- datadir = rootrp.append("rdiff-backup-data")
+ datadir = rootrp.append_path("rdiff-backup-data")
if not datadir.lstat() or not datadir.isdir():
Log.FatalError("Unable to open rdiff-backup-data dir %s" %
(datadir.path,))
@@ -487,7 +495,7 @@ def RemoveOlderThan(rootrp):
Log("Deleting increment(s) before %s" % timep, 4)
times_in_secs = [inc.getinctime() for inc in
- restore.get_inclist(datadir.append("increments"))]
+ restore.get_inclist(datadir.append_path("increments"))]
times_in_secs = filter(lambda t: t < time, times_in_secs)
if not times_in_secs:
Log.FatalError("No increments older than %s found" % timep)
diff --git a/rdiff-backup/rdiff_backup/Time.py b/rdiff-backup/rdiff_backup/Time.py
index ea85ca4..bdcfb52 100644
--- a/rdiff-backup/rdiff_backup/Time.py
+++ b/rdiff-backup/rdiff_backup/Time.py
@@ -61,9 +61,8 @@ def setprevtime_local(timeinseconds, timestr):
def timetostring(timeinseconds):
"""Return w3 datetime compliant listing of timeinseconds"""
- return time.strftime("%Y-%m-%dT%H" + Globals.time_separator +
- "%M" + Globals.time_separator + "%S",
- time.localtime(timeinseconds)) + gettzd()
+ s = time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(timeinseconds))
+ return s + gettzd()
def stringtotime(timestring):
"""Return time in seconds from w3 timestring
@@ -75,8 +74,7 @@ def stringtotime(timestring):
try:
date, daytime = timestring[:19].split("T")
year, month, day = map(int, date.split("-"))
- hour, minute, second = map(int,
- daytime.split(Globals.time_separator))
+ hour, minute, second = map(int, daytime.split(":"))
assert 1900 < year < 2100, year
assert 1 <= month <= 12
assert 1 <= day <= 31
@@ -154,15 +152,13 @@ def gettzd():
hours, minutes = map(abs, divmod(offset, 60))
assert 0 <= hours <= 23
assert 0 <= minutes <= 59
- return "%s%02d%s%02d" % (prefix, hours,
- Globals.time_separator, minutes)
+ return "%s%02d:%02d" % (prefix, hours, minutes)
def tzdtoseconds(tzd):
"""Given w3 compliant TZD, return how far ahead UTC is"""
if tzd == "Z": return 0
assert len(tzd) == 6 # only accept forms like +08:00 for now
- assert (tzd[0] == "-" or tzd[0] == "+") and \
- tzd[3] == Globals.time_separator
+ assert (tzd[0] == "-" or tzd[0] == "+") and tzd[3] == ":"
return -60 * (60 * int(tzd[:3]) + int(tzd[4:]))
def cmp(time1, time2):
diff --git a/rdiff-backup/rdiff_backup/increment.py b/rdiff-backup/rdiff_backup/increment.py
index a9d5413..76578fe 100644
--- a/rdiff-backup/rdiff_backup/increment.py
+++ b/rdiff-backup/rdiff_backup/increment.py
@@ -85,12 +85,19 @@ def makedir(mirrordir, incpref):
return dirsign
def get_inc(rp, time, typestr):
- """Return increment like rp but with time and typestr suffixes"""
+ """Return increment like rp but with time and typestr suffixes
+
+ To avoid any quoting, the returned rpath has empty index, and the
+ whole filename is in the base (which is not quoted).
+
+ """
addtostr = lambda s: "%s.%s.%s" % (s, Time.timetostring(time), typestr)
if rp.index:
incrp = rp.__class__(rp.conn, rp.base, rp.index[:-1] +
(addtostr(rp.index[-1]),))
- else: incrp = rp.__class__(rp.conn, addtostr(rp.base), rp.index)
+ else:
+ dirname, basename = rp.dirsplit()
+ incrp = rp.__class__(rp.conn, dirname, (addtostr(basename),))
return incrp
def get_inc_ext(rp, typestr, inctime = None):
diff --git a/rdiff-backup/rdiff_backup/restore.py b/rdiff-backup/rdiff_backup/restore.py
index ff09eee..3ff4ce8 100644
--- a/rdiff-backup/rdiff_backup/restore.py
+++ b/rdiff-backup/rdiff_backup/restore.py
@@ -21,8 +21,8 @@
from __future__ import generators
import tempfile, os
-import Globals, Time, Rdiff, Hardlink, FilenameMapping, rorpiter, \
- selection, rpath, log, backup, static, robust, metadata
+import Globals, Time, Rdiff, Hardlink, rorpiter, selection, rpath, \
+ log, backup, static, robust, metadata
# This should be set to selection.Select objects over the source and
@@ -52,20 +52,13 @@ def Restore(mirror_rp, inc_rpath, target, restore_to_time):
def get_inclist(inc_rpath):
"""Returns increments with given base"""
dirname, basename = inc_rpath.dirsplit()
- parent_dir = rpath.RPath(inc_rpath.conn, dirname, ())
+ parent_dir = inc_rpath.__class__(inc_rpath.conn, dirname, ())
if not parent_dir.isdir(): return [] # inc directory not created yet
index = inc_rpath.index
- if index:
- get_inc_ext = lambda filename: \
- rpath.RPath(inc_rpath.conn, inc_rpath.base,
- inc_rpath.index[:-1] + (filename,))
- else: get_inc_ext = lambda filename: \
- rpath.RPath(inc_rpath.conn, os.path.join(dirname, filename))
-
inc_list = []
for filename in parent_dir.listdir():
- inc = get_inc_ext(filename)
+ inc = parent_dir.append(filename)
if inc.isincfile() and inc.getincbase_str() == basename:
inc_list.append(inc)
return inc_list
@@ -404,26 +397,17 @@ class RestoreFile:
for mirror_rp, inc_pair in collated:
if not inc_pair:
inc_rp = self.inc_rp.new_index(mirror_rp.index)
- if Globals.quoting_enabled: inc_rp.quote_path()
inc_list = []
else: inc_rp, inc_list = inc_pair
if not mirror_rp:
mirror_rp = self.mirror_rp.new_index(inc_rp.index)
- if Globals.quoting_enabled: mirror_rp.quote_path()
yield RestoreFile(mirror_rp, inc_rp, inc_list)
def yield_mirrorrps(self, mirrorrp):
"""Yield mirrorrps underneath given mirrorrp"""
- if mirrorrp and mirrorrp.isdir():
- if Globals.quoting_enabled:
- for rp in selection.get_quoted_dir_children(mirrorrp):
- if rp.index != ('rdiff-backup-data',): yield rp
- else:
- dirlist = mirrorrp.listdir()
- dirlist.sort()
- for filename in dirlist:
- rp = mirrorrp.append(filename)
- if rp.index != ('rdiff-backup-data',): yield rp
+ for filename in robust.listrp(mirrorrp):
+ rp = mirrorrp.append(filename)
+ if rp.index != ('rdiff-backup-data',): yield rp
def yield_inc_complexes(self, inc_rpath):
"""Yield (sub_inc_rpath, inc_list) IndexedTuples from given inc_rpath
@@ -433,23 +417,19 @@ class RestoreFile:
"""
if not inc_rpath.isdir(): return
- inc_dict = {} # dictionary of basenames:inc_lists
+ inc_dict = {} # dictionary of basenames:IndexedTuples(index, inc_list)
dirlist = robust.listrp(inc_rpath)
- if Globals.quoting_enabled:
- dirlist = [FilenameMapping.unquote(fn) for fn in dirlist]
def affirm_dict_indexed(basename):
"""Make sure the rid dictionary has given basename as key"""
if not inc_dict.has_key(basename):
sub_inc_rp = inc_rpath.append(basename)
- if Globals.quoting_enabled: sub_inc_rp.quote_path()
inc_dict[basename] = rorpiter.IndexedTuple(sub_inc_rp.index,
(sub_inc_rp, []))
def add_to_dict(filename):
"""Add filename to the inc tuple dictionary"""
rp = inc_rpath.append(filename)
- if Globals.quoting_enabled: rp.quote_path()
if rp.isincfile() and rp.getinctype() != 'data':
basename = rp.getincbase_str()
affirm_dict_indexed(basename)
diff --git a/rdiff-backup/rdiff_backup/rpath.py b/rdiff-backup/rdiff_backup/rpath.py
index 49b9d2a..fb2c255 100644
--- a/rdiff-backup/rdiff_backup/rpath.py
+++ b/rdiff-backup/rdiff_backup/rpath.py
@@ -36,7 +36,7 @@ are dealing with are local or remote.
"""
import os, stat, re, sys, shutil, gzip, socket, time
-import Globals, FilenameMapping, Time, static, log
+import Globals, Time, static, log
class SkipFileException(Exception):
@@ -592,12 +592,6 @@ class RPath(RORPath):
s = self.conn.reval("lambda path: os.lstat(path).st_rdev", self.path)
return (s >> 8, s & 0xff)
- def quote_path(self):
- """Set path from quoted version of index"""
- quoted_list = [FilenameMapping.quote(path) for path in self.index]
- self.path = "/".join([self.base] + quoted_list)
- self.setdata()
-
def chmod(self, permissions):
"""Wrapper around os.chmod"""
self.conn.os.chmod(self.path, permissions)
@@ -843,7 +837,9 @@ class RPath(RORPath):
def getincbase_str(self):
"""Return the base filename string of an increment file"""
- return self.getincbase().dirsplit()[1]
+ rp = self.getincbase()
+ if rp.index: return rp.index[-1]
+ else: return rp.dirsplit()[1]
def makedev(self, type, major, minor):
"""Make a special file with specified type, and major/minor nums"""
diff --git a/rdiff-backup/rdiff_backup/selection.py b/rdiff-backup/rdiff_backup/selection.py
index d58735b..45d4c8c 100644
--- a/rdiff-backup/rdiff_backup/selection.py
+++ b/rdiff-backup/rdiff_backup/selection.py
@@ -80,19 +80,12 @@ class Select:
# This re should not match normal filenames, but usually just globs
glob_re = re.compile("(.*[*?[]|ignorecase\\:)", re.I | re.S)
- def __init__(self, rootrp, quoted_filenames = None):
- """Select initializer. rpath is the root directory
-
- When files have quoted characters in them, quoted_filenames
- should be true. Then RPath's index will be the unquoted
- version.
-
- """
+ def __init__(self, rootrp):
+ """Select initializer. rpath is the root directory"""
assert isinstance(rootrp, rpath.RPath)
self.selection_functions = []
self.rpath = rootrp
self.prefix = self.rpath.path
- self.quoting_on = Globals.quoting_enabled and quoted_filenames
def set_iter(self, iterate_parents = None, sel_func = None):
"""Initialize more variables, get ready to iterate
@@ -103,9 +96,7 @@ class Select:
"""
if not sel_func: sel_func = self.Select
self.rpath.setdata() # this may have changed since Select init
- if self.quoting_on:
- self.iter = self.Iterate(self.rpath, self.Iterate, sel_func)
- else: self.iter = self.Iterate_fast(self.rpath, sel_func)
+ self.iter = self.Iterate_fast(self.rpath, sel_func)
# only iterate parents if we are not starting from beginning
self.next = self.iter.next
@@ -113,12 +104,7 @@ class Select:
return self
def Iterate_fast(self, rpath, sel_func):
- """Like Iterate, but don't recur, saving time
-
- Only handles standard case (quoting off, starting from
- beginning).
-
- """
+ """Like Iterate, but don't recur, saving time"""
def error_handler(exc, filename):
Log("Error initializing file %s/%s" % (rpath.path, filename), 2)
return None
@@ -194,17 +180,12 @@ class Select:
Log("Error initializing file %s/%s" % (rpath.path, filename), 2)
return None
- if self.quoting_on:
- for subdir in get_quoted_dir_children(rpath):
- for rp in rec_func(subdir, rec_func, sel_func):
+ for filename in robust.listrp(rpath):
+ new_rp = robust.check_common_error(
+ error_handler, rpath.append, [filename])
+ if new_rp:
+ for rp in rec_func(new_rp, rec_func, sel_func):
yield rp
- else:
- for filename in robust.listrp(rpath):
- new_rp = robust.check_common_error(
- error_handler, rpath.append, [filename])
- if new_rp:
- for rp in rec_func(new_rp, rec_func, sel_func):
- yield rp
def Select(self, rp):
"""Run through the selection functions and return dominant val 0/1/2"""
@@ -617,22 +598,4 @@ probably isn't what you meant.""" %
return res
-def get_quoted_dir_children(rpath):
- """For rpath directory, return list of quoted children in dir
-
- This used to be in FilenameMapping, but was moved because it
- depends on the robust.listrp routine.
-
- """
- if not rpath.isdir(): return []
- dir_pairs = [(FilenameMapping.unquote(filename), filename)
- for filename in robust.listrp(rpath)]
- dir_pairs.sort() # sort by real index, not quoted part
- child_list = []
- for unquoted, filename in dir_pairs:
- childrp = rpath.append(unquoted)
- childrp.quote_path()
- child_list.append(childrp)
- return child_list
-
diff --git a/rdiff-backup/testing/FilenameMappingtest.py b/rdiff-backup/testing/FilenameMappingtest.py
new file mode 100644
index 0000000..66ab786
--- /dev/null
+++ b/rdiff-backup/testing/FilenameMappingtest.py
@@ -0,0 +1,31 @@
+import unittest
+from commontest import *
+from rdiff_backup import FilenameMapping
+
+class FilenameMappingTest(unittest.TestCase):
+ """Test the FilenameMapping class, for quoting filenames"""
+ def setUp(self):
+ """Just initialize quoting - assume windows mode"""
+ FilenameMapping.set_init_quote_vals()
+
+ def testBasicQuote(self):
+ """Test basic quoting and unquoting"""
+ filenames = ["hello", "HeLLo", "EUOeu/EUOeu", ":", "::::EU", "/:/:"]
+ for filename in filenames:
+ quoted = FilenameMapping.quote(filename)
+ assert FilenameMapping.unquote(quoted) == filename, filename
+
+ def testQuotedRPath(self):
+ """Test the QuotedRPath class"""
+
+ def testQuotedSepBase(self):
+ """Test get_quoted_sep_base function"""
+ path = ("/usr/local/mirror_metadata"
+ ".1969-12-31;08421;05833;05820-07;05800.data.gz")
+ qrp = FilenameMapping.get_quoted_sep_base(path)
+ assert qrp.base == "/usr/local", qrp.base
+ assert len(qrp.index) == 1, qrp.index
+ assert (qrp.index[0] ==
+ "mirror_metadata.1969-12-31T21:33:20-07:00.data.gz")
+
+if __name__ == "__main__": unittest.main()
diff --git a/rdiff-backup/testing/commontest.py b/rdiff-backup/testing/commontest.py
index dae825a..1e6fa82 100644
--- a/rdiff-backup/testing/commontest.py
+++ b/rdiff-backup/testing/commontest.py
@@ -5,7 +5,7 @@ from rdiff_backup.rpath import RPath
from rdiff_backup import Globals, Hardlink, SetConnections, Main, \
selection, lazy, Time, rpath
-SourceDir = "../src"
+SourceDir = "../rdiff_backup"
AbsCurdir = os.getcwd() # Absolute path name of current directory
AbsTFdir = AbsCurdir+"/testfiles"
MiscDir = "../misc"
diff --git a/rdiff-backup/testing/finaltest.py b/rdiff-backup/testing/finaltest.py
index ae48462..60bc072 100644
--- a/rdiff-backup/testing/finaltest.py
+++ b/rdiff-backup/testing/finaltest.py
@@ -1,6 +1,6 @@
import unittest, os, re, sys, time
from commontest import *
-from rdiff_backup import Globals, log, rpath, robust
+from rdiff_backup import Globals, log, rpath, robust, FilenameMapping
"""Regression tests"""
@@ -43,7 +43,7 @@ class PathSetter(unittest.TestCase):
def reset_schema(self):
self.rb_schema = SourceDir + \
- "/../rdiff-backup -v7 --remote-schema './chdir-wrapper2 %s' "
+ "/../rdiff-backup -v5 --remote-schema './chdir-wrapper2 %s' "
def refresh(self, *rp_list):
"""Reread data for the given rps"""
@@ -60,20 +60,21 @@ class PathSetter(unittest.TestCase):
def exec_rb(self, time, *args):
"""Run rdiff-backup on given arguments"""
arglist = []
- if time: arglist.append("--current-time %s" % str(time))
+ if time: arglist.extend(["--current-time", str(time)])
arglist.append(self.src_prefix + args[0])
if len(args) > 1:
arglist.append(self.dest_prefix + args[1])
assert len(args) == 2
- cmdstr = self.rb_schema + ' '.join(arglist)
+ argstring = ' '.join(map(lambda s: "'%s'" % (s,), arglist))
+ cmdstr = self.rb_schema + argstring
print "executing " + cmdstr
assert not os.system(cmdstr)
def exec_rb_extra_args(self, time, extra_args, *args):
"""Run rdiff-backup on given arguments"""
arglist = []
- if time: arglist.append("--current-time %s" % str(time))
+ if time: arglist.extend(["--current-time", str(time)])
arglist.append(self.src_prefix + args[0])
if len(args) > 1:
arglist.append(self.dest_prefix + args[1])
@@ -166,14 +167,19 @@ class PathSetter(unittest.TestCase):
"testfiles/output/rdiff-backup-data/increments/nochange"))
assert nochange_incs == 1 or nochange_incs == 0, nochange_incs
- def getinc_paths(self, basename, directory):
+ def getinc_paths(self, basename, directory, quoted = 0):
"""Return increment.______.dir paths"""
- dirrp = rpath.RPath(Globals.local_connection, directory)
- incfiles = [filename for filename in robust.listrp(dirrp)
- if filename.startswith(basename)]
- incfiles.sort()
- incrps = map(lambda f: rpath.RPath(lc, directory+"/"+f), incfiles)
- return map(lambda x: x.path, filter(rpath.RPath.isincfile, incrps))
+ if quoted:
+ FilenameMapping.set_init_quote_vals()
+ dirrp = FilenameMapping.QuotedRPath(Globals.local_connection,
+ directory)
+ else: dirrp = rpath.RPath(Globals.local_connection, directory)
+ incbasenames = [filename for filename in robust.listrp(dirrp)
+ if filename.startswith(basename)]
+ incbasenames.sort()
+ incrps = map(dirrp.append, incbasenames)
+ return map(lambda x: x.path,
+ filter(lambda incrp: incrp.isincfile(), incrps))
class Final(PathSetter):
@@ -204,7 +210,7 @@ class Final(PathSetter):
self.exec_rb(None, '../../../../../../proc', 'testfiles/procoutput')
def testProcRemote(self):
- """Test mirroring proc"""
+ """Test mirroring proc remote"""
Myrm("testfiles/procoutput")
self.set_connections(None, None, "test2/tmp/", "../../")
self.exec_rb(None, '../../../../../../proc', 'testfiles/procoutput')
@@ -226,12 +232,13 @@ class Final(PathSetter):
Globals.time_separator = "_"
inc_paths = self.getinc_paths("increments.",
- "testfiles/output/rdiff-backup-data")
+ "testfiles/output/rdiff-backup-data", 1)
Globals.time_separator = ":"
- assert len(inc_paths) == 1
+ assert len(inc_paths) == 1, inc_paths
# Restore increment2
self.exec_rb(None, inc_paths[0], 'testfiles/restoretarget2')
- assert CompareRecursive(Local.inc2rp, Local.rpout2)
+ assert CompareRecursive(Local.inc2rp, Local.rpout2,
+ compare_hardlinks = 0)
# Now check to make sure no ":" in output directory
popen_fp = os.popen("find testfiles/output -name '*:*' | wc")
@@ -242,6 +249,10 @@ class Final(PathSetter):
class FinalSelection(PathSetter):
"""Test selection options"""
+ def run(cmd):
+ print "Executing: ", cmd
+ assert not os.system(cmd)
+
def testSelLocal(self):
"""Quick backup testing a few selection options"""
self.delete_tmpdirs()
@@ -277,11 +288,11 @@ testfiles/increment2/changed_dir""")
# Test selective restoring
mirror_rp = rpath.RPath(Globals.local_connection, "testfiles/output")
restore_filename = get_increment_rp(mirror_rp, 10000).path
- assert not os.system(self.rb_schema +
- "--include testfiles/restoretarget1/various_file_types/"
- "regular_file "
- "--exclude '**' " +
- restore_filename + " testfiles/restoretarget1")
+ self.run(self.rb_schema +
+ "--include testfiles/restoretarget1/various_file_types/"
+ "regular_file "
+ "--exclude '**' " +
+ restore_filename + " testfiles/restoretarget1")
assert os.lstat("testfiles/restoretarget1/various_file_types/"
"regular_file")
self.assertRaises(OSError, os.lstat, "testfiles/restoretarget1/tester")