diff --git a/darkhttpd.c b/darkhttpd.c index c6a1a02..c69040a 100644 --- a/darkhttpd.c +++ b/darkhttpd.c @@ -1817,6 +1817,9 @@ struct dlent { }; static int dlent_cmp(const void *a, const void *b) { + if (strcmp((*((const struct dlent * const *)a))->name, "..") == 0) { + return -1; /* Special-case ".." to come first. */ + } return strcmp((*((const struct dlent * const *)a))->name, (*((const struct dlent * const *)b))->name); } @@ -1843,7 +1846,7 @@ static ssize_t make_sorted_dirlist(const char *path, struct dlent ***output) { while ((ent = readdir(dir)) != NULL) { struct stat s; - if ((ent->d_name[0] == '.') && (ent->d_name[1] == '\0')) + if (strcmp(ent->d_name, ".") == 0) continue; /* skip "." */ assert(strlen(ent->d_name) <= MAXNAMLEN); sprintf(currname, "%s%s", path, ent->d_name); diff --git a/devel/run-tests b/devel/run-tests index 43646ce..b406203 100755 --- a/devel/run-tests +++ b/devel/run-tests @@ -22,6 +22,7 @@ runtests() { rm -rf $DIR || exit 1 fi mkdir $DIR || exit 1 + mkdir $DIR/\( || exit 1 mkdir $DIR/forbidden || exit 1 chmod 0 $DIR/forbidden || exit 1 mkdir $DIR/unreadable || exit 1 diff --git a/devel/test.py b/devel/test.py index 7835c0c..65d81b9 100755 --- a/devel/test.py +++ b/devel/test.py @@ -174,6 +174,15 @@ class TestDirList(TestHelper): self.assertEqual(ord("#"), 0x23) self.assertContains(body, "escape%28this%29name", "12345") + def test_dotdot_first(self): + resp = self.get("/") + status, hdrs, body = parse(resp) + self.assertLess(b'(', b'..') # ( sorts before .. + paren_pos = body.index(b'(/') + dotdot_pos = body.index(b'../') + # But we special-case .. to come first + self.assertLess(dotdot_pos, paren_pos) + class TestCases(TestHelper): pass # these get autogenerated in setUpModule()