2 # Make local directories mirror images of a remote sites
5 # Copyright (C) 1990 - 1998 Lee McLoughlin
7 # Permission to use, copy, and distribute this software and its
8 # documentation for any purpose with or without fee is hereby granted,
9 # provided that the above copyright notice appear in all copies and
10 # that both that copyright notice and this permission notice appear
11 # in supporting documentation.
13 # Permission to modify the software is granted, but not the right to
14 # distribute the modified code. Modifications are to be distributed
15 # as patches to released version.
17 # This software is provided "as is" without express or implied warranty.
20 # The Debian system patched this file after installation to add:
21 # ls-lR file patching 2001/09/29
22 # Copyright (C) 1999-2001 Ian Maclaine-cross <iml@debian.org>
24 # Debian patches are copyright by their authors and you may use them only
25 # under the conditions of the General Public License in file GPL.
27 # $Id: mirror.pl,v 2.9 1998/05/29 19:01:07 lmjm Exp lmjm $
29 # Revision 2.9 1998/05/29 19:01:07 lmjm
30 # Lots of changes. See CHANGES since 2.8 file.
32 # Revision 2.8 1995/08/06 14:03:52 lmjm
33 # Trap a wider range of signals to aid in debugging under perl5
34 # Avoid looping processing symlinks.
36 # Revision 2.7 1995/08/06 13:59:00 lmjm
37 # No longer require socket.ph in this module.
38 # Escape at signs and dollars for perl5
39 # Make sure proxy_gateway is at least null.
40 # Added ls_fix_mappings, failed_gets_excl, store_remote_listing, passive_ftp
42 # Stop using dollar star as perl5 has dropped it.
43 # Process local directory listing before connecting to remote.
44 # Allow for remote_account pasword.
45 # Only one arg to undef, for early perl5's
46 # Use all capitals for file descriptors.
47 # Use ftp'close not ftp'quit
48 # Avoid file renaming under MACos
49 # Corrected file deleting.
51 # Revision 2.6 1994/06/10 18:28:27 lmjm
52 # Dropped debug statement.
54 # Revision 2.5 1994/06/06 18:39:21 lmjm
55 # Don't have . in the extra_path.
56 # Have 'internet-gateway' as the default proxy_gateway when INTERNET_HOST unset.
57 # Allow strip_cr (from Andrew).
58 # More symlink handling...
59 # Set type for vms correctly.
60 # Changed response from ftp'delete, also corrected path used.
62 # Revision 2.4 1994/04/29 20:11:09 lmjm
63 # Use correct variable for hostname
65 # Revision 2.3 1994/01/31 18:31:22 lmjm
66 # Allow for funny chars in filenames when calling the shell (Erez).
67 # Added compress_size_floor to avoid compressing small files (David).
68 # Added get_missing to just delete files not on remote system (Pieter).
69 # Don't try to delete old dirs if no time set (Pieter).
70 # Zap .dir$$ files, and keep then in $big_temp.
71 # Pretty print time in comparisons.
72 # Move the large comparision conditionals into routines (David).
73 # Allow for sites with limited filename lengths.
74 # Allow for deleted files when doing deletes.
75 # Don't delete dirs that are really symlinks.
77 # Revision 2.2 1993/12/14 11:09:15 lmjm
79 # Use installed socket.ph.
81 # Use percentage defaults on max_delete_*
82 # Checkout regexps before using.
83 # Allow for extra leading | in local_ignore.
84 # Return better exit codes.
85 # Fixups for recurse_hard.
86 # Smarter symlink handling.
88 # Revision 2.1 1993/06/28 14:59:00 lmjm
93 $#ARGV >= 0 or die("Try `man mirror` for help.\n");
95 # Make sure we don't go recursive processing signals
100 $on_win = ($^O
=~ /mswin/i);
101 $path_sep = $on_win ?
';' : ':';
102 $file_sep = $on_win ?
'\\' : '/';
103 # Internally mirror uses / but when looking at names from environment allow
105 $file_sep_pat = $on_win ?
"[\\/]" : "/"; # allow for c:\win/fred on windoze
108 # Default settings file loaded from a directory in PERLLIB
109 $defaults_file = 'mirror.defaults';
112 # Try to find the default location of various programs via
113 # the users PATH then using $extra_path
115 $extra_path = '/usr/local/bin:/usr/new/bin:/usr/public/bin:/usr/ucb:/usr/bin:/bin:/etc:/usr/etc:/usr/local/etc';
117 if( $extra_path ne '' ){
118 $ENV{ 'PATH' } .= $path_sep . $extra_path;
123 # If compressing a local file to send need somewhere to store the temp
124 # compressed version.
125 $big_temp = '/var/tmp';
127 # Hopefully we have flock.
130 # no debugging by default
134 # It is not an error for a program not to be found in the path as the user
135 # may be setting it as part of the package details or defaults.
137 # Used by the save_deletes option
140 # compress must be able to take the -d arg to cause it to uncompress.
141 $sys_compress_prog = &find_prog
( 'compress' );
142 $sys_compress_suffix = 'Z';
144 # Like compress gzip must be able to take -d
145 if( $gzip_prog = &find_prog
( 'gzip' ) ){
146 # Force maximum compression with gzip
148 $gzip_prog .= $gzip_level;
150 $old_gzip_suffix = 'z';
153 # For remote systems with gzipped patches to their ls-lR.gz file. The
154 # gzipped patch file is a unified diff between old and new ls-lR. The
155 # times file has modification times in decimal epoch seconds of the
156 # old and new ls-lR file on its first and second lines respectively.
157 if( $patch_prog = &find_prog
( 'patch' ) ){
158 $patch_local = '-usNT';
159 $patch_UTC = '-usNZ';
161 $patch_suffix = '.pth'; # These suffices distinct
162 $patch_gzip_suffix = '.patch.gz'; # if truncated locally.
163 $times_suffix = '.times';
165 # A mail program that can be called as: "$mail_prog person_list'
166 # Can be overridden with the mail_prog keyword.
167 # If you use $mail_subject to pass extra arguments then remember that
168 # the mail program will need to know how to handle them.
169 $mail_prog = &find_prog
( 'mailx' );
171 $mail_prog = &find_prog
( 'Mail' );
174 $mail_prog = &find_prog
( 'mail' );
177 # Used to remove directory heirarchies. This program is passed the -rf
179 $rm_prog = &find_prog
( 'rm' );
182 $sum_prog = &find_prog
( 'sum' );
184 # SPECIAL NOTE: This is eval'd, so DONT put double-quotes (") in it.
185 # You can get local variables to appear as in the second example:
186 $mail_subject = '-s \'mirror update\'';
187 # $mail_subject = ' -s \'mirror update of $package\'';
189 # When scanning the local directory, how often to prod the remote
190 # system to keep the connection alive
193 # Put the directory that mirror is actually in at the start of PERLLIB.
194 $dir = &real_dir_from_path
( $0 );
195 unshift( @INC, $dir );
197 # Debian GNU/Linux stores mirror.defaults in /etc/mirror
198 $debian_defs = '/etc/mirror';
199 unshift( @INC, $debian_defs ) if -d
$debian_defs;
201 # This, when eval'd, will get the current dir under windows NT/95
202 $win_getcwd = 'Win32::GetCwd';
204 # Make sure that your PERLLIB environment variable can get you
205 # all these or that they are installed.
207 require 'lsparse.pl';
208 require 'dateconv.pl';
210 # Find some local details
211 # The current directory
214 $hostname_cmd = &find_prog
( 'hostname' );
215 if( $hostname_cmd ne '' ){
216 chop( $hostname = `$hostname_cmd` );
218 if( $hostname eq '' ){
219 $hostname_cmd = &find_prog
( 'uname' );
220 if( $hostname_cmd ne '' ){
221 chop( $hostname = `$hostname_cmd -n` );
222 if( $hostname eq '' ){
223 chop( $hostname = `$hostname_cmd -l` );
227 if( $hostname eq '' ){
228 $hostname = 'localhost';
231 if( $hn = (gethostbyname( "$hostname" ))[ 0 ] ){
235 # Some systems hold the username in $USER, some in $LOGNAME.
236 $me = $ENV{'USER'} || $ENV{'LOGNAME'};
238 # Files matching this pattern are usually compressed.
239 $squished = '\.(Z|z|gz)$';
241 # special /bin/sh chars that must be escaped.
242 $shell_metachars = '\"|\$|`|\\\\';
244 # Remote directory parsing fail if not given input every readtime seconds.
247 # Timeout are not fatal unless you get more than this number of them.
250 # If connected to a site then this holds the site name.
254 $curr_umask = sprintf( "0%o", umask );
256 # mapping from a pathname to a number - just to make the keys to assoc arrays
258 $map_init = 1; # just so I know 0 is invalid
261 @assocs = ( 'local_map', 'remote_map' );
263 # A reasonable set of defaults
264 # these are in the same order as the documentation - except where order is
266 $default{ 'hostname' } = $hostname; # The LOCAL hostname
268 $default{ 'package' } = ''; # should be a unique handle for the "lump" to be mirrored
269 $default{ 'site' } = ''; # site to connect to
270 $default{ 'remote_dir' } = ''; # remote directory to mirror
271 $default{ 'local_dir' } = ''; # local directory to copy into
273 $default{ 'remote_user' } = 'anonymous'; # the remote guest account name
274 $default{ 'remote_password' } = "$me\@$hostname";
275 $default{ 'remote_account' } = ''; # remote account name/passwd (for systems
277 # Used for group and gpass. (As in ftp.1 site group/gpass commands.)
278 $default{ 'remote_group' } = '';
279 $default{ 'remote_gpass' } = '';
280 $default{ 'timeout' } = 120; # timeout ftp requests after this many seconds
281 $default{ 'failed_gets_excl' } = ''; # failed messages to ignore while getting,
282 # if failed to ftp'get
283 $default{ 'ftp_port' } = 21; # port number of remote ftp daemon
284 $default{ 'proxy' } = 0; # normally use regular ftp
285 $default{ 'proxy_ftp_port' } = 4514; # default from Sun
286 $default{ 'proxy_gateway' } = "$ENV{ 'INTERNET_HOST' }";
287 # Gateway to use for proxy
288 # (Null if environment not set.)
289 $default{ 'using_socks' } = 0; # Set the default perl version to the non-SOCKS one.
290 $default{ 'passive_ftp' } = 0; # Set the default ftp usage not to use passive (PASV) ftp.
291 $default{ 'retry_call' } = 1; # Retry the call if it fails first time
292 $default{ 'disconnect' } = 0; # Force close at end of package EVEN if
293 # next package is to the same site
294 $default{ 'remote_idle' } = ''; # Set the remote idle timer to this
296 $default{ 'get_patt' } = "."; # regex of pathnames to retrieve
297 $default{ 'exclude_patt' } = ''; # regex of pathnames to ignore
298 $default{ 'local_ignore' } = ''; # regex of local pathnames to totally ignore
299 $default{ 'get_newer' } = 1; # get remote file if its date is newer than local
300 $default{ 'get_size_change' } = 1; # get the file if size if different than local
301 $default{ 'make_bad_symlinks' } = 0; # prevent symlinks to non-existant files
302 $default{ 'follow_local_symlinks' } = ''; # Follow symlinks to pathnames matching this regexp.
303 $default{ 'get_symlink_files' } = 0; # If true gets file and makes symlink otherwise bad.
304 $default{ 'get_missing' } = 1; # Set get_missing to 0 to just delete files not on remote system
305 $default{ 'get_file' } = 1; # perform get, not put by default
306 $default{ 'text_mode' } = 0; # transfer in binary mode by default
307 $default{ 'strip_cr' } = 0; # Delete \r (usefull when transfering from
308 # mainframes -- set text_mode and strip_cr)
309 $default{ 'vms_keep_versions' } = 1; # Keep multiple VMS versions
310 $default{ 'vms_xfer_text' } = 'readme$|info$|listing$|\.c$';
311 # pattern of VMS files to xfer in TEXT mode
313 $default{ 'name_mappings' } = '';# remote to local pathname mappings
314 # used to change layout or zap weird chars
316 $default{ 'external_mapping' } = '';# remote to local mapping by external routine
317 $default{ 'update_local' } = 0; # Don't just update local dirs
318 $default{ 'max_days' } = 0; # Ignore age of file
319 $default{ 'max_size' } = 0; # If non-zero dont get files larger than this
320 $default{ 'chmod' } = 1; # perform a chmod after an xfer
322 $default{ 'user' } = ''; # UID/user name to give to local pathnames
323 $default{ 'group' } = ''; # GID/group name to give to local pathnames
324 $default{ 'mode_copy' } = 0; # true indicates to copy the mode bits
325 $default{ 'file_mode' } = 0444; # Mode to give files created locally
326 $default{ 'dir_mode' } = 0755; # mode to give directories created locally
327 $default{ 'force' } = 0; # don't force by default
328 $default{ 'umask' } = 07000; # DONT allow setuid things by default
329 $default{ 'use_timelocal' } = 1; # Use local time NOT gmt to timestamp files. (See also the -T flag.)
330 $default{ 'force_times' } = 1; # Force local file times to match the original
332 $default{ 'do_deletes' } = 0; # delete dest files if not in src tree
333 $default{ 'delete_patt' } = '.';# delete only files which match this pattern
334 $default{ 'delete_get_patt' } = 0;# true: set delete_patt to get_patt
335 $default{ 'delete_excl' } = ''; # regex of local pathnames to ignore when deleting
336 $default{ 'max_delete_files' } = '10%'; # Any more than this and DONT delete
337 $default{ 'max_delete_dirs' } = '10%'; # Any more than this and DONT delete
338 $default{ 'save_deletes' } = 0; # save local files if not in remote
339 $default{ 'save_dir' } = 'Old'; # directory in which to create tree for keeping
340 # files no longer in remote
341 $default{ 'store_remote_listing' } = ''; # Where to store remote site listings on local system
343 $default{ 'compress_patt' } = ''; # compress files matching this pattern
344 $default{ 'compress_excl' } = $squished; # dont compress regexp (case insensitive)
345 $default{ 'compress_prog' } = $sys_compress_prog; # Program to compress files.
346 $default{ 'compress_suffix' } = $sys_compress_suffix; # Suffix on compressed files
347 $default{ 'compress_conv_patt' } = '(\.Z|\.taz)$';
348 # compress->gzip files matching this pattern
349 $default{ 'compress_conv_expr' } = 's/\.Z$/.gz/;s/\.taz$/.tgz/';
350 # perl expressions to convert names of files from compress->gzip
351 $default{ 'compress_size_floor' } = 0; # don't compress files < this size
353 $default{ 'split_max' } = 0; # Files > this size can be split up.
354 $default{ 'split_patt' } = ''; # Files must match this pattern to be split
355 $default{ 'split_chunk' } = 100 * 1024; # Size of split-up chunks
357 $default{ 'remote_fs' } = 'unix'; # Remote filestore
358 # Other posibilies dls, netware and vms
359 $default{ 'ls_lR_file' } = ''; # remote file containing ls-lR, patch or
360 # times - else use remote ls
361 $default{ 'local_ls_lR_file' } = ''; # local file containing ls-lR
362 # used when first copying a large remote package
363 # or ls_lR_file is a remote ls-lR patch or times
364 $default{ 'recursive' } = 1; # true indicates to do recursive processing
365 $default{ 'recurse_hard' } = 0; # true indicates have to cwd+ls for each remote
366 # subdirectory - AVOID wherever possible.
367 $default{ 'flags_recursive' } = '-lRat'; # Flags passed to remote dir
368 $default{ 'flags_nonrecursive' } = '-lat'; # Flags passed to remote dir
369 $default{ 'ls_fix_mappings' } = '';# Correct pathnames in remote listings
370 # (eg s:usr/spool/pub/::) to match reality
372 $default{ 'update_log' } = ''; # Filename where an update report is to be kept
373 $default{ 'mail_to' } = ''; # Mail a report to these addresses
374 $default{ 'mail_prog' } = $mail_prog; # the mail program (see $mail_prog)
375 $default{ 'mail_subject' } = $mail_subject; # Subject passed to mail_prog
377 $default{ 'comment' } = ''; # General comment used in report
378 # If mirroring a VERY large directory then it is best to put the assoc
379 # arrays in files (use command line switch -F. to turn on).
380 $default{ 'use_files' } = 0;
381 $default{ 'interactive' } = 0; # noninteractive copy default
382 $default{ 'skip' } = ''; # If set then skip this entry giving value as reason
383 $default{ 'verbose' } = 0; # Verbose messages
384 $default{ 'algorithm' } = 0; # The mirror algorithm to use
385 $default{ 'local_dir_check' } = 0; # Check local_dir exists before mirroring?
387 # I really want to drop this option.
388 $default{ 'delete_source' } = 0;# delete source after xfer (default = NO!!!)
390 @boolean_values = ( 'get_newer', 'get_size_change', 'do_deletes',
391 'update_local', 'force_times', 'retry_call', 'recursive',
392 'mode_copy', 'disconnect', 'interactive', 'text_mode',
393 'force', 'get_file', 'verbose', 'proxy', 'delete_get_patt',
394 'delete_source', 'save_deletes', 'use_files', 'use_timelocal',
395 'make_bad_symlinks', 'get_symlink_files', 'recurse_hard',
396 'get_missing', 'strip_cr', 'passive_ftp', 'using_socks',
399 %boolean_values = ();
400 &set_assoc_from_array
( *boolean_values
);
402 @regexp_values = ( 'get_patt', 'exclude_patt', 'local_ignore',
403 'delete_patt', 'delete_excl', 'split_patt', 'save_deletes',
404 'compress_patt', 'compress_excl', 'compress_conv_patt',
405 'failed_gets_excl', 'store_remote_listing' );
408 # message levels used by &msg( level, msg )
409 # if you call msg as &msg( msg ) the level is presumed to be just $pr.
410 $pr = 0; # Always print out messages
411 $log = 1; # push this messages onto @log
413 # The max number of directory failures under algorithm 1 before giving up.
414 $max_failed_dirs = 5;
419 $exit_status_xfers = 0;
421 # "#defines" for the above
422 $exit_xfers = 16; # Add this to the exit code to show xfers took place
425 $exit_fail_noconnect = 2;
427 # -d Turn on debugging - more -d's means more debugging.
428 # -ppattern Just do packages matching pattern.
429 # -Rpattern Skip till the first package name matches pattern then do all.
430 # it and following packages.
431 # -n Do nothing, just show what would be done.
432 # -F Use files for assoc arrays (see also the variable use_files).
434 # Get all files on given site. If path matches .*/.+ then
435 # it is the name of the directory and the last part is the
436 # pattern of filenames to get. If path matches .*/ then
437 # it is the name of a directory and all its contents are retrieved.
438 # Otherwise path is the pattern to be used in '/'.
439 # -r Same as "-krecursive=false".
440 # -kvar=val set variable to value.
441 # -uusername Same as "-kremote_user=username", prompts for remote_password.
442 # -v Print version and exit.
443 # -T Dont transfer just force local timestamps to match remote.
444 # -N Don't load mirror.defaults.
445 # -L Generate a pretty list of what is being mirrored.
446 # -m Same as "-kmode_copy=true".
449 # -P Same as "-kget_file=false -kinteractive=true".
450 # -G Same as "-kget_file=true -kinteractive=true".
451 # -t Same as "-ktext_mode=true".
452 # -f Same as "-kforce=true".
453 # -sSITENAME Same as "-ksite=SITENAME.
454 # -ULOGFILE Set the upload log to LOGILE - if none given uses
455 # the file $home/upload_log.$mday.$mon.$year
457 # -DUMP Dump perl - to be later undumped -- THIS DOES NOT YET WORK!!!
461 &msg
( '$Id: mirror.pl,v 2.9 1998/05/29 19:01:07 lmjm Exp lmjm $' . "\n" );
462 &msg
( 'Debian patch version: mirror (2.9-38) Tue Jan 29 07:06:25 2002 UTC.' . "\n" );
463 &msg
( 'Copyright conditions are in file /usr/share/doc/mirror/copyright.' . "\n" );
467 while( $ARGV[ 0 ] =~ /^-/ ){
468 local( $arg ) = shift;
479 if( $arg =~ /^-(p)(.*)/ || $arg =~ /^-(R)(.*)/ ){
480 local( $flag, $p ) = ($1, $2);
482 # Skip all packages till a match is made
483 # then process ALL further packages
487 # Must be -p/-R space arg
490 if( $p !~ /[a-zA-Z0-9]/ ){
491 die "Invalid package name to -p of: $p\n";
494 # Only mirror the named packages
495 $do_packages{ $p } = 1;
501 # Do nothing - just show what would be done
509 # Use files for the dir listings assoc lookups
511 $command_line{ 'use_files' } = 1;
516 # Don't actually get any files but just force
517 # local timestamps to be the same on the remote system
519 $command_line{ 'force_times' } = 'true';
523 if( $arg =~ /^-g(.*)$/ ){
524 # the next arg is the site:path to get
525 local( $site_path ) = $1;
528 # Must be -g space arg
532 # DONT use the system defaults!
535 # This is probably interactive so print interactively
538 if( $site_path =~ /(.*):(.*)?/ ){
539 local( $site, $path ) = ($1, $2);
540 push( @get_sites, $site );
541 # Find the directory and files
542 if( $path =~ m
|^(.*)/([^/]*)$| ){
543 if( $1 eq '' && $2 eq '' ){
544 push( @get_paths, '/' );
545 push( @get_patt, '.' );
548 push( @get_paths, '/' );
551 push( @get_paths, $1 );
554 push( @get_patt, '.' );
557 push( @get_patt, "^$2\$" );
561 push( @get_paths, '.' );
562 push( @get_patt, "^$path\$" );
566 die "expected -gsite:path got $arg";
573 $command_line{ 'recursive' } = 0;
576 # Debian bug #93853, -k keyword=value did not work, jkn@softavenue.fi
577 if( $arg =~ /^-k(.*)/ ){
578 local( $key_val ) = $1;
580 # Must be -k space key=val
583 if( $key_val =~ /(.*)=(.*)/ ){
584 # set the keyword = value
585 if( !defined( $default{ "$1" } ) ){
586 warn "Invalid keyword $1\n";
588 $command_line{ "$1" } = $2;
594 if( $arg =~ /^-u(.*)/ ){
598 # must be -u space user
602 # override the user name
603 $command_line{ 'remote_user' } = $user;
604 # and ask for a password
605 $command_line{ 'remote_password' } = &get_passwd
( $user );
620 # Generate a pretty list of what is being mirrored
627 $command_line{ 'mode_copy' } = 'true';
631 # Old command line interface flags
632 if( $arg =~ /^-C(.*)/ ){
633 # specify the config file
636 die "Must give config file name -Cname ($arg)\n";
638 # Only mirror the named packages
639 push( @config_files, $c);
645 $command_line{ 'get_file' } = 'false';
646 $command_line{ 'interactive' } = 'true';
652 $command_line{ 'get_file' } = 'true';
653 $command_line{ 'interactive' } = 'true';
658 # set the file mode to text
659 $command_line{ 'text_mode' } = 'true';
664 # force file transfers irregardless of date/size matches
665 $command_line{ 'force' } = 'true';
669 if( $arg =~ /^-s(.*)/ ){
670 # override the site name
671 $command_line{ 'site' } = $1;
675 if( $arg =~ /^-U(.*)/ ){
677 if( $upload_log eq '' ){
678 local( $sec,$min,$hour,$mday,$mon,$year,
682 $upload_log = "$home/upload_log.$mday.$mon.$year";
688 if( $arg eq '-DUMP' ){
689 # THIS DOES NOT YET WORK!!!!!
691 warn "Dumping perl\n";
695 warn "Unknown arg $arg, skipping\n";
698 # Handle multiline buffers in a sane way
699 # This is deprecated in perl-5. Someone should add "/m" modifiers to any
700 # regexps that *really* need it, not all.
703 $interactive = $command_line{ 'interactive' };
705 if( ! $interactive ){
708 # The remainder of ARGV are package names
709 foreach $c ( @ARGV ){
710 push( @config_files, $c );
714 if( $interactive && $limit_packages){
715 die "Can not mix -p and interactive";
718 $value{ 'remote_user' } = $default{ 'remote_user' };
722 if( $load_defaults ){
724 foreach $dir ( @INC ){
725 local( $f ) = "$dir/$defaults_file";
732 &msg
( "defaults from $mp\n" ) if $debug > 2;
733 splice( @config_files, 0, 0, $mp );
736 warn "No $defaults_file found in perl library path\n";
740 &msg
( "not loading $defaults_file\n" );
744 &interpret_config_files
();
746 # Shut down any remaining ftp session
749 &msg
( "All done, Exiting\n" ) if $debug;
750 exit( $exit_status + $exit_status_xfers );
753 $key = ''; # The current keyword
754 $value = ''; # the value for the keyword
756 sub interpret_config_files
760 if( $#get_sites >= 0 ){
761 while( $#get_sites >= 0 ){
762 $value{ 'site' } = pop( @get_sites );
763 $value{ 'remote_dir' } = pop( @get_paths );
764 $value{ 'get_patt' } = pop( @get_patt );
765 $value{ 'local_dir' } = '.';
766 $value{ 'remote_user' } = 'anonymous';
767 $exit_status = &do_mirror
();
773 if( $command_line{ 'interactive' } ){
774 # No config file to read
775 $value{ 'package' } = 'interactive';
776 $exit_status = &do_mirror
();
780 # if no configuration files were specified use standard input
781 @ARGV = @config_files;
788 # Ignore comment and blank lines
789 next if /^\s*#/ || /^\s*$/;
793 # Is this a new package?
794 if( $value{ 'package' } && $key eq 'package' ){
795 # mirror the existing package
796 $exit_status = &do_mirror
();
801 # Make sure I'm at the right place for <> to work!
806 &msg
( "$key \"$value\"\n" );
809 $value{ $key } = $value;
811 # do an explicit close for each file so $. gets reset
814 &msg
( "-- end of config file \"$ARGV\"\n" );
820 # Mirror the last package in the file
821 if( $value{ 'package' } ){
822 $exit_status = &do_mirror
();
826 # parse each line for keyword=value
830 local( $cont ) = '&';
833 if( /^\s*([^\s=+]+)\s*([=+])(.*)?$/ ){
834 ($key, $eqpl, $value) = ($1, $2, $3);
835 # If the value ends in the continuation character then
836 # tag the next line on the end (ignoring any leading ws).
837 while( $value =~ /^(.*)$cont$/o && !eof ){
845 &msg
( "read: $key$eqpl$value\n" );
849 warn "unknown input in \"$ARGV\" line $. of: $_\n";
851 if( ! defined( $default{ "$key" } ) ){
852 die "unknown keyword in \"$ARGV\" line $. of: $key\n";
855 $value = $value{ $key } . $value;
859 # Initialise the key values to the default settings
867 # Override the current settings with command line values
868 sub command_line_override
870 local( $key, $val, $overrides );
872 while( ($key, $val) = each %command_line ){
874 if( $boolean_values{ $key } ){
876 $value{ $key } = &istrue
( $val );
878 # not a boolean value
879 $value{ $key } = $val;
885 &pr_variables
( "keywords after command line override\n" );
888 &msg
( "No command line overrides\n" );
893 # set each variable $key = $value{ $key }
898 while( ($key, $val) = each %value ){
899 # for things like passwords it is nice to have the
900 # real value in a file
901 if( $val =~ /^\<(.*)$/ ){
902 local( $val_name ) = $1;
903 open( VAL_FILE
, $val_name ) ||
904 die "can't open value file $val_name\n";
907 chop $val if $val =~ /\n$/;
910 if( $boolean_values{ $key } ){
912 eval "\$$key = &istrue( $val )";
916 # Change all \ to \\ since \'s will be escaped in
917 # the following string used in the eval.
918 $val =~ s/([^\\])(')/$1\\$2/g;
919 eval "\$$key = '$val'";
921 if( $key eq 'compress_prog' ){
922 if( $val eq 'compress' ){
923 $compress_prog = $sys_compress_prog;
924 $compress_suffix = $sys_compress_suffix;
926 elsif( $val eq 'gzip' ){
928 die "Trying to use gzip but not found in PATH\n";
930 $compress_prog = $gzip_prog;
931 $compress_suffix = $gzip_suffix;
933 elsif( $debug > 2 && $compress_prog ne $gzip_prog &&
934 $compress_prog ne $sys_compress_prog ){
935 &msg
( "compress_prog ($compress_prog) not compress or gzip, presuming program name\n" .
936 "- user must set compress_suffix\n" );
938 &upd_val
( 'compress_prog' );
939 &upd_val
( 'compress_suffix' );
942 if( $compress_patt ne '' && $compress_prog eq '' ){
943 &msg
( "compress_patt set but no compress_prog so compress_patt reset to nothing" );
948 # Reset the umask if needed.
949 # Do it here to try and get it done as early as possible.
950 # If the user doesn't use octal umasks this will cause umask
951 # to be called again unnecessarily - but that is pretty cheap.
952 if( $umask && $umask != $curr_umask ){
953 local( $val ) = $umask;
954 $val = oct( $val ) if $val =~ /^0/;
956 $curr_umask = sprintf( "0%o", umask );
965 if( $package eq 'defaults' ){
966 $default{ $key } = $value{ $key };
975 local( $key, $val, $str );
979 &msg
( "package=$package $site:$remote_dir -> $local_dir\n\t" );
982 &msg
( "package=$package $local_dir -> $site:$remote_dir\n\t" );
985 for $key ( sort keys( %value ) ){
986 next if $key eq 'package' ||
988 $key eq 'remote_dir' ||
989 # Don't show passwords when interactive
990 ($interactive && $key eq 'remote_password') ||
991 ($interactive && $key eq 'remote_gpass');
992 # Report the value in the actual variable
993 $val = eval "\$$key";
994 $str = "$key=\"$val\" ";
996 $out += length( $str );
997 # Output newlines when a line is full
1006 # Mirror the package, return exit_status
1009 local( $get_one_package ) = 0;
1011 $package = $value{ 'package' };
1013 if( $package eq 'defaults' ){
1014 # This isn't a real site - just a way to change the defaults
1020 # Only do this package if given by a -Ppack argument
1021 if( $limit_packages && ! $do_packages{ $package } ){
1026 # Found a package so process all packages from now on
1027 $skip_till = $limit_packages = 0;
1030 local( $exit_status ) = $exit_fail_noconnect; # Presume the worse.
1033 # set things from the command line arguments
1034 &command_line_override
();
1036 if( ! &checkout_regexps
() ){
1037 &msg
( "skipping package\n\n" );
1038 return $exit_status;
1041 # set each variable $key = $value{ $key }
1044 # don't trash locally glossed over things with stuff from the remote
1045 if( $local_ignore ){
1046 if( $exclude_patt ){
1047 $exclude_patt .= '|' . $local_ignore;
1050 $exclude_patt = $local_ignore;
1055 &pr_variables
( "\n" );
1057 elsif( $package && ! $pretty_print ){
1059 &msg
( "package=$package $site:$remote_dir -> $local_dir\n");
1062 &msg
( "package=$package $local_dir -> $site:$remote_dir\n" );
1064 &msg
( "algorithm=$algorithm\n") if $algorithm != 0;
1067 # Don't bother if trying to mirror here!
1068 if( !$interactive && !$force && ((gethostbyname( $site ))[0] eq $hostname) ){
1069 &msg
( "Skipping $site as it is this local site!\n\n" );
1076 if( $value{ 'max_days' } ne '0' ){
1077 $max_age = time - ($value{ 'max_days' } * 24 * 60 * 60);
1078 &msg
( "max_age = $max_age\n" ) if $debug > 1;
1081 # pull in external code, if required
1082 if( $external_mapping ){
1083 &msg
( "Loading external mapping from $external_mapping.\n" ) if $debug > 0 ;
1084 do $external_mapping || die "Cannot load from $external_mapping";
1088 # Keep the ftp debugging lower than the rest.
1089 &ftp
'debug( $debug - 1);
1092 &ftp'debug
( $verbose );
1095 if( $recurse_hard ){
1098 if( $algorithm == 1 ){
1100 $make_bad_symlinks = 1;
1101 $rem_start_len = length( $remote_dir );
1104 if( ! $interactive ){
1105 $ftp'showfd = 'STDOUT
';
1107 &ftp'set_timeout
( $timeout );
1108 &ftp
'set_signals( "main'msg
" );
1110 # set passive ftp mode
1115 # Are we using the SOCKS version of perl?
1117 $chat'using_socks = 1;
1120 # Useful string in prints
1121 $XFER = $get_file ? "get
" : "put
";
1123 # create the list of items to copy
1124 @transfer_list = ();
1126 if( $algorithm == 1 ){
1127 warn "Cannot
use algorithm
1 with interactive
, using
0\n";
1130 # copy the remainder of items from argv to the transfer list
1132 # copy the local directory
1134 push( @transfer_list, shift( @ARGV ) );
1137 # copy the remote directory
1139 push( @transfer_list, shift( @ARGV ) );
1142 die "remote directory must be specified
\n";
1145 # copy the pattern, if available
1147 push( @transfer_list, shift( @ARGV ) );
1149 push( @transfer_list, $default{ 'get_patt' } );
1155 @t = @transfer_list;
1158 printf( "local_dir
=%s remote_dir
=%s patt
=%s\n",
1159 shift( @t ), shift( @t ), shift( @t ) );
1164 push( @transfer_list, $local_dir );
1165 push( @transfer_list, $remote_dir );
1166 push( @transfer_list, $get_patt );
1167 if( $algorithm != 1 ){
1168 $get_one_package = 1;
1173 if( $update_local && $get_patt ){
1174 if( $get_patt ne $default{ 'get_patt' } ){
1175 &msg( "Cannot mix get_patt
and update_local
. get_patt ignored
\n" );
1181 if( !$site || (!$interactive && (!$local_dir || !$remote_dir)) ){
1182 &msg( "Insufficient details
for package to be fetched
\n" );
1183 &msg( "Must give at least
: site
, remote_user
, remote_dir
and local_dir
\n\n" );
1184 return $exit_status;
1187 if( $pretty_print ){
1188 # Don't actually mirror just print a pretty list
1189 # of what would be mirrored. This is for mailing to
1194 &msg( "$package \"$comment\"\n" );
1195 &msg( " $site:$remote_dir --> $local_dir\n\n" );
1200 &msg( "Skipping
$site:$package because
$skip\n\n" );
1204 $split_max = &to_bytes( $split_max );
1205 $split_chunk = &to_bytes( $split_chunk );
1207 if( $split_max && $split_max <= $split_chunk ){
1208 &msg( "split_max
<= split_chunk
- skipping
package\n" );
1209 &msg( " $split_max <= $split_chunk\n\n" );
1210 return $exit_status;
1213 if( $split_chunk && ($split_chunk & 511) ){
1214 &msg( "split_chunk bad size
- skipping
package\n" );
1215 &msg( " $split_chunk should be a multiple of
512 bytes
\n\n" );
1216 return $exit_status;
1219 if( $local_dir_check && ! -d $local_dir ){
1220 &msg( "local_dir
$local_dir does
not exist
- skipping
package\n" );
1221 return $exit_status;
1224 if( $get_one_package && $algorithm != 1 ){
1225 # If only getting one package may as well parse the
1226 # local directory listings before connecting to the
1227 # remote site. (With the status_file stuff this info
1228 # can then be reused if something goes wrong.)
1233 if( !&get_local_directory_details() ){
1234 &msg( "Cannot get
local directory details
($local_dir)\n" );
1237 return $exit_status;
1241 local( $con ) = &connect();
1243 &msg( "Cannot
connect, skipping
package\n" );
1246 return $exit_status;
1250 &msg( "login as
$remote_user\n" ) if $debug > 1;
1251 $curr_remote_user = $remote_user;
1252 if( ! &ftp'login( $remote_user, $remote_password, $remote_account ) ){
1253 &msg( "Cannot login
, skipping
package\n" );
1256 return $exit_status;
1258 $can_restart = (&ftp'restart(0) == 1);
1260 &msg( "Can
" . ($can_restart ? '' : "not ") . "do restarts
\n" );
1265 # Already connected to this site - so no need to login again
1266 &msg( "Already connected to site
$site\n" ) if $debug;
1269 if( ! &ftp'type( $text_mode ? 'A' : 'I' ) ){
1270 &msg( "Cannot set type
\n" );
1273 $exit_status = $exit_fail; # ok this is now the worse case
1275 # Mirror thinks in terms of Unix pathnames.
1276 # Ask ftp.pl to map any remote name it is about to use by
1277 # setting the namemap functions.
1278 if( $remote_fs =~ /vms/i ){
1280 &ftp'set_namemap( "main
'unix2vms", "main'vms2unix
" );
1284 # No mapping necessary
1285 &ftp'set_namemap( '' );
1288 if( ! $get_file || $remote_idle ){
1289 local( @rhelp ) = &ftp'site_commands();
1290 $remote_has_chmod = grep( $_ eq 'CHMOD', @rhelp);
1291 $remote_has_rename = grep( $_ eq 'RNFR', @rhelp) && grep( $_ eq 'RNTO', @rhelp);
1292 $remote_has_idle = grep( $_ eq 'IDLE', @rhelp);
1294 &msg( "remote site
" . ($remote_has_chmod ? "has
" : "hasn
't") . " got chmod\n" );
1295 &msg( "remote site " . ($remote_has_idle ? "has" : "hasn't
") . " got idle
\n" );
1299 if( $remote_has_idle && $remote_idle ){
1300 if( ! &ftp'quote( "site idle
$remote_idle" ) ){
1301 &msg( "Cannot set remote idle
\n" );
1303 elsif( $debug > 2 ){
1304 &msg( "remote idle has been set to
$remote_idle\n" );
1308 if( $remote_group ){
1309 if( ! &ftp'quote( "site group
$remote_group" ) ){
1310 &msg( "Cannot set remote group
\n" );
1312 elsif( $debug > 2 ){
1313 &msg( "remote group has been set to
$remote_group\n" );
1317 if( $remote_gpass ){
1318 if( ! &ftp'quote( "site gpass
$remote_gpass" ) ){
1319 &msg( "Cannot set remote gpass
\n" );
1321 elsif( $debug > 2 ){
1322 &msg( "remote gpass has been set
\n" );
1330 while( @transfer_list ){
1332 $local_dir = shift( @transfer_list );
1333 $remote_dir = shift( @transfer_list );
1334 $get_patt = shift( @transfer_list );
1337 undef( @xfer_dest );
1339 undef( @xfer_attribs );
1340 undef( @things_to_make );
1343 if( ! $get_one_package ){
1348 if( !&get_local_directory_details() ){
1349 &msg( "Cannot get
local directory details
($local_dir)\n" );
1352 return $exit_status;
1356 # Create a get_patt from the contents of the local directory
1357 if( $update_local && $#get_top >= 0 ){
1358 $get_patt = '^' . join( '|^', @get_top );
1359 $get_patt =~ s/$squished//g;
1360 &msg( "get_patt
= $get_patt\n" ) if $debug;
1363 if( !&get_remote_directory_details() ){
1364 &msg( "Cannot get remote directory details
($remote_dir)\n" );
1365 if( $algorithm == 1 ){
1366 # Skip this directory.
1368 if( $cannot < $max_failed_dirs ){
1371 # Too many failed directories. Fall thru'
1376 return $exit_status;
1382 *remote_map, *remote_time,
1383 *remote_size, *remote_type,
1385 *local_map, *local_time,
1386 *local_size, *local_type,
1387 *local_keep, *local_keep_totals );
1391 *local_map, *local_time,
1392 *local_size, *local_type,
1394 *remote_map, *remote_time,
1395 *remote_size, *remote_type,
1396 *remote_keep, *remote_keep_totals );
1401 if( $algorithm == 1 ){
1402 foreach $sd ( @sub_dirs ){
1403 push( @transfer_list, "$local_dir/$sd" );
1404 push( @transfer_list, "$remote_dir/$sd" );
1405 push( @transfer_list, $get_patt );
1413 &do_all_transfers();
1415 $exit_status = $exit_ok; # Everything went ok.
1418 # I must have finished with the remote information
1423 # clear out local info.
1427 if( $save_deletes ){
1428 # If $save_dir is null, make $save_dir to be
1429 # subdirectory 'Old' under
1431 if( ( ! defined( $save_dir ) ) || ( $save_dir eq '' ) ){
1432 $save_dir = "$cwd/Old
";
1435 # If $save_dir is not absolute, take it as
1436 # subdirectory of current path
1437 if( $save_dir !~ m,^/, ){
1438 $save_dir = "$cwd/$save_dir";
1442 if( $do_deletes || $save_deletes ){
1447 *local_type, *local_keep,
1448 *local_totals, *local_keep_totals );
1454 *remote_type, *remote_keep,
1455 *remote_totals, *remote_keep_totals );
1460 undef( @things_to_make );
1462 if( $algorithm == 1 ){
1463 foreach $sd ( @sub_dirs ){
1464 push( @transfer_list, "$local_dir/$sd" );
1465 push( @transfer_list, "$remote_dir/$sd" );
1466 push( @transfer_list, $get_patt );
1470 # No more transfers if the connection has died.
1471 last if ! $connected;
1482 # Should I force a disconnect now?
1483 if( $connected && $disconnect ){
1487 if( $dont_do || $timestamp ){
1488 # Don't generate logs/email
1490 return $exit_status;
1493 local( $now ) = &time_to_standard( time );
1495 if( ! open( LOGG, ">>$update_log" ) ){
1496 &msg( "Cannot append to
$update_log because
: $!\n\n" );
1497 # Serious but this shouldn't stop mirroring.
1498 # return $exit_fail;
1500 print LOGG "mirroring
$package ($site:$remote_dir) completed successfully \@
$now\n";
1505 if( $#log >= 0 && $mail_prog ne '' && $mail_to =~ /./ ){
1507 eval "\
$arg = \"$mail_subject\"";
1508 if( ! open( MAIL, "|$mail_prog $arg $mail_to" ) ){
1509 &msg( "Cannot run
: $com\n\n" );
1513 print MAIL "Mirrored
$package ($site:$remote_dir -> $local_dir) $comment \@
$now\n";
1516 print MAIL "Mirrored
$package ($local_dir -> $site:$remote_dir) $comment \@
$now\n";
1524 return $exit_status;
1531 &msg( "disconnecting from
$connected\n" ) if $debug;
1532 if( ! $ftp'fatalerror ){
1536 &ftp'service_closed();
1542 # Connect to the site
1543 # Return 0 on a fail,
1544 # 1 if a connection was successfully made,
1545 # 2 if already connected to the site
1548 local( $attempts ) = 1; # Retry ONCE! Be friendly.
1551 if( $connected eq $site && $curr_remote_user eq $remote_user ){
1552 # Already connected to this site!
1556 # Clear out any session active session
1560 $ftp'proxy = $proxy;
1561 $ftp'proxy_gateway = $proxy_gateway;
1562 $ftp'proxy_ftp_port = $proxy_ftp_port;
1564 $res = &ftp'open( $site, $ftp_port, $retry_call, $attempts );
1572 # This just prods the remote ftpd to prevent time-outs
1575 return unless $connected;
1578 &msg( " prodding remote ftpd
\n" );
1583 # checkout and fixup any regexps.
1584 # return 0 on an error
1585 sub checkout_regexps
1588 # Check out the regexps
1590 foreach $r ( @regexp_values ){
1591 # regexps should never begin or end with a | or have
1592 # two in a row otherwise the pattern matches everything.
1593 # Use null to match everything if thats what you mean.
1594 $value{ $r } =~ s/\|+/|/g;
1595 $value{ $r } =~ s/^\|//;
1596 $value{ $r } =~ s/\|$//;
1597 local( $val ) = $value{ $r };
1599 eval '$t =~ /$val/';
1603 &msg( "Problem with regexp
$r ($err)\n" );
1613 undef( %local_map );
1615 undef( @local_sorted );
1616 undef( @local_time );
1617 undef( @local_size );
1618 undef( @local_type );
1619 undef( @local_mode );
1620 undef( @local_keep );
1621 undef( @local_totals );
1622 undef( @local_keep_totals );
1628 undef( %remote_map );
1630 undef( @remote_sorted );
1631 undef( @remote_time );
1632 undef( @remote_size );
1633 undef( @remote_type );
1634 undef( @remote_mode );
1635 undef( @remote_keep );
1636 undef( @remote_totals );
1637 undef( @remote_keep_totals );
1640 sub get_local_directory_details
1642 local( @dirs, $dir );
1643 local( $last_prodded ) = time; # when I last prodded the remote ftpd
1645 $next_local_mapi = $map_init;
1649 # Make sure the first elem is 0.
1650 $local_time[ 0 ] = 0;
1651 $local_size[ 0 ] = 0;
1652 $local_type[ 0 ] = 0;
1653 $local_mode[ 0 ] = 0;
1657 &msg( "Scanning
local directory
$local_dir\n" ) if $debug;
1659 if( ! -d $local_dir ){
1660 &msg( "$local_dir no such directory
- creating it
\n" );
1661 if( $dont_do || $timestamp ){
1664 if( &mkdirs( $local_dir ) ){
1665 &msg( $log, "Created
local dir
$local_dir\n" );
1666 $exit_xfer_status |= $exit_xfers;
1669 &msg( $log, "FAILED to create
local dir
$local_dir\n" );
1672 if( !chdir( $local_dir ) ){
1673 &msg( "Cannot change directory to
$local_dir\n" );
1677 if( $local_dir =~ m,^/, ){
1684 # @dirs is the list of all directories to scan
1685 # As subdirs are found they are added to the end of the list
1688 # Most of these variables should be locals in blocks below but
1689 # that seems to tickle a perl bug and causes a lot of memory to
1691 local( $dir_level ) = 0;
1693 local( $path, $time, $size, $type, $mode, $name, $isdir, $value, $follow );
1694 local( $dev,$ino,$fmode,$nlink,$uid,$gid,$rdev,$ssize,
1695 $atime,$mtime,$ctime,$blksize,$blocks );
1696 while( defined( $dir = shift( @dirs ) ) ){
1698 if( !opendir( DIR, $dir ) ){
1699 &msg( "Cannot
open local directory
$dir, skipping it
\n" );
1703 while( defined( $name = readdir( DIR ) ) ){
1706 # Prod the remote system from time to time
1707 # To prevent time outs. Only look once every 50 files
1708 # to save on unnecessary systems calls.
1709 if( ($i % 50 == 0) && time > ($last_prodded + $prod_interval) ){
1710 $last_prodded = time;
1715 $path = "$dir/$name";
1716 $path =~ s,(^|/)\./,,;
1717 next if $name eq '.' || $name eq '..' ||
1718 ($local_ignore && $path =~ /$local_ignore/);
1720 $follow = ($follow_local_symlinks ne '' && $path =~ /$follow_local_symlinks/);
1721 if( !$follow && -l $path ){
1722 $value = readlink( $path );
1723 ( $dev,$ino,$fmode,$nlink,$uid,$gid,$rdev,$ssize,
1724 $atime,$mtime,$ctime,$blksize,$blocks ) =
1731 elsif( ($isdir = ($follow ? (-d $path) : (-d _))) ||
1733 ( $dev,$ino,$fmode,$nlink,$uid,$gid,$rdev,$ssize,
1734 $atime,$mtime,$ctime,$blksize,$blocks ) =
1740 push( @dirs, $path ) if $recursive;
1746 if( $dir_level == 0 && $update_local ){
1747 push( @get_top, $path );
1751 &msg( "unknown file type
$path, skipping
\n" );
1755 printf "local: %s %s %s %s 0%o\n",
1756 $path, $size, $time, $type, $mode;
1758 if( $max_age && $time != 0 && $time < $max_age ){
1759 &msg( " too old
: $path\n" ) if $debug > 1;
1763 local( $mapi ) = $next_local_mapi++;
1764 # push( @local_sorted, $path );
1765 $local_sorted[ $mapi - 1 ] = $path;
1766 $local_map{ $path } = $mapi;
1767 $local_time[ $mapi ] = $time;
1768 $local_size[ $mapi ] = $size;
1769 $local_type[ $mapi ] = $type;
1770 $local_mode[ $mapi ] = $mode;
1772 $local_totals[ 0 ]++;
1775 $local_totals[ 1 ]++;
1788 # Return true if the remote directory listing was brought back safely.
1789 sub get_remote_directory_details
1791 local( $type_changed ) = 0;
1793 local( $storename ) = "/dev/null
";
1795 &msg( "Scanning remote directory
$remote_dir\n" ) if $debug;
1797 if( $store_remote_listing ){
1798 eval "\
$storename = \"$store_remote_listing\"";
1801 $next_remote_mapi = $map_init;
1804 # Make sure the first elem is 0.
1805 $remote_time[ 0 ] = 0;
1806 $remote_size[ 0 ] = 0;
1807 $remote_type[ 0 ] = 0;
1808 $remote_mode[ 0 ] = 0;
1810 if( $remote_fs !~ /cms/ && ! &ftp'cwd( $remote_dir ) ){
1816 &msg( "Failed to change to remote directory
($remote_dir) trying to create it
\n" );
1817 &mkdirs( $remote_dir );
1819 if( ! &ftp'cwd( $remote_dir ) ){
1820 &msg( "Cannot change to remote directory
($remote_dir) because
: $ftp'response\n" );
1829 if( $local_ls_lR_file ){
1830 local( $dirtmp ) = $local_ls_lR_file;
1831 &msg( " Using local file $local_ls_lR_file for remote dir listing\n" ) if $debug;
1833 if( $dirtmp =~ /\.$sys_compress_suffix$/ ){
1834 $unsquish = $sys_compress_prog;
1836 elsif( $dirtmp =~ /\.($gzip_suffix|$old_gzip_suffix)$/ ){
1837 $unsquish = $gzip_prog;
1839 if( defined( $unsquish ) ){
1842 $f =~ s/($shell_metachars)/\\$1/g;
1843 $dirtmp = "$unsquish -d < \"$f\" |";
1845 elsif( $ls_lR_file =~ /($times_suffix|$patch_gzip_suffix)$/ ){
1846 return 0 if &patch_ls_lR_file()==0;
1848 if( ! open( DIRTMP, $dirtmp ) ){
1849 &msg( "Cannot open $dirtmp\n" );
1852 $rls = "main'DIRTMP
";
1853 # Now we don't want to overwrite our input... better test?
1854 if( $local_ls_lR_file eq $storename ){
1855 $storename = "/dev/null
";
1858 elsif( $ls_lR_file ){
1860 $dirtmp = "$big_temp/.dir
$$";
1861 if( $ls_lR_file =~ /\.($sys_compress_suffix|$gzip_suffix|$old_gzip_suffix)$/ ){
1865 &msg( " Getting directory listing from remote file
$ls_lR_file\n" ) if $debug;
1866 if( ! &ftp'get( $ls_lR_file, $dirtmp, 0 ) ){
1867 &msg( "Cannot get dir listing file
\n" );
1871 if( $dirtmp =~ /\.$sys_compress_suffix$/ ){
1872 $unsquish = $sys_compress_prog;
1874 elsif( $dirtmp =~ /\.($gzip_suffix|$old_gzip_suffix)$/ ){
1875 $unsquish = $gzip_prog;
1877 if( defined( $unsquish ) ){
1879 $uf = $udirtmp = $dirtmp;
1880 $dirtmp =~ s/($shell_metachars)/\\$1/g;
1882 $dirtmp =~ s/\.($sys_compress_suffix|$gzip_suffix|$old_gzip_suffix)$//;
1883 $udirtmp =~ s/\.($sys_compress_suffix|$gzip_suffix|$ol_gzip_suffix)$//;
1884 if( &sys( "$unsquish -d
< \"$f\" > \"$dirtmp\"" ) != 0 ){
1885 &msg( "Cannot uncompress directory listing
\n" );
1894 open( DIRTMP, $dirtmp ) || die "Cannot
open $dirtmp";
1895 $rls = "main
'DIRTMP";
1899 if( ! &ftp'type
( 'A' ) ){
1900 &msg
( "Cannot set type to ascii for dir listing, ignored\n" );
1908 $lsparse'fstype = $remote_fs;
1909 $lsparse'name
= "$site:$package";
1912 local( $flags ) = $flags_nonrecursive;
1913 if( $recursive && ! $recurse_hard ){
1914 $flags = $flags_recursive;
1916 $lsparse'report_subdirs = (! $recurse_hard && $algorithm == 0);
1917 if( !&ftp'dir_open
( $flags ) ){
1918 &msg
( "Cannot get remote directory listing because: $ftp'response\n" );
1927 # Strip this off all pathnames to make them
1928 # relative to the remote_dir
1929 $rcwd = $remote_dir;
1931 $dateconv'use_timelocal = $use_timelocal;
1932 if( !&lsparse'reset( $rcwd ) ){
1933 &msg
( "$remote_fs: unknown fstype\n" );
1937 # Need to get in terms of the full pathname
1938 # so add it back in - see unix2vms at end of mirror
1939 $vms_dir = $remote_dir;
1942 if( $storename ne "/dev/null" ){
1943 open( STORE
, ">$storename" ) || die( "Cannot write to $storename\n" );
1946 local( $parse_state ) = &parse_remote_details
();
1951 if( $local_ls_lR_file ){
1954 elsif( $ls_lR_file ){
1959 # Could optimise this out - but it makes sure that
1960 # the other end gets a command straight after a possibly
1962 if( ! &ftp
'type( $text_mode ? 'A
' : 'I
' ) ){
1963 local( $msg ) = "Cannot reset type after dir listing, ";
1964 if( $type_changed ){
1965 # I changed it before - so I must be able to
1966 # change back unless something is wrong
1967 $msg .= "aborting\n";
1972 $msg .= "ignoring\n";
1978 # If the other end dropped part way thru make sure the
1979 # higher routines know!
1980 return $parse_state;
1983 # Get remote ls-lR times or mirror gzipped patch files.
1984 sub patch_ls_lR_file
1986 if( ! $patch_prog ){
1987 &msg( "No patch program on PATH\n" );
1990 local( $f, $fr, $flb, $flt, $flp, $flz, $frb, $frt );
1992 $frb = $frt = $ls_lR_file;
1994 &msg( "Patching $flb using $frb\n" ) if $debug;
1995 local( $tlb ) = -f $flb?(stat($flb))[9]:0;
1996 $dateconv'use_timelocal
= $use_timelocal;
1997 $flp = "$flb$patch_suffix";
1998 $flz = "$flb$patch_gzip_suffix";
1999 # Get times and patch.
2000 if( $frt =~ /$times_suffix$/ ){
2001 # Use remote times file.
2002 $frb =~ s/$times_suffix$//;
2003 $flt = "$flb$times_suffix";
2004 &ftp
'get( $frt, $flt, 0 ) ?
2005 &msg( "Got $frt\n" ):
2009 $f = gmtime( <FT> );
2010 $_ = &lstime_to_time( $f );
2013 $f = "$frb$patch_gzip_suffix";
2014 if( $tlb == $to && &ftp'get
( $f, $flz, 0 ) &&
2015 ! &sys
("$gzip_prog -df <$flz >$flp") ){
2016 &msg
( $log, "Got $f\n" );
2017 unlink $flz if ! $debug;
2021 # Get time of remote patch file.
2022 $lsparse'fstype = $remote_fs;
2023 $lsparse'name
= "$site:$package";
2024 &lsparse
'reset( $remote_dir );
2025 if( ! &ftp'dir_open
( "$flags_nonrecursive $frb" ) ){
2026 &msg
( "List remote ls-lR patch: $ftp'response\n" );
2030 local( $p, $s, $trz, $t, $m ) = &lsparse'line
( ftp
'NS );
2031 &msg( "Remote ls-lR patch:\n$p $s $trz $t $m\n" ) if $debug;
2032 if( ! &ftp'dir_close
() ){
2033 &msg
( "List remote ls-lR patch: $ftp'response\n" );
2036 # If remote time does not match local get remote patch file.
2037 local( $tlz ) = -f
$flz?
(stat($flz))[9]:0;
2039 &msg
( "No new $frb\n" );
2040 &msg
( "age $trz same as $flz\n" ) if $debug;
2043 &ftp
'get( $frb, $flz, 0 )?
2044 &msg( $log, "Got $frb $s\n" ):
2046 &utime( $trz, $trz, $flz );
2048 # unzip patch and read times.
2049 $frb =~ s/$patch_gzip_suffix$//;
2050 &sys( "$gzip_prog -df <$flz >$flp" ) ?
2054 ( $fr, $f ) = split( /\t/, <FT> );
2055 $_ = &lstime_to_time( $f );
2059 # Patch or leave or get new local ls-lR file?
2060 $f = "$patch_prog ";
2061 $f .= $use_timelocal?$patch_local:$patch_UTC;
2062 if( $tlb == $to && ! &sys( "$f $flb $flp" ) ){
2063 &msg( "$flb patched\n" );
2065 elsif( $tlb == $tn ){
2066 &msg( "$flb up to date\n" );
2069 $fr = "$frb.$gzip_suffix";
2070 $f = "$flb.$gzip_suffix";
2071 if( &ftp'get
( $fr, $f, 0 ) &&
2072 ! &sys
( "$gzip_prog -df $f" ) ){
2073 &utime( $tn, $tn, $flb );
2074 &msg
( $log, "Got $fr for $flb\n" );
2077 &msg
( "Did not get $fr\nand $ftp'response\n" );
2081 unlink $flp, $flt if ! $debug;
2082 if( ! $do_deletes && $exclude_patt =~ /^\.($|\|)/ ){
2083 &msg
( "$flb check complete\n" );
2091 $parse_timed_out = 1;
2092 die "timeout: parse_remote_details";
2095 sub parse_remote_details
2100 $parse_timed_out = 0;
2103 # No need to bother with the timers
2104 return &parse_remote_details_real
();
2108 $old_sig = $SIG{ 'ALRM' };
2109 $SIG{ 'ALRM' } = "main\'parse_timeout";
2111 $ret = eval '&parse_remote_details_real()';
2115 $SIG{ 'ALRM' } = $old_sig;
2117 if( $@
=~ /^timeout/ ){
2118 &msg
( "timed out parsing directory details\n" );
2125 sub parse_remote_details_real
2127 local( $path, $size, $time, $type, $mode, $rdir, $rcwd );
2133 &alarm( $parse_time );
2136 # Need to loop in case $recurse_hard
2138 while( !eof( $rls ) ){
2139 ( $path, $size, $time, $type, $mode ) =
2140 &lsparse
'line( $rls );
2141 last if $path eq '';
2142 if( $ls_fix_mappings ){
2143 local( $old_path ) = $path;
2145 eval $ls_fix_mappings;
2146 if( $_ ne $old_path ){
2150 next if $name eq '.' || $name eq '..';
2152 printf "remote: %s %s %s %s 0%o\n",
2153 $path, $size, $time, $type, $mode;
2156 # I just got something so shouldn't timeout
2157 &alarm( $parse_time );
2160 # Prod the remote system from time to time
2161 # To prevent time outs. Only look once every
2163 # to save on unnecessary systems calls.
2164 if( ($i % 50 == 0) &&
2165 time > ($last_prodded + $prod_interval) ){
2166 $last_prodded = time;
2172 if( $algorithm == 1 ){
2173 $path0 = substr( $remote_dir, $rem_start_len );
2179 # &msg( "debug: $path0, $remote_dir, $rem_start_len\n" );
2185 if( $exclude_patt && $path0 =~ /$exclude_patt/ ){
2186 &msg
( " exclude: $path0\n" ) if $debug > 1;
2191 push( @dir_list, $path0 );
2194 if( $max_age && $time != 0 && $time < $max_age ){
2195 &msg
( " too old: $path0\n" ) if $debug > 1;
2199 # If vms and only keeping the latest version
2200 if( $vms && !$vms_keep_versions ){
2201 # If we already have a file, pick the newer
2202 # TODO: pick the greatest version number
2203 local( $ri ) = $remote_map{ $path };
2205 $time > $remote_time[ $ri ] ){
2206 $remote_time[ $ri ] = $time;
2207 $remote_size[ $ri ] = $size;
2208 $remote_type[ $ri ] = $type;
2209 $remote_mode[ $ri ] = $mode;
2214 local( $mapi ) = $next_remote_mapi++;
2215 # push( @remote_sorted, $path );
2216 $remote_sorted[ $mapi - 1 ] = $path;
2217 $remote_map{ $path } = $mapi;
2218 $remote_time[ $mapi ] = $time;
2219 $remote_size[ $mapi ] = $size;
2220 $remote_type[ $mapi ] = $type;
2221 $remote_mode[ $mapi ] = $mode;
2223 $remote_totals[ 0 ]++;
2226 $remote_totals[ 1 ]++;
2231 if( ! &ftp
'dir_close() ){
2232 &msg( "Failure at end of remote directory" .
2233 " ($rdir) because: $ftp'response
\n" );
2238 if( $recurse_hard ){
2241 if( $#dir_list < 0 ){
2242 # Make sure we end in the right directory.
2243 if( ! &ftp'cwd( $remote_dir ) ){
2244 &msg( "Cannot change to remote directory
" .
2245 " ($rdir) because
: $ftp'response\n" );
2251 $rcwd = shift( @dir_list );
2252 $rdir = "$remote_dir/$rcwd";
2254 print "scanning: $remote_dir / $rcwd\n";
2256 if( ! &ftp'cwd
( $rdir ) ){
2257 &msg
( "Cannot change to remote directory" .
2258 " ($rdir) because: $ftp'response\n" );
2266 if( !&ftp
'dir_open( $flags_nonrecursive ) ){
2267 &msg( "Cannot get remote directory" .
2268 " listing because: $ftp'response
\n" );
2271 &lsparse'reset( $rcwd );
2273 # round the loop again.
2277 # All done - snap the loop
2285 # This declaration must be "local()" because it modifies global data.
2287 *src_map, *src_time,
2288 *src_size, *src_type,
2290 *dest_map, *dest_time,
2291 *dest_size, *dest_type,
2292 *dest_keep, *dest_keep_totals ) = @_;
2293 local( $src_path, $dest_path, $i );
2294 local( $last_prodded ) = time; # when I last prodded the remote ftpd
2296 # Most of these variables should be locals in blocks below but
2297 # that seems to tickle a perl bug and causes a lot of memory to
2299 local( $desti, $srci, $compress, $srciZ, $srcigz, $split, $dest_path_real );
2300 local( $old_dest_path, $existing_path, $tmp, $restart );
2301 local( $sp, $dp ) = ($#src_paths + 1, $#dest_paths + 1);
2303 &msg( "compare directories
(src
$sp, dest
$dp)\n" ) if $debug;
2304 $total_src_size = 0;
2306 for( $i = 0; $i <= $#src_paths; $i++ ){
2307 $dest_path = $src_path = $src_paths[ $i ];
2309 $desti = $dest_map{ $dest_path };
2312 # Prod the remote system from time to time
2313 # To prevent time outs. Only look once every 50 files
2314 # to save on unnecessary systems calls.
2315 if( ($i % 50 == 0) && time > ($last_prodded + $prod_interval) ){
2316 $last_prodded = time;
2321 &msg( "Compare src
$src_path ($srci): " .
2322 &t2str( $src_time[ $srci ] ) );
2323 &msg( " $src_size[ $srci ] $src_type[ $srci ]\n" );
2326 # I'm about to do a lot of matching on this
2329 # Should I compress this file?
2330 # Don't compress this file if trying to do a compress->gzip
2333 if( &will_compress( $src_path, $srci ) ){
2334 if( $dest_path !~ /$squished/o ){
2335 $srciZ = $src_map{ "$src_path.$sys_compress_suffix" };
2336 $srcigz = $src_map{ "$src_path.$gzip_suffix" };
2337 if( $srciZ || $srcigz ){
2338 # There is a compressed version
2339 # too! Skip the uncompressed one
2340 &msg( " do not xfer
, compressed version
exists: $src_path\n" ) if $debug > 1;
2345 $dest_path .= '.' . $compress_suffix;
2346 $desti = $dest_map{ $dest_path };
2349 # need to adjust the symlink pointer?
2350 elsif( $src_type[ $srci ] =~ /^l (.*)/ ){
2351 # Am I going to squish the file this points to?
2352 local( $real, $reali, $reali1 );
2353 local( $count ) = 0;
2354 while( $count++ <= 10 ){
2355 $real = &expand_symlink( $src_path, $1 );
2356 $reali = $src_map{ $real };
2357 # Look out for when the symlink loops on itself
2358 if( defined( $reali1 ) && $reali == $reali1 ){
2362 last if $src_type[ $reali ] !~ /^l (.*)$/;
2364 if( &will_compress( $real, $reali ) ){
2365 # real is going to be (at least) squished so
2367 $dest_path .= '.' . $compress_suffix;
2368 $desti = $dest_map{ $dest_path };
2369 $src_type[ $srci ] .= '.' . $compress_suffix;
2370 &msg( " symlink pointer is now
$dest_path\n" ) if $debug > 1;
2371 if( $src_map{ $dest_path } ){
2372 &msg( "do not xfer
, $dest_path exists\n" ) if $debug > 1;
2376 if( &will_split( $real, $reali ) ){
2377 $src_type[ $srci ] .= '-split/README';
2378 &msg( " symlink pointer now to
$real-split/README
'\n" ) if $debug > 1;
2382 # If this is a file that I decided not to compress but the
2383 # remote file is compressed and I want a gziped local version
2384 # then force compression.
2385 # This ignores any compress_excl flags.
2387 $compress_suffix eq $gzip_suffix &&
2388 $compress_conv_patt && $src_path =~ /$compress_conv_patt/ ){
2390 eval $compress_conv_expr;
2392 # check if dest_path exists in the sources. If it
2393 # does, ignore this file. This is to avoid the
2394 # double mirroring problem if you are using gzip and
2395 # the source site has both foo.Z and foo.gz.
2396 if( $src_map{ $dest_path } ){
2397 &msg( "Skipping $src_path because remote site also has $dest_path\n" ) if $debug > 2;
2400 &msg( " $src_path -> $dest_path\n" ) if $debug > 2;
2401 $desti = $dest_map{ $dest_path };
2405 # Am I converting the compression on the file this points to?
2406 if( $src_type[ $srci ] =~ /^l (.*)/ &&
2407 $compress_suffix eq $gzip_suffix ){
2408 local( $value ) = $1;
2409 local( $real ) = &expand_symlink( $src_path, $value );
2410 local( $reali ) = $src_map{ $real };
2411 if( $src_type[ $reali ] ne 'd
' &&
2412 $src_type[ $reali ] ne /^l .*/ &&
2413 $compress_conv_patt && $real =~ /$compress_conv_patt/ ){
2414 $dest_path =~ s/$sys_compress_suffix$/$gzip_suffix/;
2415 $desti = $dest_map{ $dest_path };
2416 $value =~ s/$sys_compress_suffix$/$gzip_suffix/;
2417 &msg( " symlink pointer is now $dest_path (conv)\n")
2420 if( $name_mappings || $external_mapping ){
2421 local( $old ) = $value;
2422 $value = &map_name( $value );
2423 if( $value ne $old ){
2424 &msg( " Mapped symlink value is $value\n" ) if $debug > 2;
2428 $src_type[ $srci ] = "l ".$value;
2431 if( $name_mappings || $external_mapping ){
2432 local( $old_dest_path ) = $dest_path;
2433 $dest_path = &map_name( $dest_path );
2434 if( $dest_path ne $old_dest_path ){
2435 $desti = $dest_map{ $dest_path };
2436 &msg( " Mapped name is $dest_path\n" ) if $debug > 2;
2440 # Should this file be split?
2442 $dest_path_real = undef;
2443 if( &will_split( $src_path, $srci ) ){
2445 $dest_path_real = $dest_path;
2446 $dest_path .= "-split/part01";
2447 $desti = $dest_map{ $dest_path };
2451 &msg( " dest $dest_path ($desti): " .
2452 &t2str( $dest_time[ $desti ] ) );
2453 &msg( " $dest_size[ $desti ] $dest_type[ $desti ]" );
2454 &msg( " (->$compress_suffix)" ) if $compress;
2455 &msg( " (split)" ) if $split;
2459 if( $algorithm == 1 ){
2460 $src_path0 = substr( $remote_dir, $rem_start_len );
2461 if( $src_path0 ne '' ){
2464 $src_path0 .= $src_path;
2465 $src_path0 =~ s,^/,,;
2466 #&msg( "debug: $src_path0, $remote_dir, $rem_start_len\n" );
2469 $src_path0 = $src_path;
2472 if( $get_patt && $src_path0 !~ /$get_patt/ ){
2473 &msg( " do not xfer: $src_path0\n" ) if $debug > 1;
2477 # Just create any needed directories (the timestamps
2478 # should be ignored)
2479 if( $src_type[ $srci ] eq 'd
' ){
2480 if( $algorithm == 1 ){
2481 if( $exclude_patt && $src_path0 =~ /$exclude_patt/ ){
2482 &msg( " exclude: $src_path0\n" ) if $debug > 1;
2485 $rel_src_path = $src_path;
2486 $rel_src_path =~ s,.*/,,;
2487 push( @sub_dirs, $rel_src_path );
2488 &msg( " adding $rel_src_path\n" ) if $debug;
2491 if( $dest_type[ $desti ] ne 'd
' ){
2492 push( @things_to_make, "d $dest_path" );
2493 &msg( " need to mkdir $dest_path\n" ) if $debug > 1;
2495 # keep the directory once made
2496 # (Also if local is really a symlink elsewhere
2498 &keep( $desti, $dest_path, *dest_keep, *dest_keep_totals, *dest_map, 0 );
2502 # Well that just leaves files and symlinks.
2503 # Do various checks on them.
2505 if( $desti && ! $dest_keep[ $desti ] ){
2506 &keep( $desti, $dest_path, *dest_keep, *dest_keep_totals, *dest_map, 1 );
2508 # Mark all the split parts as kept
2509 local( $dpp, $dps );
2510 ($dpp, $dps) = ($dest_path =~ m,^(.*/)(part[0-9]+)$,);
2513 if( !($di = $dest_map{ $dpp . $dps }) ){
2516 &keep( $di, $dpp . $dps, *dest_keep, *dest_keep_totals, *dest_map, 1 );
2520 $di = $dest_map{ $dpp . $dps };
2522 &keep( $di, $dpp . $dps, *dest_keep, *dest_keep_totals, *dest_map, 1 );
2527 $di = $dest_map{ $dpp . $dps };
2529 &keep( $di, $dpp . $dps, *dest_keep, *dest_keep_totals, *dest_map, 0 );
2534 local( $update ) = 0;
2536 if( ! $get_missing ){
2540 if( ($max_size > 0) && ($src_size[ $srci ] > $max_size) ){
2541 &msg( " src is too big, no need to xfer it\n" ) if $debug > 2;
2545 if( $force || ! $dest_type[ $desti ] || $timestamp ){
2546 # Either I'm forcing xfers
or the file doesn
't exist
2547 # either way I should update
2551 # Maybe the src is newer?
2553 &compare_times( $src_time[ $srci ], $dest_time[ $desti ] ) ){
2554 &msg( " src is newer, xfer it\n" ) if $debug > 2;
2557 # or maybe its size has changed?
2558 # don't bother
if file was compressed
or split as the
2559 # size will have changed anyway
2561 !$compress && !$split &&
2563 ($src_type[ $srci ] eq 'f') &&
2564 ($src_size[ $srci ] != $dest_size[ $desti ]) ){
2567 &msg
( " src is different size, xfer it\n" );
2570 # Maybe it has changed type!
2572 $src_type[ $srci ] ne $dest_type[ $desti ] ){
2575 &msg
( " src has different type, xfer it\n" );
2584 if( $src_type[ $srci ] =~ /^l (.*)/ ){
2585 # If the symlink hasn't changed then may as well
2587 if( $src_type[ $srci ] eq $dest_type[ $desti ] ){
2590 # DONT FORGET TO NAME MAP!!!!
2591 $existing_path = $1;
2593 if( $compress_suffix eq $gzip_suffix &&
2594 $compress_conv_patt && $existing_path =~ /$compress_conv_patt/ ){
2595 $_ = $existing_path;
2596 eval $compress_conv_expr;
2597 $existing_path = $_;
2600 push( @things_to_make, "l $dest_path -> $existing_path" );
2601 &msg
( " need to symlink $dest_path -> $existing_path\n" ) if $debug > 2;
2605 # Now that the tests are complete use the real dest.
2606 if( defined( $dest_path_real ) ){
2607 $dest_path = $dest_path_real;
2608 $desti = $dest_map{ $dest_path };
2611 $total_src_size += $src_size[ $srci ];
2615 &msg
( "$XFER file $src_path as $dest_path ($src_size[ $srci ])".
2616 ($compress ?
" (->$compress_suffix)" : "") .
2617 ($split ?
" (split)" : "") . "\n" ) if $debug > 1;
2618 push( @xfer_dest, $dest_path );
2619 push( @xfer_src, $src_path );
2621 # If xfers can be restarted AND
2622 # a temporary file exists from a previous attempt at a
2624 # the timestamps of the exising temp file and the original
2625 # src file match then flag a restart.
2626 $tmp = &filename_to_tempname
( '', $dest_path );
2627 $tmpi = $dest_map{ $tmp };
2629 #warn "get_file = $get_file, can_restart = $can_restart, dest_size = $dest_size[ $tmpi ], dest_time = $dest_time[ $tmpi ], src_time = $src_time[ $srci ]\n";
2632 # Debian bug #24243, mirror-2.9 does not restart, adam@usa.net
2633 $dest_size[ $tmpi ] != 0 ){
2634 if ($dest_time[ $tmpi ] eq $src_time[ $srci ]) {
2635 # Then this is an xfer of the same file
2636 # so just restart where I left off
2638 } elsif ( $debug > 1 ){
2639 &msg
( "Timestamp useless on $tmp\n" );
2642 # x for xfer, c for compress, s for split
2643 push( @xfer_attribs,
2645 ($compress ?
"c" : "") .
2646 ($split ?
"s" : "") );
2648 &msg
( "to $XFER $total_src_size bytes\n" ) if $debug > 2;
2653 local( $name ) = @_;
2655 if( $name_mappings ){
2656 local( $old_name ) = $name;
2658 eval $name_mappings;
2659 if( $_ ne $old_name ){
2664 if( $external_mapping ){
2666 local( $tmp ) = &extmap
'map( $name );
2667 if( $tmp ne $old_name ){
2679 &msg( "setting timestamps\n" );
2681 &msg( "Cannot set remote timestamps\n" );
2685 local( $dest_path, $dest_loc_mapi, $src_rem_mapi, $rtime );
2687 foreach $src_path ( @xfer_src ){
2688 $dest_path = shift( @xfer_dest );
2689 $dest_loc_mapi = $local_map{ $dest_path };
2690 $src_rem_mapi = $remote_map{ $src_path };
2692 $rtime = $remote_time[ $src_rem_mapi ];
2693 if( $dest_loc_mapi && $local_time[ $dest_loc_mapi ] ne $rtime ){
2694 &set_timestamp( $dest_path, $rtime );
2701 local( $path, $time ) = @_;
2703 local( $pr_time ) = &t2str( $time );
2706 &msg( "Should set time of $path to $pr_time\n" );
2710 if( $timestamp || $debug > 2 ){
2711 &msg( "Setting time of $path to $pr_time\n" );
2714 if( ! &utime( $time, $time, $path ) ){
2715 &msg( $log, "Cannot set file times for $path to $pr_time because: $!\n" );
2723 foreach $thing ( @things_to_make ){
2724 if( $thing !~ /^d (.*)/ ){
2728 &msg( "Should mkdir $1\n" );
2741 foreach $thing ( @things_to_make ){
2742 if( $thing !~ /^l (.*) -> (.*)/ ){
2745 local( $dest, $existing ) = ($1, $2);
2746 local( $dirpart ) = &dirpart( $dest );
2747 local( $ft ) = &expand_symlink( $dest, $existing );
2749 &mkdirs( $dirpart ) if ! -d $dirpart;
2750 # symlink to existing file.
2751 # Debian bug #85353 "bad symlink stops listing with -n" <sizif@pier.botik.ru>
2752 &mksymlink( $dest, $existing );
2756 # The existing file doesn't actually exist
!
2757 # Has it been compressed, gzipped, split? or worse
2758 # compressed/gzipped AND split. (OK so it could
2759 # be another problem, bad symlink on remote host, file
2760 # that hasn't been xfer'd yet... but this is as good as
2764 "\%s.$sys_compress_suffix",
2768 "\%s-split.$sys_compress_suffix/README",
2769 "\%s-split.$gzip_suffix/README" ){
2770 local( $f ) = sprintf( $p, $existing );
2772 &msg
( "using $p\n" ) if $debug > 2;
2773 &mksymlink
( $dest, $f );
2777 if( $make_bad_symlinks ){
2778 &msg
( "symlink to non-existant file: $dest -> $existing\n" );
2779 &mksymlink
( $dest, $existing );
2781 elsif ( $get_symlink_files ){
2782 # Get file within $local_dir tree and make symlink, iml@debian.org, 2001/09/22.
2783 if( $ft =~ m
|\
.\
./| ){
2784 &msg
( "Not getting path $ft\nas not in remote_dir $remote_dir\n" );
2785 &msg
( "and not symlinking $dest -> $existing\n" );
2788 local( $dl ) = &dirpart
( $ft );
2789 &mkdirs
( $dl ) if ! -d
$dl;
2790 if( &ftp
'get( $ft, $ft, 0 ) ){
2791 &msg( $log, "Got $ft\n" );
2792 &mksymlink( $dest, $existing );
2795 &msg( "Did not get $ft\nbecause $ftp'response
\n" );
2796 &msg( "so
not symlinking
$dest -> $existing\n" );
2800 &msg( "Not symlinking
$dest -> $existing\n" );
2801 &msg( "as
no path
$ft\n" );
2806 sub do_all_transfers
2809 local( $dest_path, $attribs );
2812 if( $#xfer_src < 0 ){
2813 &msg( "No files to transfer
\n" ) if $algorithm == 0;
2817 # The Macos ftpd cannot reliably rename files
2818 $no_rename = (! $remote_has_rename) || ($remote_fs eq 'macos' && ! $get_file);
2820 foreach $src_path ( @xfer_src ){
2822 $srci = $remote_map{ $src_path };
2825 $srci = $local_map{ $src_path };
2828 $dest_path = shift( @xfer_dest );
2829 $attribs = shift( @xfer_attribs );
2832 # Skip trying to get the file.
2836 &msg( "Need to
$XFER file
$src_path as
$dest_path ($attribs)\n" ) if $debug > 1;
2839 &transfer_file( $src_path, $dest_path,
2840 $attribs, $remote_time[ $srci ] );
2841 if( $get_file && $newpath eq '' ){
2842 &msg( $log, "Failed to
$XFER file
$ftp'response\n" );
2843 if( $ftp'response
=~ /timeout|timed out/i ){
2846 if( $ftp'fatalerror || $timeouts > $max_timeouts ){
2847 &msg( $log, "Fatal error talking to site, skipping rest of transfers\n" );
2854 # File will now have been split up.
2855 if( $attribs =~ /s/ ){
2859 &set_attribs( $newpath, $src_path, 'f
' );
2861 # we can only force time for local files
2862 if( $force_times && $get_file ){
2863 &set_timestamp( $newpath, $remote_time[ $srci ] );
2871 local( $src_path, $dest_path, $attribs, $timestamp ) = @_;
2872 local( $dir, $file, $temp, $compress, $split, $restart, $mesg, $got_mesg );
2874 # Make sure the required directory exists
2876 if( $dest_path =~ /^(.+\/)([^\/]+)$/ ){
2877 ($dir, $file) = ($1, $2);
2878 if( $dest_type[ $dir ] ne 'd
' && &mkdirs( $dir ) ){
2879 &msg( $log, "Created dir $dir\n" );
2886 $temp = &filename_to_tempname( $dir, $file );
2888 # Interpret the attrib characters
2889 if( $attribs !~ /x/ ){
2893 if( $attribs =~ /c/ ){
2895 $mesg = " and compress";
2897 if( $attribs =~ /s/ ){
2899 $mesg = " and split";
2901 if( $attribs =~ /r/ ){
2906 &ftp'type
( ($src_path =~ /$vms_xfer_text/i) ?
'A' : 'I' );
2909 if( $remote_fs eq 'macos' && ! $get_file ){
2914 # put the file remotely
2915 local( $src_file ) = $src_path;
2916 local( $comptemp ) = '';
2919 # No easy way to tell wether this was compressed or not
2920 # for now just presume that it is.
2921 local( $f ) = $src_file;
2922 $f =~ s/($shell_metachars)/\\$1/g;
2923 $comptemp = "$big_temp/.out$$";
2924 &sys( "$compress_prog < \"$f\" > \"$comptemp\"" );
2925 $src_file = $comptemp;
2932 if( ! &ftp'put
( $src_file, $temp, $restart ) ){
2933 &msg
( $log, "Failed to put $src_file: $ftp'response\n" );
2934 unlink( $comptemp ) if $comptemp;
2938 unlink( $comptemp ) if $comptemp;
2939 if( !$no_rename && ! &ftp
'rename( $temp, $dest_path ) ){
2940 &msg( $log, "Failed to remote rename $temp to $dest_path: $ftp'response
\n" );
2944 local($filesize) = &filesize( $src_file );
2945 &msg( $log, "Put
$src_file $filesize bytes
\n" );
2947 &log_upload( $src_file, $dest_path, "", $filesize );
2949 # Some transfers done
2950 $exit_xfer_status |= $exit_xfers;
2952 if( $delete_source ){
2953 unlink( $src_file );
2959 # Maybe TODO: Paul Szabo suggest that if recurse_hard is set then
2960 # mirror should chdir to the directory the file is in before getting
2964 &ftp'dostrip( $strip_cr );
2966 if( ! &ftp'get( $src_path, $temp, $restart ) ){
2967 if( !$failed_gets_excl || $ftp'response !~ /$failed_gets_excl/ ){
2968 &msg( $log, "Failed to get
$src_path: $ftp'response\n" );
2971 # Time stamp the temp file to allow for a restart
2973 &utime( $timestamp, $timestamp, $temp );
2974 # Make sure this file is kept
2975 local( $ti ) = $local_map{ $temp };
2976 &keep( $ti, $temp, *local_keep, *local_keep_totals, *local_map, 0 );
2982 # Some transfers done
2983 $exit_xfer_status |= $exit_xfers;
2985 # delete source file after successful transfer
2986 if( $delete_source ){
2987 if( &ftp'delete( $src_path ) ){
2988 &msg
( $log, "Deleted remote $src_path\n");
2991 &msg
( $log, "Failed to delete remote $src_path\n");
2996 # Prevent the shell from expanding characters
2997 local( $f ) = $temp;
2999 $f =~ s/($shell_metachars)/\\$1/g;
3000 $temp = "$f.$compress_suffix";
3001 # Am I doing compress to gzip conversion?
3002 if( $compress_conv_patt && $src_path =~ /$compress_conv_patt/ &&
3003 $compress_suffix eq $gzip_suffix ){
3004 $comp = "$sys_compress_prog -d < \"$f\" | $gzip_prog > \"$temp\"";
3007 $comp = "$compress_prog < \"$f\" > \"$temp\"";
3010 $temp =~ s/\\($shell_metachars)/$1/g;
3011 $f =~ s/\\($shell_metachars)/$1/g;
3015 local( $filesize ) = &filesize
( $temp );
3016 local( $sizemsg ) = $filesize;
3017 local( $srcsize ) = $remote_size[ $remote_map{ $src_path } ];
3018 if( $srcsize > $sizemsg && !$compress ){
3019 # should never happen, right? right ...
3020 $sizemsg .= " (file shrunk from $srcsize!)";
3022 elsif( $srcsize < $sizemsg ){
3023 # compression wasn't such a great idea
3024 $sizemsg .= " (file grew from $srcsize!)";
3027 # Ok - chop it up into bits!
3031 $time = $remote_time[ $remote_map{ $src_path } ];
3033 &bsplit
( $temp, $dest_path, $time );
3035 $got_mesg .= " and split";
3038 if( -f
$dest_path ){
3039 unlink( $dest_path );
3041 if( ! rename( $temp, $dest_path ) ){
3042 &msg
( $log, "Cannot rename $temp to $dest_path: $!\n" );
3047 if( $src_path ne $dest_path ){
3048 $as = " as $dest_path";
3050 $time_taken = time - $start_time;
3051 &msg
( $log, "Got $src_path$as$got_mesg $sizemsg $time_taken\n" );
3052 # Make sure to keep what you just got! It may/may not have
3053 # been compressed or gzipped..
3054 local( $locali ) = $local_map{ $dest_path };
3055 &keep
( $locali, $dest_path, *local_keep
, *local_keep_totals
, *local_map
, 1 );
3057 &log_upload
( $src_path, $dest_path, $got_mesg, $filesize );
3059 return( $dest_path );
3062 sub filename_to_tempname
3064 local( $dir, $file ) = @_;
3066 local ( $dest_path ) = $file;
3069 if( $dest_path =~ /^(.+\/)([^\
/]+)$/ ){
3070 ($dir, $file) = ($1, $2);
3079 # if you are really limited in pathname length then
3080 # change the .in. to just .
3081 if( $remote_fs eq 'macos' && ! $get_file ){
3082 return $dir . "tmp.$file";
3084 return "$dir.in.$file.";
3088 # Open, write, close - to try and ensure that the log will allways be filled
3092 local( $src_path, $dest_path, $got_mesg, $size ) = @_;
3094 if( ! $upload_log ){
3098 if( ! open( ULOG
, ">>$upload_log" ) ){
3099 print STDERR
"Cannot write to $upload_log\n";
3103 &myflock
( 'ULOG', $LOCK_EX );
3105 print ULOG
"$site:$remote_dir/$src_path -> $local_dir/$dest_path $size ";
3108 print ULOG
"$local_dir/$dest_path -> $site:$remote_dir/$src_path $size ";
3111 print ULOG
"($got_mesg)";
3114 &myflock
( 'ULOG', $LOCK_UN );
3120 # This declaration must be "local()" because it modifies global data.
3123 *src_type
, *src_keep
,
3124 *src_totals
, *src_keep_totals
) = @_;
3125 local( $files_to_go, $dirs_to_go );
3127 if( ! ($do_deletes || $save_deletes) ){
3131 local( $src_path, $i );
3132 local( $orig_do_deletes ) = $do_deletes;
3133 local( $orig_save_deletes ) = $save_deletes;
3135 local( $del_patt ) = $delete_patt;
3136 if( $delete_get_patt ){
3137 $del_patt = $get_patt;
3140 $files_to_go = $src_totals[ 1 ] - $src_keep_totals[ 1 ];
3141 $dirs_to_go = $src_totals[ 0 ] - $src_keep_totals[ 0 ];
3143 # Adjust totals by considering del_patt
3144 for( $i = $#src_paths; $i >= 0; $i-- ){
3145 $src_path = $src_paths[ $i ];
3148 if( !$src_keep[ $srci ] && $src_path !~ /$del_patt/
3149 || $delete_excl && $src_path =~ /$delete_excl/ ){
3150 if( $src_type[ $srci ] =~ "d" ){
3159 # Check out file deletions
3160 if( $max_delete_files =~ /^(\d+)\%$/ ){
3161 # There is a % in the value - so its a percentage
3163 if( $per <= 0 || 100 < $per ){
3164 &msg
( "silly percentage $max_delete_files, not deleting\n" );
3169 # Don't do more than this percentage of files
3170 # Convert max_delete_files into the number of files
3172 int( $src_totals[ 1 ] * $max_delete_files /100 );
3175 if( $files_to_go > $max_delete_files ){
3176 &msg
( "Too many files to delete, not actually deleting ($files_to_go > $max_delete_files)\n" );
3181 # Check out directory deletions
3182 if( $max_delete_dirs =~ /^(\d+)%$/ ){
3183 # There is a % in the value - so its a percentage
3185 if( $per <= 0 || 100 < $per ){
3186 &msg
( "silly percentage $max_delete_dirs, not deleting\n" );
3191 # Don't do more than this percentage of dirs
3192 # Convert max_delete_dirs into the number of dirs
3194 int( $src_totals[ 0 ] * $max_delete_dirs / 100 );
3198 if( $dirs_to_go > $max_delete_dirs ){
3199 &msg
( "Too many directories to delete, not actually deleting ($dirs_to_go > $max_delete_dirs)\n" );
3204 # Scan the list backwards so subdirectories are dealt with first
3205 for( $i = $#src_paths; $i >= 0; $i-- ){
3206 $src_path = $src_paths[ $i ];
3209 if( $src_keep[ $srci ] ){
3210 # Keep this for sure;
3211 &msg
( "Keeping: $src_path\n" ) if $debug > 3;
3215 if( $src_path !~ /$del_patt/ ){
3216 &msg
( " not in del_patt: $src_path\n" ) if $debug > 1;
3220 if( $delete_excl && $src_path =~ /$delete_excl/ ){
3221 &msg
( " do not delete: $src_path\n" ) if $debug > 1;
3225 if( $save_deletes && $save_dir =~ m
,$cwd/(.*), ){
3226 local( $save_dir_tail ) = $1;
3227 if( $save_dir_tail && $src_path =~ m
,$save_dir_tail/*, ){
3232 if( $save_deletes ){
3233 &save_delete
( $src_path, $src_type[ $srci ] );
3236 &do_delete
( $src_path, $src_type[ $srci ] );
3240 $do_deletes = $orig_do_deletes;
3241 $save_deletes = $orig_save_deletes;
3244 # Move aside the given file. Kind is 'd' for dirs and 'f' for files.
3247 local( $save, $kind ) = @_;
3249 local( $real_save_dir, $save_dest );
3250 eval "\$real_save_dir = \"$save_dir\"";
3254 &msg
( "NEED TO implement remote save_deletes\n" );
3258 $save_dest = "$real_save_dir/$save";
3261 &msg
( "Should save_delete $save to $save_dest\n" );
3266 $save_dest =~ s
,/+$,,;
3268 # Make sure it exists
3269 &save_mkdir
( $save_dest );
3272 if( rmdir( $save ) == 1 ){
3273 &msg
( $log, "Removed directory $save\n" );
3276 &msg
( $log, "UNABLE TO REMOVE DIRECTORY $save\n" );
3283 # Make the directories under $save_dir
3285 $dirname = $save_dest;
3286 $dirname =~ s/\/[^\/]+$//;
3287 # Make sure the directory exists to mv the file into.
3288 &save_mkdir
( $dirname );
3290 if( rename( $save, $save_dest ) == 1 ){
3291 &msg
( $log, "Moved $save to $save_dest\n" );
3294 system "$mv_prog '$save' '$save_dest'";
3295 if( ( $?
>> 8 ) == 0 ){
3296 &msg
( $log, "Moved $save to $save_dest\n" );
3299 &msg
( $log, "UNABLE TO MOVE $save TO $save_dest\n" );
3309 if( &mkdirs
( $dir ) ){
3310 &msg
( $log, "Created save directory $dir\n" );
3313 &msg
( $log, "UNABLE TO CREATE $dir, aborting saves\n" );
3319 # Delete the given file. Kind is 'd' for dirs and 'f' for files.
3322 local( $del, $kind ) = @_;
3325 &msg
( "Should delete $del\n" );
3333 &msg
( $log, "rmdir $cwd/$del\n" );
3334 rmdir( "$cwd/$del" ) ||
3335 &msg
( $log, "rmdir $cwd/$del failed: $!\n" );
3338 &msg
( $log, "delete DIR $del\n" );
3339 &ftp
'deldir( "$del" ) ||
3340 &msg( $log, "ftp delete DIR $del failed\n" );
3345 &msg( $log, "NEED TO rmdir $cwd/$del\n" );
3348 &msg( $log, "NEED TO ftp'deldir
$del\n" );
3357 &msg( $log, "unlink $cwd/$del\n" );
3358 unlink( "$cwd/$del" ) ||
3359 &msg( $log, "unlink $cwd/$del failed
: $!\n" );
3362 &msg( $log, "delete FILE
$del\n" );
3363 &ftp'delete( "$del" ) ||
3364 &msg( $log, "ftp
delete FILE
$del failed
\n" );
3369 &msg( $log, "NEED TO
unlink $cwd/$del\n" );
3372 &msg( $log, "NEED TO ftp
'delete $del\n" );
3379 local( $fname ) = @_;
3385 return (stat( _ ))[ 7 ];
3394 return $val eq '1' || $val eq 'yes
' || $val eq 'ok
' ||
3400 local( $dest_path, $existing_path ) = @_;
3403 &msg( "Cannot create symlinks on remote systems ($dest_path -> $existing_path)\n" );
3407 # Debian bug #85353 "bad symlink stops listing with -n" <sizif@pier.botik.ru>
3409 &msg( "Should symlink $dest_path to $existing_path\n" );
3413 # make the symlink locally
3415 # Zap any exiting file/symlink of that name
3416 if( -d $dest_path && ! -l $dest_path ){
3417 local( $msg ) = "rmdir( $dest_path ) before symlink";
3418 if( ! rmdir( $dest_path ) ){
3419 if( $algorithm == 1 ){
3420 $msg = "rmdir( $local_dir/$dest_path ) before symlink";
3421 &msg( "$msg failed: $!\n" );
3423 &msg( "$msg failed: $!\n" );
3430 if( -e $dest_path || -l $dest_path ){
3431 local( $msg ) = "unlink( $dest_path ) before symlink";
3432 if( ! unlink( $dest_path ) ){
3433 &msg( "$msg failed: $!\n" );
3441 if( (eval 'symlink("","")', $@ eq '') ){
3442 local( $status ) = '';
3443 if( ! symlink( $existing_path, $dest_path ) ){
3444 $status = "Failed to ";
3446 &msg( $log, $status . "symlink $existing_path to $dest_path\n" );
3447 &chown( $uid, $gid, $dest_path );
3450 &msg( $log, "Tried to create symlink - but not supported locally\n" );
3455 # Make a full directory heirarchy
3456 # returns true if the directory doesn't exist
3460 local( @dir, $d, $path );
3462 # If the target directory already exists but is a symlink then
3463 # zap the symlink to recreate it as a directory
3464 if( $get_file && -l
$dir ){
3468 # Very often the directory does exist - so return now
3469 return 0 if &dir_exists
( $dir );
3471 # Make sure that the target directory exists
3472 @dirs = split( '/', $dir );
3474 # the root directory always exists
3476 if( $dirs[ 0 ] eq '' ){
3481 foreach $d ( @dirs ){
3483 if( ! &dir_exists
( $path ) ){
3484 &msg
( "mkdir $path\n" ) if $debug > 2;
3485 if( ! &make_dir
( $path, 0755 ) ){
3486 &msg
( "make_dir($path,0755) failed with $err\n" );
3489 &set_attribs
( $path, $path, 'd' );
3496 # return 0 on error, 1 on success
3499 local( $dir, $mode ) = @_;
3503 if( $on_win && $dir =~ /^[a-z]:$/i ){
3506 # make a local directory
3507 if( -e
$dir || -l
$dir ){
3510 $val = mkdir( $dir, $mode );
3514 # make a remote directory
3515 $val = &ftp
'mkdir( $dir );
3517 # The mkdir might have failed due to bad mode
3518 # So try to chmod it anyway
3519 if( $remote_has_chmod ){
3520 $val = &ftp'chmod( $dir, $mode );
3527 # return 1 if $dir exists, 0 if not
3534 # check if local directory exists
3538 # check if remote directory exists
3539 local($old_dir) = &ftp
'pwd();
3541 $val = &ftp'cwd
($dir);
3543 # If I didn't manage to change dir should be where I was!
3545 # go back to the original directory
3546 &ftp
'cwd($old_dir) || die "Cannot cd to original remote directory";
3552 # Set file/directory attributes
3555 local( $path, $src_path, $type ) = @_;
3559 &msg( "dont chmod \"$path\"\n" ) if $debug > 2;
3564 local( $pathi ) = $remote_map{ $src_path };
3565 $mode = $remote_mode[ $pathi ];
3568 local( $pathi ) = $local_map{ $path };
3569 $mode = $local_mode[ $pathi ];
3572 # If I can't figure out the mode
or I
'm not copying it
3574 if( !$mode_copy || !$mode ){
3578 elsif( $type eq 'd
' ){
3583 # Convert from octal
3584 # Suggested patch to limit bits being set
3585 # $mode = $mode & 0777;
3586 $mode = oct( $mode ) if $mode =~ /^0/;
3593 if( $user ne '' && $group ne '' ){
3594 &chown( $uid, $gid, $path );
3598 # change the remote file
3599 if( $remote_has_chmod ){
3600 &ftp'chmod( $path, $mode );
3608 local( $user ) = @_;
3612 # prompt for a password
3613 $SIG{ 'INT' } = 'IGNORE';
3614 $SIG{ 'QUIT' } = 'IGNORE';
3616 system "stty -echo </dev/tty >/dev/tty 2>&1";
3617 print "Password for $user: ";
3623 system "stty echo </dev/tty >/dev/tty 2>&1";
3625 $SIG{ 'INT' } = 'DEFAULT';
3626 $SIG{ 'QUIT' } = 'DEFAULT';
3633 # Try and allow for time zone changes (eg when a site
3634 # switches from daylight saving to non daylight saving)
3635 # by ignoring differences of exactly one hour
3637 local( $t1, $t2 ) = @_;
3638 local( $diff ) = ($t1 > $t2 ?
$t1 - $t2 : $t2 - $t1);
3640 return ($t1 > $t2) && ($diff != 3600);
3649 &msg
( "creating assocs ...\n" ) if $debug > 2;
3650 foreach $map ( @assocs ){
3651 eval "\$$map = \"\$big_temp/$map.$$\"";
3652 eval "dbmopen( $map, \$$map, 0644 )";
3654 &msg
( "creating assocs done\n" ) if $debug > 2;
3661 &msg
( "deleting assocs ...\n" ) if $debug > 2;
3662 foreach $map ( @assocs ){
3663 eval "\$$map = \"\$big_temp/$map.$$\"";
3664 eval "dbmclose( $map )";
3665 &unlink_dbm
( eval "\$$map" );
3668 &msg
( "deleting assocs done\n" ) if $debug > 2;
3673 local( $file ) = @_;
3674 unlink "$file.pag" if -e
"$file.pag";
3675 unlink "$file.dir" if -e
"$file.dir";
3676 unlink "$file.gdbm" if -e
"$file.gdbm";
3677 unlink "$file" if -e
"$file";
3680 # Chop the tmp file up
3683 local( $temp, $dest_path, $time ) = @_;
3684 local( $dest_dir ) = "$dest_path-split";
3685 local( $bufsiz ) = 512;
3686 local( $buffer, $in, $sofar );
3688 &msg
( "Splitting up $temp into $dest_dir/ ($time)\n" ) if $debug;
3690 # Stomp on the original directories
3691 local( $d ) = $dest_dir;
3692 $d =~ s/($shell_metachars)/\\$1/g;
3693 &sys
( "$rm_prog -rf \"$d\"" );
3695 &mkdirs
( $dest_dir );
3697 local( $index ) = "00";
3699 open( TMP
, $temp ) || die "Cannot open $temp!";
3700 $sofar = $split_chunk; # Force a new file
3701 while( ($in = sysread( TMP
, $buffer, $bufsiz )) > 0 ){
3702 if( $sofar >= $split_chunk ){
3706 &set_timestamp
( $part, $time );
3710 $part = "$dest_dir/part$index";
3711 &msg
( "creating $part\n" ) if $debug;
3712 open( PART
, ">$part" ) || die "Cannot create $part";
3713 # Make sure to keep this!
3714 local( $locali ) = $local_map{ $part };
3715 &keep
( $locali, $part, *local_keep
, *local_keep_totals
, *local_map
, 1 );
3718 if( ($out = syswrite( PART
, $buffer, $in )) != $in ){
3719 die "Failed to write data to $part";
3725 &set_timestamp
( $part, $time );
3729 # Generate a readme file about what is in the split directory
3730 local( $readme ) = "$dest_dir/README";
3731 open( README
, ">$readme" ) || die "Cannot create $readme";
3732 print README
"This directory contains a splitup version of $dest_path\n";
3733 print README
"to recreate the original simply concatenate all the\n";
3734 print README
"parts back together.\n\nChecksums are:\n\n";
3736 &sys
( "(cd \"$d\" ; $sum_prog part*)>> $readme" );
3742 &msg
( "$com\n" ) if $debug > 2;
3743 return system( $com ) / 256;
3746 # Set up an associative array given all an array of keys.
3748 # &set_assoc_from_array( *fred )
3749 # Creates => $fred{ 'a' } = 1
3751 sub set_assoc_from_array
3753 # This declaration must be "local()" because it modifies global data.
3754 local( *things
) = @_;
3755 foreach $thing ( @things ){
3756 $things{ $thing } = 1;
3762 local( $prog ) = @_;
3763 local( $path ) = $ENV{ 'PATH' };
3765 foreach $dir ( split( /$path_sep/, $path ) ){
3766 local( $path ) = $dir . $file_sep . $prog;
3780 sub real_dir_from_path
3782 local( $program ) = @_;
3783 local( @prog_path ) = split( m
:$file_sep_pat: , $program ); # dir collection
3786 while( -l
$program ){ # follow symlink
3787 $program = readlink( $program );
3788 if( $program =~ m
:^$file_sep_pat: ){ # full path?
3789 @prog_path = (); # start dir collection anew
3792 pop( @prog_path ); # discard file name
3794 push( @prog_path, split( m
:$file_sep_pat:, $program ) );# add new parts
3795 $program = join( $file_sep, @prog_path ); # might be a symlink again...
3798 $dir = join( $file_sep, @prog_path );
3809 local( $todo, $msg ) = (0, "");
3819 # Assign to $0 so when you do a 'ps' it says this!
3820 if( defined $package &&
3822 defined $remote_dir ){
3823 $0 = "mirror $package:$site:$remote_dir $msg";
3832 # Not sure about this one. always print the message even if its a log msg.
3840 local( $size ) = @_;
3841 if( $size =~ /^(\d+)\s*(k|b|m)s*$/i ){
3844 $size *= (1024*1024);
3846 elsif( $2 =~ /[bB]/ ){
3849 elsif( $2 =~ /[kK]/ ){
3856 # Given a unix filename map it into a vms name.
3857 # $kind is 'f' for files and 'd' for directories
3860 local( $v, $kind ) = @_;
3862 if( $v eq '.' || $v eq '/' ){
3867 $v = $vms_dir . '/' . $v;
3871 # Map a/b/c.txt into [a.b]c.txt
3872 if( $v =~ m
,(.*)/([^/]+), ){
3873 local( $dir, $rest ) = ($1, $2);
3879 # Map a/b/c into [a.b.c]
3888 local( $path ) = @_;
3889 if( $path =~ m
:/: ){
3890 $path =~ s
:^(.*)/[^/]+$:$1:;
3898 # Given a filename (not a directory) and what path it symlinks to
3899 # return a, hopefully, non-relative pathname that the symlink
3900 # really points to. This is so it can be used to index into the $src_path
3904 local( $orig_path, $points_to ) = @_;
3905 local( $dirpart ) = &dirpart
( $orig_path );
3907 return &flatten_path
( "$dirpart/$points_to" );
3910 # flatten out the effects of dir/.. and /./
3911 # The problem is not flattening out ../.. into nothing! Hence
3912 # the contortions below.
3915 local( $path ) = @_;
3916 local( $changed ) = 1;
3919 local( $rooted ) = $path =~ m
:^/:;
3920 local( $count ) = 0;
3921 local( $orig_path ) = $path;
3924 $path =~ s
:(^|/)\.(/|$)::g
;
3928 if( $count++ > 100 ){
3929 &msg
( $log, "LOOPING in flatten_path orig = $orig_path, path now $path\n" );
3932 local( $in ) = $path;
3933 local( @parts ) = split( /\//, $path );
3934 for( $i = 0; $i <= $#parts; $i++ ){
3935 if( $parts[ $i ] eq '.' ){
3936 $parts[ $i ] = undef;
3939 if( $i > 0 && $parts[ $i ] eq '..' &&
3940 $parts[ $i - 1 ] && $parts[ $i - 1 ] ne '..' ){
3941 $parts[ $i - 1 ] = $parts[ $i ] = undef;
3946 for( $i = 0; $i <= $#parts; $i++ ){
3947 next unless $parts[ $i ];
3948 $path .= '/' if $path ne '';
3949 $path .= $parts[ $i ];
3951 $changed = $in ne $path;
3960 # Fix up a package name.
3961 # strip trailing and leading ws and replace awkward characters
3962 # This doesn't guarentee a unique filename.
3965 local( $package ) = @_;
3966 $package =~ s
:[\s
/']:_:g;
3972 $src_type[ $_[1] ] eq 'f
' &&
3973 $compress_patt && $_[0] =~ /$compress_patt/ &&
3974 ( ! $compress_size_floor ||
3975 $compress_size_floor < $src_size[ $_[1] ] ) &&
3976 !($compress_excl && $_[0] =~ /$compress_excl/i) &&
3977 !($compress_suffix eq $gzip_suffix &&
3978 $compress_conv_patt && $_[0] =~ /$compress_conv_patt/);
3984 $src_size[ $_[1] ] > $split_max &&
3985 $src_type[ $_[1] ] eq 'f
' &&
3986 $split_patt && $_[0] =~ /$split_patt/;
3991 local( $file, $kind ) = @_;
3997 eval( "flock( \$file, $kind )" );
3998 if( $@ =~ /unimplemented/ ){
4000 warn "flock not unavialable, running unlocked\n";
4007 if( $use_timelocal ){
4008 @t = localtime( $_[0] );
4011 @t = gmtime( $_[0] );
4013 local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = @t;
4015 # Debian bug #48611, 1969 appeared as 2069, dsb@smart.net.
4018 return sprintf( "%04d/%02d/%02d-%02d:%02d:%02d",
4019 $year, $mon + 1, $mday, $hour, $min, $sec );
4025 if( $sigs > $max_sigs ){
4030 local( $msg ) = "Caught a SIG$sig shutting down";
4031 local( $package, $filename, $line ) = caller;
4032 warn "$package:$filename:$line $msg";
4039 foreach $sig ( 'HUP
', 'INT
', 'QUIT
', 'ILL
',
4040 'TRAP
', 'IOT
', 'BUS
', 'FPE
',
4041 'USR1
', 'SEGV
', 'USR2
',
4042 'PIPE
', 'ALRM
', 'TERM
' ){
4043 $SIG{ $sig } = "main\'handler";
4049 if( ! defined( $uid ) ){
4050 if( $user =~ /^\d+$/ ){
4051 # User is just a number - presume it is the uid
4055 $uid = (getpwnam( $user ))[ 2 ];
4058 if( ! defined( $gid ) ){
4059 if( $group =~ /\d+$/ ){
4060 # Group is just a number - presume it is the gid
4064 $gid = (getgrnam( $group ))[ 2 ];
4071 local( $pathi, $path, *keep, *keep_totals, *keep_map, $kind ) = @_;
4072 # If pathi is already kept nothing to do
4074 &msg( " keep $path NOTE null pathi\n" ) if $debug > 3;
4077 if( $keep[ $pathi ] ){
4078 &msg( " keep $path [$pathi] NOTE already kept\n" ) if $debug > 3;
4082 $keep[ $pathi ] = 1;
4083 $keep_totals[ $kind ]++;
4084 &msg( " keep $path\n" ) if $debug > 3;
4086 # Keep all the parent directories
4087 while( $path =~ m,^(.*)/([^/]+)$, ){
4089 $pathi = $keep_map{ $path };
4091 &msg( " keep $path NOTE null pathi\n" ) if $debug > 3;
4094 if( $keep[ $pathi ] ){
4095 &msg( " keep $path [$pathi] NOTE already kept\n" ) if $debug > 3;
4099 $keep[ $pathi ] = 1;
4100 $keep_totals[ 0 ]++;
4106 local( $time_to_sig ) = @_;
4107 eval "alarm( $time_to_sig )";
4112 local( $uid, $gid, $path ) = @_;
4113 eval "chown ( \$uid, \$gid, \$path )";
4118 local( $atime, $mtime, $path ) = @_;
4120 return utime( $atime, $mtime, $path );
4123 # On windoze I might have set attribs to allow the time to be changed first
4124 local( $old_mode ) = (stat( $path ))[ 2 ];
4125 local( $tmp_mode ) = $old_mode;
4129 chmod( $tmp_mode, $path );
4130 $ret = utime( $atime, $mtime, $path );
4131 chmod( $old_mode, $path );
4137 local( $lcwd ) = '';
4138 eval "\$lcwd = $win_getcwd";
4140 if( ! ($lcwd eq '' || $lcwd eq $win_getcwd) ){
4141 # Must be on windoze!
4145 # didn't manage it try
and run the pwd command instead
4146 chop( $cwd = `pwd` );