line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package File::Copy::Recursive::Reduced; |
2
|
3
|
|
|
3
|
|
187045
|
use strict; |
|
3
|
|
|
|
|
24
|
|
|
3
|
|
|
|
|
76
|
|
3
|
3
|
|
|
3
|
|
13
|
use warnings; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
74
|
|
4
|
|
|
|
|
|
|
|
5
|
3
|
|
|
3
|
|
1162
|
use parent qw( Exporter ); |
|
3
|
|
|
|
|
1157
|
|
|
3
|
|
|
|
|
15
|
|
6
|
|
|
|
|
|
|
our @EXPORT_OK = qw( dircopy fcopy rcopy ); |
7
|
|
|
|
|
|
|
our $VERSION = '0.006'; |
8
|
|
|
|
|
|
|
|
9
|
3
|
|
|
3
|
|
1592
|
use File::Copy; |
|
3
|
|
|
|
|
11940
|
|
|
3
|
|
|
|
|
145
|
|
10
|
3
|
|
|
3
|
|
18
|
use File::Find; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
159
|
|
11
|
3
|
|
|
3
|
|
17
|
use File::Path qw( mkpath ); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
177
|
|
12
|
3
|
|
|
3
|
|
17
|
use File::Spec; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
3521
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our $Link = eval { local $SIG{'__DIE__'}; link '', ''; 1 } || 0; |
15
|
|
|
|
|
|
|
our $CopyLink = eval { local $SIG{'__DIE__'}; symlink '', ''; 1 } || 0; |
16
|
|
|
|
|
|
|
our $DirPerms = 0777; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 NAME |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
File::Copy::Recursive::Reduced - Recursive copying of files and directories within Perl 5 toolchain |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 SYNOPSIS |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
use File::Copy::Recursive::Reduced qw(fcopy dircopy); |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
fcopy($orig,$new) or die $!; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
dircopy($orig,$new) or die $!; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=head1 DESCRIPTION |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
This library is intended as a not-quite-drop-in replacement for certain |
34
|
|
|
|
|
|
|
functionality provided by L
|
35
|
|
|
|
|
|
|
File-Copy-Recursive|http://search.cpan.org/dist/File-Copy-Recursive/>. The |
36
|
|
|
|
|
|
|
library provides methods similar enough to that distribution's C, |
37
|
|
|
|
|
|
|
C and C functions to be usable in those CPAN distributions |
38
|
|
|
|
|
|
|
often described as being part of the Perl toolchain. |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=head2 Rationale |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
F (hereinafter referred to as B) is heavily used |
43
|
|
|
|
|
|
|
in other CPAN libraries. Out of over 30,000 other CPAN distributions studied |
44
|
|
|
|
|
|
|
in early 2018, it ranks by one calculation as the 129th highest distribution |
45
|
|
|
|
|
|
|
in terms of its total direct and indirect reverse dependencies. In current |
46
|
|
|
|
|
|
|
parlance, it sits C Hence, it ought to work |
47
|
|
|
|
|
|
|
correctly and be installable on all operating systems where Perl is well |
48
|
|
|
|
|
|
|
supported. |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
However, as of early April 2018, FCR version 0.40 wass failing to pass its tests against either |
51
|
|
|
|
|
|
|
Perl 5.26 or Perl 5 blead on important operating systems including Windows, |
52
|
|
|
|
|
|
|
FreeBSD and NetBSD |
53
|
|
|
|
|
|
|
(L). As |
54
|
|
|
|
|
|
|
a consequence, CPAN installers such as F and F were failing to |
55
|
|
|
|
|
|
|
install it (unless one resorted to the C<--force> option). This prevented |
56
|
|
|
|
|
|
|
distributions dependent (directly or indirectly) on FCR from being installed |
57
|
|
|
|
|
|
|
as well. |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
Some patches had been provided to the L
|
60
|
|
|
|
|
|
|
tracker|https://rt.cpan.org/Dist/Display.html?Name=File-Copy-Recursive> for |
61
|
|
|
|
|
|
|
this problem. However, as late as April 18 2018 those patches had not yet |
62
|
|
|
|
|
|
|
been applied. This posed a critical problem for the ability to assess the |
63
|
|
|
|
|
|
|
impact of the soon-to-be-released perl-5.28.0 on CPAN distributions (the |
64
|
|
|
|
|
|
|
so-called "Blead Breaks CPAN" ("BBC") problem) on platforms other than Linux. |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
F (hereinafter referred to as B) is |
67
|
|
|
|
|
|
|
intended to provide a minimal subset of FCR's functionality -- just enough to |
68
|
|
|
|
|
|
|
get the Perl toolchain working on the platforms where FCR is currently |
69
|
|
|
|
|
|
|
failing. Functions will be added to FCR2 only insofar as investigation shows |
70
|
|
|
|
|
|
|
that they can replace usage of FCR functions in toolchain and other heavily |
71
|
|
|
|
|
|
|
used modules. No attempt will be made to reproduce all the functionality |
72
|
|
|
|
|
|
|
currently provided or claimed to be provided by FCR. |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
On April 19 2018, FCR's author, Daniel Muey, released version 0.41 to CPAN. |
75
|
|
|
|
|
|
|
This version included a patch submitted by Tom Hukins which corrected the |
76
|
|
|
|
|
|
|
problem addressed by FCR2. FCR once again built and tested correctly on |
77
|
|
|
|
|
|
|
FreeBSD. That meant that its 6000-plus reverse dependencies can once again be |
78
|
|
|
|
|
|
|
reached by F and other installers. That in turn means that we can |
79
|
|
|
|
|
|
|
conduct exhaustive BBC investigations on FreeBSD and other platforms. |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
With that correction in FCR, the original rationale for FCR2 has been |
82
|
|
|
|
|
|
|
superseded. I will continue to maintain the code and respond to bug reports, |
83
|
|
|
|
|
|
|
but am suspending active development. I now deem FCR2 feature-complete. |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
=head1 SUBROUTINES |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
The current version of FCR2 provides three exportable and publicly supported |
88
|
|
|
|
|
|
|
subroutines partially equivalent to the similarly named subroutines exported |
89
|
|
|
|
|
|
|
by FCR. |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=head2 C |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=over 4 |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=item * Purpose |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
A stripped-down replacement for C. |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
Copies a file to a new location, recursively creating directories as needed. |
100
|
|
|
|
|
|
|
Does not copy directories. Unlike C, C attempts |
101
|
|
|
|
|
|
|
to preserve the mode of the original file. |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=item * Arguments |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
fcopy($orig, $new) or die $!; |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
List of two required arguments: |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=over 4 |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=item * Absolute path to the file being copied; and |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=item * Absolute path to the location to which the file is being copied. |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=back |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
Four cases should be noted: |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=over 4 |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=item 1 Create copy within same directory but new basename |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
fcopy('/path/to/filename', '/path/to/newfile'); |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
The second argument must be the absolute path to the new file. (Otherwise |
126
|
|
|
|
|
|
|
the file will be created in the current working directory, which is almost |
127
|
|
|
|
|
|
|
certainly what you do not want.) |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=item 2 Create copy within different, already B directory, same basename |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
fcopy('/path/to/filename', '/path/to/existing/directory'); |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
The second argument can be merely the path to the existing directory; will |
134
|
|
|
|
|
|
|
create F. |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=item 3 Create copy within different, not yet existing directory, same basename |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
fcopy('/path/to/filename', '/path/not/yet/existing/directory/filename'); |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
The second argument will be interpreted as the complete path to the newly |
141
|
|
|
|
|
|
|
created file. The basename must be included even if it is the same as in the |
142
|
|
|
|
|
|
|
first argument. Will create F. |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=item 4 Create copy within different, not yet existing directory, different basename |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
fcopy('/path/to/filename', '/path/not/yet/existing/directory/newfile'); |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
The second argument will be interpreted as the complete path to the newly |
149
|
|
|
|
|
|
|
created file. Will create F. |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=back |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=item * Return Value |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
Returns C<1> upon success; C<0> upon failure. Returns an undefined value if, |
156
|
|
|
|
|
|
|
for example, function cannot validate arguments. |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=item * Comment |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
Since C internally uses C to perform the copying, |
161
|
|
|
|
|
|
|
the arguments are subject to the same qualifications as that function's |
162
|
|
|
|
|
|
|
arguments. Call F for discussion of those arguments. |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=back |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=cut |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
sub fcopy { |
169
|
63
|
100
|
|
63
|
1
|
52153
|
return unless @_ == 2; |
170
|
60
|
|
|
|
|
168
|
my ($from, $to) = @_; |
171
|
|
|
|
|
|
|
#return unless _samecheck($from, $to); |
172
|
60
|
100
|
|
|
|
157
|
return unless _basic_samecheck($from, $to); |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# TODO: Explore whether we should check (-e $from) here. |
175
|
|
|
|
|
|
|
# If we don't have a starting point, it shouldn't make any sense to go |
176
|
|
|
|
|
|
|
# farther. |
177
|
|
|
|
|
|
|
|
178
|
57
|
100
|
|
|
|
147
|
return unless _dev_ino_check($from, $to); |
179
|
|
|
|
|
|
|
|
180
|
56
|
|
|
|
|
165
|
return _fcopy($from, $to); |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
sub _fcopy { |
184
|
65
|
|
|
65
|
|
141
|
my ($from, $to) = @_; |
185
|
65
|
|
|
|
|
783
|
my ( $volm, $path ) = File::Spec->splitpath($to); |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
# TODO: Explore whether it's possible for $path to be Perl-false in |
188
|
|
|
|
|
|
|
# following line. If not, remove. |
189
|
65
|
100
|
66
|
|
|
860
|
if ( $path && !-d $path ) { |
190
|
6
|
|
|
|
|
69
|
pathmk(File::Spec->catpath($volm, $path, '')); |
191
|
|
|
|
|
|
|
} |
192
|
|
|
|
|
|
|
|
193
|
65
|
100
|
66
|
|
|
1273
|
if ( -l $from && $CopyLink ) { |
|
|
100
|
66
|
|
|
|
|
194
|
4
|
|
|
|
|
40
|
my $target = readlink( $from ); |
195
|
|
|
|
|
|
|
# FCR: mass-untaint is OK since we have to allow what the file system does |
196
|
4
|
|
|
|
|
22
|
($target) = $target =~ m/(.*)/; |
197
|
4
|
100
|
|
|
|
126
|
warn "Copying a symlink ($from) whose target does not exist" |
198
|
|
|
|
|
|
|
if !-e $target; |
199
|
4
|
|
|
|
|
15
|
my $new = $to; |
200
|
4
|
50
|
|
|
|
35
|
unlink $new if -l $new; |
201
|
4
|
50
|
|
|
|
115
|
symlink( $target, $new ) or return; |
202
|
|
|
|
|
|
|
} |
203
|
2
|
|
|
|
|
12
|
elsif (-d $from && -f $to) { return; } |
204
|
|
|
|
|
|
|
else { |
205
|
59
|
50
|
|
|
|
299
|
copy($from, $to) or return; |
206
|
|
|
|
|
|
|
|
207
|
59
|
|
|
|
|
15857
|
my @base_file = File::Spec->splitpath( $from ); |
208
|
59
|
100
|
|
|
|
875
|
my $mode_trg = -d $to ? File::Spec->catfile( $to, $base_file[$#base_file] ) : $to; |
209
|
|
|
|
|
|
|
|
210
|
59
|
|
|
|
|
1358
|
chmod scalar((stat($from))[2]), $mode_trg; |
211
|
|
|
|
|
|
|
} |
212
|
63
|
|
|
|
|
269
|
return 1; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
sub pathmk { |
216
|
17
|
|
|
17
|
0
|
192
|
my ( $vol, $dir, $file ) = File::Spec->splitpath( shift() ); |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
# TODO: Exploration whether $dir can be undef at this point. |
219
|
|
|
|
|
|
|
# If possible, then we should probably return immediately. |
220
|
17
|
50
|
|
|
|
54
|
if ( defined($dir) ) { |
221
|
17
|
|
|
|
|
92
|
my (@dirs) = File::Spec->splitdir($dir); |
222
|
|
|
|
|
|
|
|
223
|
17
|
|
|
|
|
61
|
for ( my $i = 0; $i < scalar(@dirs); $i++ ) { |
224
|
86
|
|
|
|
|
591
|
my $newdir = File::Spec->catdir( @dirs[ 0 .. $i ] ); |
225
|
86
|
|
|
|
|
432
|
my $newpth = File::Spec->catpath( $vol, $newdir, "" ); |
226
|
86
|
|
|
|
|
1324
|
mkdir( $newpth ); |
227
|
86
|
50
|
|
|
|
1031
|
return unless -d $newpth; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# TODO: Exploration whether $file can be undef at this point. |
232
|
|
|
|
|
|
|
# If possible, then we should probably return immediately. |
233
|
17
|
50
|
|
|
|
54
|
if ( defined($file) ) { |
234
|
17
|
|
|
|
|
97
|
my $newpth = File::Spec->catpath( $vol, $dir, $file ); |
235
|
17
|
|
|
|
|
436
|
mkdir( $newpth ); |
236
|
17
|
50
|
|
|
|
204
|
return unless -d $newpth; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
17
|
|
|
|
|
59
|
return 1; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=head2 C |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=over 4 |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=item * Purpose |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
A stripped-down replacement for C. |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
Given the path to the directory specified by the first argument, the function |
252
|
|
|
|
|
|
|
copies all of the files and directories beneath it to the directory specified |
253
|
|
|
|
|
|
|
by the second argument. |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=item * Arguments |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
my $count = dircopy($orig, $new); |
258
|
|
|
|
|
|
|
warn "dircopy() returned undefined value" unless defined $count; |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
=item * Return Value |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
Upon completion, returns the count of directories and files created -- which |
263
|
|
|
|
|
|
|
might be C<0>. |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
Should the function not complete (but not C), an undefined value will be |
266
|
|
|
|
|
|
|
returned. That generally indicates problems with argument validation. This |
267
|
|
|
|
|
|
|
approach is taken for consistency with C. |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
In list context the return value is a one-item list holding the same value as |
270
|
|
|
|
|
|
|
returned in scalar context. The three-item list return value of |
271
|
|
|
|
|
|
|
C is not supported. |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=item * Restrictions |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
None of C's bells and whistles. No guaranteed |
276
|
|
|
|
|
|
|
preservation of file or directory modes. No restriction on maximum depth. No |
277
|
|
|
|
|
|
|
nothing; this is fine-tuned to the needs of Perl toolchain modules and their |
278
|
|
|
|
|
|
|
test suites. |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=back |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=cut |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
sub dircopy { |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# I'm not supporting the buffer limitation, at this point I can insert a |
287
|
|
|
|
|
|
|
# check for the correct number of arguments: 2 |
288
|
|
|
|
|
|
|
# FCR2 dircopy does not support buffer limit as third argument |
289
|
|
|
|
|
|
|
|
290
|
20
|
100
|
|
20
|
1
|
42666
|
return unless @_ == 2; |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
# Check the definedness and string inequality of the arguments now; |
293
|
|
|
|
|
|
|
# Failure to do it now means that if $_[0] is not defined, you'll get an |
294
|
|
|
|
|
|
|
# uninitalized value warning in the first line that calls 'substr' below. |
295
|
|
|
|
|
|
|
|
296
|
17
|
100
|
|
|
|
45
|
return unless _basic_samecheck(@_); |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# See local file globstar-investigation.pl |
299
|
|
|
|
|
|
|
# What the block above does is to trim the 'from' argument so that, if user |
300
|
|
|
|
|
|
|
# said 'dircopy(/path/to/directory/*, /path/to/copy)', the first argument |
301
|
|
|
|
|
|
|
# is effectively reduced to '/path/to/directory/' but inside $globstar is |
302
|
|
|
|
|
|
|
# set to true. Have to see what impact of $globstar true is. |
303
|
|
|
|
|
|
|
|
304
|
14
|
|
|
|
|
29
|
return _dircopy(@_); |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub _dircopy { |
308
|
26
|
|
|
26
|
|
45
|
my $globstar = 0; |
309
|
26
|
|
|
|
|
46
|
my $_zero = $_[0]; |
310
|
26
|
|
|
|
|
46
|
my $_one = $_[1]; |
311
|
26
|
100
|
|
|
|
69
|
if ( substr( $_zero, ( 1 * -1 ), 1 ) eq '*' ) { |
312
|
2
|
|
|
|
|
6
|
$globstar = 1; |
313
|
2
|
|
|
|
|
6
|
$_zero = substr( $_zero, 0, ( length($_zero) - 1 ) ); |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
# Note also that, in the above, $_[0] and $_[1], while assigned to |
317
|
|
|
|
|
|
|
# variables, are not shifted-in. Hence they retain their original values. |
318
|
|
|
|
|
|
|
# TODO: Investigate whether replacing $_[1] from this point forward with a |
319
|
|
|
|
|
|
|
# 'my' variable would be harmful. |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
# Both arguments must now be defined (though not necessarily true -- yet); |
322
|
|
|
|
|
|
|
# they can't be equal; they can't be "dev-ino" equal on non-Win32 systems. |
323
|
|
|
|
|
|
|
# Verify that. |
324
|
|
|
|
|
|
|
|
325
|
26
|
100
|
|
|
|
57
|
return unless _dev_ino_check( $_zero, $_[1] ); |
326
|
|
|
|
|
|
|
|
327
|
25
|
100
|
100
|
|
|
517
|
if ( !-d $_zero || ( -e $_[1] && !-d $_[1] ) ) { |
|
|
|
100
|
|
|
|
|
328
|
4
|
|
|
|
|
13
|
$! = 20; |
329
|
4
|
|
|
|
|
13
|
return; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
# If the second argument is not an already existing directory, |
333
|
|
|
|
|
|
|
# then, create that directory now (the top-level 'to'). |
334
|
|
|
|
|
|
|
|
335
|
21
|
100
|
|
|
|
182
|
if ( !-d $_[1] ) { |
336
|
11
|
50
|
|
|
|
36
|
pathmk( $_[1] ) or return; |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
# If the second argument is an existing directory ... |
339
|
|
|
|
|
|
|
# ... $globstar false is the typical case, i.e., no '/*' at end of 2nd argument |
340
|
|
|
|
|
|
|
|
341
|
21
|
|
|
|
|
51
|
my $baseend = $_one; |
342
|
21
|
|
|
|
|
28
|
my $level = 0; |
343
|
21
|
|
|
|
|
28
|
my $filen = 0; |
344
|
21
|
|
|
|
|
29
|
my $dirn = 0; |
345
|
|
|
|
|
|
|
|
346
|
21
|
|
|
|
|
25
|
my $recurs; #must be my()ed before sub {} since it calls itself |
347
|
|
|
|
|
|
|
$recurs = sub { |
348
|
90
|
|
|
90
|
|
188
|
my ( $str, $end ) = @_; |
349
|
90
|
100
|
|
|
|
183
|
$filen++ if $end eq $baseend; |
350
|
90
|
100
|
|
|
|
145
|
$dirn++ if $end eq $baseend; |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
# On each pass of the recursive coderef, create the directory in the |
353
|
|
|
|
|
|
|
# 2nd argument or return (undef) if that does not succeed |
354
|
|
|
|
|
|
|
|
355
|
90
|
100
|
50
|
|
|
3169
|
mkdir( $end ) or return if !-d $end; |
356
|
90
|
|
|
|
|
215
|
$level++; |
357
|
|
|
|
|
|
|
|
358
|
90
|
50
|
|
|
|
2234
|
opendir( my $str_dh, $str ) or return; |
359
|
90
|
|
100
|
|
|
2063
|
my @entities = grep( $_ ne '.' && $_ ne '..', readdir($str_dh) ); |
360
|
90
|
|
|
|
|
782
|
closedir $str_dh; |
361
|
|
|
|
|
|
|
|
362
|
90
|
|
|
|
|
231
|
for my $entity (@entities) { |
363
|
119
|
|
|
|
|
547
|
my ($entity_ut) = $entity =~ m{ (.*) }xms; |
364
|
119
|
|
|
|
|
1076
|
my $from = File::Spec->catfile( $str, $entity_ut ); |
365
|
119
|
|
|
|
|
613
|
my $to = File::Spec->catfile( $end, $entity_ut ); |
366
|
119
|
100
|
66
|
|
|
2344
|
if ( -l $from && $CopyLink ) { |
|
|
100
|
|
|
|
|
|
367
|
9
|
|
|
|
|
88
|
my $target = readlink($from); |
368
|
|
|
|
|
|
|
# mass-untaint is OK since we have to allow what the file system does |
369
|
9
|
|
|
|
|
38
|
($target) = $target =~ m/(.*)/; |
370
|
9
|
100
|
|
|
|
127
|
warn "Copying a symlink ($from) whose target does not exist" |
371
|
|
|
|
|
|
|
if !-e $target; |
372
|
9
|
50
|
|
|
|
118
|
unlink $to if -l $to; |
373
|
9
|
50
|
|
|
|
199
|
symlink( $target, $to ) or return; |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
elsif ( -d $from ) { |
376
|
69
|
|
|
|
|
146
|
my $rc; |
377
|
69
|
|
|
|
|
270
|
$rc = $recurs->( $from, $to ); |
378
|
69
|
50
|
|
|
|
121
|
return unless $rc; |
379
|
69
|
|
|
|
|
78
|
$filen++; |
380
|
69
|
|
|
|
|
101
|
$dirn++; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
else { |
383
|
41
|
50
|
|
|
|
120
|
fcopy( $from, $to ) or return; |
384
|
41
|
|
|
|
|
101
|
$filen++; |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
} # End 'for' loop around @entities |
387
|
90
|
|
|
|
|
115
|
$level--; |
388
|
90
|
|
|
|
|
234
|
1; |
389
|
|
|
|
|
|
|
|
390
|
21
|
|
|
|
|
133
|
}; # END definition of $recurs |
391
|
|
|
|
|
|
|
|
392
|
21
|
50
|
|
|
|
52
|
$recurs->( $_zero, $_one ) or return; |
393
|
21
|
|
|
|
|
78
|
return $filen; |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
sub _basic_samecheck { |
397
|
108
|
|
|
108
|
|
223
|
my ($from, $to) = @_; |
398
|
108
|
100
|
100
|
|
|
486
|
return if !defined $from || !defined $to; |
399
|
100
|
100
|
|
|
|
245
|
return if $from eq $to; |
400
|
96
|
|
|
|
|
262
|
return 1; |
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
sub _dev_ino_check { |
404
|
108
|
|
|
108
|
|
203
|
my ($from, $to) = @_; |
405
|
108
|
50
|
|
|
|
338
|
return 1 if $^O eq 'MSWin32'; |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
# perldoc perlport: "(Win32) "dev" and "ino" are not meaningful." |
408
|
|
|
|
|
|
|
# Will probably have to add restrictions for VMS and other OSes. |
409
|
108
|
|
100
|
|
|
1655
|
my $one = join( '-', ( stat $from )[ 0, 1 ] ) || ''; |
410
|
108
|
|
100
|
|
|
1739
|
my $two = join( '-', ( stat $to )[ 0, 1 ] ) || ''; |
411
|
108
|
100
|
100
|
|
|
454
|
if ( $one and $one eq $two ) { |
412
|
4
|
|
|
|
|
170
|
warn "$from and $to are identical"; |
413
|
4
|
|
|
|
|
40
|
return; |
414
|
|
|
|
|
|
|
} |
415
|
104
|
|
|
|
|
313
|
return 1; |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
=head2 C |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
=over 4 |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=item * Purpose |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
A stripped-down replacement for C. As is the |
425
|
|
|
|
|
|
|
case with that FCR function, C is more or less a wrapper around |
426
|
|
|
|
|
|
|
C or C, depending on the nature of the first argument. |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=item * Arguments |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
rcopy($orig, $new) or die $!; |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
List of two required arguments: |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
=over 4 |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=item * Absolute path to the entity (file or directory) being copied; and |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=item * Absolute path to the location to which the entity is being copied. |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
=back |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=item * Return Value |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
Returns C<1> upon success; C<0> upon failure. Returns an undefined value if, |
445
|
|
|
|
|
|
|
for example, function cannot validate arguments. |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=item * Comment |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
Please read the documentation for C or C, depending on the |
450
|
|
|
|
|
|
|
nature of the first argument. |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
=back |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
=cut |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
sub rcopy { |
457
|
37
|
100
|
|
37
|
1
|
76047
|
return unless @_ == 2; |
458
|
31
|
|
|
|
|
64
|
my ($from, $to) = @_; |
459
|
31
|
100
|
|
|
|
70
|
return unless _basic_samecheck($from, $to); |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
# TODO: Explore whether we should check (-e $from) here. |
462
|
|
|
|
|
|
|
# If we don't have a starting point, it shouldn't make any sense to go |
463
|
|
|
|
|
|
|
# farther. |
464
|
|
|
|
|
|
|
|
465
|
25
|
100
|
|
|
|
49
|
return unless _dev_ino_check($from, $to); |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
# symlinks not yet supported |
468
|
|
|
|
|
|
|
#return if -l $_[0]; |
469
|
23
|
50
|
66
|
|
|
239
|
goto &fcopy if -l $_[0] && $CopyLink; |
470
|
|
|
|
|
|
|
|
471
|
21
|
100
|
100
|
|
|
270
|
goto &_dircopy if -d $_[0] || substr( $_[0], ( 1 * -1 ), 1 ) eq '*'; |
472
|
9
|
|
|
|
|
38
|
goto &_fcopy; |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=head2 File::Copy::Recursive Subroutines Not Supported in File::Copy::Recursive::Reduced |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
As of the current version, FCR2 has no publicly documented, exportable subroutines equivalent |
479
|
|
|
|
|
|
|
to the following FCR exportable subroutines: |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
rcopy_glob |
482
|
|
|
|
|
|
|
fmove |
483
|
|
|
|
|
|
|
rmove |
484
|
|
|
|
|
|
|
rmove_glob |
485
|
|
|
|
|
|
|
dirmove |
486
|
|
|
|
|
|
|
pathempty |
487
|
|
|
|
|
|
|
pathrm |
488
|
|
|
|
|
|
|
pathrmdir |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
Consideration is being given to supporting C. |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
=head1 BUGS AND SUPPORT |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
Please report any bugs by mail to C |
495
|
|
|
|
|
|
|
or through the web interface at L. |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
Notwithstanding the fact that this distribution is being released to address |
500
|
|
|
|
|
|
|
certain problems in File-Copy-Recursive, credit must be given to FCR author |
501
|
|
|
|
|
|
|
L for ingenious |
502
|
|
|
|
|
|
|
conception and execution. The implementation of the subroutines provided by |
503
|
|
|
|
|
|
|
FCR2 follows that found in FCR to a significant extent. |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
Thanks also to Tom Hukins for supplying the patch which corrects FCR's |
506
|
|
|
|
|
|
|
problems and which has been incorporated into FCR2 as well. |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=head1 AUTHOR |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
James E Keenan |
511
|
|
|
|
|
|
|
CPAN ID: JKEENAN |
512
|
|
|
|
|
|
|
jkeenan@cpan.org |
513
|
|
|
|
|
|
|
http://thenceforward.net/perl |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
=head1 COPYRIGHT |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
This program is free software; you can redistribute |
518
|
|
|
|
|
|
|
it and/or modify it under the same terms as Perl itself. |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
The full text of the license can be found in the |
521
|
|
|
|
|
|
|
LICENSE file included with this module. |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
Copyright James E Keenan 2018. All rights reserved. |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
=head1 SEE ALSO |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
perl(1). File::Copy::Recursive(3). |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
=cut |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
1; |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
__END__ |