Looking through the manpages today and inspecting the libc/gen/{base,dir}name.c, I noticed that there wasn't a dirname_r -- so I whipped one up quickly this morning and tested it out. I also documented the undocumented errors that could occur if malloc(3) failed in basename(3) or dirname(3). Fix: Patch attached with submission follows: How-To-Repeat: $ cat ~/test_dirname.c #include <sys/param.h> #include <assert.h> #include <errno.h> #include <libgen.h> #include <stdio.h> #include <stdlib.h> #include <string.h> struct testcase { const char *input; const char *exp_res; int exp_errno; }; struct testcase testcases[] = { { ".", ".", 0 }, { "/", "/", 0 }, { "", ".", 0 }, { "a.b.c.d", ".", 0 }, { "a/b/c/d", "a/b/c", 0 }, { "a/b/c/d/", "a/b/c", 0 }, { (const char*)NULL, ".", 0 }, /* python -c 'print "/" + "a" * 1025 + "/b/"' */ { "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/b/", NULL, ENAMETOOLONG }, }; int main(int argc, char *argv[]) { char *buf, *res1, *res2; int failed, i; failed = 0; /* Slop */ buf = malloc(5*MAXPATHLEN); assert(buf != NULL); for (i = 0; i < sizeof(testcases)/sizeof(testcases[0]); i++) { res1 = dirname(testcases[i].input); res2 = dirname_r(testcases[i].input, buf); if (testcases[i].exp_res == NULL) { assert(res1 == res2); if (res1 != NULL || errno != testcases[i].exp_errno) { printf("FAIL: dirname(\"%s\") != NULL (was %s)\n", testcases[i].input, res1); failed++; } else if (errno != testcases[i].exp_errno) { printf("FAIL: dirname(\"%s\") didn't set errno == %d (was %d)\n", testcases[i].input, testcases[i].exp_errno, errno); failed++; } else printf("OK: dirname(\"%s\") == NULL and set errno == %d\n", testcases[i].input, testcases[i].exp_errno); } else { assert(strcmp(res1, res2) == 0); if (strcmp(res1, testcases[i].exp_res) != 0) { printf("FAIL: dirname(\"%s\") != \"%s\" (was %s)\n", testcases[i].input, testcases[i].exp_res, res1); failed++; } else printf("OK: dirname(\"%s\") == '%s'\n", testcases[i].input, testcases[i].exp_res); } } return (failed); } $ gcc -Wall -o ~/test_dirname ~/test_dirname.c $ ~/test_dirname OK: dirname(".") == '.' OK: dirname("/") == '/' OK: dirname("") == '.' OK: dirname("a.b.c.d") == '.' OK: dirname("a/b/c/d") == 'a/b/c' OK: dirname("a/b/c/d/") == 'a/b/c' OK: dirname("(null)") == '.' OK: dirname("/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/b/") == NULL and set errno == 63 $
Garrett, do you still plan to get this committed? I was working on similar implementation and end up finding this PR.
(In reply to Renato Botelho from comment #1) I'll take this -- thanks :).
Closing this bug, as dirname() in FreeBSD -HEAD has already been overhauled to be thread-safe. :-)