(oatoi): declare arg to be const
[gnulib.git] / lib / makepath.c
index 8ac46fe..99119a2 100644 (file)
@@ -1,5 +1,5 @@
 /* makepath.c -- Ensure that a directory path exists.
-   Copyright (C) 1990, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1990, 1997, 1998 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -71,6 +71,16 @@ extern int errno;
 # endif
 #endif
 
+#ifndef S_IWUSR
+# define S_IWUSR 0200
+#endif
+
+#ifndef S_IXUSR
+# define S_IXUSR 0100
+#endif
+
+#define WX_USR (S_IWUSR | S_IXUSR)
+
 #ifdef __MSDOS__
 typedef int uid_t;
 typedef int gid_t;
@@ -123,7 +133,6 @@ void strip_trailing_slashes ();
    Return 0 if ARGPATH exists as a directory with the proper
    ownership and permissions when done, otherwise 1.  */
 
-#if __STDC__
 int
 make_path (const char *argpath,
           int mode,
@@ -132,18 +141,6 @@ make_path (const char *argpath,
           gid_t group,
           int preserve_existing,
           const char *verbose_fmt_string)
-#else
-int
-make_path (argpath, mode, parent_mode, owner, group, preserve_existing,
-          verbose_fmt_string)
-     const char *argpath;
-     int mode;
-     int parent_mode;
-     uid_t owner;
-     gid_t group;
-     int preserve_existing;
-     const char *verbose_fmt_string;
-#endif
 {
   struct stat stats;
   int retval = 0;
@@ -175,8 +172,8 @@ make_path (argpath, mode, parent_mode, owner, group, preserve_existing,
       /* If leading directories shouldn't be writable or executable,
         or should have set[ug]id or sticky bits set and we are setting
         their owners, we need to fix their permissions after making them.  */
-      if (((parent_mode & 0300) != 0300)
-         || (owner != (uid_t) -1 && group != (gid_t) -1
+      if (((parent_mode & WX_USR) != WX_USR)
+         || ((owner != (uid_t) -1 || group != (gid_t) -1)
              && (parent_mode & 07000) != 0))
        {
          tmp_mode = 0700;
@@ -220,6 +217,14 @@ make_path (argpath, mode, parent_mode, owner, group, preserve_existing,
          if (!do_chdir)
            basename_dir = dirpath;
 
+         /* The mkdir and stat calls below appear to be reversed.
+            They are not.  It is important to call mkdir first and then to
+            call stat (to distinguish the three cases) only if mkdir fails.
+            The alternative to this approach is to `stat' each directory,
+            then to call mkdir if it doesn't exist.  But if some other process
+            were to create the directory between the stat & mkdir, the mkdir
+            would fail with EEXIST.  */
+
          *slash = '\0';
          if (mkdir (basename_dir, tmp_mode))
            {
@@ -242,28 +247,31 @@ make_path (argpath, mode, parent_mode, owner, group, preserve_existing,
                }
            }
 
-         if (newly_created_dir && verbose_fmt_string != NULL)
-           error (0, 0, verbose_fmt_string, dirpath);
+         if (newly_created_dir)
+           {
+             if (verbose_fmt_string)
+               fprintf (stderr, verbose_fmt_string, dirpath);
 
-         if (owner != (uid_t) -1 && group != (gid_t) -1
-             && chown (basename_dir, owner, group)
+             if ((owner != (uid_t) -1 || group != (gid_t) -1)
+                 && chown (basename_dir, owner, group)
 #if defined(AFS) && defined (EPERM)
-             && errno != EPERM
+                 && errno != EPERM
 #endif
-             )
-           {
-             error (0, errno, "%s", dirpath);
-             CLEANUP;
-             return 1;
-           }
+                 )
+               {
+                 error (0, errno, "%s", dirpath);
+                 CLEANUP;
+                 return 1;
+               }
 
-         if (re_protect)
-           {
-             struct ptr_list *new = (struct ptr_list *)
-               alloca (sizeof (struct ptr_list));
-             new->dirname_end = slash;
-             new->next = leading_dirs;
-             leading_dirs = new;
+             if (re_protect)
+               {
+                 struct ptr_list *new = (struct ptr_list *)
+                   alloca (sizeof (struct ptr_list));
+                 new->dirname_end = slash;
+                 new->next = leading_dirs;
+                 leading_dirs = new;
+               }
            }
 
          /* If we were able to save the initial working directory,
@@ -361,7 +369,7 @@ make_path (argpath, mode, parent_mode, owner, group, preserve_existing,
             On System V, users can give away files with chown and then not
             be able to chmod them.  So don't give files away.  */
 
-         if (owner != (uid_t) -1 && group != (gid_t) -1
+         if ((owner != (uid_t) -1 || group != (gid_t) -1)
              && chown (dirpath, owner, group)
 #ifdef AFS
              && errno != EPERM