From 8008228b940bd8c28a7ae8ee1c2568cb2127f1d1 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 27 Feb 2012 02:46:31 +0100 Subject: [PATCH] samba.xattr: Massively simplify copytree_with_xattrs. --- source4/scripting/bin/upgradeprovision | 2 +- source4/scripting/python/samba/tests/xattr.py | 25 ++++- source4/scripting/python/samba/xattr.py | 98 +++++++------------ 3 files changed, 59 insertions(+), 66 deletions(-) diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 8066ac38d48..7003717b4e1 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -1471,7 +1471,7 @@ def backup_provision(paths, dir): :param paths: Paths to different objects :param dir: Directory where to store the backup """ - if paths.sysvol is not None: + if paths.sysvol: copytree_with_xattrs(paths.sysvol, os.path.join(dir, "sysvol")) shutil.copy2(paths.samdb, dir) shutil.copy2(paths.secrets, dir) diff --git a/source4/scripting/python/samba/tests/xattr.py b/source4/scripting/python/samba/tests/xattr.py index 7b4627fdad9..1f325322fa2 100644 --- a/source4/scripting/python/samba/tests/xattr.py +++ b/source4/scripting/python/samba/tests/xattr.py @@ -20,10 +20,16 @@ """Tests for samba.xattr_native and samba.xattr_tdb.""" import samba.xattr_native, samba.xattr_tdb +from samba.xattr import copytree_with_xattrs from samba.dcerpc import xattr from samba.ndr import ndr_pack -from samba.tests import TestCase, TestSkipped +from samba.tests import ( + TestCase, + TestCaseInTempDir, + TestSkipped, + ) import random +import shutil import os class XattrTests(TestCase): @@ -103,3 +109,20 @@ class XattrTests(TestCase): finally: os.unlink(tempf) os.unlink(eadb_path) + + +class TestCopyTreeWithXattrs(TestCaseInTempDir): + + def test_simple(self): + os.chdir(self.tempdir) + os.mkdir("a") + os.mkdir("a/b") + os.mkdir("a/b/c") + f = open('a/b/c/d', 'w') + try: + f.write("foo") + finally: + f.close() + copytree_with_xattrs("a", "b") + shutil.rmtree("a") + shutil.rmtree("b") diff --git a/source4/scripting/python/samba/xattr.py b/source4/scripting/python/samba/xattr.py index 55ae0416759..1c53ae810db 100644 --- a/source4/scripting/python/samba/xattr.py +++ b/source4/scripting/python/samba/xattr.py @@ -3,7 +3,6 @@ # # Utility code for dealing with POSIX extended attributes # -# Copyright (C) Matthieu Patou 2009 - 2010 # Copyright (C) Jelmer Vernooij 2012 # # This program is free software; you can redistribute it and/or modify @@ -25,70 +24,41 @@ import samba.xattr_native import shutil -def copytree_with_xattrs(source, target): - """Copy a tree but preserve extended attributes. - - :param source: Source tree path - :param target: Target path - """ - shutil.copytree(source, target) - copyxattrs(target, source) +def copyattrs(frompath, topath): + """Copy ACL related attributes from a path to another path.""" + for attr_name in (xattr.XATTR_NTACL_NAME, "system.posix_acl_access"): + # Get the xattr attributes if any + try: + attribute = samba.xattr_native.wrap_getxattr(frompath, + xattr.XATTR_NTACL_NAME) + samba.xattr_native.wrap_setxattr(topath, + xattr.XATTR_NTACL_NAME, + attribute) + except Exception: + pass + # FIXME:Catch a specific exception -def copyxattrs(dir, refdir): - """Copy extended attributes from a reference dir to a destination dir +def copytree_with_xattrs(src, dst): + """Recursively copy a directory tree using shutil.copy2(), preserving xattrs. - Both dir are supposed to hold the same files - :param dir: Destination dir - :param refdir: Reference directory""" - - for root, dirs, files in os.walk(dir, topdown=True): - for name in files: - subdir = root[len(dir):] - ref = os.path.join(refdir, subdir, name) - statsinfo = os.stat(ref) - tgt = os.path.join(root, name) - try: - os.chown(tgt, statsinfo.st_uid, statsinfo.st_gid) - # Get the xattr attributes if any - try: - attribute = samba.xattr_native.wrap_getxattr(ref, - xattr.XATTR_NTACL_NAME) - samba.xattr_native.wrap_setxattr(tgt, - xattr.XATTR_NTACL_NAME, - attribute) - except Exception: - pass - # FIXME:Catch a specific exception - attribute = samba.xattr_native.wrap_getxattr(ref, - "system.posix_acl_access") - samba.xattr_native.wrap_setxattr(tgt, - "system.posix_acl_access", - attribute) - except Exception: - # FIXME: Catch a specific exception - continue - for name in dirs: - subdir = root[len(dir):] - ref = os.path.join(refdir, subdir, name) - statsinfo = os.stat(ref) - tgt = os.path.join(root, name) - try: - os.chown(os.path.join(root, name), statsinfo.st_uid, - statsinfo.st_gid) - try: - attribute = samba.xattr_native.wrap_getxattr(ref, - xattr.XATTR_NTACL_NAME) - samba.xattr_native.wrap_setxattr(tgt, - xattr.XATTR_NTACL_NAME, - attribute) - except Exception: - pass # FIXME: Catch a specific exception - attribute = samba.xattr_native.wrap_getxattr(ref, - "system.posix_acl_access") - samba.xattr_native.wrap_setxattr(tgt, - "system.posix_acl_access", - attribute) + The destination directory must not already exist. + If exception(s) occur, an Error is raised with a list of reasons. + """ + names = os.listdir(src) - except Exception: - continue + os.makedirs(dst) + errors = [] + for name in names: + srcname = os.path.join(src, name) + dstname = os.path.join(dst, name) + if os.path.islink(srcname): + linkto = os.readlink(srcname) + os.symlink(linkto, dstname) + elif os.path.isdir(srcname): + copytree_with_xattrs(srcname, dstname) + else: + # Will raise a SpecialFileError for unsupported file types + shutil.copy2(srcname, dstname) + shutil.copystat(src, dst) + copyattrs(src, dst) -- 2.34.1