Hey,

On Thu, Jul 12, 2007 at 10:24:03AM +0200, Patrick Georgi wrote:
> > +int mkdirp(const char *parent, const char *dirpath, mode_t mode)
> conflicts with: (where libgen is a compatibility dummy in solaris
> 10 at least, deferring that object to libc, so it always conflicts)
> 
>       int mkdirp(const char *path, mode_t mode);

Thanks!

New patch, rename mkdirp() to mkdirp_below(). :)

I just had a thought; parent and dirpath are currently treated as
either absolute or relative cwd but perhaps dirpath should always
be treated as absolute or relative parent instead?

mkdirp_below("subdir","x/y/z",077);

would create subdir/x/y/z. Feels much more intuitive, no?


//Peter
Replaces mkdirp() with mkdirp_below() that aborts directory creation and
returns an error if a part of dirpath is located outside the specified
parent directory. Use the parent "/" to allow new directories anywhere.

Signed-off-by: Peter Stuge <[EMAIL PROTECTED]>

Index: util/lar/lib.c
===================================================================
--- util/lar/lib.c      (revision 447)
+++ util/lar/lib.c      (working copy)
@@ -24,6 +24,7 @@
 #include <strings.h>
 #include <unistd.h>
 #include <dirent.h>
+#include <errno.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -33,42 +34,80 @@
 
 static struct file *files = NULL;
 
-int mkdirp(const char *dirpath, mode_t mode)
+/**
+ * Create a new directory including any missing parent directories.
+ *
+ * NOTE: This function does not do complete path resolution as described in
+ * Linux path_resolution(2) and hence will fail for complex paths:
+ *
+ * e.g.: mkdirp_below("subdir", "subdir/../subdir/x", 0777);
+ *
+ * This call should create subdir/x, but since subdir/.. is outside subdir,
+ * the function will fail.
+ *
+ * @param parent Return an error if a new directory would be created outside
+ * this directory. Pass "/" to allow new directories to be created anywhere.
+ * @param dirpath The new directory that should be created.
+ * @param mode Permissions to use for newly created directories.
+ */
+int mkdirp_below(const char *parent, const char *dirpath, mode_t mode)
 {
-       char *pos, *currpath, *path;
-       char cwd[MAX_PATH];
-       int ret = 0;
+       int ret = -1;
+       size_t dirsep, parlen, sublen;
+       char c, *r, *path = NULL, *subdir, rpar[PATH_MAX], rsub[PATH_MAX];
 
+       if (!dirpath) {
+               fprintf(stderr, "mkdirp_below: No new directory specified\n");
+               goto done;
+       }
+
        path = strdup(dirpath);
        if (!path) {
-               fprintf(stderr, "Out of memory.\n");
-               exit(1);
+               perror("Duplicate new directory failed:");
+               goto done;
        }
 
-       currpath = path;
-
-       if (!getcwd(cwd, MAX_PATH)) {
-               free(path);
-               fprintf(stderr, "Error getting cwd.\n");
-               return -1;
+       if (NULL == realpath(parent, rpar)) {
+               fprintf(stderr, "realpath(%s) failed: %s\n", parent,
+                       strerror(errno));
+               goto done;
        }
+       parlen = strlen(rpar);
 
-       do {
-               pos = index(currpath, '/');
-               if (pos)
-                       *pos = 0;
+       for (subdir = path, dirsep = 0; subdir[dirsep]; subdir += dirsep) {
+               dirsep = strcspn(subdir, "/\\");
+               if (!dirsep) {
+                       subdir++;
+                       continue;
+               }
 
-               /* printf("cp=%s\n", currpath); */
-               mkdir(currpath, mode);
-               ret = chdir(currpath);
+               c = subdir[dirsep];
+               subdir[dirsep] = 0;
+               r = realpath(path, rsub);
+               sublen = strlen(rsub);
+               if (NULL == r) {
+                       if(ENOENT != errno) {
+                               fprintf(stderr, "realpath(%s) failed: %s\n",
+                                       path, strerror(errno));
+                               goto done;
+                       }
+               } else if (sublen < parlen || strncmp(rpar, rsub, parlen)) {
+                       fprintf(stderr, "Abort: %s is outside %s\n", dirpath,
+                               parent);
+                       goto done;
+               }
+               if(-1 == mkdir(path, mode) && EEXIST != errno) {
+                       fprintf(stderr, "mkdir(%s): %s\n", path,
+                               strerror(errno));
+                       goto done;
+               }
+               subdir[dirsep] = c;
+       }
+       ret = 0;
 
-               if (pos)
-                       currpath = pos + 1;
-       } while (pos && !ret && strlen(currpath));
-
-       chdir(cwd);
-       free(path);
-
+done:
+       if (path)
+               free(path);
        return ret;
 }
 
Index: util/lar/extract.c
===================================================================
--- util/lar/extract.c  (revision 447)
+++ util/lar/extract.c  (working copy)
@@ -119,7 +119,7 @@
                if (pos) {
                        pos[1] = 0;
                        /* printf("Pathname %s\n",pathname); */
-                       mkdirp(pathname, 0755);
+                       mkdirp_below(".", pathname, 0755);
                }
                free(pathname);
 
Index: util/lar/lib.h
===================================================================
--- util/lar/lib.h      (revision 447)
+++ util/lar/lib.h      (working copy)
@@ -41,7 +41,7 @@
 char *get_bootblock(void);
 
 /* prototypes for lib.c functions */
-int mkdirp(const char *dirpath, mode_t mode);
+int mkdirp_below(const char *parent, const char *dirpath, mode_t mode);
 
 int add_files(const char *name);
 int add_file_or_directory(const char *name);
-- 
linuxbios mailing list
[email protected]
http://www.linuxbios.org/mailman/listinfo/linuxbios

Reply via email to