File::Spec & NetWare
[p5sagit/p5-mst-13.2.git] / lib / File / Copy.pm
1 # File/Copy.pm. Written in 1994 by Aaron Sherman <ajs@ajs.com>. This
2 # source code has been placed in the public domain by the author.
3 # Please be kind and preserve the documentation.
4 #
5 # Additions copyright 1996 by Charles Bailey.  Permission is granted
6 # to distribute the revised code under the same terms as Perl itself.
7
8 package File::Copy;
9
10 use 5.006;
11 use strict;
12 use warnings;
13 use Carp;
14 use File::Spec;
15 use Config;
16 our(@ISA, @EXPORT, @EXPORT_OK, $VERSION, $Too_Big, $Syscopy_is_copy);
17 sub copy;
18 sub syscopy;
19 sub cp;
20 sub mv;
21
22 # Note that this module implements only *part* of the API defined by
23 # the File/Copy.pm module of the File-Tools-2.0 package.  However, that
24 # package has not yet been updated to work with Perl 5.004, and so it
25 # would be a Bad Thing for the CPAN module to grab it and replace this
26 # module.  Therefore, we set this module's version higher than 2.0.
27 $VERSION = '2.05';
28
29 require Exporter;
30 @ISA = qw(Exporter);
31 @EXPORT = qw(copy move);
32 @EXPORT_OK = qw(cp mv);
33
34 $Too_Big = 1024 * 1024 * 2;
35
36 sub _catname {
37     my($from, $to) = @_;
38     if (not defined &basename) {
39         require File::Basename;
40         import  File::Basename 'basename';
41     }
42
43     if ($^O eq 'MacOS') {
44         # a partial dir name that's valid only in the cwd (e.g. 'tmp')
45         $to = ':' . $to if $to !~ /:/;
46     }
47
48     return File::Spec->catfile($to, basename($from));
49 }
50
51 sub copy {
52     croak("Usage: copy(FROM, TO [, BUFFERSIZE]) ")
53       unless(@_ == 2 || @_ == 3);
54
55     my $from = shift;
56     my $to = shift;
57
58     my $from_a_handle = (ref($from)
59                          ? (ref($from) eq 'GLOB'
60                             || UNIVERSAL::isa($from, 'GLOB')
61                             || UNIVERSAL::isa($from, 'IO::Handle'))
62                          : (ref(\$from) eq 'GLOB'));
63     my $to_a_handle =   (ref($to)
64                          ? (ref($to) eq 'GLOB'
65                             || UNIVERSAL::isa($to, 'GLOB')
66                             || UNIVERSAL::isa($to, 'IO::Handle'))
67                          : (ref(\$to) eq 'GLOB'));
68
69     if ($from eq $to) { # works for references, too
70         croak("'$from' and '$to' are identical (not copied)");
71     }
72
73     if ($Config{d_symlink} && $Config{d_readlink} &&
74         !($^O eq 'Win32' || $^O eq 'os2' || $^O eq 'vms')) {
75         if ((-e $from && -l $from) || (-e $to && -l $to)) {
76             my @fs = stat($from);
77             my @ts = stat($to);
78             if (@fs && @ts && $fs[0] == $ts[0] && $fs[1] == $ts[1]) {
79                 croak("'$from' and '$to' are identical (not copied)");
80             }
81         }
82     }
83
84     if (!$from_a_handle && !$to_a_handle && -d $to && ! -d $from) {
85         $to = _catname($from, $to);
86     }
87
88     if (defined &syscopy && !$Syscopy_is_copy
89         && !$to_a_handle
90         && !($from_a_handle && $^O eq 'os2' )   # OS/2 cannot handle handles
91         && !($from_a_handle && $^O eq 'mpeix')  # and neither can MPE/iX.
92         && !($from_a_handle && $^O eq 'MSWin32')
93         && !($from_a_handle && $^O eq 'MacOS')
94         && !($from_a_handle && $^O eq 'NetWare')
95        )
96     {
97         return syscopy($from, $to);
98     }
99
100     my $closefrom = 0;
101     my $closeto = 0;
102     my ($size, $status, $r, $buf);
103     local($\) = '';
104
105     my $from_h;
106     if ($from_a_handle) {
107        $from_h = $from;
108     } else {
109         $from = _protect($from) if $from =~ /^\s/s;
110        $from_h = \do { local *FH };
111        open($from_h, "< $from\0") or goto fail_open1;
112        binmode $from_h or die "($!,$^E)";
113         $closefrom = 1;
114     }
115
116     my $to_h;
117     if ($to_a_handle) {
118        $to_h = $to;
119     } else {
120         $to = _protect($to) if $to =~ /^\s/s;
121        $to_h = \do { local *FH };
122        open($to_h,"> $to\0") or goto fail_open2;
123        binmode $to_h or die "($!,$^E)";
124         $closeto = 1;
125     }
126
127     if (@_) {
128         $size = shift(@_) + 0;
129         croak("Bad buffer size for copy: $size\n") unless ($size > 0);
130     } else {
131         $size = tied(*$from_h) ? 0 : -s $from_h || 0;
132         $size = 1024 if ($size < 512);
133         $size = $Too_Big if ($size > $Too_Big);
134     }
135
136     $! = 0;
137     for (;;) {
138         my ($r, $w, $t);
139        defined($r = sysread($from_h, $buf, $size))
140             or goto fail_inner;
141         last unless $r;
142         for ($w = 0; $w < $r; $w += $t) {
143            $t = syswrite($to_h, $buf, $r - $w, $w)
144                 or goto fail_inner;
145         }
146     }
147
148     close($to_h) || goto fail_open2 if $closeto;
149     close($from_h) || goto fail_open1 if $closefrom;
150
151     # Use this idiom to avoid uninitialized value warning.
152     return 1;
153
154     # All of these contortions try to preserve error messages...
155   fail_inner:
156     if ($closeto) {
157         $status = $!;
158         $! = 0;
159        close $to_h;
160         $! = $status unless $!;
161     }
162   fail_open2:
163     if ($closefrom) {
164         $status = $!;
165         $! = 0;
166        close $from_h;
167         $! = $status unless $!;
168     }
169   fail_open1:
170     return 0;
171 }
172
173 sub move {
174     my($from,$to) = @_;
175     my($copied,$fromsz,$tosz1,$tomt1,$tosz2,$tomt2,$sts,$ossts);
176
177     if (-d $to && ! -d $from) {
178         $to = _catname($from, $to);
179     }
180
181     ($tosz1,$tomt1) = (stat($to))[7,9];
182     $fromsz = -s $from;
183     if ($^O eq 'os2' and defined $tosz1 and defined $fromsz) {
184       # will not rename with overwrite
185       unlink $to;
186     }
187     return 1 if rename $from, $to;
188
189     ($sts,$ossts) = ($! + 0, $^E + 0);
190     # Did rename return an error even though it succeeded, because $to
191     # is on a remote NFS file system, and NFS lost the server's ack?
192     return 1 if defined($fromsz) && !-e $from &&           # $from disappeared
193                 (($tosz2,$tomt2) = (stat($to))[7,9]) &&    # $to's there
194                 ($tosz1 != $tosz2 or $tomt1 != $tomt2) &&  #   and changed
195                 $tosz2 == $fromsz;                         # it's all there
196
197     ($tosz1,$tomt1) = (stat($to))[7,9];  # just in case rename did something
198     return 1 if ($copied = copy($from,$to)) && unlink($from);
199
200     ($tosz2,$tomt2) = ((stat($to))[7,9],0,0) if defined $tomt1;
201     unlink($to) if !defined($tomt1) or $tomt1 != $tomt2 or $tosz1 != $tosz2;
202     ($!,$^E) = ($sts,$ossts);
203     return 0;
204 }
205
206 *cp = \&copy;
207 *mv = \&move;
208
209
210 if ($^O eq 'MacOS') {
211     *_protect = sub { MacPerl::MakeFSSpec($_[0]) };
212 } else {
213     *_protect = sub { "./$_[0]" };
214 }
215
216 # &syscopy is an XSUB under OS/2
217 unless (defined &syscopy) {
218     if ($^O eq 'VMS') {
219         *syscopy = \&rmscopy;
220     } elsif ($^O eq 'mpeix') {
221         *syscopy = sub {
222             return 0 unless @_ == 2;
223             # Use the MPE cp program in order to
224             # preserve MPE file attributes.
225             return system('/bin/cp', '-f', $_[0], $_[1]) == 0;
226         };
227     } elsif ($^O eq 'MSWin32') {
228         *syscopy = sub {
229             return 0 unless @_ == 2;
230             return Win32::CopyFile(@_, 1);
231         };
232     } elsif ($^O eq 'MacOS') {
233         require Mac::MoreFiles;
234         *syscopy = sub {
235             my($from, $to) = @_;
236             my($dir, $toname);
237
238             return 0 unless -e $from;
239
240             if ($to =~ /(.*:)([^:]+):?$/) {
241                 ($dir, $toname) = ($1, $2);
242             } else {
243                 ($dir, $toname) = (":", $to);
244             }
245
246             unlink($to);
247             Mac::MoreFiles::FSpFileCopy($from, $dir, $toname, 1);
248         };
249     } else {
250         $Syscopy_is_copy = 1;
251         *syscopy = \&copy;
252     }
253 }
254
255 1;
256
257 __END__
258
259 =head1 NAME
260
261 File::Copy - Copy files or filehandles
262
263 =head1 SYNOPSIS
264
265         use File::Copy;
266
267         copy("file1","file2");
268         copy("Copy.pm",\*STDOUT);'
269         move("/dev1/fileA","/dev2/fileB");
270
271         use POSIX;
272         use File::Copy cp;
273
274         $n = FileHandle->new("/a/file","r");
275         cp($n,"x");'
276
277 =head1 DESCRIPTION
278
279 The File::Copy module provides two basic functions, C<copy> and
280 C<move>, which are useful for getting the contents of a file from
281 one place to another.
282
283 =over 4
284
285 =item *
286
287 The C<copy> function takes two
288 parameters: a file to copy from and a file to copy to. Either
289 argument may be a string, a FileHandle reference or a FileHandle
290 glob. Obviously, if the first argument is a filehandle of some
291 sort, it will be read from, and if it is a file I<name> it will
292 be opened for reading. Likewise, the second argument will be
293 written to (and created if need be).  Trying to copy a file on top
294 of itself is a fatal error.
295
296 B<Note that passing in
297 files as handles instead of names may lead to loss of information
298 on some operating systems; it is recommended that you use file
299 names whenever possible.>  Files are opened in binary mode where
300 applicable.  To get a consistent behaviour when copying from a
301 filehandle to a file, use C<binmode> on the filehandle.
302
303 An optional third parameter can be used to specify the buffer
304 size used for copying. This is the number of bytes from the
305 first file, that wil be held in memory at any given time, before
306 being written to the second file. The default buffer size depends
307 upon the file, but will generally be the whole file (up to 2Mb), or
308 1k for filehandles that do not reference files (eg. sockets).
309
310 You may use the syntax C<use File::Copy "cp"> to get at the
311 "cp" alias for this function. The syntax is I<exactly> the same.
312
313 =item *
314
315 The C<move> function also takes two parameters: the current name
316 and the intended name of the file to be moved.  If the destination
317 already exists and is a directory, and the source is not a
318 directory, then the source file will be renamed into the directory
319 specified by the destination.
320
321 If possible, move() will simply rename the file.  Otherwise, it copies
322 the file to the new location and deletes the original.  If an error occurs
323 during this copy-and-delete process, you may be left with a (possibly partial)
324 copy of the file under the destination name.
325
326 You may use the "mv" alias for this function in the same way that
327 you may use the "cp" alias for C<copy>.
328
329 =back
330
331 File::Copy also provides the C<syscopy> routine, which copies the
332 file specified in the first parameter to the file specified in the
333 second parameter, preserving OS-specific attributes and file
334 structure.  For Unix systems, this is equivalent to the simple
335 C<copy> routine.  For VMS systems, this calls the C<rmscopy>
336 routine (see below).  For OS/2 systems, this calls the C<syscopy>
337 XSUB directly. For Win32 systems, this calls C<Win32::CopyFile>.
338
339 =head2 Special behaviour if C<syscopy> is defined (OS/2, VMS and Win32)
340
341 If both arguments to C<copy> are not file handles,
342 then C<copy> will perform a "system copy" of
343 the input file to a new output file, in order to preserve file
344 attributes, indexed file structure, I<etc.>  The buffer size
345 parameter is ignored.  If either argument to C<copy> is a
346 handle to an opened file, then data is copied using Perl
347 operators, and no effort is made to preserve file attributes
348 or record structure.
349
350 The system copy routine may also be called directly under VMS and OS/2
351 as C<File::Copy::syscopy> (or under VMS as C<File::Copy::rmscopy>, which
352 is the routine that does the actual work for syscopy).
353
354 =over 4
355
356 =item rmscopy($from,$to[,$date_flag])
357
358 The first and second arguments may be strings, typeglobs, typeglob
359 references, or objects inheriting from IO::Handle;
360 they are used in all cases to obtain the
361 I<filespec> of the input and output files, respectively.  The
362 name and type of the input file are used as defaults for the
363 output file, if necessary.
364
365 A new version of the output file is always created, which
366 inherits the structure and RMS attributes of the input file,
367 except for owner and protections (and possibly timestamps;
368 see below).  All data from the input file is copied to the
369 output file; if either of the first two parameters to C<rmscopy>
370 is a file handle, its position is unchanged.  (Note that this
371 means a file handle pointing to the output file will be
372 associated with an old version of that file after C<rmscopy>
373 returns, not the newly created version.)
374
375 The third parameter is an integer flag, which tells C<rmscopy>
376 how to handle timestamps.  If it is E<lt> 0, none of the input file's
377 timestamps are propagated to the output file.  If it is E<gt> 0, then
378 it is interpreted as a bitmask: if bit 0 (the LSB) is set, then
379 timestamps other than the revision date are propagated; if bit 1
380 is set, the revision date is propagated.  If the third parameter
381 to C<rmscopy> is 0, then it behaves much like the DCL COPY command:
382 if the name or type of the output file was explicitly specified,
383 then no timestamps are propagated, but if they were taken implicitly
384 from the input filespec, then all timestamps other than the
385 revision date are propagated.  If this parameter is not supplied,
386 it defaults to 0.
387
388 Like C<copy>, C<rmscopy> returns 1 on success.  If an error occurs,
389 it sets C<$!>, deletes the output file, and returns 0.
390
391 =back
392
393 =head1 RETURN
394
395 All functions return 1 on success, 0 on failure.
396 $! will be set if an error was encountered.
397
398 =head1 NOTES
399
400 =over 4
401
402 =item *
403
404 On Mac OS (Classic), the path separator is ':', not '/', and the 
405 current directory is denoted as ':', not '.'. You should be careful 
406 about specifying relative pathnames. While a full path always begins 
407 with a volume name, a relative pathname should always begin with a 
408 ':'.  If specifying a volume name only, a trailing ':' is required.
409
410 E.g.
411
412   copy("file1", "tmp");        # creates the file 'tmp' in the current directory
413   copy("file1", ":tmp:");      # creates :tmp:file1
414   copy("file1", ":tmp");       # same as above
415   copy("file1", "tmp");        # same as above, if 'tmp' is a directory (but don't do   
416                                # that, since it may cause confusion, see example #1)
417   copy("file1", "tmp:file1");  # error, since 'tmp:' is not a volume
418   copy("file1", ":tmp:file1"); # ok, partial path
419   copy("file1", "DataHD:");    # creates DataHD:file1
420   
421   move("MacintoshHD:fileA", "DataHD:fileB"); # moves (don't copies) files from one 
422                                              # volume to another
423
424 =back
425
426 =head1 AUTHOR
427
428 File::Copy was written by Aaron Sherman I<E<lt>ajs@ajs.comE<gt>> in 1995,
429 and updated by Charles Bailey I<E<lt>bailey@newman.upenn.eduE<gt>> in 1996.
430
431 =cut
432