-/* BSD compatible make directory function for System V
- Copyright (C) 1988, 1990, 1998 Free Software Foundation, Inc.
+/* On some systems, mkdir ("foo/", 0700) fails because of the trailing
+ slash. On those systems, this wrapper removes the trailing slash.
- This program is free software; you can redistribute it and/or modify
+ Copyright (C) 2001, 2003, 2006, 2008-2013 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
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
+/* written by Jim Meyering */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#ifndef errno
-extern int errno;
-#endif
+#include <config.h>
-#if STAT_MACROS_BROKEN
-# undef S_ISDIR
-#endif
+/* Specification. */
+#include <sys/stat.h>
-#if !defined(S_ISDIR) && defined(S_IFDIR)
-# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dirname.h"
+
+/* Disable the definition of mkdir to rpl_mkdir (from the <sys/stat.h>
+ substitute) in this file. Otherwise, we'd get an endless recursion. */
+#undef mkdir
+
+/* mingw's _mkdir() function has 1 argument, but we pass 2 arguments.
+ Additionally, it declares _mkdir (and depending on compile flags, an
+ alias mkdir), only in the nonstandard includes <direct.h> and <io.h>,
+ which are included in the <sys/stat.h> override. */
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# define mkdir(name,mode) _mkdir (name)
+# define maybe_unused _GL_UNUSED
+#else
+# define maybe_unused /* empty */
#endif
-/* mkdir adapted from GNU tar. */
-
-/* Make directory DPATH, with permission mode DMODE.
-
- Written by Robert Rother, Mariah Corporation, August 1985
- (sdcsvax!rmr or rmr@uscd). If you want it, it's yours.
-
- Severely hacked over by John Gilmore to make a 4.2BSD compatible
- subroutine. 11Mar86; hoptoad!gnu
-
- Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
- subroutine didn't return EEXIST. It does now. */
+/* This function is required at least for NetBSD 1.5.2. */
int
-mkdir (const char *dpath, int dmode)
+rpl_mkdir (char const *dir, mode_t mode maybe_unused)
{
- int cpid, status;
- struct stat statbuf;
+ int ret_val;
+ char *tmp_dir;
+ size_t len = strlen (dir);
- if (stat (dpath, &statbuf) == 0)
+ if (len && dir[len - 1] == '/')
{
- errno = EEXIST; /* stat worked, so it already exists. */
- return -1;
+ tmp_dir = strdup (dir);
+ if (!tmp_dir)
+ {
+ /* Rather than rely on strdup-posix, we set errno ourselves. */
+ errno = ENOMEM;
+ return -1;
+ }
+ strip_trailing_slashes (tmp_dir);
}
-
- /* If stat fails for a reason other than non-existence, return error. */
- if (errno != ENOENT)
- return -1;
-
- cpid = fork ();
- switch (cpid)
+ else
{
- case -1: /* Cannot fork. */
- return -1; /* errno is already set. */
-
- case 0: /* Child process. */
- /* Cheap hack to set mode of new directory. Since this child
- process is going away anyway, we zap its umask.
- This won't suffice to set SUID, SGID, etc. on this
- directory, so the parent process calls chmod afterward. */
- status = umask (0); /* Get current umask. */
- umask (status | (0777 & ~dmode)); /* Set for mkdir. */
- execl ("/bin/mkdir", "mkdir", dpath, (char *) 0);
- _exit (1);
-
- default: /* Parent process. */
- /* Wait for kid to finish. */
- while (wait (&status) != cpid)
- /* Do nothing. */ ;
-
- if (status & 0xFFFF)
- {
- /* /bin/mkdir failed. */
- errno = EIO;
- return -1;
- }
- return chmod (dpath, dmode);
+ tmp_dir = (char *) dir;
}
+#if FUNC_MKDIR_DOT_BUG
+ /* Additionally, cygwin 1.5 mistakenly creates a directory "d/./". */
+ {
+ char *last = last_component (tmp_dir);
+ if (*last == '.' && (last[1] == '\0'
+ || (last[1] == '.' && last[2] == '\0')))
+ {
+ struct stat st;
+ if (stat (tmp_dir, &st) == 0)
+ errno = EEXIST;
+ return -1;
+ }
+ }
+#endif /* FUNC_MKDIR_DOT_BUG */
+
+ ret_val = mkdir (tmp_dir, mode);
+
+ if (tmp_dir != dir)
+ free (tmp_dir);
+
+ return ret_val;
}