#!/usr/bin/perl
#
# Copyright (c) 1998 Tomokazu ISHII <t-ishii@tryplanet.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#================================================
# ftpfind v0.996 1998/12/08
# find directory&file on a ftp server
#================================================
#--------------------------------
# equ definition
$verbose = 1; # 0:off, 1:normal, 2:debug
$SOCK_STREAM = 1; # Solaris:2, other:1
$copy_timestamp = 1; # 0:no, 1:copy
$opt_cpmod = 1; # 0:no, 1:yes
$sock_addr = 'S n a4 x8';
$cport = 21; # control port
$dport = 0; # data port (0:let system pick one)
$AF_INET = 2;
$use_pasv = 0; # 0:no, 1:yes
#--------------------------------
# options
$opt_url = '';
$opt_server = '';
$opt_dir = '';
$opt_localdir = '';
$opt_login = '';
$opt_password = '';
$opt_proxy = '';
$opt_ls = 0;
@opt_regexp = ();
$opt_print = 0;
@opt_types = (); # d:directory, f:file, l:symbolic link
$opt_movekind = 0; # 0:none, 1:delete, 2:get, 3:put, 4:chmod
$opt_new = 0;
$opt_resume = 0;
$opt_chmod = '';
#--------------------------------
# main
$oldfh = select(STDERR);
$| = 1;
select(STDOUT);
$| = 1;
select($oldfh);
$ENV{'TZ'} = 'GMT';
&set_opt();
&print_opt();
# connect
&copen();
if ($opt_proxy eq '') {
&cconnect($opt_server, $cport);
&login($opt_login, $opt_password);
}
else {
&cconnect($opt_proxy, $cport);
&login($opt_login.'@'.$opt_server, $opt_password);
}
&cmdTYPE("i");
if ($opt_dir eq '') {
$opt_dir = &cmdPWD();
if ($opt_dir eq '') {
$opt_dir = '/';
}
}
&do_all();
# end process
&cmdQUIT();
close(SCTRL);
&print_msg(2,"process end.\n");
exit 0;
#--------------------------------
# do_all()
sub do_all {
local(@files,$file,@words);
if (($opt_movekind == 0) || ($opt_movekind == 4)) { # none or chmod
if (&cmdCWD($opt_dir) == 0) {
if ($opt_dir !~ /\/$/) {
$opt_dir .= '/';
}
&do_print_alldirs($opt_dir);
}
else {
@files = &cmdLIST($opt_dir);
$file = $files[0];
$file =~ s/[\r\n]//g;
@words = &lsparse($file);
if (($#files != 0) || ($#words == 0)) {
&print_msg(1,"%s: No such file or directory\n",$opt_dir);
}
else {
&do_print_onefile($opt_dir,$file);
}
}
}
elsif ($opt_movekind == 1) { # delete
if (&cmdCWD($opt_dir) == 0) {
if ($opt_dir !~ /\/$/) {
$opt_dir .= '/';
}
&do_delete_alldirs($opt_dir);
}
else {
@files = &cmdLIST($opt_dir);
$file = $files[0];
$file =~ s/[\r\n]//g;
@words = &lsparse($file);
if (($#files != 0) || ($#words == 0)) {
&print_msg(1,"%s: No such file or directory\n",$opt_dir);
}
else {
&do_delete_onefile($opt_dir,$file);
}
}
}
elsif ($opt_movekind == 2) { # get
if ($opt_localdir !~ /\/$/) {
$opt_localdir .= '/';
}
if (&cmdCWD($opt_dir) == 0) {
if ($opt_dir !~ /\/$/) {
$opt_dir .= '/';
}
&do_get_alldirs($opt_dir,$opt_localdir);
}
else {
if ($opt_dir =~ /\/$/) {
&print_msg(1,"%s: No such directory\n",$opt_dir);
return;
}
@files = &cmdLIST($opt_dir);
$file = $files[0];
$file =~ s/[\r\n]//g;
@words = &lsparse($file);
if (($#files != 0) || ($#words == 0)) {
&print_msg(1,"%s: No such file or directory\n",$opt_dir);
}
else {
local(@tmp) = split(/\//,$words[0]);
&do_get_onefile($opt_dir,$file,
$opt_localdir . $tmp[$#tmp],0);
}
}
}
elsif ($opt_movekind == 3) { # put
if (-e $opt_localdir) {
if ($opt_dir !~ /\/$/) {
$opt_dir .= '/';
}
if (-d $opt_localdir) {
if ($opt_localdir !~ /\/$/) {
$opt_localdir .= '/';
}
&do_put_alldirs($opt_dir,$opt_localdir);
}
elsif ($opt_localdir !~ /\/$/) {
@words = split(/\//,$opt_localdir);
&do_put_onefile($opt_dir . $words[$#words],$opt_localdir);
}
}
}
}
#--------------------------------
# usage()
sub usage {
print "usage: $0 URL [-proxy proxy_server] \\\n";
print " [-login login_name] [-password password] \\\n";
print " [-regexp pattern] [-type d|f|l] [-ls] [-print] \\\n";
print " [-delete|-get [directory] [-new] [-resume] \\\n";
print " |-put [directory] [-new] \\\n";
print " |-chmod 0???]\n";
}
#--------------------------------
# print_msg()
sub print_msg {
local($level) = shift(@_);
if ($level <= $verbose) {
printf(STDERR @_);
}
}
#--------------------------------
# lsparse(file_status)
sub lsparse {
local($file_status) = $_[0];
if ($file_status =~ /^(\S+)$/) {
return ($1,$1);
}
elsif ($file_status =~ /^([\-dFl][\-rwxSsTt]{9})\s+(.*)\s+(.*) -> (.*)$/) {
return ($3,$1,$2,$4);
}
elsif ($file_status =~ /^([\-dFl][\-rwxSsTt]{9})\s+(.*)\s+(.*)$/) {
return ($3,$1,$2);
}
else {
if (($file_status =~ /^\S{10}(\s+\S+){8}/)
|| ($file_status =~ /^\S{10}(\s+\S+){10}/)) {
&print_msg(2, "%s: unsupported file mode\n", $file_status);
}
else {
&print_msg(2, "%s: parse error\n", $file_status);
}
return;
}
}
#++++++++++++++++++++++++++++++++++++++++++++++++
# -ls, -print option only ...plus chmod
#++++++++++++++++++++++++++++++++++++++++++++++++
#--------------------------------
# do_print_alldirs(path)
sub do_print_alldirs {
local($path_remote) = $_[0];
local(@files,$file,@words);
local($i,$path_tmp);
if ($path_remote !~ /\/$/) {
$path_remote .= '/';
}
@files = &cmdLIST('.');
for ($i=0 ; $i<=$#files ; $i++) {
$file = $files[$i];
$file =~ s/[\r\n]//g;
@words = &lsparse($file);
if (($#words == 0) || ($words[0] eq '.') || ($words[0] eq '..')) {
next;
}
&do_print_onefile($path_remote . $words[0],$file);
if ($#words == 1) {
if (&cmdCWD($path_remote . $words[0]) == 0) {
&do_print_alldirs($path_remote . $words[0]);
}
}
elsif ($words[1] =~ /^d/) {
if (&cmdCWD($path_remote . $words[0]) == 0) {
&do_print_alldirs($path_remote . $words[0]);
}
}
elsif (($words[1] =~ /^l/) && ($#words == 3)) {
if (&check_scope($opt_dir,$path_remote,$words[3]) != 0) {
if (&cmdCWD($path_remote . $words[0]) == 0) {
&do_print_alldirs($path_remote . $words[0]);
}
}
}
}
}
#--------------------------------
# do_print_onefile(path_remote,file_status)
sub do_print_onefile {
local($path) = $_[0];
local($file) = $_[1];
if (&ifselect($file) != 0) {
&do_ls($path,$file);
&do_print($path);
if ($opt_movekind == 4) { # chmod
&cmdCHMOD($opt_chmod,$path);
}
}
}
#--------------------------------
# ifselect(file_status)
sub ifselect {
local($i);
local(@words) = &lsparse($_[0]);
local($flag) = 1;
for ($i = 0; $i <= $#opt_regexp; $i++) {
if ($words[0] !~ $opt_regexp[$i]) {
$flag = 0;
}
}
for ($i = 0; $i <= $#opt_types; $i++) {
if ($words[1] !~ /^$opt_types[$i]/) {
$flag = 0;
}
}
return $flag;
}
#--------------------------------
# do_ls(path_remote,file_status)
sub do_ls {
if ($opt_ls != 0) {
local(@words) = &lsparse($_[1]);
if ($#words <= 1) {
&do_print($_[0]);
return;
}
printf("%s ", $words[1]);
local(@w2) = split(/ +/,$words[2]);
printf("%4s ", $w2[0]);
if ($#w2 == 5) {
printf("%-17s ", $w2[1]);
printf("%8s ", $w2[2]);
printf("%4s %4s %6s ", $w2[3], $w2[4], $w2[5]);
}
elsif ($#w2 == 6) {
printf("%-8s %-8s ", $w2[1], $w2[2]);
printf("%8s ", $w2[3]);
printf("%4s %4s %6s ", $w2[4], $w2[5], $w2[6]);
}
else {
&print_msg(2, "%s: parse error\n", $words[2]);
}
if ($#words == 3) {
printf("%s -> %s",$_[0],$words[3]);
}
else {
printf("%s",$_[0]);
}
printf("\n");
return;
}
}
#--------------------------------
# do_print(path)
sub do_print {
if ($opt_print != 0) {
printf("$_[0]\n");
}
}
#++++++++++++++++++++++++++++++++++++++++++++++++
# -delete option
#++++++++++++++++++++++++++++++++++++++++++++++++
#--------------------------------
# do_delete_alldirs(directory)
sub do_delete_alldirs {
local($path) = $_[0];
local(@files,$file,@words);
local($i,$path_tmp);
if ($path !~ /\/$/) {
$path .= '/';
}
@files = &cmdLIST('.');
for ($i=0 ; $i<=$#files ; $i++) {
$file = $files[$i];
$file =~ s/[\r\n]//g;
@words = &lsparse($file);
if (($#words == 0) || ($words[0] eq '.') || ($words[0] eq '..')) {
next;
}
if ($#words == 1) {
if (&cmdCWD($path . $words[0]) == 0) {
&do_delete_alldirs($path . $words[0]);
&cmdCWD('..');
&do_delete_onefile($path . $words[0], 'd');
}
else {
&do_delete_onefile($path . $words[0], 'f');
}
}
else {
if ($words[1] =~ /^d/) {
if (&cmdCWD($path . $words[0]) == 0) {
&do_delete_alldirs($path . $words[0]);
&cmdCWD('..');
}
}
if ($words[1] =~ /^[\-Fdl]/) {
&do_delete_onefile($path . $words[0], $file);
}
}
}
}
#--------------------------------
# do_delete_onefile(path_remote,file_status)
sub do_delete_onefile {
local($path) = $_[0];
local($file) = $_[1];
if (&ifselect($file) != 0) {
&do_ls($path,$file);
&do_print($path,$file);
&do_delete($path,$file);
}
}
#--------------------------------
# do_delete(path_remote,file_status)
sub do_delete {
local($path) = $_[0];
local($file) = $_[1];
if ($file =~ /^d/) {
&cmdRMD($path);
}
else {
&cmdDELE($path);
}
}
#++++++++++++++++++++++++++++++++++++++++++++++++
# -get option
#++++++++++++++++++++++++++++++++++++++++++++++++
#--------------------------------
# do_get_alldirs(path_remote,path_local)
sub do_get_alldirs {
local($path_remote) = $_[0];
local($path_local) = $_[1];
local(@files,$file,@words);
local($i,$path_tmp);
if ($path_remote !~ /\/$/) {
$path_remote .= '/';
}
@files = &cmdLIST('.');
if ($path_local !~ /\/$/) {
$path_local .= '/';
}
for ($i=0 ; $i<=$#files ; $i++) {
$file = $files[$i];
$file =~ s/[\r\n]//g;
@words = &lsparse($file);
if (($#words == 0) || ($words[0] eq '.') || ($words[0] eq '..')) {
next;
}
if ($#words == 1) {
if (&cmdCWD($path_remote . $words[0]) == 0) {
&do_get_onefile($path_remote . $words[0],$file,
$path_local . $words[0],1);
&do_get_alldirs($path_remote . $words[0],
$path_local . $words[0]);
}
else {
&do_get_onefile($path_remote . $words[0],$file,
$path_local . $words[0],0);
}
}
elsif ($words[1] =~ /^[\-F]/) {
&do_get_onefile($path_remote . $words[0],$file,
$path_local . $words[0],0);
}
elsif ($words[1] =~ /^d/) {
if (&cmdCWD($path_remote . $words[0]) == 0) {
&do_get_onefile($path_remote . $words[0],$file,
$path_local . $words[0],1);
&do_get_alldirs($path_remote . $words[0],
$path_local . $words[0]);
}
}
elsif (($words[1] =~ /^l/) && ($#words == 3)) {
if (&check_scope($opt_dir,$path_remote,$words[3]) == 0) {
&do_get_onefile($path_remote . $words[0],$file,
$path_local . $words[0],2);
}
else {
if (&cmdCWD($path_remote . $words[0]) == 0) {
&do_get_onefile($path_remote . $words[0],$file,
$path_local . $words[0],1);
&do_get_alldirs($path_remote . $words[0],
$path_local . $words[0]);
}
else {
&do_get_onefile($path_remote . $words[0],$file,
$path_local . $words[0],0);
}
}
}
}
}
#--------------------------------
# do_get_onefile(path_remote,file_status,path_local,type)
# type: 0=file,1=directory,2=symlink
sub do_get_onefile {
local($path_remote) = $_[0];
local($file) = $_[1];
local($path_local) = $_[2];
local($type) = $_[3];
local($flag_chmod) = 1;
local(@words,$len,$get_type);
local($timestamp);
# get_type: 0=all,1=append
if (&ifselect($file) != 0) {
$get_type = 0;
if ($opt_resume != 0) {
$len = -s $path_local;
@words = split(/ +/,$file);
if ($words[4] <= $len) {
return;
}
$get_type = 1;
}
if ($copy_timestamp != 0) {
$timestamp = &cmdMDTM($path_remote);
}
if (($opt_new != 0) && (-e $path_local)) {
if ($type == 0) {
if ($copy_timestamp == 0) {
if (&check_time($path_remote,$path_local) <= 0) {
return;
}
}
else {
if (&check_time2($timestamp,$path_local) <= 0) {
return;
}
}
$get_type = 0;
}
elsif ($type == 1) {
return;
}
}
&do_print_onefile($path_remote,$file);
if ($type == 0) { # file
&create_localdir($path_local);
&do_get($path_remote,$path_local,$get_type);
if (($copy_timestamp != 0) && ($timestamp ne '00000000000000')) {
&set_timestamp($timestamp, $path_local);
}
}
elsif ($type == 1) { # directory
if ($path_local !~ /\/$/) {
$path_local .= '/';
}
&create_localdir($path_local);
}
elsif ($type == 2) { # symlink
$flag_chmod = 0;
@words = &lsparse($file);
if ($words[3] =~ /^\//) {
$words[3] =~ s/^$opt_dir/$opt_localdir/;
}
&create_localdir($path_local);
if (-e $path_local) {
if (unlink($path_local) != 1) {
&print_msg(1,"unlink: %s\n",$!);
}
}
symlink($words[3],$path_local);
}
if (($opt_cpmod != 0) && ($flag_chmod != 0)) {
local($mode) = &get_permission_remote($file);
&print_msg(2,"chmod %04o %s\n",$mode,$path_local);
if (chmod($mode,$path_local) == 0) {
&print_msg(1,"cannot execute \'chmod %04o %s\'.\n",
$mode,$path_local);
# exit 1;
}
}
}
}
#--------------------------------
# do_get(path_remote,path_local,get_type)
# get_type: 0=all,1=append
sub do_get {
if ($_[2] == 0) {
&cmdRETR($_[0],$_[1]);
}
else {
&cmdREST($_[0],$_[1],-s $_[1]);
}
}
#--------------------------------
# create_localdir(path_local)
sub create_localdir {
local($path) = $_[0];
local(@words) = split(/\//,$path);
local($tmp) = '';
local($i);
if ($path =~ /\/$/) {
$imax = $#words;
}
else {
$imax = $#words - 1;
}
for ( $i = 0 ; $i <= $imax ; $i++ ) {
if ($words[$i] eq '') {
next;
}
$tmp .= '/' . $words[$i];
if ((-d $tmp) == 0) {
if (mkdir($tmp,0777) == 0) {
&print_msg(1,"mkdir: %s\n",$!);
exit 1;
}
}
}
return 0;
}
#--------------------------------
# check_time(file_remote,file_local)
# return 0: equal
# -1: file_remote <(new) file_local
# 1: file_remote (new)> file_local
sub check_time {
local($time_remote) = &cmdMDTM($_[0]);
local(@status) = stat($_[1]);
local(@time_tmp) = gmtime($status[9]);
local($time_local)
= sprintf("19%02d%02d%02d%02d%02d%02d",
$time_tmp[5],$time_tmp[4]+1,
$time_tmp[3],$time_tmp[2],
$time_tmp[1],$time_tmp[0] );
if ($time_remote eq $time_local) {
return 0;
}
elsif ($time_remote lt $time_local) {
return -1;
}
else {
return 1;
}
}
#--------------------------------
# check_time2(time_remote,file_local)
# return 0: equal
# -1: time_remote <(new) file_local
# 1: time_remote (new)> file_local
sub check_time2 {
local($time_remote) = $_[0];
local(@status) = stat($_[1]);
local(@time_tmp) = gmtime($status[9]);
local($time_local)
= sprintf("19%02d%02d%02d%02d%02d%02d",
$time_tmp[5],$time_tmp[4]+1,
$time_tmp[3],$time_tmp[2],
$time_tmp[1],$time_tmp[0] );
if ($time_remote eq $time_local) {
return 0;
}
elsif ($time_remote lt $time_local) {
return -1;
}
else {
return 1;
}
}
#--------------------------------
# get_permission_remote(file_status)
sub get_permission_remote {
local($status) = $_[0];
local($l,$c,$r) = (0,0,0);
if ($status =~ /^.r......../) { $l += 4; }
if ($status =~ /^..w......./) { $l += 2; }
if ($status =~ /^...x....../) { $l += 1; }
if ($status =~ /^....r...../) { $c += 4; }
if ($status =~ /^.....w..../) { $c += 2; }
if ($status =~ /^......x.../) { $c += 1; }
if ($status =~ /^.......r../) { $r += 4; }
if ($status =~ /^........w./) { $r += 2; }
if ($status =~ /^.........x/) { $r += 1; }
return (($l*8*8)+($c*8)+$r);
}
#--------------------------------
# check_scope(basedir,remote_path,file)
sub check_scope {
local($basedir) = $_[0];
local($remote_path) = $_[1];
local($file) = $_[2];
if ($file =~ /^\//) {
if ($file =~ /^$basedir/) {
return 0;
}
}
else {
local($q0,$q1,$total);
local($min,$q2,$q3);
if ($basedir eq $remote_path) {
$total = 0;
}
else {
local(@words) = split(/^$basedir/,$remote_path);
if ( $#words != 1 ) {
return 1;
}
($q0,$q1,$total) = &ptoi($words[1]);
}
($min,$q2,$q3) = &ptoi($file);
if (0 <= ($total+$min)) {
return 0;
}
}
return 1;
}
#--------------------------------
# ptoi(path)
sub ptoi {
local(@words) = split(/\//,$_[0]);
local($min,$max,$total) = (0,0,0);
local($i);
for ($i = 0 ; $i <= $#words ; $i++) {
if ( $words[$i] eq '.' ) {
next;
} elsif ( $words[$i] eq '..' ) {
$total--;
} else {
$total++;
}
if ($total < $min) {
$min = $total;
}
if ($max < $total) {
$max = $total;
}
}
return ($min,$max,$total);
}
#--------------------------------
# set_timestamp(timestamp, path)
sub set_timestamp {
local($timestamp) = $_[0];
local($path) = $_[1];
if ($timestamp =~ /^(\d{12})(\d\d)$/) {
local(@args) = ("touch","-am","-t","$1.$2","$path");
if (system(@args) != 0) {
&print_msg(1,"touch %s: %s\n", $path, $!);
exit 1;
}
}
}
#++++++++++++++++++++++++++++++++++++++++++++++++
# -put option
#++++++++++++++++++++++++++++++++++++++++++++++++
#--------------------------------
# do_put_alldirs(path_remote,path_local)
sub do_put_alldirs {
local($path_remote) = $_[0];
local($path_local) = $_[1];
local($file);
local(@tmp);
if ($path_remote =~ /\/$/) {
chop($path_remote);
}
if (-d $path_local) {
if ($path_local =~ /\/$/) {
chop($path_local);
}
}
else {
if ($path_local =~ /\/$/) {
&usage();
exit 1;
}
}
local(@allfiles) = &local_allfilename($path_local);
while(@allfiles) {
@tmp = split(/$path_local/,$allfiles[0]);
$file = $tmp[1];
if ($file eq '') {
shift @allfiles;
next;
}
&do_put_onefile($path_remote . $file,$allfiles[0]);
shift @allfiles;
}
}
#--------------------------------
# do_put_onefile(path_remote,path_local)
sub do_put_onefile {
local($path_remote) = $_[0];
local($path_local) = $_[1];
local($mode);
if (&ifselect_local($path_local) != 0) {
if ($opt_new != 0) {
if (&check_time($path_remote,$path_local) >= 0) {
return;
}
}
if (-d $path_local) {
&do_print_local($path_remote);
&cmdMKD($path_remote);
}
else {
&do_print_local($path_remote);
&cmdSTOR($path_local,$path_remote);
}
if ($opt_cpmod != 0) {
$mode = sprintf("%04o",&get_permission_local($path_local));
&print_msg(2,"chmod %s %s\n",$mode,$path_remote);
&cmdCHMOD($mode,$path_remote);
}
}
}
#--------------------------------
# local_allfilename(directory)
sub local_allfilename {
local(@files,@status,@allfiles);
local($dir) = $_[0];
if (open(FILES,"find $dir -print -follow|") == 0) {
&print_msg(1,"open: %s\n",$!);
exit 1;
}
while (<FILES>) {
chop($_);
push(@files,$_);
}
close(FILES);
@allfiles = sort(@files);
}
#--------------------------------
# ifselect_local(file_local)
sub ifselect_local {
local($path) = $_[0];
local(@words) = split(/\//,$path);
local($file) = $words[$#words];
local($flag) = 1;
local($i);
for ($i = 0 ; $i <= $#opt_regexp ; $i++) {
if ($file !~ $opt_regexp[$i]) {
$flag = 0;
}
}
for ( $i = 0 ; $i <= $#opt_types ; $i++ ) {
if (-l $path) {
if ($opt_types[$i] ne 'l') {
$flag = 0;
}
}
elsif (-d $path) {
if ($opt_types[$i] ne 'd') {
$flag = 0;
}
}
elsif (-f $path) {
if ($opt_types[$i] ne '-') {
$flag = 0;
}
}
}
return $flag;
}
#--------------------------------
# do_print_local(path)
sub do_print_local {
if (($opt_print != 0) || ($opt_ls != 0)) {
printf("$_[0]\n");
}
}
#--------------------------------
# get_permission_local(path)
sub get_permission_local {
local(@status) = stat($_[0]);
return ($status[2]%(8*8*8));
}
#++++++++++++++++++++++++++++++++++++++++++++++++
# parse option
#++++++++++++++++++++++++++++++++++++++++++++++++
#--------------------------------
# print_opt()
sub print_opt {
local($i);
if (2 <= $verbose) {
printf( STDERR "url: %s\n", $opt_url );
printf( STDERR "server: %s\n", $opt_server );
printf( STDERR "dir: %s\n", $opt_dir );
printf( STDERR "proxy: %s\n", $opt_proxy );
printf( STDERR "login: %s\n", $opt_login );
if (3 <= $verbose) {
printf( STDERR "password: %s\n", $opt_password );
}
printf( STDERR "ls: %d\n", $opt_ls );
for ( $i = 0 ; $i <= $#opt_regexp ; $i++ ) {
printf( STDERR "regexp%d: %s\n", $i, $opt_regexp[$i] );
}
for ( $i = 0 ; $i <= $#opt_types ; $i++ ) {
printf( STDERR "type%d: %s\n", $i, $opt_types[$i] );
}
printf( STDERR "print: %d\n", $opt_print );
printf( STDERR "(0:none,1:delete,2:get,3:put,4:chmod): %d\n", $opt_movekind);
printf( STDERR "localdir: %s\n", $opt_localdir );
printf( STDERR "new: %d\n", $opt_new );
printf( STDERR "resume: %d\n", $opt_resume );
printf( STDERR "chmod: %s\n", $opt_chmod );
printf( STDERR "cpmod: %d\n", $opt_cpmod );
}
}
#--------------------------------
# set_opt()
sub set_opt {
local($ret_login,$ret_password);
local($tmp);
&analyze_args();
($opt_server,$opt_dir) = &analyze_url($opt_url);
($ret_login,$ret_password) = &read_netrc($opt_server);
if ($opt_login eq '') {
$opt_login = $ret_login;
if ($opt_login eq '') {
$opt_login = getlogin();
printf(STDERR "Name (%s:%s): ", $opt_server,$opt_login);
$tmp = <STDIN>;
chop($tmp);
if ($tmp =~ /\S+/) {
$opt_login = $&;
}
}
}
if ($opt_password eq '') {
$opt_password = $ret_password;
if ($opt_password eq '') {
system 'stty', '-echo';
printf(STDERR "Password: ");
$opt_password = <STDIN>;
printf(STDERR "\n");
chop($opt_password);
system 'stty', 'echo';
}
}
}
#--------------------------------
# analyze_args()
sub analyze_args {
local($i);
if ($#ARGV < 0) {
&usage();
exit 1;
}
$i = 0; # url
$opt_url = $ARGV[$i];
$i++;
for ( ; $i <= $#ARGV ; $i++ ) {
if ($ARGV[$i] eq '-login') { # -login
$i++;
if (($#ARGV < $i) || ($opt_login ne '')) {
&usage();
exit 1;
}
$opt_login = $ARGV[$i];
}
elsif ($ARGV[$i] eq '-password') { # -password
$i++;
if (($#ARGV < $i) || ($opt_password ne '')) {
&usage();
exit 1;
}
$opt_password = $ARGV[$i];
}
elsif ($ARGV[$i] eq '-ls') { # -ls
$opt_ls = 1;
}
elsif ($ARGV[$i] eq '-regexp') { # -regexp
$i++;
if ($#ARGV < $i) {
&usage();
exit 1;
}
push(@opt_regexp,$ARGV[$i]);
}
elsif ($ARGV[$i] eq '-type') { # -type
$i++;
if ($#ARGV < $i) {
&usage();
exit 1;
}
if ($ARGV[$i] !~ /^[dfl]$/) {
&usage();
exit 1;
}
if ($ARGV[$i] !~ /f/) {
push(@opt_types,$ARGV[$i]);
}
else {
push(@opt_types,'-');
}
}
elsif ($ARGV[$i] eq '-print') { # -print
$opt_print = 1;
}
elsif ($ARGV[$i] eq '-delete') { # -delete
if ($opt_movekind != 0) {
&usage();
exit 1;
}
$opt_movekind = 1;
}
elsif ($ARGV[$i] eq '-get') { # -get
if ($opt_movekind != 0) {
&usage();
exit 1;
}
$opt_movekind = 2;
if (($i < $#ARGV) && ($ARGV[$i+1] !~ /^-/)) {
$i++;
$opt_localdir = $ARGV[$i];
}
}
elsif ($ARGV[$i] eq '-put') { # -put
if ($opt_movekind != 0) {
&usage();
exit 1;
}
$opt_movekind = 3;
if (($i < $#ARGV) && ($ARGV[$i+1] !~ /^-/)) {
$i++;
$opt_localdir = $ARGV[$i];
}
}
elsif ($ARGV[$i] eq '-new') { # -new
if (($opt_movekind != 2) && ($opt_movekind != 3)) {
&usage();
exit 1;
}
$opt_new = 1;
}
elsif ($ARGV[$i] eq '-resume') { # -resume
if ($opt_movekind != 2) {
&usage();
exit 1;
}
$opt_resume = 1;
}
elsif ($ARGV[$i] eq '-chmod') { # -chmod
$i++;
if (($opt_movekind != 0) || ($#ARGV < $i)) {
&usage();
exit 1;
}
if ($ARGV[$i] !~ /^0[0-7][0-7][0-7]$/) {
&usage();
exit 1;
}
$opt_movekind = 4;
$opt_chmod = $ARGV[$i];
}
elsif ($ARGV[$i] eq '-cpmod') { # -cpmod
if (($opt_movekind != 2) && ($opt_movekind != 3)) {
&usage();
exit 1;
}
$opt_cpmod = 1;
}
elsif ($ARGV[$i] eq '-proxy') { # -proxy
$i++;
if (($#ARGV < $i) || ($opt_proxy ne '')) {
&usage();
exit 1;
}
$opt_proxy = $ARGV[$i];
}
else {
&usage();
exit 1;
}
}
if (($opt_movekind == 2) || ($opt_movekind == 3)) {
if ($opt_localdir !~ /^\//) {
$opt_localdir = $ENV{'PWD'} . '/' . $opt_localdir;
}
}
if (($opt_movekind == 0)
&& ($opt_ls == 0)
&& ($opt_print == 0)) {
$opt_print = 1;
}
}
#--------------------------------
# analyze_url(url)
sub analyze_url {
local($url) = $_[0];
local($server,$directory);
if ($url =~ /^ftp:\/\/(\S+)/) {
$url = $1;
}
if (($i = index($url,'/')) == -1) {
$server = $url;
}
else {
$server = substr($url,0,$i);
$directory = substr($url,$i);
}
return ($server,$directory);
}
#--------------------------------
# read_netrc(machine)
sub read_netrc {
local($machine) = $_[0];
local($file) = $ENV{'HOME'};
local($ret_login) = '';
local($ret_password) = '';
local(@words);
if ($file =~ /\/$/) {
$file .= '.netrc';
}
else {
$file .= '/' . '.netrc';
}
if (open(NETRC,$file) == 0) {
&print_msg(2,"cannot open %s.\n",$file);
return ('','');
}
$i = 0;
while (<NETRC>) {
chop($_);
@words = split(/ +/,$_);
if (($words[0] =~ /^machine/) && ($words[1] eq $machine)) {
$i = 2;
}
elsif ($words[0] =~ /^default/) {
$i = 1;
}
if ($i != 0) {
for ( ; $i <= $#words ; $i++ ) {
if ($words[$i] eq 'login') {
$i++;
$ret_login = $words[$i];
}
elsif ($words[$i] eq 'password') {
$i++;
$ret_password = $words[$i];
}
}
last;
}
}
close(NETRC);
return ($ret_login,$ret_password);
}
#++++++++++++++++++++++++++++++++++++++++++++++++
# socket
#++++++++++++++++++++++++++++++++++++++++++++++++
#--------------------------------
# copen()
sub copen {
local($oldfh);
if (socket(SCTRL,$AF_INET,$SOCK_STREAM,0) == 0) {
&print_msg(1,"socket: %s\n",$!);
exit 1;
}
$oldfh = select(SCTRL);
$| = 1;
select($oldfh);
}
#--------------------------------
# cconnect(server,port)
sub cconnect {
local($name,$aliases,$type,$len,$thataddr,$that);
($name,$aliases,$type,$len,$thataddr) = gethostbyname($_[0]);
$that = pack($sock_addr,$AF_INET,$_[1],$thataddr);
if (connect(SCTRL,$that) == 0) {
&print_msg(1,"connect: %s\n",$!);
exit 1;
}
local($tmp);
for (;;) {
$tmp = &cgets();
if ($tmp !~ /^2/) {
&print_msg(1,"connect failed.\n");
exit 1;
}
elsif ($tmp =~ /^220[ \t]/) {
last;
}
}
}
#--------------------------------
sub cprintf {
&print_msg(2,@_);
printf(SCTRL @_);
}
#--------------------------------
sub cgets {
local($s);
$s = <SCTRL>;
&print_msg(2,"%s",$s);
$s;
}
#--------------------------------
# dopen()
sub dopen {
local($oldfh);
local($this);
if ($use_pasv) {
if (socket(NSDATA,$AF_INET,$SOCK_STREAM,0) == 0) {
&print_msg(1,"socket: %s\n",$!);
exit 1;
}
local(@adr) = &cmdPASV();
if ($#adr == 0) {
&print_msg(1,"Passive mode refused.\n");
exit 1;
}
local($ipadr) = sprintf("%d.%d.%d.%d", $adr[0],$adr[1],$adr[2],$adr[3]);
local($port) = $adr[4]*256 + $adr[5];
local($name,$aliases,$type,$len,$thataddr,$that);
($name,$aliases,$type,$len,$thataddr) = gethostbyname($ipadr);
$that = pack($sock_addr,$AF_INET,$port,$thataddr);
if (connect(NSDATA,$that) == 0) {
&print_msg(1,"connect: %s\n",$!);
exit 1;
}
}
else {
if (socket(SDATA,$AF_INET,$SOCK_STREAM,0) == 0) {
&print_msg(1,"socket: %s\n",$!);
exit 1;
}
$oldfh = select(SDATA);
$| = 1;
select($oldfh);
$this = pack($sock_addr,$AF_INET,$dport,"\0\0\0\0");
if (bind(SDATA,$this) == 0) {
&print_msg(1,"bind: %s\n",$!);
exit 1;
}
if (listen(SDATA,5) == 0) {
&print_msg(1,"listen: %s\n",$!);
exit 1;
}
&cmdPORT();
}
}
#--------------------------------
# dconnect()
sub dconnect {
if ($use_pasv) {
# NOP
}
else {
if (accept(NSDATA,SDATA) != 0) {
&print_msg(1,"accept: %s\n",$!);
exit 1;
}
close(SDATA);
}
}
#--------------------------------
# dclose()
sub dclose {
close(NSDATA);
}
#++++++++++++++++++++++++++++++++++++++++++++++++
# ftp command
#++++++++++++++++++++++++++++++++++++++++++++++++
#--------------------------------
sub login {
local($tmp);
&cprintf("USER %s\n", $_[0]);
for (;;) {
$tmp = &cgets();
if ($tmp =~ /^230[ \t]/) {
&print_msg(2,"login ok.\n");
return;
} elsif ($tmp =~ /^331[ \t]/) {
last;
} elsif ($tmp =~ /^\d{3}-/) {
next;
} else {
&print_msg(1,"%s",$tmp);
exit 1;
}
}
&cprintf("PASS %s\n", $_[1]);
for (;;) {
$tmp = &cgets();
if (($tmp !~ /^2/) || ($tmp =~ /^202/)) {
&print_msg(1,"%s",$tmp);
exit 1;
}
elsif ($tmp =~ /^230[ \t]/) {
last;
}
}
&print_msg(2,"login ok.\n");
}
#--------------------------------
# cmdPORT()
sub cmdPORT {
local($mysockaddr,$family,$port,$myaddr,$myport);
local($a,$b,$c,$d,$hi,$lo);
# get myport number
$mysockaddr = getsockname(SDATA);
($family,$myport,$myaddr) = unpack($sock_addr,$mysockaddr);
# get myaddr
$mysockaddr = getsockname(SCTRL);
($family,$port,$myaddr) = unpack($sock_addr,$mysockaddr);
# write to server "PORT x,x,x,x,x,x"
($a,$b,$c,$d) = unpack('C4',$myaddr);
$hi = ($myport >> 8) & 0x00ff;
$lo = $myport & 0x00ff;
&cprintf("PORT %d,%d,%d,%d,%d,%d\n", $a,$b,$c,$d,$hi,$lo);
local($tmp) = &cgets();
if ($tmp !~ /^2/) {
&print_msg(1,"%s",$tmp);
exit 1;
}
}
#--------------------------------
# cmdLIST(directory)
sub cmdLIST {
local($tmp);
&dopen();
&cprintf("LIST %s\n",$_[0]);
$tmp = &cgets();
if ($tmp !~ /^150/) {
&print_msg(1,"%s",$tmp);
exit 1;
}
&dconnect();
local(@ret) = <NSDATA>;
&dclose();
$tmp = &cgets();
if ($tmp !~ /^2/) {
&print_msg(1,"%s",$tmp);
exit 1;
}
@ret;
}
#--------------------------------
# cmdNLST(directory)
sub cmdNLST {
local($tmp);
&dopen();
&cprintf("NLST %s\n",$_[0]);
&cgets();
&dconnect();
local(@ret) = <NSDATA>;
&dclose();
$tmp = &cgets();
if ($tmp !~ /^2/) {
&print_msg(1,"%s",$tmp);
exit 1;
}
@ret;
}
#--------------------------------
# cmdTYPE(type)
sub cmdTYPE {
&cprintf("TYPE %s\n",$_[0]);
local($tmp) = &cgets();
if ($tmp !~ /^2/) {
&print_msg(1,"%s",$tmp);
exit 1;
}
}
#--------------------------------
# cmdQUIT()
sub cmdQUIT {
&cprintf("QUIT\n");
local($tmp) = &cgets();
if ($tmp !~ /^2/) {
&print_msg(1,"%s",$tmp);
exit 1;
}
}
#--------------------------------
# cmdRMD(directory)
sub cmdRMD {
&cprintf("RMD %s\n",$_[0]);
local($tmp) = &cgets();
if ($tmp !~ /^2/) {
&print_msg(1,"%s",$tmp);
}
}
#--------------------------------
# cmdDELE(file)
sub cmdDELE {
&cprintf("DELE %s\n",$_[0]);
local($tmp) = &cgets();
if ($tmp !~ /^2/) {
&print_msg(1,"%s",$tmp);
}
}
#--------------------------------
# cmdRETR(fromfile,tofile)
sub cmdRETR {
&dopen();
&cprintf("RETR %s\n",$_[0]);
local($ret) = &cgets();
if ($ret !~ /^150/) {
&print_msg(1,"%s",$ret);
&dclose();
return;
}
if (open(TO,">$_[1]") == 0) {
&print_msg(1,"open %s: %s\n", $_[1], $!);
exit 1;
}
&dconnect();
while (<NSDATA>) {
print TO $_;
}
close(TO);
&dclose();
$ret = &cgets();
if ($ret !~ /^2/) {
&print_msg(1,"%s",$ret);
exit 1;
}
}
#--------------------------------
# cmdCWD(directory)
sub cmdCWD {
local($tmp);
&cprintf("CWD %s\n",$_[0]);
for (;;) {
$tmp = &cgets();
if ($tmp !~ /^250-/) {
if ($tmp =~ /^250/) {
return 0;
}
else {
return 1;
}
}
}
}
#--------------------------------
# cmdMKD(directory)
sub cmdMKD {
&cprintf("MKD %s\n",$_[0]);
&cgets();
}
#--------------------------------
# cmdSTOR(fromfile,tofile)
sub cmdSTOR {
local($tmp);
&dopen();
&cprintf("STOR %s\n",$_[1]);
$tmp = &cgets();
if ($tmp !~ /^150/) {
&print_msg(1,"%s",$tmp);
exit 1;
}
if (open(FROM,$_[0]) == 0) {
&print_msg(1,"open %s: %s\n", $_[0], $!);
# exit 1;
}
&dconnect();
while (<FROM>) {
print NSDATA $_;
}
close(FROM);
&dclose();
$tmp = &cgets();
if ($tmp !~ /^2/) {
&print_msg(1,"%s",$tmp);
exit 1;
}
}
#--------------------------------
# cmdMDTM(file)
sub cmdMDTM {
local($tmp);
&cprintf("MDTM %s\n",$_[0]);
if (($tmp=&cgets()) !~ /^2/) {
return "00000000000000";
}
local(@ret) = split(/ +/,$tmp);
$ret[1] =~ s/[\r\n]//g;
return $ret[1];
}
#--------------------------------
# cmdREST(fromfile,tofile,len)
sub cmdREST {
&dopen();
&cprintf("REST %d\n",$_[2]);
local($ret) = &cgets();
if ($ret !~ /^350/) {
&print_msg(1,"%s",$ret);
&dclose();
return;
}
&cprintf("RETR %s\n",$_[0]);
$ret = &cgets();
if ($ret !~ /^150/) {
&print_msg(1,"%s",$ret);
&dclose();
return;
}
if (open(TO,">>$_[1]") == 0) {
&print_msg(1,"open %s: %s\n", $_[1], $!);
exit 1;
}
&dconnect();
while (<NSDATA>) {
print TO $_;
}
close(TO);
&dclose();
$tmp = &cgets();
if ($tmp !~ /^2/) {
&print_msg(1,"%s",$tmp);
exit 1;
}
}
#--------------------------------
# cmdPWD()
sub cmdPWD {
&cprintf("PWD\n");
local($tmp) = &cgets();
if ($tmp !~ /^2/) {
return '';
}
local(@word) = split(/ +/,$tmp);
$word[1] =~ s/[\"]//g;
return $word[1];
}
#--------------------------------
# cmdCHMOD(mode,path)
sub cmdCHMOD {
&cprintf("SITE CHMOD %s %s\n",$_[0],$_[1]);
local($tmp) = &cgets();
if ($tmp !~ /^2/) {
&print_msg(1,"%s",$tmp);
exit 1;
}
return;
}
#--------------------------------
# cmdPASV()
sub cmdPASV {
&cprintf("PASV\n");
local($tmp) = &cgets();
if ($tmp !~ /^227\s+/) {
return 0;
}
if ($tmp =~ /(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)/) {
return ($1,$2,$3,$4,$5,$6);
}
else {
return 0;
}
}
syntax highlighted by Code2HTML, v. 0.9.1