#include "c.h"#include <sys/stat.h>
Go to the source code of this file.
Functions | |
| int | pg_mkdir_p (char *path, int omode) |
| int pg_mkdir_p | ( | char * | path, | |
| int | omode | |||
| ) |
Definition at line 57 of file pgmkdirp.c.
References mkdir, NULL, S_IRWXG, and S_IRWXO.
Referenced by create_xlog_symlink(), mkdatadir(), and verify_dir_is_empty_or_create().
{
struct stat sb;
mode_t numask,
oumask;
int last,
retval;
char *p;
retval = 0;
p = path;
#ifdef WIN32
/* skip network and drive specifiers for win32 */
if (strlen(p) >= 2)
{
if (p[0] == '/' && p[1] == '/')
{
/* network drive */
p = strstr(p + 2, "/");
if (p == NULL)
{
errno = EINVAL;
return -1;
}
}
else if (p[1] == ':' &&
((p[0] >= 'a' && p[0] <= 'z') ||
(p[0] >= 'A' && p[0] <= 'Z')))
{
/* local drive */
p += 2;
}
}
#endif
/*
* POSIX 1003.2: For each dir operand that does not name an existing
* directory, effects equivalent to those caused by the following command
* shall occcur:
*
* mkdir -p -m $(umask -S),u+wx $(dirname dir) && mkdir [-m mode] dir
*
* We change the user's umask and then restore it, instead of doing
* chmod's. Note we assume umask() can't change errno.
*/
oumask = umask(0);
numask = oumask & ~(S_IWUSR | S_IXUSR);
(void) umask(numask);
if (p[0] == '/') /* Skip leading '/'. */
++p;
for (last = 0; !last; ++p)
{
if (p[0] == '\0')
last = 1;
else if (p[0] != '/')
continue;
*p = '\0';
if (!last && p[1] == '\0')
last = 1;
if (last)
(void) umask(oumask);
/* check for pre-existing directory */
if (stat(path, &sb) == 0)
{
if (!S_ISDIR(sb.st_mode))
{
if (last)
errno = EEXIST;
else
errno = ENOTDIR;
retval = -1;
break;
}
}
else if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0)
{
retval = -1;
break;
}
if (!last)
*p = '/';
}
/* ensure we restored umask */
(void) umask(oumask);
return retval;
}
1.7.1