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()