summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2023-09-29 15:13:41 -0400
committerTavian Barnes <tavianator@tavianator.com>2023-09-29 15:14:40 -0400
commit25660f5c062cf1e0d0982457614c9aa4584fa565 (patch)
tree79139e7afbdc492925599870918b7e91a471f683
parent52de184ba28551734e1cb13233588504ab5f62ec (diff)
downloadbfs-25660f5c062cf1e0d0982457614c9aa4584fa565.tar.xz
tests/xtouch: Try creating the immediate parent first
-rw-r--r--tests/xtouch.c39
1 files changed, 24 insertions, 15 deletions
diff --git a/tests/xtouch.c b/tests/xtouch.c
index 4a02bf3..80fad8d 100644
--- a/tests/xtouch.c
+++ b/tests/xtouch.c
@@ -48,31 +48,40 @@ static int at_flags(const struct args *args) {
/** Create any parent directories of the given path. */
static int mkdirs(const char *path, mode_t mode) {
- char *copy = strdup(path);
- if (!copy) {
- return -1;
+ int ret = -1;
+ char *dir = xdirname(path);
+ if (!dir) {
+ goto err;
}
- int ret = -1;
- char *cur = copy + strspn(copy, "/");
- while (true) {
- cur += strcspn(cur, "/");
+ if (strcmp(dir, ".") == 0) {
+ goto done;
+ }
+
+ // Optimistically try the immediate parent first
+ if (mkdir(dir, mode) == 0 || errno == EEXIST) {
+ goto done;
+ }
+ // Create the parents one-at-a-time
+ char *cur = dir + strspn(dir, "/");
+ while (*cur) {
+ cur += strcspn(cur, "/");
char *next = cur + strspn(cur, "/");
- if (!*next) {
- ret = 0;
- break;
- }
+ char c = *cur;
*cur = '\0';
- if (mkdir(copy, mode) != 0 && errno != EEXIST) {
- break;
+ if (mkdir(dir, mode) != 0 && errno != EEXIST) {
+ goto err;
}
- *cur = '/';
+ *cur = c;
cur = next;
}
- free(copy);
+done:
+ ret = 0;
+err:
+ free(dir);
return ret;
}