From 09af33ec1a4cb29602272277887862d95e66bd59 Mon Sep 17 00:00:00 2001
From: "Bryn M. Reeves" <bmr@redhat.com>
Date: Mon, 30 Jun 2014 18:26:08 +0100
Subject: [PATCH] [plugintools] preserve permissions on all path components

When a path is added to the archive via addCopySpec() we copy the
content itself with shutil.copy2() which propagates permissions
from the source to the destination.

This ignores any directory components in the path leading up to
the item to be copied. For e.g.:

  self.addCopySpec("/foo/bar/baz/qux")

Will collect the file 'qux' and preserve its permissions vai a
shutil.copy2() call but '/foo/bar/baz' will be created via an
os.makedirs() call (receiving whatever permissions the current
umask allows).

Fix this by replacing the call to os.makedirs() with a call to
Plugin.__copydirs() which will walk the path from root down to the
final containing directory calling makedirs() and copystat() as
appropriate to copy permissions for the entire path.
---
 sos/plugintools.py | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/sos/plugintools.py b/sos/plugintools.py
index 1034ac3..6b02fa5 100644
--- a/sos/plugintools.py
+++ b/sos/plugintools.py
@@ -274,6 +274,19 @@ class PluginBase:
 
         return abspath
 
+    # Permission-copying version of makedirs(). For each component in a path
+    # ensure that the corresponding directory in dstroot exists and copy the
+    # permissions over from the host file system.
+    def __copydirs(self, src_dir, dst_root):
+        pathcomps = src_dir.split(os.path.sep)
+        path = ""
+        for comp in pathcomps:
+            path = os.path.join(path, comp)
+            dst_path = os.path.join(dst_root, path)
+            if not os.path.exists(dst_path):
+                os.makedirs(dst_path)
+                shutil.copystat(os.path.join('/', path), dst_path)
+
     def __copyFile(self, src):
         """ call cp to copy a file, collect return status and output. Returns the
         destination file name.
@@ -284,7 +297,7 @@ class PluginBase:
 
         if not os.path.exists(new_fname):
             if not os.path.isdir(new_dir):
-                os.makedirs(new_dir)
+                self.__copydirs(os.path.dirname(src), self.cInfo['dstroot'])
 
             if os.path.islink(src):
                 linkto = os.readlink(src)
-- 
1.9.3

