ziegast@eng.umd.edu (Eric W. Ziegast) (05/15/91)
Here's a good project for someone to try if it hasn't been done already... Don't you wish there was an anonymous rcp protocol? Tonight I just downloadd the InterViews distribution from stanford using ftp. They put alot of stuff in sub-directories especially things like compiled code. It would have been easier for me if I could just anon-rcp -r interviews.stanford.edu:dist /software/interviews Instead I spent lots of time using mkdirs, cd's, lcd's, mgets , etc. to get all of it's subdirectories transferred to my machine. Do you suppose someone could create a program to sign on as ftp and recursively go through some specified directory and transfer the whole thing in one non-interactive command? I've seen some feeds about a chat2.pl (?) that could help do such non-interactive things and I wonder if anyone has thought about doing this. The only alternative is an extension to the ftp protocol to allow recursive transfers. +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+ | Eric W. Ziegast Internet: ziegast@eng.umd.edu | | Univ. of Merryland Phonenet: Eric@[301.405.3689] | +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
clipper@csd.uwo.ca (Khun Yee Fung) (05/15/91)
Sorry if this does not have a lot to do with Perl.
>>>>> On 15 May 91 00:51:36 GMT, ziegast@eng.umd.edu (Eric W. Ziegast) said:
Eric> Do you suppose someone could create a program to sign on as ftp and
Eric> recursively go through some specified directory and transfer the
Eric> whole thing in one non-interactive command?
I have been thinking about this for a long time. All the solutions I
could think of are all basically hacks. The biggest problem is the
multitude of operating systems out there. All with different ways of
organizing directories and files. If you assume only Unix systems,
then I have encountered three very different ftpds. One is the
pseudo-standard vanilla ftpd from Berkeley, one is like the ftpd of
the emsworth node of CMU, and the other one I forgot where I saw but
it has brief explanations on the same lines as the file and directory
entries. You can of course write a program just to handle the
pseudo-standard ftpds. There is already one such program, a bourne
shell script. I once had a copy. If that is all you want, find that
program.
Suppose the ftp protocol allows recursive transfering. There is still
a problem: some operating systems do not have a tree-like file system.
Too bad. If you define how the file system should look like in ftp,
think about millions of people who use ftp to transfer files to and
from different machines. They surely do not want to have a different
look to their directories and files when they log in as a user and log
in via ftp. So this solution is out as anonymous ftp is only one small
application of ftp. I personally think that the purposes of ftp and
anonymous ftp are very different. The only solution is then to define
a protocol specifically for anonymous ftp. In this way, you can
include all the features (e.g. a line of description for each file or
directory) you want without worrying about other ftp applications. I
somehow don't think the networking gods will be interested in this. It
is up to us, anonymous ftp users, to derive our own protocol and make
it the de facto standard, I guess.
I wrote a ftp client long ago and posted it here a few weeks ago. All
the basic stuff is there and you can surely modify it to recursively
get all the files in a directory tree. This program allows you to
specify a command file even now. It will also let you change your mind
half way, specify a set of commands, get rid of the control terminal,
and send the whole thing to background.
Khun Yee
P.S. If you are interested, I have a draft anonymous ftp protocol I
wrote last year. Not many people cared.
--
Name: Khun Yee Fung Email: clipper@csd.uwo.ca
Paper mail: Department of Computer Science, Middlesex College
The University of Western Ontario, London, Ontario, N6A 5B7 CANADA
cristy@eplrx7.uucp (John Cristy) (05/15/91)
In article <1991May15.005136.20447@eng.umd.edu> ziegast@eng.umd.edu (Eric W. Ziegast) writes: > >Do you suppose someone could create a program to sign on as ftp and >recursively go through some specified directory and transfer the >whole thing in one non-interactive command? > Fetch contrib/ImageMagick.tar.Z on export.lcs.mit.edu. You will find XTP in the ImageMagick/xtp directory. DESCRIPTION Xtp is a utility for retrieving, listing, or printing files from a remote network site, or sending files to a remote network site. Xtp performs most of the same functions as the ftp program, but does not require any interactive commands. You simply specify the file transfer task on the command line and xtp performs the task automatically. EXAMPLES To retrieve file display.tar.Z from host wizard.dupont.com, use: xtp -binary -retrieve display.tar.Z wizard.dupont.com To retrieve all the files from directory public/documents from host wizard.dupont.com, use: xtp -binary -retrieve documents/ wizard.dupont.com public cristy@dupont.com -- The UUCP Mailer
russell@ccu1.aukuni.ac.nz (Russell J Fulton;ccc032u) (05/16/91)
ziegast@eng.umd.edu (Eric W. Ziegast) writes: >Here's a good project for someone to try if it hasn't been done >already... >Don't you wish there was an anonymous rcp protocol? Tonight I just >downloadd the InterViews distribution from stanford using ftp. >They put alot of stuff in sub-directories especially things like >compiled code. It would have been easier for me if I could just I have a package called rftp that I got of this list a while back. It was written by Mike Ferrara <mikef@hpsadle.hp.com>. The r is for recursive it is written in perl and requires sockets. I suggest you contact Mike. Russell BTW Does anybody archive *all* the code that is posted to this group? -- Russell Fulton, Computer Center, University of Auckland, New Zealand. <rj_fulton@aukuni.ac.nz>
tchrist@convex.COM (Tom Christiansen) (05/17/91)
From the keyboard of russell@ccu1.aukuni.ac.nz (Russell J Fulton;ccc032u): :BTW Does anybody archive *all* the code that is posted to this group? Barring news glitches, I have every article posted except for a few in the beginning. So does Larry, I believe. But they aren't in any decent retrieval system (I use MH, but it's far too slow for complex retrievals.) From the FAQ: 5) Are archives of comp.lang.perl available? Yes, although they're poorly organized. You can get them from the host betwixt.cs.caltech.edu (131.215.128.4) in the directory /pub/comp.lang.perl. Perhaps by next month you'll be able to get them from uunet as well. It contains these things: comp.lang.perl.tar.Z -- the 5M tarchive in MH/news format archives/ -- the unpacked 5M tarchive unviewed/ -- new comp.lang.perl messages since 4-Feb or 5-Feb. These are currently stored in news- or MH-style format; there are subdirectories named things like "arrays", "programs", "taint", and "emacs". Unfortunately, only the first ~1600 or so messages have been so categorized, and we're now up to almost 5000. Furthermore, even this categorization was haphazardly done and contains errors. A more sophisticated query and retrieval mechanism is desirable. Preferably one that allows you to retrieve article using a fast-access indices, keyed on at least author, date, subject, thread (as in "trn") and probably keywords. Right now, the MH pick command works for this, but it is very slow to select on 5000 articles. If you're serious about this, your best bet is probably to retrieve the compressed tarchive and play with what you get. Any suggestions how to better sort this all out are extremely welcome. --tom -- Tom Christiansen tchrist@convex.com convex!tchrist "So much mail, so little time."
csu@alembic.acs.com (Dave Mack) (05/19/91)
In article <1991May15.005136.20447@eng.umd.edu> ziegast@eng.umd.edu (Eric W. Ziegast) writes: >Here's a good project for someone to try if it hasn't been done >already... > >Don't you wish there was an anonymous rcp protocol? Tonight I just >downloadd the InterViews distribution from stanford using ftp. >They put alot of stuff in sub-directories especially things like >compiled code. It would have been easier for me if I could just > > anon-rcp -r interviews.stanford.edu:dist /software/interviews > >Instead I spent lots of time using mkdirs, cd's, lcd's, mgets , etc. >to get all of it's subdirectories transferred to my machine. > >Do you suppose someone could create a program to sign on as ftp and >recursively go through some specified directory and transfer the >whole thing in one non-interactive command? Someone has. This (almost) works like a champ, the one flaw being that the logic for placing the ftp'd hierarchy on the receiving machine is slightly brain damaged. I put an alias in my .cshrc: alias anonrftp rftp -uftp:mack2@mdsol1.mdc.com then running "anonrftp -sdir/subdir -g host.subdom.domain" will put everything in dir/subdir in my current working directory. My thanks to Mike Ferrara for making this available. Here's the shar file: Path: wuarchive!texbell!cs.utexas.edu!uunet!allbery From: mikef@hpsadle.hp.com (Mike Ferrara) Newsgroups: comp.sources.misc Subject: v13i026: recursive ftp'er in Perl Message-ID: <92118@uunet.UU.NET> Date: 5 Jun 90 23:26:50 GMT Sender: allbery@uunet.UU.NET Lines: 683 Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) Posting-number: Volume 13, Issue 26 Submitted-by: mikef@hpsadle.hp.com (Mike Ferrara) Archive-name: rftp/part01 Here's a recursive ftp'er for grabbing, putting, and listing whole file trees via ftp. It uses perl to drive ftp, so in order to use it you need perl. There are two versions, rftp and rftp.nosockets. rftp.nosockets is much smaller, slower and has many fewer features. It was my proof of concept code, but it works without perl sockets. That's why I put it in the shar. For more info, see the code, or the man page. You may also need to fool with the #! line at the beginning, and make sure you've done a "makelib" (from perl distribution) on /usr/include/sys/sockets.h. This has been tested on perl 3 patchlevel 18. Mike Ferrara M/S 2LRR HP Signal Analysis Div R&D 1212 Valley House Drive Rohnert Park, CA 94928 (707) 794-4479 mikef%hpsadle@hp-sde.sde.hp.com mikef@hpsadle.hp.com --------------------------cut here----------------------------- # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by Mike Ferrara <mikef@hpsadle> on Tue Jun 5 10:41:15 1990 # # This archive contains: # rftp # LANG=""; export LANG PATH=/bin:/usr/bin:$PATH; export PATH echo mkdir - rftp mkdir rftp echo x - rftp/rftp cat >rftp/rftp <<'@EOF' #!/usr/local/bin/perl #Recursively decend via anon FTP and either get a listing #or retrieve the tree. # Usage: # rftp [options] host [list-file] # Options --- # [-s<source_dir>] Specify the root for transfer on remote host (default "/") # [-d<dest_dir>] Specify the root for transfer on local host (default ".") # [-l] Just a listing, thank you. # [-a] ASCII mode transfers (default: BIN) # [-g] get files # [-p] put files # [-u<user>:<passwd>] Specify a userid and passwd # [-b] debug mode # # return value is 0 if ok. # 1 if an error occurred during transfer. # 2 if login failed. # # # Mail bugs or comments to: # # Mike Ferrara M/S 2LRR # HP Signal Analysis Div R&D # 1212 Valley House Drive # Rohnert Park, CA 94928 # (707) 794-4479 # mikef%hpsadle@hp-sde.sde.hp.com # mikef@hpsadle.hp.com #main $cd=""; $dirs[1]='/'; $source='.'; $dest='.'; $ftpin="/tmp/ftpin$$"; $ftpout="/tmp/ftpout$$"; $listing=1; $bin=1; $reader=0; $writer=0; $user='anonymous'; $passwd=`hostname`; $debug=0; #Setup signal handler $SIG{'INT'}='cleanup'; $SIG{'HUP'}='cleanup'; $SIG{'QUIT'}='cleanup'; $SIG{'TERM'}='cleanup'; &parseopts; if (!($putting)&&!($listing)) { if (-d $dest) { } else { system("mkdir -p $dest"); } chdir $dest; } &setupcomm; if ($writer) { open(LSOUT,">$lsout"); open(FTPIN,"| ftp -i -v -n 1>$ftpout 2>&1"); select(FTPIN);$|=1;select(stdout); &sendftp ("open $host"); &sendftp ("user $user $passwd"); while (1) { #Read from the socket to see if login worked. $_=<NS>; last if (/^230\s/); exit(2) if (/^530\s/); } if ($bin==1) { &sendftp("bin"); } undef($lastdirectory); if (!$putting) { &recurse; } if ($putting) { &putfiles; } &sendftp("quit"); close(FTPIN); &cleanup; } if ($reader) { &readloop; } sub putfiles { &sendftp("bin") if ($bin); open(FIND,"find $source -print |"); while ($_=<FIND>) { chop; $destfile="$dest/$_"; $destfile=~s,/\./,/,g; $destfile=~s,//,/,g; $destfile=~s,\.$,,; $destfile=~s,/$,,; $srcfile="$source/$_"; $srcfile=~s,/\./,/,g; $srcfile=~s,//,/,g; if (-f $_) { &sendftp("put $srcfile $destfile"); &readsock; next; } if (-d $_) { &sendftp("mkdir $destfile"); } } close(FIND); } sub parseopts { &Getopts('abs:d:lu:pg'); $host=shift(@ARGV); if (! defined($host)) { die "I need you to tell me the hostname!"; } if (defined($opt_s)) { $source=$opt_s; } if (defined($opt_d)) { $dest=$opt_d; } if ($opt_a==1) { $bin=0; } if ($opt_l) { $listing=1; $bin=0; $lsout=shift(@ARGV); } if (defined($lsout)) { } else { $lsout='-'; } if (defined($opt_u)) { ($user,$passwd)=split(":",$opt_u); } if (defined($opt_g)) { $listing=0; $putting=0; die "What do you want to do? put OR get?" if (defined($opt_p)); } if (defined($opt_p)) { $listing=0; $putting=1; die "What do you want to do? put OR get?" if (defined($opt_g)); } $debug=1 if (defined($opt_b)); } # getopts.pl - a better getopt.pl # Usage: # do Getopts('a:bc'); # -a takes arg. -b & -c not. Sets opt_* as a # # side effect. sub Getopts { local($argumentative) = @_; local(@args,$_,$first,$rest,$errs); local($[) = 0; @args = split( / */, $argumentative ); while(($_ = $ARGV[0]) =~ /^-(.)(.*)/) { ($first,$rest) = ($1,$2); $pos = index($argumentative,$first); if($pos >= $[) { if($args[$pos+1] eq ':') { shift(@ARGV); if($rest eq '') { $rest = shift(@ARGV); } eval "\$opt_$first = \$rest;"; } else { eval "\$opt_$first = 1"; if($rest eq '') { shift(@ARGV); } else { $ARGV[0] = "-$rest"; } } } else { print STDERR "Unknown option: $first\n"; ++$errs; if($rest ne '') { $ARGV[0] = "-$rest"; } else { shift(@ARGV); } } } $errs == 0; } # # readloop -- keep reading stuff from the $ftpout file and # stuffing it over the socket. # sub readloop { while (1) { if (-f $ftpout) { open (FTPOUT,$ftpout); while (1) { $_=<FTPOUT>; if (/^221\sGoodbye/) { last; } print(S $_); } exit(0); } } } # # Workhorse subroutine, gets a whole directory or listing # of a whole directory. It also forms the list of directories # below the current one. # sub readsock { $i=1; $n=0; while (1) { $_=<NS>; if ($listing==1) { print (LSOUT $_) if (!/^\s?$/ && !/^[0-9]*\s/); } if (/^d/) { chop; split; $dirs[$i]=pop(@_); $i=$i+1; } if (/^-/) { chop; split; $fname[$n]=pop(@_); $n=$n+1; } if (/^226\s/) { last; } if ((/^5[0-9][0-9]\s/)&&(!/^5[0-9][0-9]\sbytes/i)) { print (stderr "A fatal error occurred during transfer:"); print (stderr $_); exit(1); } } } # # Do the recursion, using getdir as the workhorse. # sub recurse { local(@dirlist)=@dirs; local($currentparent)=shift(@dirlist); while (defined($child=shift(@dirlist))) { $cd="$source/$currentparent/$child"; undef @dirs; $cd=~s,//,/,g; $cd=~s,//,/,g; $cd=~s,/$,,; if (($cd EQ $lastdirectory) && ($lastdirectory NE "")) { die "OOOPS! I'm looping!!"; } &sendftp("dir $cd"); # print ("dir $cd\n"); if ($listing==1) { print(LSOUT "\n$cd:\n"); } &readsock; if ($listing == 0) { $ddir="$dest/$currentparent/$child"; $ddir=~s,//,/,g; $ddir=~s,//,/,g; system("mkdir -p $ddir"); while (defined($file=shift(@fname))){ &sendftp("get $cd/$file $ddir/$file"); &readsock; } } $lastdirectory=$cd; $dirs[0]="$currentparent/$child"; &recurse; } } # # Delete the temporary files, close the output, and leave # sub cleanup { unlink($ftpout); kill 15,$childpid; close(LSOUT); exit(0); } sub sendftp { $line=@_[0]; $line="$line\n" if (!($line=~m/\n$/)); print (STDERR "$line") if ($debug); print (FTPIN $line); } # # Setup socket based communication between the child and parent # and fork # sub setupcomm { do 'sys/socket.h' || die "Can't do sys/socket.h"; $port=$$; $sockaddr='S n a4 x8'; chop($hostname=`hostname`); ($name,$aliases,$proto)=getprotobyname('tcp'); ($name,$aliases,$type,$len,$thisaddr)=gethostbyname($hostname); if ($childpid == fork) { $reader=1; #The child reads FTP output, client sleep 3; $client=pack($sockaddr,&AF_INET,0,$thisaddr); $server=pack($sockaddr,&AF_INET,$port,$thisaddr); socket(S,&PF_INET,&SOCK_STREAM,$proto) || die "socket: $!"; bind(S,$client) || die "bind: $!"; connect(S,$server) || die "connect: $!"; select(S);$|=1;select(stdout); } else { $writer=1; #The parent writes FTP input and effects transfers., server. $server=pack($sockaddr,&AF_INET,$port,"\0\0\0\0"); select(NS);$|=1;select(stdout); socket(S,&PF_INET,&SOCK_STREAM,$proto) || die "socket: $!"; bind(S,$server) || die "bind: $!"; listen(S,5) || die "connect: $!"; select(S);$|=1;select(stdout); loop: ($addr=accept(NS,S)) || goto loop; ($af,$port,$inetaddr)=unpack($sockaddr,$addr); } } @EOF chmod 755 rftp/rftp echo x - rftp/rftp.1 cat >rftp/rftp.1 <<'@EOF' .TH RFTP 1 .ds )H .ds ]W March 1990 .SH NAME rftp \- recursively ftp on a remote machine .SH SYNOPSIS .B rftp [ .I options ] .I host [ .I listing-file ] .SH DESCRIPTION .I Rftp\^ Drives ftp to recursively descend file trees, either for listings, or to get or put a bunch of files keeping the tree structure intact. Rftp is written in perl and requires that berkeley sockets be wired into it. This generally requires that a "makelib" be run on "/usr/include/sys/sockets.h" before running rftp. Rftp works as follows: 1) fork a copy of itself, and setup socket based IPC between parent and child. 2) start ftp, with output redirected to /tmp/ftpout$$. 3) poke stdin of ftp while child reads /tmp/ftpout$$, and stuffs the output back to the parent over the socket. .SS Options .PP There are several options: .TP .B [\-s source-dir] specifies the source directory for the transfer. Default is "." .TP .B [\-d dest-dir] specifies the destination directory for the transfer. Default is "." .TP .B [\-a] force transfer mode to ascii. Default is binary (image). .TP .B [\-l] for directory listing only. This is the default action. Listings will go to stdout or to "listing-file" if specified. .TP .B [\-u username:passwd] specify a user name and password for logging in. Default is user "anonymous" password `hostname`. .TP .B [-g] get files from remote host. .TP .B [\-p] send (put) files to remote host. .TP .SH DIAGNOSTICS The program tries to clue you in to common failures. Source is available. Return codes are as follows: 0 for normal exit, 1 for a failure during a transfer, and 2 for a login failure .SH EXAMPLES This command gets a directory listing from machine "jupiter" and writes it in file "xyzzy". .IP rftp jupiter xyzzy .TP This command retrieves the tree headed at "pub/pub" into "/users/foo/xx" on machine "jupiter" .IP rftp -spub/pub -d/users/foo/xx -g jupiter .SH AUTHOR .I rftp was developed by Mike Ferrara of Hewlett-Packard (Signal Analysis Division) mikef%hpsad@hp-sde.sde.hp.com or mikef@hpsadle.hp.com. .PP .SH "STANDARDS CONFORMANCE" .IR None. @EOF chmod 666 rftp/rftp.1 echo x - rftp/rftp.nosockets cat >rftp/rftp.nosockets <<'@EOF' #!/usr/local/bin/perl #Recursively decend via anon FTP and either get a listing #or retrieve the tree. # Usage: # rftp [options] host [list-file] # Options --- # [-s<source_dir>] Specify the root for transfer on remote host (default "/") # [-d<dest_dir>] Specify the root for transfer on local host (default ".") # [-l] Just a listing, thank you. # [-a] ASCII mode transfers (default: BIN) # ;# getopts.pl - a better getopt.pl ;# Usage: ;# do Getopts('a:bc'); # -a takes arg. -b & -c not. Sets opt_* as a ;# # side effect. sub Getopts { local($argumentative) = @_; local(@args,$_,$first,$rest,$errs); local($[) = 0; @args = split( / */, $argumentative ); while(($_ = $ARGV[0]) =~ /^-(.)(.*)/) { ($first,$rest) = ($1,$2); $pos = index($argumentative,$first); if($pos >= $[) { if($args[$pos+1] eq ':') { shift(@ARGV); if($rest eq '') { $rest = shift(@ARGV); } eval "\$opt_$first = \$rest;"; } else { eval "\$opt_$first = 1"; if($rest eq '') { shift(@ARGV); } else { $ARGV[0] = "-$rest"; } } } else { print STDERR "Unknown option: $first\n"; ++$errs; if($rest ne '') { $ARGV[0] = "-$rest"; } else { shift(@ARGV); } } } $errs == 0; } 1; sub getdir { $i=1; undef @dirs; $cd=~s,//,/,g; $mcd=$cd; $mcd=~s,^/,,; if ($cd EQ $lastdirectory) { die "OOOPS! I'm looping!!"; } open(FTPIN,">$ftpin"); print(FTPIN "open $host \n"); print(FTPIN "user anonymous xx\n"); print(FTPIN "cd /\n"); if ($bin==1) { print(FTPIN "bin \n"); } print(FTPIN "dir $cd\n"); if ($listing == 0) { system("mkdir -p $dest/$cd"); print (FTPIN "mget $mcd/* \n"); } print(FTPIN "quit \n"); close(FTPIN); # system("ftp -i -n <$ftpin 1>$ftpout 2>&1"); system("ftp -i -n <$ftpin 1>$ftpout "); open(FTPOUT,"$ftpout"); if ($listing==1) { print(LSOUT "\n$cd:\n"); } $dirs[0]=$cd; while($_=<FTPOUT>) { if ($listing==1) { print (LSOUT $_) if (!/^\s?$/); } if (/^\s?d/) { chop; split; $dirs[$i]=pop(@_); $i=$i+1; } } close(FTPOUT); $lastdirectory=$cd; } sub recurse { local(@dirlist)=@dirs; local($currentparent)=shift(@dirlist); while (defined($child=shift(@dirlist))) { $cd="$currentparent/$child"; &getdir; &recurse; } } sub cleanup { unlink($ftpin,$ftpout); } #main $cd=""; $dirs[1]='/'; $dest='.'; $ftpin="/tmp/ftpin$$"; $ftpout="/tmp/ftpout$$"; $listing=0; $bin=1; $SIG{'INT'}='cleanup'; $SIG{'HUP'}='cleanup'; $SIG{'QUIT'}='cleanup'; $SIG{'TERM'}='cleanup'; &Getopts('as:d:l'); $host=shift(@ARGV); if (! defined($host)) { die "I need you to tell me the hostname!"; } if (defined($opt_s)) { $dirs[1]=$opt_s; } if (defined($opt_d)) { $dest=$opt_d; } if ($opt_a==1) { $bin=0; } if (-d $dest) { } else { mkdir($dest,0755) || die "$dest already exists and is not a directory!"; } if ($opt_l) { $listing=1; $bin=0; $lsout=shift(@ARGV); } if (defined($lsout)) { } else { $lsout='-'; } open(LSOUT,">$lsout"); chdir $dest; &recurse; &cleanup; close(LSOUT); exit(0); @EOF chmod 755 rftp/rftp.nosockets chmod 755 rftp exit 0