#include <string.h>
#include <errno.h>
#include <sys/stat.h>
+#include <fcntl.h>
-/* This extended version of mkpath_np is provided to help NSFileManager
- * maintain binary compatibility. If firstdir is not NULL, *firstdir will be
- * set to the path of the first created directory, and it is the caller's
- * responsibility to free the returned string. This SPI is subject to removal
- * once NSFileManager no longer has a need for it, and use in new code is
- * highly discouraged.
- *
- * See: <rdar://problem/9888987>
- */
-
-int
-_mkpath_np(const char *path, mode_t omode, const char ** firstdir)
+static int
+_mkpath(int dfd, const char *path, mode_t omode, const char ** firstdir)
{
char *apath = NULL, *opath = NULL, *s, *sn, *sl;
unsigned int depth = 0;
struct stat sbuf;
/* Try the trivial case first. */
- if (0 == mkdir(path, omode)) {
+ if (0 == mkdirat(dfd, path, omode)) {
if (firstdir) {
*firstdir = strdup(path);
}
case ENOENT:
break;
case EEXIST:
- if (stat(path, &sbuf) == 0) {
+ if (fstatat(dfd, path, &sbuf, 0) == 0) {
if (S_ISDIR(sbuf.st_mode)) {
retval = EEXIST;
} else {
}
/* Retry the trivial case after having stripped of trailing /. <rdar://problem/14351794> */
- if (0 == mkdir(path, omode)) {
+ if (0 == mkdirat(dfd, path, omode)) {
if (firstdir) {
*firstdir = strdup(path);
}
*s = '\0';
depth++;
- if (0 == mkdir(apath, S_IRWXU | S_IRWXG | S_IRWXO)) {
+ if (0 == mkdirat(dfd, apath, S_IRWXU | S_IRWXG | S_IRWXO)) {
/* Found our starting point */
/* POSIX 1003.2:
*/
struct stat dirstat;
- if (-1 == stat(apath, &dirstat)) {
+ if (-1 == fstatat(dfd, apath, &dirstat, 0)) {
/* Really unfortunate timing ... */
retval = ENOENT;
goto mkpath_exit;
if ((dirstat.st_mode & (S_IWUSR | S_IXUSR)) != (S_IWUSR | S_IXUSR)) {
chmod_mode = dirstat.st_mode | S_IWUSR | S_IXUSR;
- if (-1 == chmod(apath, chmod_mode)) {
+ if (-1 == fchmodat(dfd, apath, chmod_mode, 0)) {
/* Really unfortunate timing ... */
retval = ENOENT;
goto mkpath_exit;
* before we did. We will use this as our starting point.
* See: <rdar://problem/10279893>
*/
- if (stat(apath, &sbuf) == 0 &&
+ if (fstatat(dfd, apath, &sbuf, 0) == 0 &&
S_ISDIR(sbuf.st_mode)) {
if (firstdir) {
*s = '/';
depth--;
- if (-1 == mkdir(apath, S_IRWXU | S_IRWXG | S_IRWXO)) {
+ if (-1 == mkdirat(dfd, apath, S_IRWXU | S_IRWXG | S_IRWXO)) {
/* This handles "." and ".." added to the new section of path */
if (errno == EEXIST)
continue;
}
if (chmod_mode) {
- if (-1 == chmod(apath, chmod_mode)) {
+ if (-1 == fchmodat(dfd, apath, chmod_mode, 0)) {
/* Really unfortunate timing ... */
retval = ENOENT;
goto mkpath_exit;
}
}
- if (-1 == mkdir(path, omode)) {
+ if (-1 == mkdirat(dfd, path, omode)) {
retval = errno;
if (errno == EEXIST &&
- stat(path, &sbuf) == 0 &&
+ fstatat(dfd, path, &sbuf, 0) == 0 &&
!S_ISDIR(sbuf.st_mode)) {
retval = ENOTDIR;
}
return retval;
}
+/* This extended version of mkpath_np is provided to help NSFileManager
+ * maintain binary compatibility. If firstdir is not NULL, *firstdir will be
+ * set to the path of the first created directory, and it is the caller's
+ * responsibility to free the returned string. This SPI is subject to removal
+ * once NSFileManager no longer has a need for it, and use in new code is
+ * highly discouraged.
+ *
+ * See: <rdar://problem/9888987>
+ */
+
+int
+_mkpath_np(const char *path, mode_t omode, const char ** firstdir) {
+ return _mkpath(AT_FDCWD, path, omode, firstdir);
+}
+
int mkpath_np(const char *path, mode_t omode) {
- return _mkpath_np(path, omode, NULL);
+ return _mkpath(AT_FDCWD, path, omode, NULL);
+}
+
+int mkpathat_np(int dfd, const char *path, mode_t omode) {
+ return _mkpath(dfd, path, omode, NULL);
}