Commit 2aae3044 authored by bescoto's avatar bescoto

Added tests for and fixed problem with backing up unreadable regular

files as root on source and non-root on dest.


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@399 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent e6f02f86
...@@ -4,6 +4,10 @@ New in v0.13.2 (??????????) ...@@ -4,6 +4,10 @@ New in v0.13.2 (??????????)
Specified socket type as SOCK_STREAM. (Error reported by Erik Specified socket type as SOCK_STREAM. (Error reported by Erik
Forsberg.) Forsberg.)
Fixed bug backing up unreadable regular files when rdiff-backup is run
by root on the source site and non-root on the destination side.
(Reported by Troels Arvin and Arkadiusz Miskiewicz.)
New in v0.13.1 (2003/08/08) New in v0.13.1 (2003/08/08)
--------------------------- ---------------------------
......
...@@ -423,8 +423,10 @@ def restore_set_fs_globals(target): ...@@ -423,8 +423,10 @@ def restore_set_fs_globals(target):
target_fsa = fs_abilities.FSAbilities('destination').init_readwrite( target_fsa = fs_abilities.FSAbilities('destination').init_readwrite(
target, 0) target, 0)
Log(str(target_fsa), 3)
mirror_fsa = fs_abilities.FSAbilities('source').init_readwrite( mirror_fsa = fs_abilities.FSAbilities('source').init_readwrite(
Globals.rbdir) Globals.rbdir)
Log(str(mirror_fsa), 3)
update_bool_global('read_acls', target_fsa.acls) update_bool_global('read_acls', target_fsa.acls)
update_bool_global('write_acls', target_fsa.acls) update_bool_global('write_acls', target_fsa.acls)
......
...@@ -184,15 +184,26 @@ class DestinationStruct: ...@@ -184,15 +184,26 @@ class DestinationStruct:
elif dest_rorp: elif dest_rorp:
dest_sig = dest_rorp.getRORPath() dest_sig = dest_rorp.getRORPath()
if dest_rorp.isreg(): if dest_rorp.isreg():
dest_rp = dest_base_rpath.new_index(index) sig_fp = cls.get_one_sig_fp(dest_base_rpath.new_index(index))
if not dest_rp.isreg(): if sig_fp is None: return None
log.ErrorLog.write_if_open("UpdateError", dest_rp, dest_sig.setfile(sig_fp)
"File changed from regular file before signature")
return None
dest_sig.setfile(Rdiff.get_signature(dest_rp))
else: dest_sig = rpath.RORPath(index) else: dest_sig = rpath.RORPath(index)
return dest_sig return dest_sig
def get_one_sig_fp(cls, dest_rp):
"""Return a signature fp of given index, corresponding to reg file"""
if not dest_rp.isreg():
log.ErrorLog.write_if_open("UpdateError", dest_rp,
"File changed from regular file before signature")
return None
if Globals.process_uid != 0 and not dest_rp.readable():
# This branch can happen with root source and non-root
# destination. Permissions are changed permanently, which
# should propogate to the diffs
assert dest_rp.isowner(), 'no ownership of %s' % (dest_rp.path,)
dest_rp.chmod(0400 | dest_rp.getperms())
return Rdiff.get_signature(dest_rp)
def patch(cls, dest_rpath, source_diffiter, start_index = ()): def patch(cls, dest_rpath, source_diffiter, start_index = ()):
"""Patch dest_rpath with an rorpiter of diffs""" """Patch dest_rpath with an rorpiter of diffs"""
ITR = rorpiter.IterTreeReducer(PatchITRB, [dest_rpath, cls.CCPP]) ITR = rorpiter.IterTreeReducer(PatchITRB, [dest_rpath, cls.CCPP])
......
...@@ -79,7 +79,13 @@ def makediff(new, mirror, incpref): ...@@ -79,7 +79,13 @@ def makediff(new, mirror, incpref):
if compress: diff = get_inc(incpref, "diff.gz") if compress: diff = get_inc(incpref, "diff.gz")
else: diff = get_inc(incpref, "diff") else: diff = get_inc(incpref, "diff")
Rdiff.write_delta(new, mirror, diff, compress) if Globals.process_uid != 0 and not new.readable():
# Check for unreadable files
old_new_perms = new.getperms()
new.chmod(0400 | old_new_perms)
Rdiff.write_delta(new, mirror, diff, compress)
new.chmod(old_new_perms)
else: Rdiff.write_delta(new, mirror, diff, compress)
rpath.copy_attribs(mirror, diff) rpath.copy_attribs(mirror, diff)
return diff return diff
......
...@@ -885,6 +885,14 @@ class RPath(RORPath): ...@@ -885,6 +885,14 @@ class RPath(RORPath):
raise RPathException("Error closing file") raise RPathException("Error closing file")
self.setdata() self.setdata()
def write_string(self, s, compress = None):
"""Write string s into rpath"""
assert not self.lstat(), "File %s already exists" % (self.path,)
outfp = self.open("wb", compress = compress)
outfp.write(s)
assert not outfp.close()
self.setdata()
def isincfile(self): def isincfile(self):
"""Return true if path looks like an increment file """Return true if path looks like an increment file
......
...@@ -2,15 +2,19 @@ import unittest, os ...@@ -2,15 +2,19 @@ import unittest, os
from commontest import * from commontest import *
from rdiff_backup import Globals, log from rdiff_backup import Globals, log
"""Root tests """Root tests - contain tests which need to be run as root.
Some of the quoting here may not work with csh (works on bash). Also,
if you aren't me, check out the 'user' global variable.
This is mainly a copy of regressiontest.py, but contains the two tests
that are meant to be run as root.
""" """
Globals.set('change_source_perms', None) Globals.set('change_source_perms', None)
Globals.counter = 0 Globals.counter = 0
log.Log.setverbosity(6) verbosity = 3
log.Log.setverbosity(verbosity)
user = 'ben' # Non-root user to su to
assert os.getuid() == 0, "Run this test as root!"
def Run(cmd): def Run(cmd):
print "Running: ", cmd print "Running: ", cmd
...@@ -24,6 +28,56 @@ class RootTest(unittest.TestCase): ...@@ -24,6 +28,56 @@ class RootTest(unittest.TestCase):
def testLocal2(self): BackupRestoreSeries(1, 1, self.dirlist2) def testLocal2(self): BackupRestoreSeries(1, 1, self.dirlist2)
def testRemote(self): BackupRestoreSeries(None, None, self.dirlist1) def testRemote(self): BackupRestoreSeries(None, None, self.dirlist1)
class HalfRoot(unittest.TestCase):
"""Backing up files where origin is root and destination is non-root"""
def make_dirs(self):
"""Make source directories, return rpaths
These make a directory with a changing file that is not
self-readable. (Caused problems earlier.)
"""
rp1 = rpath.RPath(Globals.local_connection, "testfiles/root_half1")
if rp1.lstat(): Myrm(rp1.path)
rp1.mkdir()
rp1_1 = rp1.append('foo')
rp1_1.write_string('hello')
rp1_1.chmod(0)
rp1_2 = rp1.append('to be deleted')
rp1_2.write_string('aosetuhaosetnuhontu')
rp1_2.chmod(0)
rp2 = rpath.RPath(Globals.local_connection, "testfiles/root_half2")
if rp2.lstat(): Myrm(rp2.path)
rp2.mkdir()
rp2_1 = rp2.append('foo')
rp2_1.write_string('goodbye')
rp2_1.chmod(0)
return rp1, rp2
def test_backup(self):
"""Right now just test backing up"""
in_rp1, in_rp2 = self.make_dirs()
outrp = rpath.RPath(Globals.local_connection, "testfiles/output")
if outrp.lstat(): outrp.delete()
remote_schema = 'su -c "rdiff-backup --server" %s' % (user,)
cmd_schema = ("rdiff-backup -v" + str(verbosity) +
" --current-time %s --remote-schema '%%s' %s '%s'::%s")
cmd1 = cmd_schema % (10000, in_rp1.path, remote_schema, outrp.path)
print "Executing: ", cmd1
assert not os.system(cmd1)
in_rp1.setdata()
outrp.setdata()
assert CompareRecursive(in_rp1, outrp)
cmd2 = cmd_schema % (20000, in_rp2.path, remote_schema, outrp.path)
print "Executing: ", cmd2
assert not os.system(cmd2)
in_rp2.setdata()
outrp.setdata()
assert CompareRecursive(in_rp2, outrp)
class NonRoot(unittest.TestCase): class NonRoot(unittest.TestCase):
"""Test backing up as non-root user """Test backing up as non-root user
...@@ -32,7 +86,6 @@ class NonRoot(unittest.TestCase): ...@@ -32,7 +86,6 @@ class NonRoot(unittest.TestCase):
root, everything should be restored normally. root, everything should be restored normally.
""" """
user = 'ben'
def make_root_dirs(self): def make_root_dirs(self):
"""Make directory createable only by root""" """Make directory createable only by root"""
rp = rpath.RPath(Globals.local_connection, "testfiles/root_out1") rp = rpath.RPath(Globals.local_connection, "testfiles/root_out1")
...@@ -61,10 +114,11 @@ class NonRoot(unittest.TestCase): ...@@ -61,10 +114,11 @@ class NonRoot(unittest.TestCase):
return rp, sp return rp, sp
def backup(self, input_rp, output_rp, time): def backup(self, input_rp, output_rp, time):
global user
backup_cmd = ("rdiff-backup --no-compare-inode " backup_cmd = ("rdiff-backup --no-compare-inode "
"--current-time %s %s %s" % "--current-time %s %s %s" %
(time, input_rp.path, output_rp.path)) (time, input_rp.path, output_rp.path))
Run("su %s -c '%s'" % (self.user, backup_cmd)) Run("su %s -c '%s'" % (user, backup_cmd))
def restore(self, dest_rp, restore_rp, time = None): def restore(self, dest_rp, restore_rp, time = None):
assert restore_rp.path == "testfiles/rest_out" assert restore_rp.path == "testfiles/rest_out"
......
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