]> git.ipfire.org Git - thirdparty/kmod.git/commitdiff
testsuite: Fix mkdir_p corner cases
authorLucas De Marchi <lucas.demarchi@intel.com>
Mon, 15 Jul 2013 04:21:27 +0000 (01:21 -0300)
committerLucas De Marchi <lucas.demarchi@intel.com>
Mon, 15 Jul 2013 15:44:26 +0000 (12:44 -0300)
 - Fix infinite loop when path is relative
 - Fix not considering EEXIST as a success
 - General refactor to mkdir_p so it never calls mkdir for an existing
   dir (given no one creates it from outside)

testsuite/mkdir.c

index 0a7de694b8a3bf0ba83ca8123e49685d66321694..f692c5a04e76ad012acaec27ee6e8a613e490a4f 100644 (file)
 #include "mkdir.h"
 #include "testsuite.h"
 
+static inline int is_dir(const char *path)
+{
+       struct stat st;
+
+       if (stat(path, &st) >= 0)
+               return S_ISDIR(st.st_mode);
+
+       return -errno;
+}
+
 TS_EXPORT int mkdir_p(const char *path, mode_t mode)
 {
        char *start = strdupa(path);
        int len = strlen(path);
        char *end = start + len;
-       struct stat st;
 
        /*
         * scan backwards, replacing '/' with '\0' while the component doesn't
         * exist
         */
        for (;;) {
-               if (stat(start, &st) >= 0) {
-                       if (S_ISDIR(st.st_mode))
-                               break;
-                       return -ENOTDIR;
-               }
+               int r = is_dir(start);
+               if (r > 0) {
+                       end += strlen(end);
 
-               /* Find the next component, backwards, discarding extra '/'*/
-               for (; end != start && *end != '/'; end--)
-                       ;
+                       if (end == start + len)
+                               return 0;
 
-               for (; end != start - 1 && *end == '/'; end--)
-                       ;
+                       /* end != start, since it would be caught on the first
+                        * iteration */
+                       *end = '/';
+                       break;
+               } else if (r == 0)
+                       return -ENOTDIR;
 
-               end++;
                if (end == start)
                        break;
 
                *end = '\0';
-       }
 
-       if (end == start + len)
-               return 0;
+               /* Find the next component, backwards, discarding extra '/'*/
+               while (end > start && *end != '/')
+                       end--;
 
-       for (; end < start + len;) {
-               *end = '/';
-               end += strlen(end);
+               while (end > start && *(end - 1) == '/')
+                       end--;
+       }
 
-               if (mkdir(start, mode) < 0)
+       for (; end < start + len;) {
+               if (mkdir(start, mode) < 0 && errno != EEXIST)
                        return -errno;
+
+               end += strlen(end);
+               *end = '/';
        }
 
        return 0;