From: Lucas De Marchi <[email protected]>

 - 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 creates it from outside)
---
 testsuite/mkdir.c | 54 +++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 35 insertions(+), 19 deletions(-)

diff --git a/testsuite/mkdir.c b/testsuite/mkdir.c
index 0a7de69..be2e37b 100644
--- a/testsuite/mkdir.c
+++ b/testsuite/mkdir.c
@@ -23,47 +23,63 @@
 #include "mkdir.h"
 #include "testsuite.h"
 
+static inline int is_dir(const char *path)
+{
+       struct stat st;
+
+       if (stat(path, &st) >= 0) {
+               if (S_ISDIR(st.st_mode))
+                       return 1;
+               return 0;
+       }
+
+       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;
-- 
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-modules" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to