Commit 70835e69 authored by bescoto's avatar bescoto

Yet another change dealing with unreadable directories


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@431 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent d629acfc
......@@ -53,9 +53,6 @@ process_gid = os.getgid()
# If true, when copying attributes, also change target's uid/gid
change_ownership = None
# If true, when copying attributes, also change target's permission.
change_permissions = 1
# If true, change the permissions of unwriteable mirror files
# (such as directories) so that they can be written, and then
# change them back. This defaults to 1 just in case the process
......
......@@ -288,7 +288,6 @@ def backup_set_rbdir(rpin, rpout):
assert rpout.lstat(), (rpout.path, rpout.lstat())
if rpout.isdir() and not rpout.listdir(): # rpout is empty dir
if Globals.change_permissions:
rpout.chmod(0700) # just make sure permissions aren't too lax
elif not Globals.rbdir.lstat() and not force: Log.FatalError(
"""Destination directory
......
......@@ -234,7 +234,7 @@ static.MakeClass(DestinationStruct)
class CacheCollatedPostProcess:
"""Cache a collated iter of (source_rorp, dest_rorp) pairs
This is necessary for two reasons:
This is necessary for three reasons:
1. The patch function may need the original source_rorp or
dest_rp information, which is not present in the diff it
......@@ -247,6 +247,11 @@ class CacheCollatedPostProcess:
any metadata until we know the file has been procesed
correctly.
3. We may lack permissions on certain destination directories.
The permissions of these directories need to be relaxed before
we enter them to computer signatures, and then reset after we
are done patching everything inside them.
The class caches older source_rorps and dest_rps so the patch
function can retrieve them if necessary. The patch function can
also update the processed correctly flag. When an item falls out
......@@ -281,6 +286,11 @@ class CacheCollatedPostProcess:
self.cache_dict = {}
self.cache_indicies = []
# Contains a list of pairs (destination_rps, permissions) to
# be used to reset the permissions of certain directories
# after we're finished with them
self.dir_perms_list = []
def __iter__(self): return self
def next(self):
......@@ -304,10 +314,21 @@ class CacheCollatedPostProcess:
"""
if source_rorp: Hardlink.add_rorp(source_rorp, source = 1)
if dest_rorp: Hardlink.add_rorp(dest_rorp, source = 0)
if (dest_rorp and dest_rorp.isdir() and Globals.process_uid != 0 and
dest_rorp.getperms() % 01000 < 0700):
if (dest_rorp and dest_rorp.isdir() and Globals.process_uid != 0
and dest_rorp.getperms() % 01000 < 0700):
self.unreadable_dir_init(source_rorp, dest_rorp)
def unreadable_dir_init(self, source_rorp, dest_rorp):
"""Initialize an unreadable dir.
Make it readable, and if necessary, store the old permissions
in self.dir_perms_list so the old perms can be restored.
"""
dest_rp = self.dest_root_rp.new_index(dest_rorp.index)
dest_rp.chmod(0700 | dest_rorp.getperms())
if source_rorp and source_rorp.isdir():
self.dir_perms_list.append((dest_rp, source_rorp.getperms()))
def shorten_cache(self):
"""Remove one element from cache, possibly adding it to metadata"""
......@@ -322,6 +343,7 @@ class CacheCollatedPostProcess:
del self.cache_dict[first_index]
self.post_process(old_source_rorp, old_dest_rorp,
changed_flag, success_flag, inc)
if self.dir_perms_list: self.reset_dir_perms(first_index)
def post_process(self, source_rorp, dest_rorp, changed, success, inc):
"""Post process source_rorp and dest_rorp.
......@@ -352,12 +374,13 @@ class CacheCollatedPostProcess:
if Globals.file_statistics:
statistics.FileStats.update(source_rorp, dest_rorp, changed, inc)
# Update permissions of unreadable directory
if (source_rorp and source_rorp.isdir() and Globals.process_uid != 0
and success and source_rorp.getperms() % 01000 < 0700):
dest_rp = self.dest_root_rp.new_index(source_rorp.index)
assert dest_rp.isdir(), dest_rp
dest_rp.chmod(source_rorp.getperms())
def reset_dir_perms(self, current_index):
"""Reset the permissions of directories when we have left them"""
dir_rp, perms = self.dir_perms_list[-1]
dir_index = dir_rp.index
if (current_index > dir_index and
current_index[:len(dir_index)] != dir_index):
dir_rp.chmod(perms) # out of directory, reset perms now
def in_cache(self, index):
"""Return true if given index is cached"""
......@@ -506,6 +529,7 @@ class PatchITRB(rorpiter.ITRBranch):
"""Set self.dir_replacement, which holds data until done with dir
This is used when base_rp is a dir, and diff_rorp is not.
Returns 1 for success or 0 for failure
"""
assert diff_rorp.get_attached_filetype() == 'snapshot'
......@@ -515,10 +539,8 @@ class PatchITRB(rorpiter.ITRBranch):
# Was an error, so now restore original directory
rpath.copy_with_attribs(self.CCPP.get_mirror_rorp(diff_rorp.index),
self.dir_replacement)
success = 0
else: success = 1
if base_rp.isdir() and Globals.change_permissions: base_rp.chmod(0700)
return success
return 0
else: return 1
def prepare_dir(self, diff_rorp, base_rp):
"""Prepare base_rp to turn into a directory"""
......@@ -530,7 +552,6 @@ class PatchITRB(rorpiter.ITRBranch):
else: # maybe no change, so query CCPP before tagging success
if self.CCPP.in_cache(diff_rorp.index):
self.CCPP.flag_success(diff_rorp.index)
if Globals.change_permissions: base_rp.chmod(0700)
def end_process(self):
"""Finish processing directory"""
......
......@@ -249,8 +249,7 @@ class RegressITRB(rorpiter.ITRBranch):
if not rf.mirror_rp.isdir():
if rf.mirror_rp.lstat(): rf.mirror_rp.delete()
rf.mirror_rp.mkdir()
if Globals.change_permissions and not rf.mirror_rp.hasfullperms():
rf.mirror_rp.chmod(0700)
if not rf.mirror_rp.hasfullperms(): rf.mirror_rp.chmod(0700)
self.rf = rf
def end_process(self):
......
......@@ -582,7 +582,7 @@ class PatchITRB(rorpiter.ITRBranch):
assert diff_rorp.get_attached_filetype() == 'snapshot'
self.dir_replacement = TempFile.new(base_rp)
rpath.copy_with_attribs(diff_rorp, self.dir_replacement)
if base_rp.isdir() and Globals.change_permissions: base_rp.chmod(0700)
if base_rp.isdir(): base_rp.chmod(0700)
def prepare_dir(self, diff_rorp, base_rp):
"""Prepare base_rp to turn into a directory"""
......@@ -590,7 +590,7 @@ class PatchITRB(rorpiter.ITRBranch):
if not base_rp.isdir():
if base_rp.lstat(): base_rp.delete()
base_rp.mkdir()
if Globals.change_permissions: base_rp.chmod(0700)
base_rp.chmod(0700)
def end_process(self):
"""Finish processing directory"""
......
......@@ -157,7 +157,7 @@ def copy_attribs(rpin, rpout, acls = 1):
rpout.write_resource_fork(rpin.get_resource_fork())
if Globals.write_eas: rpout.write_ea(rpin.get_ea())
if Globals.change_ownership: apply(rpout.chown, rpin.getuidgid())
if Globals.change_permissions: rpout.chmod(rpin.getperms())
rpout.chmod(rpin.getperms())
if Globals.write_acls and acls: rpout.write_acl(rpin.get_acl())
if not rpin.isdev(): rpout.setmtime(rpin.getmtime())
......@@ -267,7 +267,6 @@ class RORPath:
for key in self.data.keys(): # compare dicts key by key
if (key == 'uid' or key == 'gid') and self.issym():
pass # Don't compare gid/uid for symlinks
elif key == 'perms' and not Globals.change_permissions: pass
elif key == 'atime' and not Globals.preserve_atime: pass
elif key == 'ctime': pass
elif key == 'devloc' or key == 'nlink': pass
......@@ -306,7 +305,6 @@ class RORPath:
elif key == 'ctime': pass
elif key == 'devloc' or key == 'nlink': pass
elif key == 'size' and not self.isreg(): pass
elif key == 'perms' and not Globals.change_permissions: pass
elif key == 'inode': pass
elif key == 'ea' and not Globals.write_eas: pass
elif key == 'acl' and not Globals.write_acls: pass
......@@ -329,7 +327,6 @@ class RORPath:
(self.issym() or not compare_ownership)):
# Don't compare gid/uid for symlinks, or if told not to
pass
elif key == 'perms' and not Globals.change_permissions: pass
elif key == 'atime' and not Globals.preserve_atime: pass
elif key == 'ctime': pass
elif key == 'devloc' or key == 'nlink': pass
......
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