home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bbs / gnu / fileutils-3.9-src.lha / src / amiga / fileutils-3.9 / lib / makepath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-12  |  6.9 KB  |  287 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. #ifdef HAVE_CONFIG_H
  22. #if defined (CONFIG_BROKETS)
  23. /* We use <config.h> instead of "config.h" so that a compilation
  24.    using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
  25.    (which it would do because it found this file in $srcdir).  */
  26. #include <config.h>
  27. #else
  28. #include "config.h"
  29. #endif
  30. #endif
  31.  
  32. #ifdef __GNUC__
  33. #define alloca __builtin_alloca
  34. #else
  35. #ifdef HAVE_ALLOCA_H
  36. #include <alloca.h>
  37. #else
  38. #ifdef _AIX
  39.  #pragma alloca
  40. #else
  41. char *alloca ();
  42. #endif
  43. #endif
  44. #endif
  45.  
  46. #include <stdio.h>
  47. #include <sys/types.h>
  48. #include <sys/stat.h>
  49. #ifdef HAVE_UNISTD_H
  50. #include <unistd.h>
  51. #endif
  52.  
  53. #ifdef    STAT_MACROS_BROKEN
  54. #ifdef S_ISDIR
  55. #undef S_ISDIR
  56. #endif
  57. #endif    /* STAT_MACROS_BROKEN.  */
  58.  
  59. #if !defined(S_ISDIR) && defined(S_IFDIR)
  60. #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  61. #endif
  62.  
  63. #ifdef STDC_HEADERS
  64. #include <stdlib.h>
  65. #endif
  66.  
  67. #ifdef HAVE_ERRNO_H
  68. #include <errno.h>
  69. #endif
  70.  
  71. #ifndef STDC_HEADERS
  72. extern int errno;
  73. #endif
  74.  
  75. #if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
  76. #include <string.h>
  77. #ifndef index
  78. #define index strchr
  79. #endif
  80. #else
  81. #include <strings.h>
  82. #endif
  83.  
  84. #ifdef __MSDOS__
  85. typedef int uid_t;
  86. typedef int gid_t;
  87. #endif
  88.  
  89. void error ();
  90.  
  91. /* Ensure that the directory ARGPATH exists.
  92.    Remove any trailing slashes from ARGPATH before calling this function.
  93.  
  94.    Make any leading directories that don't already exist, with
  95.    permissions PARENT_MODE.
  96.    If the last element of ARGPATH does not exist, create it as
  97.    a new directory with permissions MODE.
  98.    If OWNER and GROUP are non-negative, make them the UID and GID of
  99.    created directories.
  100.    If VERBOSE_FMT_STRING is nonzero, use it as a printf format
  101.    string for printing a message after successfully making a directory,
  102.    with the name of the directory that was just made as an argument.
  103.  
  104.    Return 0 if ARGPATH exists as a directory with the proper
  105.    ownership and permissions when done, otherwise 1.  */
  106.  
  107. int
  108. make_path (argpath, mode, parent_mode, owner, group, verbose_fmt_string)
  109.      char *argpath;
  110.      int mode;
  111.      int parent_mode;
  112.      uid_t owner;
  113.      gid_t group;
  114.      char *verbose_fmt_string;
  115. {
  116.   char *dirpath;        /* A copy we can scribble NULs on.  */
  117.   struct stat stats;
  118.   int retval = 0;
  119.   int oldmask = umask (0);
  120.  
  121.   dirpath = (char *) alloca (strlen (argpath) + 1);
  122.   strcpy (dirpath, argpath);
  123.  
  124.   if (stat (dirpath, &stats))
  125.     {
  126.       char *slash;
  127.       int tmp_mode;        /* Initial perms for leading dirs.  */
  128.       int re_protect;        /* Should leading dirs be unwritable? */
  129.       struct ptr_list
  130.       {
  131.     char *dirname_end;
  132.     struct ptr_list *next;
  133.       };
  134.       struct ptr_list *p, *leading_dirs = NULL;
  135.  
  136.       /* If leading directories shouldn't be writable or executable,
  137.      or should have set[ug]id or sticky bits set and we are setting
  138.      their owners, we need to fix their permissions after making them.  */
  139.       if (((parent_mode & 0300) != 0300)
  140.       || (owner != (uid_t) -1 && group != (gid_t) -1
  141.           && (parent_mode & 07000) != 0))
  142.     {
  143.       tmp_mode = 0700;
  144.       re_protect = 1;
  145.     }
  146.       else
  147.     {
  148.       tmp_mode = parent_mode;
  149.       re_protect = 0;
  150.     }
  151.  
  152.       slash = dirpath;
  153.       while (*slash == '/')
  154.     slash++;
  155.       while ((slash = index (slash, '/')))
  156.     {
  157.       *slash = '\0';
  158.       if (stat (dirpath, &stats))
  159.         {
  160.           if (mkdir (dirpath, tmp_mode))
  161.         {
  162.           error (0, errno, "cannot make directory `%s'", dirpath);
  163.           umask (oldmask);
  164.           return 1;
  165.         }
  166.           else
  167.         {
  168.           if (verbose_fmt_string != NULL)
  169.             error (0, 0, verbose_fmt_string, dirpath);
  170.  
  171.           if (owner != (uid_t) -1 && group != (gid_t) -1
  172.               && chown (dirpath, owner, group)
  173. #if defined(AFS) && defined (EPERM)
  174.               && errno != EPERM
  175. #endif
  176.               )
  177.             {
  178.               error (0, errno, "%s", dirpath);
  179.               retval = 1;
  180.             }
  181.           if (re_protect)
  182.             {
  183.               struct ptr_list *new = (struct ptr_list *)
  184.             alloca (sizeof (struct ptr_list));
  185.               new->dirname_end = slash;
  186.               new->next = leading_dirs;
  187.               leading_dirs = new;
  188.             }
  189.         }
  190.         }
  191.       else if (!S_ISDIR (stats.st_mode))
  192.         {
  193.           error (0, 0, "`%s' exists but is not a directory", dirpath);
  194.           umask (oldmask);
  195.           return 1;
  196.         }
  197.  
  198.       *slash++ = '/';
  199.  
  200.       /* Avoid unnecessary calls to `stat' when given
  201.          pathnames containing multiple adjacent slashes.  */
  202.       while (*slash == '/')
  203.         slash++;
  204.     }
  205.  
  206.       /* We're done making leading directories.
  207.      Make the final component of the path.  */
  208.  
  209.       if (mkdir (dirpath, mode))
  210.     {
  211.       error (0, errno, "cannot make directory `%s'", dirpath);
  212.       umask (oldmask);
  213.       return 1;
  214.     }
  215.       if (verbose_fmt_string != NULL)
  216.     error (0, 0, verbose_fmt_string, dirpath);
  217.  
  218.       if (owner != (uid_t) -1 && group != (gid_t) -1)
  219.     {
  220.       if (chown (dirpath, owner, group)
  221. #ifdef AFS
  222.           && errno != EPERM
  223. #endif
  224.           )
  225.         {
  226.           error (0, errno, "%s", dirpath);
  227.           retval = 1;
  228.         }
  229.       /* chown may have turned off some permission bits we wanted.  */
  230.       if ((mode & 07000) != 0 && chmod (dirpath, mode))
  231.         {
  232.           error (0, errno, "%s", dirpath);
  233.           retval = 1;
  234.         }
  235.     }
  236.  
  237.       /* If the mode for leading directories didn't include owner "wx"
  238.      privileges, we have to reset their protections to the correct
  239.      value.  */
  240.       for (p = leading_dirs; p != NULL; p = p->next)
  241.     {
  242.       *(p->dirname_end) = '\0';
  243.       if (chmod (dirpath, parent_mode))
  244.         {
  245.           error (0, errno, "%s", dirpath);
  246.           retval = 1;
  247.         }
  248.     }
  249.     }
  250.   else
  251.     {
  252.       /* We get here if the entire path already exists.  */
  253.  
  254.       if (!S_ISDIR (stats.st_mode))
  255.     {
  256.       error (0, 0, "`%s' exists but is not a directory", dirpath);
  257.       umask (oldmask);
  258.       return 1;
  259.     }
  260.  
  261.       /* chown must precede chmod because on some systems,
  262.      chown clears the set[ug]id bits for non-superusers,
  263.      resulting in incorrect permissions.
  264.      On System V, users can give away files with chown and then not
  265.      be able to chmod them.  So don't give files away.  */
  266.  
  267.       if (owner != (uid_t) -1 && group != (gid_t) -1
  268.       && chown (dirpath, owner, group)
  269. #ifdef AFS
  270.       && errno != EPERM
  271. #endif
  272.       )
  273.     {
  274.       error (0, errno, "%s", dirpath);
  275.       retval = 1;
  276.     }
  277.       if (chmod (dirpath, mode))
  278.     {
  279.       error (0, errno, "%s", dirpath);
  280.       retval = 1;
  281.     }
  282.     }
  283.  
  284.   umask (oldmask);
  285.   return retval;
  286. }
  287.