Commit 6d6a48ad authored by bescoto's avatar bescoto

Added lchown to cmodule so rdiff-backup can preserve symlink uid/gid


git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup@606 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109
parent 8cf39d7e
...@@ -43,6 +43,9 @@ posix1e module. ...@@ -43,6 +43,9 @@ posix1e module.
bug#13613: Fix for overflow error that could happen when backing up bug#13613: Fix for overflow error that could happen when backing up
files with dates far in the future on a 64bit machine to a 32 bit one. files with dates far in the future on a 64bit machine to a 32 bit one.
Symlink ownership should be preserved now. Reported by Naoki
Takebayashi and others.
New in v0.13.6 (2005/04/07) New in v0.13.6 (2005/04/07)
--------------------------- ---------------------------
......
...@@ -368,6 +368,36 @@ static PyObject *acl_unquote(PyObject *self, PyObject *args) ...@@ -368,6 +368,36 @@ static PyObject *acl_unquote(PyObject *self, PyObject *args)
return Py_BuildValue("s", unquote(s)); return Py_BuildValue("s", unquote(s));
} }
/* ------------- lchown taken from Python's posixmodule.c -------------- */
/* duplicate here to avoid v2.3 requirement */
static PyObject *
posix_error_with_allocated_filename(char* name)
{
PyObject *rc = PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);
PyMem_Free(name);
return rc;
}
static PyObject *
posix_lchown(PyObject *self, PyObject *args)
{
char *path = NULL;
int uid, gid;
int res;
if (!PyArg_ParseTuple(args, "etii:lchown",
Py_FileSystemDefaultEncoding, &path,
&uid, &gid))
return NULL;
Py_BEGIN_ALLOW_THREADS
res = lchown(path, (uid_t) uid, (gid_t) gid);
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error_with_allocated_filename(path);
PyMem_Free(path);
Py_INCREF(Py_None);
return Py_None;
}
/* ------------- Python export lists -------------------------------- */ /* ------------- Python export lists -------------------------------- */
...@@ -381,6 +411,8 @@ static PyMethodDef CMethods[] = { ...@@ -381,6 +411,8 @@ static PyMethodDef CMethods[] = {
"Quote string, escaping non-printables"}, "Quote string, escaping non-printables"},
{"acl_unquote", acl_unquote, METH_VARARGS, {"acl_unquote", acl_unquote, METH_VARARGS,
"Unquote string, producing original input to quote"}, "Unquote string, producing original input to quote"},
{"lchown", posix_lchown, METH_VARARGS,
"Like chown, but don't follow symlinks"},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };
......
...@@ -152,13 +152,13 @@ def copy_attribs(rpin, rpout): ...@@ -152,13 +152,13 @@ def copy_attribs(rpin, rpout):
""" """
log.Log("Copying attributes from %s to %s" % (rpin.index, rpout.path), 7) log.Log("Copying attributes from %s to %s" % (rpin.index, rpout.path), 7)
assert rpin.lstat() == rpout.lstat() or rpin.isspecial() assert rpin.lstat() == rpout.lstat() or rpin.isspecial()
if rpin.issym(): return # symlinks have no valid attributes if Globals.change_ownership: rpout.chown(*user_group.map_rpath(rpin))
if rpin.issym(): return # symlinks don't have times or perms
if Globals.resource_forks_write and rpin.isreg(): if Globals.resource_forks_write and rpin.isreg():
rpout.write_resource_fork(rpin.get_resource_fork()) rpout.write_resource_fork(rpin.get_resource_fork())
if Globals.carbonfile_write and rpin.isreg(): if Globals.carbonfile_write and rpin.isreg():
rpout.write_carbonfile(rpin.get_carbonfile()) rpout.write_carbonfile(rpin.get_carbonfile())
if Globals.eas_write: 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()) rpout.chmod(rpin.getperms())
if Globals.acls_write: rpout.write_acl(rpin.get_acl()) if Globals.acls_write: rpout.write_acl(rpin.get_acl())
if not rpin.isdev(): rpout.setmtime(rpin.getmtime()) if not rpin.isdev(): rpout.setmtime(rpin.getmtime())
...@@ -173,13 +173,13 @@ def copy_attribs_inc(rpin, rpout): ...@@ -173,13 +173,13 @@ def copy_attribs_inc(rpin, rpout):
""" """
log.Log("Copying inc attrs from %s to %s" % (rpin.index, rpout.path), 7) log.Log("Copying inc attrs from %s to %s" % (rpin.index, rpout.path), 7)
check_for_files(rpin, rpout) check_for_files(rpin, rpout)
if rpin.issym(): return # symlinks have no valid attributes if Globals.change_ownership: apply(rpout.chown, rpin.getuidgid())
if rpin.issym(): return # symlinks don't have times or perms
if Globals.resource_forks_write 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()) rpout.write_resource_fork(rpin.get_resource_fork())
if Globals.carbonfile_write and rpin.isreg() and rpout.isreg(): if Globals.carbonfile_write and rpin.isreg() and rpout.isreg():
rpout.write_carbonfile(rpin.get_carbonfile()) rpout.write_carbonfile(rpin.get_carbonfile())
if Globals.eas_write: 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(): if rpin.isdir() and not rpout.isdir():
rpout.chmod(rpin.getperms() & 0777) rpout.chmod(rpin.getperms() & 0777)
else: rpout.chmod(rpin.getperms()) else: rpout.chmod(rpin.getperms())
...@@ -775,7 +775,7 @@ class RPath(RORPath): ...@@ -775,7 +775,7 @@ class RPath(RORPath):
def chown(self, uid, gid): def chown(self, uid, gid):
"""Set file's uid and gid""" """Set file's uid and gid"""
self.conn.os.chown(self.path, uid, gid) self.conn.C.lchown(self.path, uid, gid)
self.data['uid'] = uid self.data['uid'] = uid
self.data['gid'] = gid self.data['gid'] = gid
......
...@@ -245,7 +245,6 @@ other::---""") ...@@ -245,7 +245,6 @@ other::---""")
new_acl = AccessControlLists(()) new_acl = AccessControlLists(())
tempdir.chmod(0700) tempdir.chmod(0700)
new_acl.read_from_rp(tempdir) new_acl.read_from_rp(tempdir)
print "@", new_acl
assert new_acl.is_basic(), str(new_acl) assert new_acl.is_basic(), str(new_acl)
assert not new_acl == self.sample_acl assert not new_acl == self.sample_acl
assert new_acl != self.sample_acl assert new_acl != self.sample_acl
......
...@@ -39,6 +39,9 @@ class RootTest(unittest.TestCase): ...@@ -39,6 +39,9 @@ class RootTest(unittest.TestCase):
This checks for a bug in 0.13.4 where uids and gids would not This checks for a bug in 0.13.4 where uids and gids would not
be restored correctly. be restored correctly.
Also test to make sure symlinks get the right ownership.
(Earlier symlink ownership was not preserved.)
""" """
dirrp = rpath.RPath(Globals.local_connection, "testfiles/root_owner") dirrp = rpath.RPath(Globals.local_connection, "testfiles/root_owner")
def make_dir(): def make_dir():
...@@ -47,17 +50,25 @@ class RootTest(unittest.TestCase): ...@@ -47,17 +50,25 @@ class RootTest(unittest.TestCase):
rp2 = dirrp.append('file2') rp2 = dirrp.append('file2')
rp3 = dirrp.append('file3') rp3 = dirrp.append('file3')
rp4 = dirrp.append('file4') rp4 = dirrp.append('file4')
rp5 = dirrp.append('symlink')
rp1.touch() rp1.touch()
rp2.touch() rp2.touch()
rp3.touch() rp3.touch()
rp4.touch() rp4.touch()
rp5.symlink('foobar')
rp1.chown(2000, 2000) rp1.chown(2000, 2000)
rp2.chown(2001, 2001) rp2.chown(2001, 2001)
rp3.chown(2002, 2002) rp3.chown(2002, 2002)
rp4.chown(2003, 2003) rp4.chown(2003, 2003)
rp5.chown(2004, 2004)
make_dir() make_dir()
BackupRestoreSeries(1, 1, ['testfiles/root_owner', 'testfiles/empty'], BackupRestoreSeries(1, 1, ['testfiles/root_owner', 'testfiles/empty',
'testfiles/root_owner'],
compare_ownership = 1) compare_ownership = 1)
symrp = rpath.RPath(Globals.local_connection,
'testfiles/output/symlink')
assert symrp.issym(), symrp
assert symrp.getuidgid() == (2004, 2004), symrp.getuidgid()
def test_ownership_mapping(self): def test_ownership_mapping(self):
"""Test --user-mapping-file and --group-mapping-file options""" """Test --user-mapping-file and --group-mapping-file options"""
......
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