#!@PERL@ # # Directory list CGI by Hironori Sakamoto (hsaka@mth.biglobe.ne.jp) # if ( $^O =~ /^(ms)?(dos|win(32|nt)?)/i ) { $WIN32 = 1; $CYGPATH = 1; } elsif ( $^O =~ /cygwin|os2/i ) { $WIN32 = 1; $CYGPATH = 0; } else { $WIN32 = 0; $CYGPATH = 0; } $RC_DIR = '@RC_DIR@'; $RC_DIR =~ s@^~/@$ENV{'HOME'}/@; if ($CYGPATH) { $RC_DIR = &cygwin_pathconv("$RC_DIR"); } $CONFIG = "$RC_DIR/dirlist"; $CGI = $ENV{'SCRIPT_NAME'} || $0; $CGI = "file://" . &file_encode("$CGI"); $AFMT = '<a href="%s"><nobr>%s</nobr></a>'; $NOW = time(); @OPT = &init_option($CONFIG); $query = $ENV{'QUERY_STRING'}; $dir = ''; $cmd = ''; $cookie = ''; $local_cookie = ''; foreach(split(/\&/, $query)) { if (s/^dir=//) { $dir = &form_decode($_); } } $body = undef; if ($ENV{'REQUEST_METHOD'} eq 'POST') { sysread(STDIN, $body, $ENV{'CONTENT_LENGTH'}); foreach(split(/\&/, $body)) { if (s/^dir=//) { $dir = &form_decode($_); } elsif (s/^opt(\d+)=//) { $OPT[$1] = $_; } elsif (s/^cmd=//) { $cmd = $_; } elsif (s/^cookie=//) { $cookie = &form_decode($_); } } } $cookie_file = $ENV{'LOCAL_COOKIE_FILE'}; if (-f $cookie_file) { open(F, "< $cookie_file"); $local_cookie = <F>; close(F); } if ($local_cookie eq '' || (defined($body) && $cookie ne $local_cookie)) { print <<EOF; Content-Type: text/plain Local cookie doesn't match: It may be an illegal execution EOF exit(1); } $local_cookie = &html_quote($local_cookie); if ($dir !~ m@/$@) { $dir .= '/'; } if ($dir =~ m@^/@ && $CYGPATH) { $dir = &cygwin_pathconv("$dir"); } $ROOT = ''; if ($WIN32) { if (($dir =~ s@^//[^/]+@@) || ($dir =~ s@^[a-z]:@@i)) { $ROOT = $&; } if ($CYGPATH) { $ROOT = &cygwin_pathconv("$ROOT"); } } $dir = &cleanup($dir); $TYPE = $OPT[$OPT_TYPE]; $FORMAT = $OPT[$OPT_FORMAT]; $SORT = $OPT[$OPT_SORT]; if ($cmd) { &update_option($CONFIG); } $qdir = "$ROOT" . &html_quote("$dir"); $edir = "$ROOT" . &file_encode("$dir"); if (! opendir(DIR, "$ROOT$dir")) { print <<EOF; Content-Type: text/html <html> <head> <title>Directory list of $qdir</title> </head> <body> <b>$qdir</b>: $! ! </body> </html> EOF exit 1; } print <<EOF; Content-Type: text/html <html> <head> <title>Directory list of $qdir</title> </head> <body> <h1>Directory list of $qdir</h1> EOF &print_form($qdir, @OPT); print <<EOF; <hr> EOF $dir =~ s@/$@@; @sdirs = split('/', $dir); $_ = $sdirs[0]; if ($_ eq '') { $_ = '/'; } if ($TYPE eq $TYPE_TREE) { print <<EOF; <table hborder width="640"> <tr valign=top><td width="160"> <pre> EOF $q = "$ROOT". &html_quote("$_"); $e = "$ROOT" . &file_encode("$_"); if ($dir =~ m@^$@) { $n = "\" name=\"current"; } else { $n = ''; } printf("$AFMT\n", "$e$n", "<b>$q</b>"); $N = 0; $SKIPLINE = ""; &left_dir('', @sdirs); print <<EOF; </pre> </td><td width="400"> <pre>$SKIPLINE EOF } else { print <<EOF; <pre> EOF } &right_dir($dir); if ($TYPE eq $TYPE_TREE) { print <<EOF; </pre> </td></tr> </table> </body> </html> EOF } else { print <<EOF; </pre> </body> </html> EOF } sub left_dir { local($pre, $dir, @sdirs) = @_; local($ok) = (@sdirs == 0); local(@cdirs) = (); local($_, $dir0, $d, $qdir, $q, $edir, $e); $dir0 = "$dir/"; $dir = "$dir0"; opendir(DIR, "$ROOT$dir") || return; foreach(sort readdir(DIR)) { -d "$ROOT$dir$_" || next; /^\.$/ && next; /^\.\.$/ && next; push(@cdirs, $_); } closedir(DIR); $qdir = "$ROOT" . &html_quote($dir); $edir = "$ROOT" . &file_encode($dir); while(@cdirs) { $_ = shift @cdirs; $q = &html_quote($_); $e = &file_encode($_); $N++; if (!$ok && $_ eq $sdirs[0]) { $d = $dir0 . shift @sdirs; if (!@sdirs) { $n = "\" name=\"current"; $SKIPLINE = "\n" x $N; } else { $n = ''; } printf("${pre}o-$AFMT\n", "$edir$e$n", "<b>$q</b>"); &left_dir(@cdirs ? "$pre| " : "$pre ", $d, @sdirs); $ok = 1; } else { printf("${pre}+-$AFMT\n", "$edir$e", $q); } } } sub right_dir { local($dir) = @_; local(@list); local($_, $qdir, $q, $edir, $e, $f, $max, @d, $type, $u, $g); local($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks); local(%sizes, %ctimes, %prints); $dir = "$dir/"; opendir(DIR, "$ROOT$dir") || return; $qdir = "$ROOT" . &html_quote($dir); $edir = "$ROOT" . &file_encode($dir); if ($TYPE eq $TYPE_TREE) { print "<b>$qdir</b>\n"; } @list = (); $max = 0; foreach(readdir(DIR)) { /^\.$/ && next; # if ($TYPE eq $TYPE_TREE) { # /^\.\.$/ && next; # } $f = "$ROOT$dir$_"; (($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = lstat($f)) || next; push(@list, $_); $sizes{$_} = $size; $ctimes{$_} = $ctime; if ($FORMAT eq $FORMAT_COLUMN) { if (length($_) > $max) { $max = length($_); } next; } $type = &utype($mode); if ($FORMAT eq $FORMAT_SHORT) { $prints{$_} = sprintf("%-6s ", "[$type]"); next; } if ($type =~ /^[CB]/) { $size = sprintf("%3u, %3u", ($rdev >> 8) & 0xff, $rdev & 0xffff00ff); } if ($FORMAT eq $FORMAT_LONG) { $u = $USER{$uid} || ($USER{$uid} = getpwuid($uid) || $uid); $g = $GROUP{$gid} || ($GROUP{$gid} = getgrgid($gid) || $gid); $prints{$_} = sprintf( "%s %-8s %-8s %8s %s ", &umode($mode), $u, $g, $size, &utime($ctime)); # } elsif ($FORMAT eq $FORMAT_STANDARD) { } else { $prints{$_} = sprintf("%-6s %8s %s ", "[$type]", $size, &utime($ctime)); } } closedir(DIR); if ($SORT eq $SORT_SIZE) { @list = sort { $sizes{$b} <=> $sizes{$a} || $a cmp $b } @list; } elsif ($SORT eq $SORT_TIME) { @list = sort { $ctimes{$b} <=> $ctimes{$a} || $a cmp $b } @list; } else { @list = sort @list; } if ($FORMAT eq $FORMAT_COLUMN) { local($COLS, $l, $nr, $n); if ($TYPE eq $TYPE_TREE) { $COLS = 60; } else { $COLS = 80; } $l = int($COLS / ($max + 2)) || 1; $nr = int($#list / $l + 1); $n = 0; print "<table>\n<tr valign=top>"; foreach(@list) { $f = "$ROOT$dir$_"; $q = &html_quote($_); $e = &file_encode($_); if ($n % $nr == 0) { print "<td>"; } if (-d $f) { printf($AFMT, "$edir$e", "$q/"); } else { printf($AFMT, "$edir$e", $q); } $n++; if ($n % $nr == 0) { print "</td>\n"; } else { print "<br>\n"; } } print "</tr></table>\n"; return; } foreach(@list) { $f = "$ROOT$dir$_"; $q = &html_quote($_); $e = &file_encode($_); print $prints{$_}; if (-d $f) { printf($AFMT, "$edir$e", "$q/"); } else { printf($AFMT, "$edir$e", $q); } if (-l $f) { print " -> ", &html_quote(readlink($f)); } print "\n"; } } sub init_option { local($config) = @_; $OPT_TYPE = 0; $OPT_FORMAT = 1; $OPT_SORT = 2; $TYPE_TREE = 't'; $TYPE_STANDARD = 'd'; $FORMAT_SHORT = 's'; $FORMAT_STANDARD = 'd'; $FORMAT_LONG = 'l'; $FORMAT_COLUMN = 'c'; $SORT_NAME = 'n'; $SORT_SIZE = 's'; $SORT_TIME = 't'; local(@opt) = ($TYPE_TREE, $FORMAT_STANDARD, $SORT_NAME); local($_); open(CONFIG, "< $config") || return @opt; while(<CONFIG>) { chop; s/^\s+//; tr/A-Z/a-z/; if (/^type\s+(\S)/i) { $opt[$OPT_TYPE] = $1; } elsif (/^format\s+(\S)/i) { $opt[$OPT_FORMAT] = $1 } elsif (/^sort\s+(\S)/i) { $opt[$OPT_SORT] = $1; } } close(CONFIG); return @opt; } sub update_option { local($config) = @_; open(CONFIG, "> $config") || return; print CONFIG <<EOF; type $TYPE format $FORMAT sort $SORT EOF close(CONFIG); } sub print_form { local($d, @OPT) = @_; local(@disc) = ('Type', 'Format', 'Sort'); local(@val) = ( "('t', 'd')", "('s', 'd', 'c')", "('n', 's', 't')", ); local(@opt) = ( "('Tree', 'Standard')", "('Short', 'Standard', 'Column')", "('By Name', 'By Size', 'By Time')" ); local($_, @vs, @os, $v, $o); print <<EOF; <form method=post action=\"$CGI#current\"> <center> <table cellpadding=0> <tr valign=top> EOF foreach(0 .. 2) { print "<td align> $disc[$_]</td>\n"; } print "</tr><tr>\n"; foreach(0 .. 2) { print "<td><select name=opt$_>\n"; eval "\@vs = $val[$_]"; eval "\@os = $opt[$_]"; foreach $v (@vs) { $o = shift(@os); if ($v eq $OPT[$_]) { print "<option value=$v selected>$o\n"; } else { print "<option value=$v>$o\n"; } } print "</select></td>\n"; } print <<EOF; <td><input type=submit name=cmd value="Update"></td> </tr> </table> </center> <input type=hidden name=dir value="$d"> <input type=hidden name=cookie value="$local_cookie"> </form> EOF } sub html_quote { local($_) = @_; local(%QUOTE) = ( '<', '<', '>', '>', '&', '&', '"', '"', ); s/[<>&"]/$QUOTE{$&}/g; return $_; } sub file_encode { local($_) = @_; s/[\000-\040\+:#?&%<>"\177-\377]/sprintf('%%%02X', unpack('C', $&))/eg; return $_; } sub form_decode { local($_) = @_; s/\+/ /g; s/%([\da-f][\da-f])/pack('C', hex($1))/egi; return $_; } sub cleanup { local($_) = @_; s@//+@/@g; s@/\./@/@g; while(m@/\.\./@) { s@^/(\.\./)+@/@; s@/[^/]+/\.\./@/@; } return $_; } sub utype { local($_) = @_; local(%T) = ( 0010000, 'PIPE', 0020000, 'CHR', 0040000, 'DIR', 0060000, 'BLK', 0100000, 'FILE', 0120000, 'LINK', 0140000, 'SOCK', ); return $T{($_ & 0170000)} || 'FILE'; } sub umode { local($_) = @_; local(%T) = ( 0010000, 'p', 0020000, 'c', 0040000, 'd', 0060000, 'b', 0100000, '-', 0120000, 'l', 0140000, 's', ); return ($T{($_ & 0170000)} || '-') . (($_ & 00400) ? 'r' : '-') . (($_ & 00200) ? 'w' : '-') . (($_ & 04000) ? 's' : (($_ & 00100) ? 'x' : '-')) . (($_ & 00040) ? 'r' : '-') . (($_ & 00020) ? 'w' : '-') . (($_ & 02000) ? 's' : (($_ & 00010) ? 'x' : '-')) . (($_ & 00004) ? 'r' : '-') . (($_ & 00002) ? 'w' : '-') . (($_ & 01000) ? 't' : (($_ & 00001) ? 'x' : '-')); } sub utime { local($_) = @_; local(@MON) = ( 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ); local($sec,$min,$hour,$mday,$mon, $year,$wday,$yday,$isdst) = localtime($_); if ($_ > $NOW - 182*24*60*60 && $_ < $NOW + 183*24*60*60) { return sprintf("%3s %2d %.2d:%.2d", $MON[$mon], $mday, $hour, $min); } else { return sprintf("%3s %2d %5d", $MON[$mon], $mday, 1900+$year); } } sub cygwin_pathconv { local($_) = @_; local(*CYGPATH); open(CYGPATH, '-|') || exec('cygpath', '-w', $_); $_ = <CYGPATH>; close(CYGPATH); s/\r?\n$//; s!\\!/!g; s!/$!!; return $_; }