Commit 94f13694 authored by owsla's avatar owsla

Add ability to requote a repository


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@863 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent d0ed4f68
New in v1.1.15 (????/??/??)
---------------------------
New feature: If quoting requirements change, rdiff-backup can requote the
entire repository if user specifies the --force option. (Andrew Ferguson)
Don't print the warning message about unsupported hard links if the user
has specified the --no-hard-links option. (Suggested by Andreas Olsson)
......
......@@ -29,7 +29,8 @@ handle that error.)
"""
import re, types
from __future__ import generators
import os, re, types
import Globals, log, rpath
# If true, enable character quoting, and set characters making
......@@ -71,7 +72,7 @@ def init_quoting_regexps():
re.compile("[%s]|%s" % (chars_to_quote, quoting_char), re.S)
unquoting_regexp = re.compile("%s[0-9]{3}" % quoting_char, re.S)
except re.error:
log.Log.FatalError("Error '%s' when processing char quote list '%s'" %
log.Log.FatalError("Error '%s' when processing char quote list %r" %
(re.error, chars_to_quote))
def quote(path):
......@@ -171,3 +172,84 @@ def get_quotedrpath(rp, separate_basename = 0):
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)
def update_quoting(rbdir):
"""Update the quoting of a repository by renaming any
files that should be quoted differently.
"""
def requote(name):
unquoted_name = unquote(name)
quoted_name = quote(unquoted_name)
if name != quoted_name:
return quoted_name
else:
return None
def process(dirpath_rp, name, list):
new_name = requote(name)
if new_name:
if list:
list.remove(name)
list.append(new_name)
name_rp = dirpath_rp.append(name)
new_rp = dirpath_rp.append(new_name)
log.Log("Re-quoting %s to %s" % (name_rp.path, new_rp.path), 5)
rpath.move(name_rp, new_rp)
assert rbdir.conn is Globals.local_connection
mirror_rp = rbdir.get_parent_rp()
mirror = mirror_rp.path
log.Log("Re-quoting repository %s" % mirror_rp.path, 3)
try:
os_walk = os.walk
except AttributeError:
os_walk = walk
for dirpath, dirs, files in os_walk(mirror):
dirpath_rp = mirror_rp.newpath(dirpath)
for name in dirs: process(dirpath_rp, name, dirs)
for name in files: process(dirpath_rp, name, None)
"""
os.walk() copied directly from Python 2.5.1's os.py
Backported here for Python 2.2 support. os.walk() was first added
in Python 2.3.
"""
def walk(top, topdown=True, onerror=None):
from os import error, listdir
from os.path import join, isdir, islink
# We may not have read permission for top, in which case we can't
# get a list of the files the directory contains. os.path.walk
# always suppressed the exception then, rather than blow up for a
# minor reason when (say) a thousand readable directories are still
# left to visit. That logic is copied here.
try:
# Note that listdir and error are globals in this module due
# to earlier import-*.
names = listdir(top)
except error, err:
if onerror is not None:
onerror(err)
return
dirs, nondirs = [], []
for name in names:
if isdir(join(top, name)):
dirs.append(name)
else:
nondirs.append(name)
if topdown:
yield top, dirs, nondirs
for name in dirs:
path = join(top, name)
if not islink(path):
for x in walk(path, topdown, onerror):
yield x
if not topdown:
yield top, dirs, nondirs
......@@ -329,7 +329,7 @@ def Backup(rpin, rpout):
SetConnections.BackupInitConnections(rpin.conn, rpout.conn)
backup_check_dirs(rpin, rpout)
backup_set_rbdir(rpin, rpout)
rpout.conn.fs_abilities.backup_set_globals(rpin)
rpout.conn.fs_abilities.backup_set_globals(rpin, force)
if Globals.chars_to_quote: rpout = backup_quoted_rpaths(rpout)
init_user_group_mapping(rpout.conn)
backup_final_init(rpout)
......
......@@ -577,7 +577,7 @@ class BackupSetGlobals(SetGlobals):
log.Log("Backup: must_escape_dos_devices = %d" % \
(self.src_fsa.escape_dos_devices or local_edd), 4)
def set_chars_to_quote(self, rbdir):
def set_chars_to_quote(self, rbdir, force):
"""Set chars_to_quote setting for backup session
Unlike the other options, the chars_to_quote setting also
......@@ -585,10 +585,12 @@ class BackupSetGlobals(SetGlobals):
directory, not just the current fs features.
"""
ctq = self.compare_ctq_file(rbdir, self.get_ctq_from_fsas())
(ctq, update) = self.compare_ctq_file(rbdir,
self.get_ctq_from_fsas(), force)
SetConnections.UpdateGlobal('chars_to_quote', ctq)
if Globals.chars_to_quote: FilenameMapping.set_init_quote_vals()
return update
def get_ctq_from_fsas(self):
"""Determine chars_to_quote just from filesystems, no ctq file"""
......@@ -608,24 +610,32 @@ class BackupSetGlobals(SetGlobals):
if ctq: ctq.append(';') # Quote quoting char if quoting anything
return "".join(ctq)
def compare_ctq_file(self, rbdir, suggested_ctq):
def compare_ctq_file(self, rbdir, suggested_ctq, force):
"""Compare ctq file with suggested result, return actual ctq"""
ctq_rp = rbdir.append("chars_to_quote")
if not ctq_rp.lstat():
if Globals.chars_to_quote is None: actual_ctq = suggested_ctq
else: actual_ctq = Globals.chars_to_quote
ctq_rp.write_string(actual_ctq)
return actual_ctq
return (actual_ctq, None)
if Globals.chars_to_quote is None: actual_ctq = ctq_rp.get_data()
else: actual_ctq = Globals.chars_to_quote # Globals override
if actual_ctq == suggested_ctq: return actual_ctq
if actual_ctq == suggested_ctq: return (actual_ctq, None)
if suggested_ctq == "":
log.Log("Warning: File system no longer needs quoting, "
"but we will retain for backwards compatibility.", 2)
return actual_ctq
return (actual_ctq, None)
if Globals.chars_to_quote is None:
if force:
log.Log("Warning: migrating rdiff-backup repository from"
"old quoting chars %r to new quoting chars %r" %
(actual_ctq, suggested_ctq), 2)
ctq_rp.delete()
ctq_rp.write_string(suggested_ctq)
return (suggested_ctq, 1)
else:
log.Log.FatalError("""New quoting requirements!
The quoting chars this session needs %r do not match
......@@ -637,7 +647,11 @@ This may be caused when you copy an rdiff-backup repository from a
normal file system onto a windows one that cannot support the same
characters, or if you backup a case-sensitive file system onto a
case-insensitive one that previously only had case-insensitive ones
backed up onto it.""" % (suggested_ctq, actual_ctq, ctq_rp.path))
backed up onto it.
By specificying the --force option, rdiff-backup will migrate the
repository from the old quoting chars to the new ones.""" %
(suggested_ctq, actual_ctq, ctq_rp.path))
class RestoreSetGlobals(SetGlobals):
......@@ -719,7 +733,7 @@ class SingleSetGlobals(RestoreSetGlobals):
('carbonfile_active', 'carbonfile_write', 'carbonfile_conn'))
def backup_set_globals(rpin):
def backup_set_globals(rpin, force):
"""Given rps for source filesystem and repository, set fsa globals
This should be run on the destination connection, because we may
......@@ -742,10 +756,14 @@ def backup_set_globals(rpin):
bsg.set_change_ownership()
bsg.set_high_perms()
bsg.set_symlink_perms()
bsg.set_chars_to_quote(Globals.rbdir)
update_quoting = bsg.set_chars_to_quote(Globals.rbdir, force)
bsg.set_escape_dos_devices()
bsg.set_must_escape_dos_devices(Globals.rbdir)
if update_quoting and force:
FilenameMapping.update_quoting(Globals.rbdir)
def restore_set_globals(rpout):
"""Set fsa related globals for restore session, given in/out rps"""
assert rpout.conn is Globals.local_connection
......
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