From ac41194deb402b5611a624be6837e8527a0fd592 Mon Sep 17 00:00:00 2001 From: bescoto Date: Thu, 11 Aug 2005 03:34:03 +0000 Subject: Added lchown to cmodule so rdiff-backup can preserve symlink uid/gid git-svn-id: http://svn.savannah.nongnu.org/svn/rdiff-backup/trunk@606 2b77aa54-bcbc-44c9-a7ec-4f6cf2b41109 --- rdiff-backup/CHANGELOG | 3 +++ rdiff-backup/rdiff_backup/cmodule.c | 32 ++++++++++++++++++++++++++++++++ rdiff-backup/rdiff_backup/rpath.py | 10 +++++----- rdiff-backup/testing/eas_aclstest.py | 1 - rdiff-backup/testing/roottest.py | 13 ++++++++++++- 5 files changed, 52 insertions(+), 7 deletions(-) diff --git a/rdiff-backup/CHANGELOG b/rdiff-backup/CHANGELOG index 730b483..ae81a47 100644 --- a/rdiff-backup/CHANGELOG +++ b/rdiff-backup/CHANGELOG @@ -43,6 +43,9 @@ posix1e module. 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. +Symlink ownership should be preserved now. Reported by Naoki +Takebayashi and others. + New in v0.13.6 (2005/04/07) --------------------------- diff --git a/rdiff-backup/rdiff_backup/cmodule.c b/rdiff-backup/rdiff_backup/cmodule.c index 6fafde7..f6a44a3 100644 --- a/rdiff-backup/rdiff_backup/cmodule.c +++ b/rdiff-backup/rdiff_backup/cmodule.c @@ -368,6 +368,36 @@ static PyObject *acl_unquote(PyObject *self, PyObject *args) 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 -------------------------------- */ @@ -381,6 +411,8 @@ static PyMethodDef CMethods[] = { "Quote string, escaping non-printables"}, {"acl_unquote", acl_unquote, METH_VARARGS, "Unquote string, producing original input to quote"}, + {"lchown", posix_lchown, METH_VARARGS, + "Like chown, but don't follow symlinks"}, {NULL, NULL, 0, NULL} }; diff --git a/rdiff-backup/rdiff_backup/rpath.py b/rdiff-backup/rdiff_backup/rpath.py index 0b17934..2816c91 100644 --- a/rdiff-backup/rdiff_backup/rpath.py +++ b/rdiff-backup/rdiff_backup/rpath.py @@ -152,13 +152,13 @@ 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.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(): rpout.write_resource_fork(rpin.get_resource_fork()) if Globals.carbonfile_write and rpin.isreg(): rpout.write_carbonfile(rpin.get_carbonfile()) 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.acls_write: rpout.write_acl(rpin.get_acl()) if not rpin.isdev(): rpout.setmtime(rpin.getmtime()) @@ -173,13 +173,13 @@ 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.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(): rpout.write_resource_fork(rpin.get_resource_fork()) if Globals.carbonfile_write and rpin.isreg() and rpout.isreg(): rpout.write_carbonfile(rpin.get_carbonfile()) 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()) @@ -775,7 +775,7 @@ class RPath(RORPath): def chown(self, uid, 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['gid'] = gid diff --git a/rdiff-backup/testing/eas_aclstest.py b/rdiff-backup/testing/eas_aclstest.py index a595cfe..4d6535f 100644 --- a/rdiff-backup/testing/eas_aclstest.py +++ b/rdiff-backup/testing/eas_aclstest.py @@ -245,7 +245,6 @@ other::---""") new_acl = AccessControlLists(()) tempdir.chmod(0700) new_acl.read_from_rp(tempdir) - print "@", new_acl assert new_acl.is_basic(), str(new_acl) assert not new_acl == self.sample_acl assert new_acl != self.sample_acl diff --git a/rdiff-backup/testing/roottest.py b/rdiff-backup/testing/roottest.py index 11da994..4950993 100644 --- a/rdiff-backup/testing/roottest.py +++ b/rdiff-backup/testing/roottest.py @@ -39,6 +39,9 @@ class RootTest(unittest.TestCase): This checks for a bug in 0.13.4 where uids and gids would not 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") def make_dir(): @@ -47,17 +50,25 @@ class RootTest(unittest.TestCase): rp2 = dirrp.append('file2') rp3 = dirrp.append('file3') rp4 = dirrp.append('file4') + rp5 = dirrp.append('symlink') rp1.touch() rp2.touch() rp3.touch() rp4.touch() + rp5.symlink('foobar') rp1.chown(2000, 2000) rp2.chown(2001, 2001) rp3.chown(2002, 2002) rp4.chown(2003, 2003) + rp5.chown(2004, 2004) make_dir() - BackupRestoreSeries(1, 1, ['testfiles/root_owner', 'testfiles/empty'], + BackupRestoreSeries(1, 1, ['testfiles/root_owner', 'testfiles/empty', + 'testfiles/root_owner'], 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): """Test --user-mapping-file and --group-mapping-file options""" -- cgit v1.2.1