#!/opt/bin/perl

# inspired by treescan by Jamie Lokier <jamie@imbolc.ucc.ie>
# about 40% faster than the original version (on my fs and raid :)

use strict;
use Getopt::Long;
use IO::AIO;

our $VERSION = $IO::AIO::VERSION;

Getopt::Long::Configure ("bundling", "no_ignore_case", "require_order", "auto_help", "auto_version");

my ($opt_silent, $opt_print0, $opt_stat, $opt_nodirs, $opt_nofiles);

GetOptions
   "quiet|q"  => \$opt_silent,
   "print0|0" => \$opt_print0,
   "stat|s"   => \$opt_stat,
   "dirs|d"   => \$opt_nofiles,
   "files|f"  => \$opt_nodirs,
   or die "Usage: try $0 --help";

@ARGV = "." unless @ARGV;

sub printfn {
   my ($prefix, $files, $suffix) = @_;

   if ($opt_print0) {
      print map "$prefix$_$suffix\0", @$files;
   } elsif (!$opt_silent) {
      print map "$prefix$_$suffix\n", @$files;
   }
}

sub scan {
   my ($path) = @_;

   $path .= "/";

   aioreq_pri -1;
   aio_scandir $path, 8, sub {
      my ($dirs, $files) = @_;

      printfn "", [$path]   unless $opt_nodirs;
      printfn $path, $files unless $opt_nofiles;

      if ($opt_stat) {
         aio_lstat "$path$_" for @$files;
      }

      &scan ("$path$_") for @$dirs;
   };
}

IO::AIO::max_outstanding 64;
IO::AIO::min_parallel 32;

for my $seed (@ARGV) {
   $seed =~ s/\/+$//;
   aio_lstat "$seed/.", sub {
      if ($_[0]) {
         print STDERR "$seed: $!\n";
      } elsif (-d _) {
         scan $seed;
      } else {
         printfn "", $seed, "/";
      }
   };
}

IO::AIO::flush;

