#!/usr/bin/perl
# vim: tabstop=2 smarttab expandtab softtabstop=2 shiftwidth=2
# in your vimrc, please add:
#   set modeline
#   set modelines=2

use strict;
use warnings;

BEGIN {
  use FindBin;
  do $FindBin::RealBin . '/../etc/config.pm' ;
}

use Data::Dumper;
use POSIX;
use Fcntl ':mode';

my %STRING_FILE_TYPES = (
  S_IFREG => '-',
  S_IFDIR => 'd',
  S_IFLNK => 'l',
  S_IFBLK => 'b',
  S_IFCHR => 'c',
  S_IFIFO => 'p',
  S_IFSOCK => 'S',
);
my %FILE_TYPES = map { eval($_) => $STRING_FILE_TYPES{$_} }
  keys %STRING_FILE_TYPES;
my @FILE_RIGHTS = (
  [ S_IRUSR, 1, 'r' ],
  [ S_IWUSR, 2, 'w' ],
  [ S_IXUSR, 3, 'x' ],

  [ S_IRGRP, 4, 'r' ],
  [ S_IWGRP, 5, 'w' ],
  [ S_IXGRP, 6, 'x' ],

  [ S_IROTH, 7, 'r' ],
  [ S_IWOTH, 8, 'w' ],
  [ S_IXOTH, 9, 'x' ],

  [ S_ISUID, 3, 's' ],
  [ S_ISGID, 6, 's' ],
);

sub getFileInfo {
  my ($fnm) = @_;
  my $perms = '----------';
  my $owner;
  my $time ;

  -e $fnm and do {
    my ($mode, $uid, $gid, $mtime) = (stat $fnm)[2,4,5,9];
    my $user = getpwuid($uid);
    my $group = getgrgid($gid);

    my $type = S_IFMT($mode);
    my $stype = $FILE_TYPES{$type};
    defined $stype or $stype = '?';
    substr($perms, 0, 1) = $stype;

    for my $e (@FILE_RIGHTS) {
      my ($n, $p, $c) = @$e;
      ($mode & $n) == $n or next;
      substr($perms, $p, 1) = $c;
    }
    $owner = $user . '.' . $group;
    $time = strftime("%Y-%m-%d %H:%M:%S", localtime($mtime));
  };

  return $owner, $perms, $time;
}

sub browse;
sub browse {
  my ($path) = @_;
  my @files;
  opendir my $dir, $path or die $!;
  while (my $fnm = readdir $dir) {
    $fnm =~ /^\.\.?$/ and next;

    my $full = $path . '/' . $fnm;
    my ($owner, $perms) = getFileInfo $full;
    push @files, [ $perms, $owner, $full ];
    -d $full and push @files, browse($full);
  }
  closedir $dir;
  return @files;
}

my @files = sort { $$a[2] cmp $$b[2] } browse(MOUNT_DIR);

unshift @files, [ qw/perms owner path/ ];
my @len;
for my $e (@files) {
  for my $i (0..$#$e) {
    defined $len[$i] or $len[$i] = 0;
    my $len = length $$e[$i];
    $len[$i] < $len and $len[$i] = $len;
  }
}

my $fmt = join(' ', map { "%-${_}s" } @len) . "\n";
for my $e (@files) {
  printf $fmt, @$e;
}
