I added a second loop to list the files recursively, next in line is C multi threads and another sub hash to divide the record types easily.
#!/usr/bin/env perl
use 5.012;
use strict;
use warnings;
use Data::Dumper qw(Dumper);
my $str = &listfiles('<directory>');
print Dumper \$str;
use Inline C => <<'END_OF_C_CODE';
#include <dirent.h> /* Defines DT_* constants */
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#define handle_error(msg) do { perror(msg); exit(EXIT_FAILURE); } whil
+e (0)
struct linux_dirent {
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[];
};
#define BUF_SIZE 1024*1024*5
SV* listfiles(const char * dir) {
int fd, nread;
struct linux_dirent *d;
int bpos;
char inode, d_type;
char * buf = malloc(BUF_SIZE);
static HV* hash;
if (!(hash)) hash = newHV();
fd = open(dir, O_RDONLY | O_DIRECTORY);
if (fd == -1) handle_error("open");
for ( ; ; ) {
nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
if (nread == -1) handle_error("getdents");
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,
+ "..") && strcmp(d->d_name, ".snapshot")) {
size_t nbytes = snprintf(NULL, 0, "%d", d->d_ino) + 1;
char *inode = malloc(nbytes);
snprintf(inode, nbytes, "%d", d->d_ino);
hv_store(hash, inode, strlen(inode), newSVpvf("%s/%s",(
+char *) dir,d->d_name, 0), 0);
if(d_type == DT_DIR) {
int dir_len = strlen(dir);
char * subdir = calloc(1, PATH_MAX + 1);
strcat(subdir, dir);
strcat(subdir + dir_len, "/");
strcat(subdir + dir_len + 1, d->d_name);
listfiles(subdir);
free(subdir);
}
}
}
}
close(fd);
free(buf);
return newRV_noinc((SV*) hash);
}
END_OF_C_CODE
|