Radek Brich c94c071
Redhat-bugzilla: 430835
Radek Brich c94c071
Radek Brich c94c071
* revert make_path code to previous state, which worked better
Radek Brich c94c071
* this can be dropped when permission issues are solved in upstream
Radek Brich c94c071
Radek Brich c94c071
Radek Brich c94c071
diff -up cpio-2.9/src/extern.h.dir_perm cpio-2.9/src/extern.h
Radek Brich c94c071
--- cpio-2.9/src/extern.h.dir_perm	2007-06-28 14:59:38.000000000 +0200
Radek Brich c94c071
+++ cpio-2.9/src/extern.h	2008-03-03 11:57:43.000000000 +0100
Radek Brich c94c071
@@ -140,8 +140,8 @@ void process_args (int argc, char *argv[
Radek Brich c94c071
 void initialize_buffers (void);
Radek Brich c94c071
 
Radek Brich c94c071
 /* makepath.c */
Radek Brich c94c071
-int make_path (char *argpath, uid_t owner, gid_t group,
Radek Brich c94c071
-	       const char *verbose_fmt_string);
Radek Brich c94c071
+int make_path (char *argpath, int mode, int parent_mode,
Radek Brich c94c071
+               uid_t owner, gid_t group, char *verbose_fmt_string);
Radek Brich c94c071
 
Radek Brich c94c071
 /* tar.c */
Radek Brich c94c071
 void write_out_tar_header (struct cpio_file_stat *file_hdr, int out_des);
Radek Brich c94c071
diff -up cpio-2.9/src/util.c.dir_perm cpio-2.9/src/util.c
Radek Brich c94c071
--- cpio-2.9/src/util.c.dir_perm	2007-06-28 15:04:51.000000000 +0200
Radek Brich c94c071
+++ cpio-2.9/src/util.c	2008-03-03 11:45:00.000000000 +0100
Radek Brich c94c071
@@ -618,14 +618,7 @@ create_all_directories (char *name)
Radek Brich c94c071
     error (2, 0, _("virtual memory exhausted"));
Radek Brich c94c071
 
Radek Brich c94c071
   if (dir[0] != '.' || dir[1] != '\0')
Radek Brich c94c071
-    {
Radek Brich c94c071
-      const char *fmt;
Radek Brich c94c071
-      if (warn_option & CPIO_WARN_INTERDIR)
Radek Brich c94c071
-	fmt = _("Creating intermediate directory `%s'");
Radek Brich c94c071
-      else
Radek Brich c94c071
-	fmt = NULL;
Radek Brich c94c071
-      make_path (dir, -1, -1, fmt);
Radek Brich c94c071
-    }
Radek Brich c94c071
+    make_path (dir, mode, 0700, -1, -1, (char *) NULL);
Radek Brich c94c071
 
Radek Brich c94c071
   free (dir);
Radek Brich c94c071
 }
Radek Brich c94c071
diff -up cpio-2.9/src/makepath.c.dir_perm cpio-2.9/src/makepath.c
Radek Brich c94c071
--- cpio-2.9/src/makepath.c.dir_perm	2007-06-28 15:09:47.000000000 +0200
Radek Brich c94c071
+++ cpio-2.9/src/makepath.c	2008-03-03 11:45:00.000000000 +0100
Radek Brich c94c071
@@ -29,15 +29,14 @@
Radek Brich c94c071
 #include <stdio.h>
Radek Brich c94c071
 #include <sys/types.h>
Radek Brich c94c071
 #include <sys/stat.h>
Radek Brich c94c071
-#include "cpiohdr.h"
Radek Brich c94c071
-#include "dstring.h"
Radek Brich c94c071
-#include "extern.h"
Radek Brich c94c071
 
Radek Brich c94c071
 /* Ensure that the directory ARGPATH exists.
Radek Brich c94c071
    Remove any trailing slashes from ARGPATH before calling this function.
Radek Brich c94c071
 
Radek Brich c94c071
-   Make all directory components that don't already exist with
Radek Brich c94c071
-   permissions 700.
Radek Brich c94c071
+   Make any leading directories that don't already exist, with
Radek Brich c94c071
+   permissions PARENT_MODE.
Radek Brich c94c071
+   If the last element of ARGPATH does not exist, create it as
Radek Brich c94c071
+   a new directory with permissions MODE.
Radek Brich c94c071
    If OWNER and GROUP are non-negative, make them the UID and GID of
Radek Brich c94c071
    created directories.
Radek Brich c94c071
    If VERBOSE_FMT_STRING is nonzero, use it as a printf format
Radek Brich c94c071
@@ -49,26 +48,48 @@
Radek Brich c94c071
 
Radek Brich c94c071
 int
Radek Brich c94c071
 make_path (char *argpath,
Radek Brich c94c071
+	   int mode,
Radek Brich c94c071
+	   int parent_mode,
Radek Brich c94c071
 	   uid_t owner,
Radek Brich c94c071
 	   gid_t group,
Radek Brich c94c071
-	   const char *verbose_fmt_string)
Radek Brich c94c071
+	   char *verbose_fmt_string)
Radek Brich c94c071
 {
Radek Brich c94c071
   char *dirpath;		/* A copy we can scribble NULs on.  */
Radek Brich c94c071
   struct stat stats;
Radek Brich c94c071
   int retval = 0;
Radek Brich c94c071
-  mode_t tmpmode;
Radek Brich c94c071
-  mode_t invert_permissions;
Radek Brich c94c071
-  int we_are_root = getuid () == 0;
Radek Brich c94c071
+  int oldmask = umask (0);
Radek Brich c94c071
   dirpath = alloca (strlen (argpath) + 1);
Radek Brich c94c071
-
Radek Brich c94c071
   strcpy (dirpath, argpath);
Radek Brich c94c071
 
Radek Brich c94c071
   if (stat (dirpath, &stats))
Radek Brich c94c071
     {
Radek Brich c94c071
-      tmpmode = MODE_RWX & ~ newdir_umask;
Radek Brich c94c071
-      invert_permissions = we_are_root ? 0 : MODE_WXUSR & ~ tmpmode;
Radek Brich c94c071
+      char *slash;
Radek Brich c94c071
+      int tmp_mode;		/* Initial perms for leading dirs.  */
Radek Brich c94c071
+      int re_protect;		/* Should leading dirs be unwritable? */
Radek Brich c94c071
+      struct ptr_list
Radek Brich c94c071
+      {
Radek Brich c94c071
+	char *dirname_end;
Radek Brich c94c071
+	struct ptr_list *next;
Radek Brich c94c071
+      };
Radek Brich c94c071
+      struct ptr_list *p, *leading_dirs = NULL;
Radek Brich e95f529
+
Radek Brich c94c071
+      /* If leading directories shouldn't be writable or executable,
Radek Brich c94c071
+	 or should have set[ug]id or sticky bits set and we are setting
Radek Brich c94c071
+	 their owners, we need to fix their permissions after making them.  */
Radek Brich c94c071
+      if (((parent_mode & 0300) != 0300)
Radek Brich c94c071
+	  || (owner != (uid_t) -1 && group != (gid_t) -1
Radek Brich c94c071
+	      && (parent_mode & 07000) != 0))
Radek Brich c94c071
+	{
Radek Brich c94c071
+	  tmp_mode = 0700;
Radek Brich c94c071
+	  re_protect = 1;
Radek Brich c94c071
+	}
Radek Brich c94c071
+      else
Radek Brich c94c071
+	{
Radek Brich c94c071
+	  tmp_mode = parent_mode;
Radek Brich c94c071
+	  re_protect = 0;
Radek Brich c94c071
+	}
Radek Brich c94c071
 
Radek Brich c94c071
-      char *slash = dirpath;
Radek Brich c94c071
+      slash = dirpath;
Radek Brich c94c071
       while (*slash == '/')
Radek Brich c94c071
 	slash++;
Radek Brich c94c071
       while ((slash = strchr (slash, '/')))
Radek Brich c94c071
@@ -91,9 +112,10 @@ make_path (char *argpath,
Radek Brich c94c071
 		  *(slash -1) = '\0';
Radek Brich c94c071
 		}
Radek Brich e95f529
 #endif
Radek Brich c94c071
-	      if (mkdir (dirpath, tmpmode ^ invert_permissions))
Radek Brich c94c071
+	      if (mkdir (dirpath, tmp_mode))
Radek Brich c94c071
 		{
Radek Brich c94c071
 		  error (0, errno, _("cannot make directory `%s'"), dirpath);
Radek Brich c94c071
+		  umask (oldmask);
Radek Brich c94c071
 		  return 1;
Radek Brich c94c071
 		}
Radek Brich c94c071
 	      else
Radek Brich c94c071
@@ -101,18 +123,24 @@ make_path (char *argpath,
Radek Brich c94c071
 		  if (verbose_fmt_string != NULL)
Radek Brich c94c071
 		    error (0, 0, verbose_fmt_string, dirpath);
Radek Brich c94c071
 
Radek Brich c94c071
-		  if (stat (dirpath, &stats))
Radek Brich c94c071
-		    stat_error (dirpath);
Radek Brich c94c071
-		  else
Radek Brich c94c071
+		  if (owner != (uid_t) -1 && group != (gid_t) -1
Radek Brich c94c071
+		      && chown (dirpath, owner, group)
Radek Brich c94c071
+#ifdef AFS
Radek Brich c94c071
+		      && errno != EPERM
Radek Brich c94c071
+#endif
Radek Brich c94c071
+		      )
Radek Brich c94c071
+		    {
Radek Brich c94c071
+		      chown_error_details (dirpath, owner, group);
Radek Brich c94c071
+		      retval = 1;
Radek Brich c94c071
+		    }
Radek Brich c94c071
+		  if (re_protect)
Radek Brich c94c071
 		    {
Radek Brich c94c071
-		      if (owner != -1)
Radek Brich c94c071
-			stats.st_uid = owner;
Radek Brich c94c071
-		      if (group != -1)
Radek Brich c94c071
-			stats.st_gid = group;
Radek Brich c94c071
-		      
Radek Brich c94c071
-		      delay_set_stat (dirpath, &stats, invert_permissions);
Radek Brich c94c071
+		      struct ptr_list *new = (struct ptr_list *)
Radek Brich c94c071
+			alloca (sizeof (struct ptr_list));
Radek Brich c94c071
+		      new->dirname_end = slash;
Radek Brich c94c071
+		      new->next = leading_dirs;
Radek Brich c94c071
+		      leading_dirs = new;
Radek Brich c94c071
 		    }
Radek Brich c94c071
-		  
Radek Brich c94c071
 #ifdef HPUX_CDF
Radek Brich c94c071
 		  if (iscdf)
Radek Brich c94c071
 		    {
Radek Brich c94c071
@@ -129,6 +157,7 @@ make_path (char *argpath,
Radek Brich c94c071
 	  else if (!S_ISDIR (stats.st_mode))
Radek Brich c94c071
 	    {
Radek Brich c94c071
 	      error (0, 0, _("`%s' exists but is not a directory"), dirpath);
Radek Brich c94c071
+	      umask (oldmask);
Radek Brich c94c071
 	      return 1;
Radek Brich c94c071
 	    }
Radek Brich c94c071
 
Radek Brich c94c071
@@ -143,7 +172,7 @@ make_path (char *argpath,
Radek Brich c94c071
       /* We're done making leading directories.
Radek Brich c94c071
 	 Make the final component of the path. */
Radek Brich c94c071
 
Radek Brich c94c071
-      if (mkdir (dirpath, tmpmode ^ invert_permissions))
Radek Brich c94c071
+      if (mkdir (dirpath, mode))
Radek Brich e95f529
 	{
Radek Brich c94c071
 	  /* In some cases, if the final component in dirpath was `.' then we 
Radek Brich c94c071
 	     just got an EEXIST error from that last mkdir().  If that's
Radek Brich c94c071
@@ -153,24 +182,51 @@ make_path (char *argpath,
Radek Brich c94c071
 	       (!S_ISDIR (stats.st_mode) ) )
Radek Brich c94c071
 	    {
Radek Brich c94c071
 	      error (0, errno, _("cannot make directory `%s'"), dirpath);
Radek Brich c94c071
+	      umask (oldmask);
Radek Brich c94c071
 	      return 1;
Radek Brich c94c071
 	    }
Radek Brich e95f529
 	}
Radek Brich c94c071
-      else if (stat (dirpath, &stats))
Radek Brich c94c071
-	stat_error (dirpath);
Radek Brich c94c071
-      else
Radek Brich c94c071
-	{
Radek Brich c94c071
-	  if (owner != -1)
Radek Brich c94c071
-	    stats.st_uid = owner;
Radek Brich c94c071
-	  if (group != -1)
Radek Brich c94c071
-	    stats.st_gid = group;
Radek Brich c94c071
-	  
Radek Brich c94c071
-	  delay_set_stat (dirpath, &stats, invert_permissions);
Radek Brich c94c071
-	}
Radek Brich c94c071
-	
Radek Brich c94c071
       if (verbose_fmt_string != NULL)
Radek Brich c94c071
 	error (0, 0, verbose_fmt_string, dirpath);
Radek Brich e95f529
 
Radek Brich c94c071
+      if (owner != (uid_t) -1 && group != (gid_t) -1)
Radek Brich c94c071
+	{
Radek Brich c94c071
+	  if (chown (dirpath, owner, group)
Radek Brich c94c071
+#ifdef AFS
Radek Brich c94c071
+	      && errno != EPERM
Radek Brich c94c071
+#endif
Radek Brich c94c071
+	      )
Radek Brich c94c071
+	    {
Radek Brich c94c071
+	      chown_error_details (dirpath, owner, group);
Radek Brich c94c071
+	      retval = 1;
Radek Brich c94c071
+	    }
Radek Brich c94c071
+	}
Radek Brich c94c071
+      /* chown may have turned off some permission bits we wanted.  */
Radek Brich c94c071
+      if ((mode & 07000) != 0 && chmod (dirpath, mode))
Radek Brich c94c071
+	{
Radek Brich c94c071
+	  chmod_error_details (dirpath, mode);
Radek Brich c94c071
+	  retval = 1;
Radek Brich c94c071
+	}
Radek Brich c94c071
+
Radek Brich c94c071
+      /* If the mode for leading directories didn't include owner "wx"
Radek Brich c94c071
+	 privileges, we have to reset their protections to the correct
Radek Brich c94c071
+	 value.  */
Radek Brich c94c071
+      for (p = leading_dirs; p != NULL; p = p->next)
Radek Brich c94c071
+	{
Radek Brich c94c071
+	  *p->dirname_end = '\0';
Radek Brich c94c071
+#if 0
Radek Brich c94c071
+	  /* cpio always calls make_path with parent mode 0700, so
Radek Brich c94c071
+	     we don't have to do this.  If we ever do have to do this,
Radek Brich c94c071
+	     we have to stat the directory first to get the setuid
Radek Brich c94c071
+	     bit so we don't break HP CDF's.  */
Radek Brich c94c071
+	  if (chmod (dirpath, parent_mode))
Radek Brich c94c071
+	    {
Radek Brich c94c071
+	      chmod_error_details (dirpath, parent_mode);
Radek Brich c94c071
+	      retval = 1;
Radek Brich c94c071
+	    }
Radek Brich c94c071
+#endif
Radek Brich c94c071
+
Radek Brich c94c071
+	}
Radek Brich c94c071
     }
Radek Brich c94c071
   else
Radek Brich c94c071
     {
Radek Brich c94c071
@@ -179,10 +235,33 @@ make_path (char *argpath,
Radek Brich c94c071
       if (!S_ISDIR (stats.st_mode))
Radek Brich e95f529
 	{
Radek Brich c94c071
 	  error (0, 0, _("`%s' exists but is not a directory"), dirpath);
Radek Brich c94c071
+	  umask (oldmask);
Radek Brich c94c071
 	  return 1;
Radek Brich e95f529
 	}
Radek Brich c94c071
 
Radek Brich c94c071
+      /* chown must precede chmod because on some systems,
Radek Brich c94c071
+	 chown clears the set[ug]id bits for non-superusers,
Radek Brich c94c071
+	 resulting in incorrect permissions.
Radek Brich c94c071
+	 On System V, users can give away files with chown and then not
Radek Brich c94c071
+	 be able to chmod them.  So don't give files away.  */
Radek Brich c94c071
+
Radek Brich c94c071
+      if (owner != (uid_t) -1 && group != (gid_t) -1
Radek Brich c94c071
+	  && chown (dirpath, owner, group)
Radek Brich c94c071
+#ifdef AFS
Radek Brich c94c071
+	  && errno != EPERM
Radek Brich c94c071
+#endif
Radek Brich c94c071
+	  )
Radek Brich c94c071
+	{
Radek Brich c94c071
+	  chown_error_details (dirpath, owner, group);
Radek Brich c94c071
+	  retval = 1;
Radek Brich c94c071
+	}
Radek Brich c94c071
+      if (chmod (dirpath, mode))
Radek Brich c94c071
+	{
Radek Brich c94c071
+	  chmod_error_details (dirpath, mode);
Radek Brich c94c071
+	  retval = 1;
Radek Brich c94c071
+	}
Radek Brich e95f529
     }
Radek Brich e95f529
 
Radek Brich c94c071
+  umask (oldmask);
Radek Brich c94c071
   return retval;
Radek Brich e95f529
 }