diff options
Diffstat (limited to 'rdiff-backup/rdiff_backup/FilenameMapping.py')
-rw-r--r-- | rdiff-backup/rdiff_backup/FilenameMapping.py | 64 |
1 files changed, 58 insertions, 6 deletions
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) |