summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bfs.c23
-rw-r--r--bftw.c14
2 files changed, 34 insertions, 3 deletions
diff --git a/bfs.c b/bfs.c
index fcd1383..6bbfa05 100644
--- a/bfs.c
+++ b/bfs.c
@@ -15,8 +15,27 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/resource.h>
#include <unistd.h>
+static int infer_nopenfd() {
+ int ret = 4096;
+
+ struct rlimit rl;
+ if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
+ if (rl.rlim_cur != RLIM_INFINITY) {
+ ret = rl.rlim_cur;
+ }
+ }
+
+ // Account for std{in,out,err}
+ if (ret > 3) {
+ ret -= 3;
+ }
+
+ return ret;
+}
+
typedef struct {
const char *path;
color_table *colors;
@@ -85,8 +104,8 @@ int main(int argc, char *argv[]) {
opts.colors = parse_colors(getenv("LS_COLORS"));
}
- // TODO: getrlimit(RLIMIT_NOFILE)
- if (bftw(opts.path, callback, 1024, flags, &opts) != 0) {
+ int nopenfd = infer_nopenfd();
+ if (bftw(opts.path, callback, nopenfd, flags, &opts) != 0) {
perror("bftw()");
goto done;
}
diff --git a/bftw.c b/bftw.c
index 31e6fe2..75a208c 100644
--- a/bftw.c
+++ b/bftw.c
@@ -291,7 +291,19 @@ static DIR *dircache_entry_open(dircache *cache, dircache_entry *entry, const ch
fd = dirfd(base->dir);
}
- DIR *dir = opendirat(fd, path + nameoff);
+ const char *relpath = path + nameoff;
+ DIR *dir = opendirat(fd, relpath);
+
+ if (!dir
+ && errno == EMFILE
+ && cache->lru_tail
+ && cache->lru_tail != base) {
+ // Too many open files, shrink the LRU cache
+ dircache_entry_close(cache, cache->lru_tail);
+ --cache->lru_remaining;
+ dir = opendirat(fd, relpath);
+ }
+
if (dir) {
entry->dir = dir;
dircache_lru_add(cache, entry);