build/contrib/detpax/INSTALL | 2 ++ build/contrib/detpax/main.c | 59 +++++++++++++++++++++++++++++++++++++++++++++-------- diff --git a/build/contrib/detpax/INSTALL b/build/contrib/detpax/INSTALL index c4c3f6b293210f0e26f198b58802e2d4190a875727f8c548bd732130f73181ea..ac8d1791145430adbe1f45749b212db8f01ea01f324376655f8954cddf9ee9d5 100644 --- a/build/contrib/detpax/INSTALL +++ b/build/contrib/detpax/INSTALL @@ -4,3 +4,5 @@ For glibc maybe you will need: $ CFLAGS=-D_DEFAULT_SOURCE ./build For debug build: $ STRIP=: CFLAGS="-g -O0 -Weverything" ./build + +Add -DWITH_GETDENTS to use non-POSIX more efficient getdents(). diff --git a/build/contrib/detpax/main.c b/build/contrib/detpax/main.c index e68701063fdc4436ba3b64c5874d9de6c7194773423e80539571007fbb2b4611..4bfa7792c5af92bcef449b2e7c53366070a6da7c9d93d3ed1fd0475e6c80a4de 100644 --- a/build/contrib/detpax/main.c +++ b/build/contrib/detpax/main.c @@ -47,6 +47,18 @@ static size_t LinksLen = 0; // hardlinks count static size_t DirsLen = 0; // directories count static size_t SymlinksLen = 0; // symlinks count +static bool +isDots(const char *fn, const size_t fnLen) +{ + if ((fnLen == 2) && (fn[0] == '.') && (fn[1] == '.')) { + return true; + } + if ((fnLen == 1) && (fn[0] == '.')) { + return true; + } + return false; +} + static void walk(const struct Path *dir) { @@ -54,15 +66,48 @@ Scratch[ScratchLen - 1] = 0; size_t curLen = PathMarshal((char *)Scratch, ScratchLen - 1, dir); char *cur = (char *)Scratch + ScratchLen - 1 - curLen; { + char *fn = NULL; + size_t fnLen = 0; + struct Str *strp = NULL; + struct dirent *e = NULL; +#ifdef WITH_GETDENTS + int d = open(cur, O_RDONLY | O_DIRECTORY); + if (d == -1) { + err2("open(dir)", cur); + } + ssize_t n = -1; + ssize_t off = 0; + for (;;) { + n = getdents(d, (char *)Scratch, ScratchLen); + if (n <= 0) { + if (n < 0) { + PathMarshal((char *)Scratch, ScratchLen - 1, dir); + err2("getdents", cur); + } + break; + } + off = 0; + while (off < n) { + e = (void *)&(Scratch[off]); + off += e->d_reclen; + fn = e->d_name; + fnLen = e->d_namlen; + if (isDots(fn, fnLen)) { + continue; + } + strp = KEKSMemPoolGet(&DirEnts); + memEnough("dirEnt", strp != NULL); + *strp = StrNewVal(fn, fnLen); + } + } + close(d); +#else // WITH_GETDENTS DIR *d = opendir(cur); if (d == NULL) { err2("opendir", cur); } - struct dirent *e = NULL; - char *fn = NULL; - size_t fnLen = 0; - struct Str *strp = NULL; for (;;) { + errno = 0; e = readdir(d); if (e == NULL) { if (errno != 0) { @@ -72,10 +117,7 @@ break; } fn = e->d_name; fnLen = strlen(fn); - if ((fnLen == 2) && (fn[0] == '.') && (fn[1] == '.')) { - continue; - } - if ((fnLen == 1) && (fn[0] == '.')) { + if (isDots(fn, fnLen)) { continue; } strp = KEKSMemPoolGet(&DirEnts); @@ -83,6 +125,7 @@ memEnough("dirEnt", strp != NULL); *strp = StrNewVal(fn, fnLen); } closedir(d); +#endif // WITH_GETDENTS } const size_t pathsLen = DirEnts.len; struct Str *paths = calloc(pathsLen, sizeof(struct Str));