Commit ed425d54 authored by bescoto's avatar bescoto

Fix bug backing up acl system to no-acl system


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@473 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent 3110c652
......@@ -20,6 +20,9 @@ this is the last of the unreadable file bugs...
Rewrote hard link tracking system. New way should use less memory.
Fixed bug causing rdiff-backup to crash when backing up from system
supporting EAs/ACLs to one that didn't.
New in v0.13.2 (2003/09/16)
---------------------------
......
Figure out why files getting unnecessarily incremented when upgrading
from 0.12.x.
Fix support of case when source has EAs or ACLs, dest doesn't.
Consider adding --datadir option (Jean-Sébastien GOETSCHY)
See if regressing takes too much memory (large directories).
......
......@@ -63,28 +63,27 @@ change_mirror_perms = (process_uid != 0)
# If true, try to reset the atimes of the source partition.
preserve_atime = None
# If true, save the extended attributes when backing up.
read_eas = None
# If true, preserve the extended attributes on the mirror directory
# when backing up, or write them to the restore directory. This
# requires read_eas.
write_eas = None
# If true, save access control lists when backup up.
read_acls = None
# If true, write access control list information to the destination
# when backing up or restoring. Requires read_acls.
write_acls = None
# If true, look for and save resource fork information when backing
# up.
read_resource_forks = None
# If true, write resource fork information to destination when backing
# up or restoring. Requires read_resource_forks.
write_resource_forks = None
# The following three attributes represent whether extended attributes
# are supported. If eas_active is true, then the current session
# supports them. If eas_write is true, then the extended attributes
# should also be written to the destination side. Finally, eas_conn
# is relative to the current connection, and should be true iff that
# particular connection supports extended attributes.
eas_active = None
eas_write = None
eas_conn = None
# The following settings are like the extended attribute settings, but
# apply to access control lists instead.
acls_active = None
acls_write = None
acls_conn = None
# Like above two setting groups, but applies to support of Mac OS X
# style resource forks.
resource_forks_active = None
resource_forks_write = None
resource_forks_conn = None
# This will be set as soon as the LocalConnection class loads
local_connection = None
......@@ -231,6 +230,10 @@ def set(name, val):
changed_settings.append(name)
globals()[name] = val
def set_local(name, val):
"""Like set above, but only set current connection"""
globals()[name] = val
def set_integer(name, val):
"""Like set, but make sure val is an integer"""
try: intval = int(val)
......
......@@ -111,12 +111,12 @@ def parse_cmdlineoptions(arglist):
action = "list-increments"
elif opt == '--list-increment-sizes': action = 'list-increment-sizes'
elif opt == "--never-drop-acls": Globals.set("never_drop_acls", 1)
elif opt == "--no-acls": Globals.set("read_acls", 0)
elif opt == "--no-acls": Globals.set("acls_active", 0)
elif opt == "--no-compare-inode": Globals.set("compare_inode", 0)
elif opt == "--no-compression": Globals.set("compression", None)
elif opt == "--no-compression-regexp":
Globals.set("no_compression_regexp_string", arg)
elif opt == "--no-eas": Globals.set("read_eas", 0)
elif opt == "--no-eas": Globals.set("eas_active", 0)
elif opt == "--no-file-statistics": Globals.set('file_statistics', 0)
elif opt == "--no-hard-links": Globals.set('preserve_hardlinks', 0)
elif opt == "--null-separator": Globals.set("null_separator", 1)
......@@ -358,31 +358,38 @@ def backup_final_init(rpout):
def backup_set_fs_globals(rpin, rpout):
"""Use fs_abilities to set the globals that depend on filesystem"""
def update_bool_global(attr, bool):
"""If bool is not None, update Globals.attr accordingly"""
if Globals.get(attr) is None:
SetConnections.UpdateGlobal(attr, bool)
def update_triple(src_support, dest_support, attr_triple):
"""Update global settings for feature based on fsa results"""
active_attr, write_attr, conn_attr = attr_triple
if Globals.get(active_attr) == 0: return # don't override 0
for attr in attr_triple: SetConnections.UpdateGlobal(attr, None)
if not src_support: return # if source doesn't support, nothing
SetConnections.UpdateGlobal(active_attr, 1)
rpin.conn.Globals.set_local(conn_attr, 1)
if dest_support:
SetConnections.UpdateGlobal(write_attr, 1)
rpout.conn.Globals.set_local(conn_attr, 1)
src_fsa = rpin.conn.fs_abilities.get_fsabilities_readonly('source', rpin)
Log(str(src_fsa), 3)
dest_fsa = rpout.conn.fs_abilities.get_fsabilities_readwrite(
'destination', Globals.rbdir, 1, Globals.chars_to_quote)
Log(str(dest_fsa), 3)
if Globals.never_drop_acls and not dest_fsa.acls:
update_triple(src_fsa.eas, dest_fsa.eas,
('eas_active', 'eas_write', 'eas_conn'))
update_triple(src_fsa.acls, dest_fsa.acls,
('acls_active', 'acls_write', 'acls_conn'))
update_triple(src_fsa.resource_forks, dest_fsa.resource_forks,
('resource_forks_active', 'resource_forks_write',
'resource_forks_conn'))
if Globals.never_drop_acls and not Globals.acls_active:
Log.FatalError("--never-drop-acls specified, but ACL support\n"
"disabled on destination filesystem")
if Globals.read_acls != 0: update_bool_global('read_acls', src_fsa.acls)
if Globals.read_eas != 0: update_bool_global('read_eas', src_fsa.eas)
update_bool_global('read_resource_forks', src_fsa.resource_forks)
SetConnections.UpdateGlobal('preserve_hardlinks', dest_fsa.hardlinks)
SetConnections.UpdateGlobal('fsync_directories', dest_fsa.fsync_dirs)
SetConnections.UpdateGlobal('change_ownership', dest_fsa.ownership)
update_bool_global('write_acls', Globals.read_acls and dest_fsa.acls)
update_bool_global('write_eas', Globals.read_eas and dest_fsa.eas)
update_bool_global('write_resource_forks',
Globals.read_resource_forks and dest_fsa.resource_forks)
SetConnections.UpdateGlobal('chars_to_quote', dest_fsa.chars_to_quote)
if Globals.chars_to_quote:
for conn in Globals.connections:
......@@ -455,9 +462,16 @@ def restore_init_quoting(src_rp):
def restore_set_fs_globals(target):
"""Use fs_abilities to set the globals that depend on filesystem"""
def update_bool_global(attr, bool):
"""If bool is not None, update Globals.attr accordingly"""
if Globals.get(attr) is None: SetConnections.UpdateGlobal(attr, bool)
def update_triple(src_support, dest_support, attr_triple):
"""Update global settings for feature based on fsa results"""
active_attr, write_attr, conn_attr = attr_triple
if Globals.get(active_attr) == 0: return # don't override 0
for attr in attr_triple: SetConnections.UpdateGlobal(attr, None)
if not dest_support: return # if dest doesn't support, do nothing
SetConnections.UpdateGlobal(active_attr, 1)
target.conn.Globals.set_local(conn_attr, 1)
target.conn.Globals.set_local(write_attr, 1)
if src_support: Globals.rbdir.conn.Globals.set_local(conn_attr, 1)
target_fsa = target.conn.fs_abilities.get_fsabilities_readwrite(
'destination', target, 0)
......@@ -465,18 +479,18 @@ def restore_set_fs_globals(target):
mirror_fsa = Globals.rbdir.conn.fs_abilities.get_fsabilities_restoresource(
Globals.rbdir)
Log(str(mirror_fsa), 3)
if Globals.never_drop_acls and not target_fsa.acls:
update_triple(mirror_fsa.eas, target_fsa.eas,
('eas_active', 'eas_write', 'eas_conn'))
update_triple(mirror_fsa.acls, target_fsa.acls,
('acls_active', 'acls_write', 'acls_conn'))
update_triple(mirror_fsa.resource_forks, target_fsa.resource_forks,
('resource_forks_active', 'resource_forks_write',
'resource_forks_conn'))
if Globals.never_drop_acls and not Globals.acls_active:
Log.FatalError("--never-drop-acls specified, but ACL support\n"
"disabled on destination filesystem")
if Globals.read_acls != 0:
update_bool_global('read_acls', target_fsa.acls)
update_bool_global('write_acls', target_fsa.acls)
if Globals.read_eas != 0:
update_bool_global('read_eas', target_fsa.eas)
update_bool_global('write_eas', target_fsa.eas)
update_bool_global('read_resource_forks', target_fsa.resource_forks)
update_bool_global('write_resource_forks', target_fsa.resource_forks)
SetConnections.UpdateGlobal('preserve_hardlinks', target_fsa.hardlinks)
SetConnections.UpdateGlobal('change_ownership', target_fsa.ownership)
......
......@@ -135,7 +135,7 @@ class DestinationStruct:
if use_metadata:
rorp_iter = eas_acls.GetCombinedMetadataIter(
Globals.rbdir, Time.prevtime,
acls = Globals.read_acls, eas = Globals.read_eas)
acls = Globals.acls_active, eas = Globals.eas_active)
if rorp_iter: return rorp_iter
return get_iter_from_fs()
......@@ -268,8 +268,8 @@ class CacheCollatedPostProcess:
self.statfileobj = statistics.init_statfileobj()
if Globals.file_statistics: statistics.FileStats.init()
metadata.MetadataFile.open_file()
if Globals.read_eas: eas_acls.ExtendedAttributesFile.open_file()
if Globals.read_acls: eas_acls.AccessControlListFile.open_file()
if Globals.eas_active: eas_acls.ExtendedAttributesFile.open_file()
if Globals.acls_active: eas_acls.AccessControlListFile.open_file()
# the following should map indicies to lists
# [source_rorp, dest_rorp, changed_flag, success_flag, increment]
......@@ -368,10 +368,10 @@ class CacheCollatedPostProcess:
else: metadata_rorp = None
if metadata_rorp and metadata_rorp.lstat():
metadata.MetadataFile.write_object(metadata_rorp)
if Globals.read_eas and not metadata_rorp.get_ea().empty():
if Globals.eas_active and not metadata_rorp.get_ea().empty():
eas_acls.ExtendedAttributesFile.write_object(
metadata_rorp.get_ea())
if Globals.read_acls and not metadata_rorp.get_acl().is_basic():
if Globals.acls_active and not metadata_rorp.get_acl().is_basic():
eas_acls.AccessControlListFile.write_object(
metadata_rorp.get_acl())
if Globals.file_statistics:
......@@ -427,8 +427,8 @@ class CacheCollatedPostProcess:
dir_rp, perms = self.dir_perms_list.pop()
dir_rp.chmod(perms)
metadata.MetadataFile.close_file()
if Globals.read_eas: eas_acls.ExtendedAttributesFile.close_file()
if Globals.read_acls: eas_acls.AccessControlListFile.close_file()
if Globals.eas_active: eas_acls.ExtendedAttributesFile.close_file()
if Globals.acls_active: eas_acls.AccessControlListFile.close_file()
if Globals.print_statistics: statistics.print_active_stats()
if Globals.file_statistics: statistics.FileStats.close()
statistics.write_active_statfileobj()
......
......@@ -177,7 +177,7 @@ class MirrorStruct:
rorp_iter = eas_acls.GetCombinedMetadataIter(
Globals.rbdir, rest_time, restrict_index = cls.mirror_base.index,
acls = Globals.write_acls, eas = Globals.write_eas)
acls = Globals.acls_active, eas = Globals.eas_active)
if not rorp_iter:
if require_metadata:
log.Log.FatalError("Mirror metadata not found")
......
......@@ -153,12 +153,12 @@ def copy_attribs(rpin, rpout):
log.Log("Copying attributes from %s to %s" % (rpin.index, rpout.path), 7)
assert rpin.lstat() == rpout.lstat() or rpin.isspecial()
if rpin.issym(): return # symlinks have no valid attributes
if Globals.write_resource_forks and rpin.isreg():
if Globals.resource_forks_write and rpin.isreg():
rpout.write_resource_fork(rpin.get_resource_fork())
if Globals.write_eas: rpout.write_ea(rpin.get_ea())
if Globals.eas_write: rpout.write_ea(rpin.get_ea())
if Globals.change_ownership: rpout.chown(*user_group.map_rpath(rpin))
rpout.chmod(rpin.getperms())
if Globals.write_acls: rpout.write_acl(rpin.get_acl())
if Globals.acls_write: rpout.write_acl(rpin.get_acl())
if not rpin.isdev(): rpout.setmtime(rpin.getmtime())
def copy_attribs_inc(rpin, rpout):
......@@ -172,14 +172,14 @@ def copy_attribs_inc(rpin, rpout):
log.Log("Copying inc attrs from %s to %s" % (rpin.index, rpout.path), 7)
check_for_files(rpin, rpout)
if rpin.issym(): return # symlinks have no valid attributes
if Globals.write_resource_forks and rpin.isreg() and rpout.isreg():
if Globals.resource_forks_write and rpin.isreg() and rpout.isreg():
rpout.write_resource_fork(rpin.get_resource_fork())
if Globals.write_eas: rpout.write_ea(rpin.get_ea())
if Globals.eas_write: rpout.write_ea(rpin.get_ea())
if Globals.change_ownership: apply(rpout.chown, rpin.getuidgid())
if rpin.isdir() and not rpout.isdir():
rpout.chmod(rpin.getperms() & 0777)
else: rpout.chmod(rpin.getperms())
if Globals.write_acls: rpout.write_acl(rpin.get_acl(), map_names = 0)
if Globals.acls_write: rpout.write_acl(rpin.get_acl(), map_names = 0)
if not rpin.isdev(): rpout.setmtime(rpin.getmtime())
def cmp_attribs(rp1, rp2):
......@@ -292,9 +292,9 @@ class RORPath:
elif key == 'ctime': pass
elif key == 'devloc' or key == 'nlink': pass
elif key == 'size' and not self.isreg(): pass
elif key == 'ea' and not Globals.read_eas: pass
elif key == 'acl' and not Globals.read_acls: pass
elif key == 'resourcefork' and not Globals.read_resource_forks:
elif key == 'ea' and not Globals.eas_active: pass
elif key == 'acl' and not Globals.acls_active: pass
elif key == 'resourcefork' and not Globals.resource_forks_active:
pass
elif (key == 'inode' and
(not self.isreg() or self.getnumlinks() == 1 or
......@@ -324,9 +324,9 @@ class RORPath:
elif key == 'devloc' or key == 'nlink': pass
elif key == 'size' and not self.isreg(): pass
elif key == 'inode': pass
elif key == 'ea' and not Globals.write_eas: pass
elif key == 'acl' and not Globals.write_acls: pass
elif key == 'resourcefork' and not Globals.write_resource_forks:
elif key == 'ea' and not Globals.eas_write: pass
elif key == 'acl' and not Globals.acls_write: pass
elif key == 'resourcefork' and not Globals.resource_forks_write:
pass
elif (not other.data.has_key(key) or
self.data[key] != other.data[key]): return 0
......@@ -653,13 +653,7 @@ class RPath(RORPath):
def setdata(self):
"""Set data dictionary using C extension"""
self.data = self.conn.C.make_file_dict(self.path)
if not self.lstat(): return
self.data['uname'] = self.conn.user_group.uid2uname(self.data['uid'])
self.data['gname'] = self.conn.user_group.gid2gname(self.data['gid'])
if Globals.read_eas: self.data['ea'] = self.conn.rpath.ea_get(self)
if Globals.read_acls: self.data['acl'] = self.conn.rpath.acl_get(self)
if Globals.read_resource_forks and self.isreg():
self.get_resource_fork()
if self.lstat(): self.conn.rpath.setdata_local(self)
def make_file_dict_old(self):
"""Create the data dictionary"""
......@@ -1097,9 +1091,23 @@ class RPathFileHook:
return result
def setdata_local(rpath):
"""Set eas/acls, uid/gid, resource fork in data dictionary
This is a global function because it must be called locally, since
these features may exist or not depending on the connection.
"""
assert rpath.conn is Globals.local_connection
rpath.data['uname'] = user_group.uid2uname(rpath.data['uid'])
rpath.data['gname'] = user_group.gid2gname(rpath.data['gid'])
if Globals.eas_conn: rpath.data['ea'] = ea_get(rpath)
if Globals.acls_conn: rpath.data['acl'] = acl_get(rpath)
if Globals.resource_forks_conn and rpath.isreg():
rpath.get_resource_fork()
# These two are overwritten by the eas_acls.py module. We can't
# import that module directory because of circular dependency
# problems.
# import that module directly because of circular dependency problems.
def acl_get(rp): assert 0
def ea_get(rp): assert 0
......@@ -75,7 +75,7 @@ def cmd_schemas2rps(schema_list, remote_schema):
SetConnections.get_cmd_pairs(schema_list, remote_schema))
def InternalBackup(source_local, dest_local, src_dir, dest_dir,
current_time = None):
current_time = None, eas = None, acls = None):
"""Backup src to dest internally
This is like rdiff_backup but instead of running a separate
......@@ -96,6 +96,10 @@ def InternalBackup(source_local, dest_local, src_dir, dest_dir,
% (SourceDir, dest_dir)
rpin, rpout = cmd_schemas2rps([src_dir, dest_dir], remote_schema)
for attr in ('eas_active', 'eas_write', 'eas_conn'):
SetConnections.UpdateGlobal(attr, eas)
for attr in ('acls_active', 'acls_write', 'acls_conn'):
SetConnections.UpdateGlobal(attr, acls)
Main.misc_setup([rpin, rpout])
Main.Backup(rpin, rpout)
Main.cleanup()
......@@ -118,7 +122,8 @@ def InternalMirror(source_local, dest_local, src_dir, dest_dir):
# Restore old attributes
rpath.copy_attribs(src_root, dest_root)
def InternalRestore(mirror_local, dest_local, mirror_dir, dest_dir, time):
def InternalRestore(mirror_local, dest_local, mirror_dir, dest_dir, time,
eas = None, acls = None):
"""Restore mirror_dir to dest_dir at given time
This will automatically find the increments.XXX.dir representing
......@@ -138,6 +143,10 @@ def InternalRestore(mirror_local, dest_local, mirror_dir, dest_dir, time):
% (SourceDir, dest_dir)
mirror_rp, dest_rp = cmd_schemas2rps([mirror_dir, dest_dir], remote_schema)
for attr in ('eas_active', 'eas_write', 'eas_conn'):
SetConnections.UpdateGlobal(attr, eas)
for attr in ('acls_active', 'acls_write', 'acls_conn'):
SetConnections.UpdateGlobal(attr, acls)
Main.misc_setup([mirror_rp, dest_rp])
inc = get_increment_rp(mirror_rp, time)
if inc: Main.Restore(get_increment_rp(mirror_rp, time), dest_rp)
......@@ -299,10 +308,6 @@ def BackupRestoreSeries(source_local, dest_local, list_of_dirnames,
"""
Globals.set('preserve_hardlinks', compare_hardlinks)
Globals.set('write_eas', compare_eas)
Globals.set('read_eas', compare_eas)
Globals.set('write_acls', compare_acls)
Globals.set('read_acls', compare_acls)
time = 10000
dest_rp = rpath.RPath(Globals.local_connection, dest_dirname)
restore_rp = rpath.RPath(Globals.local_connection, restore_dirname)
......@@ -313,7 +318,8 @@ def BackupRestoreSeries(source_local, dest_local, list_of_dirnames,
reset_hardlink_dicts()
_reset_connections(src_rp, dest_rp)
InternalBackup(source_local, dest_local, dirname, dest_dirname, time)
InternalBackup(source_local, dest_local, dirname, dest_dirname, time,
eas = compare_eas, acls = compare_acls)
time += 10000
_reset_connections(src_rp, dest_rp)
if compare_backups:
......@@ -326,7 +332,8 @@ def BackupRestoreSeries(source_local, dest_local, list_of_dirnames,
reset_hardlink_dicts()
Myrm(restore_dirname)
InternalRestore(dest_local, source_local, dest_dirname,
restore_dirname, time)
restore_dirname, time,
eas = compare_eas, acls = compare_acls)
src_rp = rpath.RPath(Globals.local_connection, dirname)
assert CompareRecursive(src_rp, restore_rp,
compare_eas = compare_eas,
......
import unittest, os, time, cStringIO, posix1e, pwd, grp
from commontest import *
from rdiff_backup.eas_acls import *
from rdiff_backup import Globals, rpath, Time, user_group
from rdiff_backup import Globals, rpath, Time, user_group, log
user_group.init_user_mapping()
user_group.init_group_mapping()
tempdir = rpath.RPath(Globals.local_connection, "testfiles/output")
restore_dir = rpath.RPath(Globals.local_connection,
"testfiles/restore_out")
log.Log.setverbosity(7)
class EATest(unittest.TestCase):
"""Test extended attributes"""
......
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