summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLucas De Marchi <lucas.demarchi@intel.com>2013-07-15 01:21:27 -0300
committerLucas De Marchi <lucas.demarchi@intel.com>2013-07-15 12:44:26 -0300
commit7980eaf0ec0ffd47e2af79f647f5eed1d22f5e32 (patch)
treec7164a3c1078b4107e171a1c0a6b5bdbac306d79
parent83b855a6ed7028173e231eab0a39c929a962ddf5 (diff)
downloadkmod-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.c51
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;