]> git.saurik.com Git - apple/libc.git/blobdiff - util/mkpath_np.c
Libc-1158.1.2.tar.gz
[apple/libc.git] / util / mkpath_np.c
index fb02297278e1346d02d1250df992d007f0176e65..b830b3f63e396f5d93d2b876feb021c0feca6c58 100644 (file)
 #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;
@@ -48,7 +39,7 @@ _mkpath_np(const char *path, mode_t omode, const char ** firstdir)
        struct stat sbuf;
 
        /* Try the trivial case first. */
-       if (0 == mkdir(path, omode)) {
+       if (0 == mkdirat(dfd, path, omode)) {
                if (firstdir) {
                        *firstdir = strdup(path);
                }
@@ -63,7 +54,7 @@ _mkpath_np(const char *path, mode_t omode, const char ** firstdir)
                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 {
@@ -107,7 +98,7 @@ _mkpath_np(const char *path, mode_t omode, const char ** firstdir)
        }
 
        /* 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);
                }
@@ -127,7 +118,7 @@ _mkpath_np(const char *path, mode_t omode, const char ** firstdir)
                *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:
@@ -140,7 +131,7 @@ _mkpath_np(const char *path, mode_t omode, const char ** firstdir)
                         */
 
                        struct stat dirstat;
-                       if (-1 == stat(apath, &dirstat)) {
+                       if (-1 == fstatat(dfd, apath, &dirstat, 0)) {
                                /* Really unfortunate timing ... */
                                retval = ENOENT;
                                goto mkpath_exit;
@@ -148,7 +139,7 @@ _mkpath_np(const char *path, mode_t omode, const char ** firstdir)
 
                        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;
@@ -164,7 +155,7 @@ _mkpath_np(const char *path, mode_t omode, const char ** firstdir)
                         * 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) {
@@ -187,7 +178,7 @@ _mkpath_np(const char *path, mode_t omode, const char ** 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;
@@ -196,7 +187,7 @@ _mkpath_np(const char *path, mode_t omode, const char ** firstdir)
                }
 
                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;
@@ -204,10 +195,10 @@ _mkpath_np(const char *path, mode_t omode, const char ** firstdir)
                }
        }
 
-       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;
                }
@@ -221,6 +212,25 @@ mkpath_exit:
        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);
 }