Skip to content

Instantly share code, notes, and snippets.

@dinvlad
Forked from mackstann/gist:4229933
Last active July 28, 2019 07:40
Show Gist options
  • Save dinvlad/83c078481649a35e16d9112d2743dab9 to your computer and use it in GitHub Desktop.
Save dinvlad/83c078481649a35e16d9112d2743dab9 to your computer and use it in GitHub Desktop.
Gigantic recursive directory entry counter
// http://www.olark.com/spw/2011/08/you-can-list-a-directory-with-8-million-files-but-not-with-ls/
#define _GNU_SOURCE
#include <dirent.h> /* Defines DT_* constants */
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#define handle_error(msg) perror(msg)
struct linux_dirent {
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[];
};
#define BUF_SIZE (1024 * 1024 * 128)
void listdir(const char * dirname, size_t * ntotal)
{
int fd, nread;
struct linux_dirent *d;
int bpos;
char d_type;
char * buf = malloc(BUF_SIZE);
fd = open(dirname, O_RDONLY | O_DIRECTORY);
if (fd == -1)
return handle_error(dirname);
for ( ; ; ) {
nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
if (nread == -1)
return handle_error(dirname);
if (nread == 0)
break;
for (bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) (buf + bpos);
d_type = *(buf + bpos + d->d_reclen - 1);
bpos += d->d_reclen;
if(d->d_ino && strcmp(d->d_name, ".") && strcmp(d->d_name, ".."))
{
(*ntotal)++;
if(d_type == DT_DIR)
{
int dirname_len = strlen(dirname);
char * subdir = calloc(1, PATH_MAX + 1);
strcat(subdir, dirname);
strcat(subdir + dirname_len, "/");
strcat(subdir + dirname_len + 1, d->d_name);
listdir(subdir, ntotal);
free(subdir);
}
}
}
}
close(fd);
free(buf);
}
int
main(int argc, char *argv[])
{
size_t ntotal = 0;
listdir(argc > 1 ? argv[1] : ".", &ntotal);
printf("%d\n", ntotal);
exit(EXIT_SUCCESS);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment