home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / gnu / cpio-2.3-src.lha / src / amiga / cpio-2.3 / makepath.c < prev    next >
C/C++ Source or Header  |  1993-03-29  |  8KB  |  298 lines

  1. /* makepath.c -- Ensure that a directory path exists.
  2.    Copyright (C) 1990 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Written by David MacKenzie <djm@gnu.ai.mit.edu> and
  19.    Jim Meyering <meyering@cs.utexas.edu>.  */
  20.  
  21. /* This copy of makepath is almost like the fileutils one, but has
  22.    changes for HPUX CDF's.  Maybe the 2 versions of makepath can
  23.    come together again in the future.  */
  24.  
  25. #ifdef __GNUC__
  26. #define alloca __builtin_alloca
  27. #else
  28. #ifdef HAVE_ALLOCA_H
  29. #include <alloca.h>
  30. #else
  31. #ifdef _AIX
  32.  #pragma alloca
  33. #else
  34. char *alloca ();
  35. #endif
  36. #endif
  37. #endif
  38.  
  39. #include <stdio.h>
  40. #include <sys/types.h>
  41. #include <sys/stat.h>
  42. #ifdef HAVE_UNISTD_H
  43. #include <unistd.h>
  44. #endif
  45. #if !defined(S_ISDIR) && defined(S_IFDIR)
  46. #define    S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  47. #endif
  48.  
  49. #ifdef STDC_HEADERS
  50. #include <errno.h>
  51. #include <stdlib.h>
  52. #else
  53. extern int errno;
  54. #endif
  55.  
  56. #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
  57. #include <string.h>
  58. #define index strchr
  59. #else
  60. #include <strings.h>
  61. #endif
  62.  
  63. #ifdef __MSDOS__
  64. typedef int uid_t;
  65. typedef int gid_t;
  66. #endif
  67.  
  68. void error ();
  69.  
  70. /* Ensure that the directory ARGPATH exists.
  71.    Remove any trailing slashes from ARGPATH before calling this function.
  72.  
  73.    Make any leading directories that don't already exist, with
  74.    permissions PARENT_MODE.
  75.    If the last element of ARGPATH does not exist, create it as
  76.    a new directory with permissions MODE.
  77.    If OWNER and GROUP are non-negative, make them the UID and GID of
  78.    created directories.
  79.    If VERBOSE_FMT_STRING is nonzero, use it as a printf format
  80.    string for printing a message after successfully making a directory,
  81.    with the name of the directory that was just made as an argument.
  82.  
  83.    Return 0 if ARGPATH exists as a directory with the proper
  84.    ownership and permissions when done, otherwise 1.  */
  85.  
  86. int
  87. make_path (argpath, mode, parent_mode, owner, group, verbose_fmt_string)
  88.      char *argpath;
  89.      int mode;
  90.      int parent_mode;
  91.      uid_t owner;
  92.      gid_t group;
  93.      char *verbose_fmt_string;
  94. {
  95.   char *dirpath;        /* A copy we can scribble NULs on.  */
  96.   struct stat stats;
  97.   int retval = 0;
  98.   int oldmask = umask (0);
  99.   dirpath = alloca (strlen (argpath) + 1);
  100.   strcpy (dirpath, argpath);
  101.  
  102.   if (stat (dirpath, &stats))
  103.     {
  104.       char *slash;
  105.       int tmp_mode;        /* Initial perms for leading dirs.  */
  106.       int re_protect;        /* Should leading dirs be unwritable? */
  107.       struct ptr_list
  108.       {
  109.     char *dirname_end;
  110.     struct ptr_list *next;
  111.       };
  112.       struct ptr_list *p, *leading_dirs = NULL;
  113.  
  114.       /* If leading directories shouldn't be writable or executable,
  115.      or should have set[ug]id or sticky bits set and we are setting
  116.      their owners, we need to fix their permissions after making them.  */
  117.       if (((parent_mode & 0300) != 0300)
  118.       || (owner != (uid_t) -1 && group != (gid_t) -1
  119.           && (parent_mode & 07000) != 0))
  120.     {
  121.       tmp_mode = 0700;
  122.       re_protect = 1;
  123.     }
  124.       else
  125.     {
  126.       tmp_mode = parent_mode;
  127.       re_protect = 0;
  128.     }
  129.  
  130.       slash = dirpath;
  131.       while (*slash == '/')
  132.     slash++;
  133.       while ((slash = index (slash, '/')))
  134.     {
  135. #ifdef HPUX_CDF
  136.       int    iscdf;
  137.       iscdf = 0;
  138. #endif
  139.       *slash = '\0';
  140.       if (stat (dirpath, &stats))
  141.         {
  142. #ifdef HPUX_CDF
  143.           /* If this component of the pathname ends in `+' and is
  144.          followed by 2 `/'s, then this is a CDF.  We remove the
  145.          `+' from the name and create the directory.  Later
  146.          we will "hide" the directory.  */
  147.           if ( (*(slash +1) == '/') && (*(slash -1) == '+') )
  148.         { 
  149.           iscdf = 1;
  150.           *(slash -1) = '\0';
  151.         }
  152. #endif
  153.           if (mkdir (dirpath, tmp_mode))
  154.         {
  155.           error (0, errno, "cannot make directory `%s'", dirpath);
  156.           umask (oldmask);
  157.           return 1;
  158.         }
  159.           else
  160.         {
  161.           if (verbose_fmt_string != NULL)
  162.             error (0, 0, verbose_fmt_string, dirpath);
  163.  
  164.           if (owner != (uid_t) -1 && group != (gid_t) -1
  165.               && chown (dirpath, owner, group)
  166. #ifdef AFS
  167.               && errno != EPERM
  168. #endif
  169.               )
  170.             {
  171.               error (0, errno, "%s", dirpath);
  172.               retval = 1;
  173.             }
  174.           if (re_protect)
  175.             {
  176.               struct ptr_list *new = (struct ptr_list *)
  177.             alloca (sizeof (struct ptr_list));
  178.               new->dirname_end = slash;
  179.               new->next = leading_dirs;
  180.               leading_dirs = new;
  181.             }
  182. #ifdef HPUX_CDF
  183.           if (iscdf)
  184.             {
  185.               /*  If this is a CDF, "hide" the directory by setting
  186.               its hidden/setuid bit.  Also add the `+' back to
  187.               its name (since once it's "hidden" we must refer
  188.               to as `name+' instead of `name').  */
  189.               chmod (dirpath, 04700);
  190.               *(slash - 1) = '+';
  191.             }
  192. #endif
  193.         }
  194.         }
  195.       else if (!S_ISDIR (stats.st_mode))
  196.         {
  197.           error (0, 0, "`%s' exists but is not a directory", dirpath);
  198.           umask (oldmask);
  199.           return 1;
  200.         }
  201.  
  202.       *slash++ = '/';
  203.  
  204.       /* Avoid unnecessary calls to `stat' when given
  205.          pathnames containing multiple adjacent slashes.  */
  206.       while (*slash == '/')
  207.         slash++;
  208.     }
  209.  
  210.       /* We're done making leading directories.
  211.      Make the final component of the path.  */
  212.  
  213.       if (mkdir (dirpath, mode))
  214.     {
  215.       error (0, errno, "cannot make directory `%s'", dirpath);
  216.       umask (oldmask);
  217.       return 1;
  218.     }
  219.       if (verbose_fmt_string != NULL)
  220.     error (0, 0, verbose_fmt_string, dirpath);
  221.  
  222.       if (owner != (uid_t) -1 && group != (gid_t) -1)
  223.     {
  224.       if (chown (dirpath, owner, group)
  225. #ifdef AFS
  226.           && errno != EPERM
  227. #endif
  228.           )
  229.         {
  230.           error (0, errno, "%s", dirpath);
  231.           retval = 1;
  232.         }
  233.     }
  234.       /* chown may have turned off some permission bits we wanted.  */
  235.       if ((mode & 07000) != 0 && chmod (dirpath, mode))
  236.         {
  237.           error (0, errno, "%s", dirpath);
  238.           retval = 1;
  239.         }
  240.  
  241.       /* If the mode for leading directories didn't include owner "wx"
  242.      privileges, we have to reset their protections to the correct
  243.      value.  */
  244.       for (p = leading_dirs; p != NULL; p = p->next)
  245.     {
  246.       *(p->dirname_end) = '\0';
  247. #if 0
  248.       /* cpio always calls make_path with parent mode 0700, so
  249.          we don't have to do this.  If we ever do have to do this,
  250.          we have to stat the directory first to get the setuid
  251.          bit so we don't break HP CDF's.  */
  252.       if (chmod (dirpath, parent_mode))
  253.         {
  254.           error (0, errno, "%s", dirpath);
  255.           retval = 1;
  256.         }
  257. #endif
  258.  
  259.     }
  260.     }
  261.   else
  262.     {
  263.       /* We get here if the entire path already exists.  */
  264.  
  265.       if (!S_ISDIR (stats.st_mode))
  266.     {
  267.       error (0, 0, "`%s' exists but is not a directory", dirpath);
  268.       umask (oldmask);
  269.       return 1;
  270.     }
  271.  
  272.       /* chown must precede chmod because on some systems,
  273.      chown clears the set[ug]id bits for non-superusers,
  274.      resulting in incorrect permissions.
  275.      On System V, users can give away files with chown and then not
  276.      be able to chmod them.  So don't give files away.  */
  277.  
  278.       if (owner != (uid_t) -1 && group != (gid_t) -1
  279.       && chown (dirpath, owner, group)
  280. #ifdef AFS
  281.       && errno != EPERM
  282. #endif
  283.       )
  284.     {
  285.       error (0, errno, "%s", dirpath);
  286.       retval = 1;
  287.     }
  288.       if (chmod (dirpath, mode))
  289.     {
  290.       error (0, errno, "%s", dirpath);
  291.       retval = 1;
  292.     }
  293.     }
  294.  
  295.   umask (oldmask);
  296.   return retval;
  297. }
  298.