diff options
author | Lucas De Marchi <lucas.demarchi@intel.com> | 2013-07-15 01:21:27 -0300 |
---|---|---|
committer | Lucas De Marchi <lucas.demarchi@intel.com> | 2013-07-15 12:44:26 -0300 |
commit | 7980eaf0ec0ffd47e2af79f647f5eed1d22f5e32 (patch) | |
tree | c7164a3c1078b4107e171a1c0a6b5bdbac306d79 | |
parent | 83b855a6ed7028173e231eab0a39c929a962ddf5 (diff) | |
download | kmod-7980eaf0ec0ffd47e2af79f647f5eed1d22f5e32.tar.gz kmod-7980eaf0ec0ffd47e2af79f647f5eed1d22f5e32.tar.bz2 kmod-7980eaf0ec0ffd47e2af79f647f5eed1d22f5e32.zip |
testsuite: Fix mkdir_p corner cases
- 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)
-rw-r--r-- | testsuite/mkdir.c | 51 |
1 files changed, 32 insertions, 19 deletions
diff --git a/testsuite/mkdir.c b/testsuite/mkdir.c index 0a7de69..f692c5a 100644 --- a/testsuite/mkdir.c +++ b/testsuite/mkdir.c @@ -23,47 +23,60 @@ #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; |