samba.xattr: Massively simplify copytree_with_xattrs.
authorJelmer Vernooij <jelmer@samba.org>
Mon, 27 Feb 2012 01:46:31 +0000 (02:46 +0100)
committerJelmer Vernooij <jelmer@samba.org>
Mon, 27 Feb 2012 02:52:05 +0000 (03:52 +0100)
source4/scripting/bin/upgradeprovision
source4/scripting/python/samba/tests/xattr.py
source4/scripting/python/samba/xattr.py

index 8066ac38d484715c94e0b040193475363ecf656e..7003717b4e19d06a3b4f34a2b34655dfda40809d 100755 (executable)
@@ -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)
index 7b4627fdad987b91536a27b377bf3c38f4127820..1f325322fa21abfd2eb1e5bed644bddfc88c41e9 100644 (file)
 """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")
index 55ae0416759ef54151639c41fd39e2271f39c4e5..1c53ae810dbc33bcaf065432366ffdfa71a769f3 100644 (file)
@@ -3,7 +3,6 @@
 #
 # Utility code for dealing with POSIX extended attributes
 #
-# Copyright (C) Matthieu Patou <mat@matws.net> 2009 - 2010
 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 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)