commit 444dad86beaaa60bd96790c7097aa66bb331e645 from: Omar Polo date: Thu Oct 07 21:57:04 2021 UTC dirname fix dirname(3) is really one of the worst part of POSIX, portability-wise. Implementors can decide to either modify the passed string or return a pointer to an internal storage. The current code fails when dirname returns a pointer to an internal storage because between the strcmp call and the mkdir we go into a recursion that can modify `path'. We can't use copy either because *some* implementation of dirname would have changed that. How to escape from this hell? Take yet another copy of the path! commit - eb2ed626f304f3f1e00711c20d76ecfd8dcc5ce7 commit + 444dad86beaaa60bd96790c7097aa66bb331e645 blob - fe5290ef682562a940933715bda1bf34554c84d7 blob + e645e7b3ee272bc80cbf72eb8d497f07c7520b1b --- fs.c +++ fs.c @@ -581,18 +581,19 @@ getenv_default(char *buf, const char *name, const char static void mkdirs(const char *path, mode_t mode) { - char copy[PATH_MAX+1], *parent; + char copy[PATH_MAX+1], orig[PATH_MAX+1], *parent; strlcpy(copy, path, sizeof(copy)); + strlcpy(orig, path, sizeof(orig)); parent = dirname(copy); if (!strcmp(parent, "/")) return; mkdirs(parent, mode); - if (mkdir(path, mode) != 0) { + if (mkdir(orig, mode) != 0) { if (errno == EEXIST) return; - err(1, "can't mkdir %s", path); + err(1, "can't mkdir %s", orig); } }