summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbescoto <bescoto@2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109>2003-08-23 23:42:57 +0000
committerbescoto <bescoto@2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109>2003-08-23 23:42:57 +0000
commit94da66c4015094e2c5a71e945ef3562644543c0f (patch)
tree9c658f51d1259e0427f131a4b8001b5ebef97eab
parent9c8889d79e47e88564cd636efa050243be69ead5 (diff)
downloadrdiff-backup-94da66c4015094e2c5a71e945ef3562644543c0f.tar.gz
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/trunk@399 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
-rw-r--r--rdiff-backup/CHANGELOG4
-rw-r--r--rdiff-backup/rdiff_backup/Main.py2
-rw-r--r--rdiff-backup/rdiff_backup/backup.py23
-rw-r--r--rdiff-backup/rdiff_backup/increment.py8
-rw-r--r--rdiff-backup/rdiff_backup/rpath.py8
-rw-r--r--rdiff-backup/testing/roottest.py66
6 files changed, 98 insertions, 13 deletions
diff --git a/rdiff-backup/CHANGELOG b/rdiff-backup/CHANGELOG
index 98f2e5f..71c1e07 100644
--- a/rdiff-backup/CHANGELOG
+++ b/rdiff-backup/CHANGELOG
@@ -4,6 +4,10 @@ New in v0.13.2 (??????????)
Specified socket type as SOCK_STREAM. (Error reported by Erik
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)
---------------------------
diff --git a/rdiff-backup/rdiff_backup/Main.py b/rdiff-backup/rdiff_backup/Main.py
index e8167d6..638f137 100644
--- a/rdiff-backup/rdiff_backup/Main.py
+++ b/rdiff-backup/rdiff_backup/Main.py
@@ -423,8 +423,10 @@ def restore_set_fs_globals(target):
target_fsa = fs_abilities.FSAbilities('destination').init_readwrite(
target, 0)
+ Log(str(target_fsa), 3)
mirror_fsa = fs_abilities.FSAbilities('source').init_readwrite(
Globals.rbdir)
+ Log(str(mirror_fsa), 3)
update_bool_global('read_acls', target_fsa.acls)
update_bool_global('write_acls', target_fsa.acls)
diff --git a/rdiff-backup/rdiff_backup/backup.py b/rdiff-backup/rdiff_backup/backup.py
index 33e97bf..0909722 100644
--- a/rdiff-backup/rdiff_backup/backup.py
+++ b/rdiff-backup/rdiff_backup/backup.py
@@ -184,15 +184,26 @@ class DestinationStruct:
elif dest_rorp:
dest_sig = dest_rorp.getRORPath()
if dest_rorp.isreg():
- dest_rp = dest_base_rpath.new_index(index)
- if not dest_rp.isreg():
- log.ErrorLog.write_if_open("UpdateError", dest_rp,
- "File changed from regular file before signature")
- return None
- dest_sig.setfile(Rdiff.get_signature(dest_rp))
+ sig_fp = cls.get_one_sig_fp(dest_base_rpath.new_index(index))
+ if sig_fp is None: return None
+ dest_sig.setfile(sig_fp)
else: dest_sig = rpath.RORPath(index)
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 = ()):
"""Patch dest_rpath with an rorpiter of diffs"""
ITR = rorpiter.IterTreeReducer(PatchITRB, [dest_rpath, cls.CCPP])
diff --git a/rdiff-backup/rdiff_backup/increment.py b/rdiff-backup/rdiff_backup/increment.py
index 8d829e2..ea7a81d 100644
--- a/rdiff-backup/rdiff_backup/increment.py
+++ b/rdiff-backup/rdiff_backup/increment.py
@@ -79,7 +79,13 @@ def makediff(new, mirror, incpref):
if compress: diff = get_inc(incpref, "diff.gz")
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)
return diff
diff --git a/rdiff-backup/rdiff_backup/rpath.py b/rdiff-backup/rdiff_backup/rpath.py
index 247dc40..43f14e3 100644
--- a/rdiff-backup/rdiff_backup/rpath.py
+++ b/rdiff-backup/rdiff_backup/rpath.py
@@ -885,6 +885,14 @@ class RPath(RORPath):
raise RPathException("Error closing file")
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):
"""Return true if path looks like an increment file
diff --git a/rdiff-backup/testing/roottest.py b/rdiff-backup/testing/roottest.py
index 6193893..ab0c580 100644
--- a/rdiff-backup/testing/roottest.py
+++ b/rdiff-backup/testing/roottest.py
@@ -2,15 +2,19 @@ import unittest, os
from commontest import *
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.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):
print "Running: ", cmd
@@ -24,6 +28,56 @@ class RootTest(unittest.TestCase):
def testLocal2(self): BackupRestoreSeries(1, 1, self.dirlist2)
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):
"""Test backing up as non-root user
@@ -32,7 +86,6 @@ class NonRoot(unittest.TestCase):
root, everything should be restored normally.
"""
- user = 'ben'
def make_root_dirs(self):
"""Make directory createable only by root"""
rp = rpath.RPath(Globals.local_connection, "testfiles/root_out1")
@@ -61,10 +114,11 @@ class NonRoot(unittest.TestCase):
return rp, sp
def backup(self, input_rp, output_rp, time):
+ global user
backup_cmd = ("rdiff-backup --no-compare-inode "
"--current-time %s %s %s" %
(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):
assert restore_rp.path == "testfiles/rest_out"