Filename | /usr/share/perl5/File/Copy/Recursive.pm |
Statements | Executed 168 statements in 4.27ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
6 | 1 | 1 | 466µs | 606ms | fcopy | File::Copy::Recursive::
6 | 1 | 1 | 419µs | 558µs | __ANON__[:84] | File::Copy::Recursive::
18 | 3 | 1 | 166µs | 166µs | CORE:stat (opcode) | File::Copy::Recursive::
30 | 5 | 1 | 139µs | 139µs | CORE:ftdir (opcode) | File::Copy::Recursive::
6 | 1 | 1 | 58µs | 58µs | CORE:chmod (opcode) | File::Copy::Recursive::
1 | 1 | 1 | 17µs | 22µs | BEGIN@3 | File::Copy::Recursive::
1 | 1 | 1 | 11µs | 11µs | CORE:symlink (opcode) | File::Copy::Recursive::
6 | 1 | 1 | 10µs | 10µs | CORE:ftlink (opcode) | File::Copy::Recursive::
1 | 1 | 1 | 10µs | 11µs | BEGIN@13 | File::Copy::Recursive::
1 | 1 | 1 | 8µs | 48µs | BEGIN@11 | File::Copy::Recursive::
1 | 1 | 1 | 8µs | 151µs | BEGIN@16 | File::Copy::Recursive::
1 | 1 | 1 | 8µs | 39µs | BEGIN@9 | File::Copy::Recursive::
1 | 1 | 1 | 6µs | 88µs | BEGIN@12 | File::Copy::Recursive::
1 | 1 | 1 | 4µs | 4µs | BEGIN@5 | File::Copy::Recursive::
1 | 1 | 1 | 3µs | 3µs | BEGIN@14 | File::Copy::Recursive::
1 | 1 | 1 | 600ns | 600ns | __ANON__ (xsub) | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | __ANON__[:123] | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | __ANON__[:137] | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | __ANON__[:319] | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | __ANON__[:99] | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | _bail_if_changed | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | dircopy | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | dirmove | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | fmove | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | pathempty | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | pathmk | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | pathrm | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | pathrmdir | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | rcopy | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | rcopy_glob | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | rmove | File::Copy::Recursive::
0 | 0 | 0 | 0s | 0s | rmove_glob | File::Copy::Recursive::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package File::Copy::Recursive; | ||||
2 | |||||
3 | 2 | 51µs | 2 | 27µs | # spent 22µs (17+5) within File::Copy::Recursive::BEGIN@3 which was called:
# once (17µs+5µs) by RBM::BEGIN@15 at line 3 # spent 22µs making 1 call to File::Copy::Recursive::BEGIN@3
# spent 5µs making 1 call to strict::import |
4 | |||||
5 | # spent 4µs within File::Copy::Recursive::BEGIN@5 which was called:
# once (4µs+0s) by RBM::BEGIN@15 at line 8 | ||||
6 | # Keep older versions of Perl from trying to use lexical warnings | ||||
7 | 1 | 4µs | $INC{'warnings.pm'} = "fake warnings entry for < 5.6 perl ($])" if $] < 5.006; | ||
8 | 1 | 16µs | 1 | 4µs | } # spent 4µs making 1 call to File::Copy::Recursive::BEGIN@5 |
9 | 2 | 24µs | 2 | 71µs | # spent 39µs (8+31) within File::Copy::Recursive::BEGIN@9 which was called:
# once (8µs+31µs) by RBM::BEGIN@15 at line 9 # spent 39µs making 1 call to File::Copy::Recursive::BEGIN@9
# spent 32µs making 1 call to warnings::import |
10 | |||||
11 | 2 | 22µs | 2 | 88µs | # spent 48µs (8+40) within File::Copy::Recursive::BEGIN@11 which was called:
# once (8µs+40µs) by RBM::BEGIN@15 at line 11 # spent 48µs making 1 call to File::Copy::Recursive::BEGIN@11
# spent 40µs making 1 call to Exporter::import |
12 | 2 | 21µs | 2 | 170µs | # spent 88µs (6+82) within File::Copy::Recursive::BEGIN@12 which was called:
# once (6µs+82µs) by RBM::BEGIN@15 at line 12 # spent 88µs making 1 call to File::Copy::Recursive::BEGIN@12
# spent 82µs making 1 call to Exporter::import |
13 | 2 | 29µs | 2 | 11µs | # spent 11µs (10+600ns) within File::Copy::Recursive::BEGIN@13 which was called:
# once (10µs+600ns) by RBM::BEGIN@15 at line 13 # spent 11µs making 1 call to File::Copy::Recursive::BEGIN@13
# spent 600ns making 1 call to File::Copy::Recursive::__ANON__ |
14 | 2 | 34µs | 1 | 3µs | # spent 3µs within File::Copy::Recursive::BEGIN@14 which was called:
# once (3µs+0s) by RBM::BEGIN@15 at line 14 # spent 3µs making 1 call to File::Copy::Recursive::BEGIN@14 |
15 | |||||
16 | 1 | 7µs | 1 | 143µs | # spent 151µs (8+143) within File::Copy::Recursive::BEGIN@16 which was called:
# once (8µs+143µs) by RBM::BEGIN@15 at line 20 # spent 143µs making 1 call to vars::import |
17 | @ISA @EXPORT_OK $VERSION $MaxDepth $KeepMode $CPRFComp $CopyLink | ||||
18 | $PFSCheck $RemvBase $NoFtlPth $ForcePth $CopyLoop $RMTrgFil $RMTrgDir | ||||
19 | $CondCopy $BdTrgWrn $SkipFlop $DirPerms | ||||
20 | 1 | 2.76ms | 1 | 151µs | ); # spent 151µs making 1 call to File::Copy::Recursive::BEGIN@16 |
21 | |||||
22 | 1 | 1µs | require Exporter; | ||
23 | 1 | 9µs | @ISA = qw(Exporter); | ||
24 | 1 | 1µs | @EXPORT_OK = qw(fcopy rcopy dircopy fmove rmove dirmove pathmk pathrm pathempty pathrmdir rcopy_glob rmove_glob); | ||
25 | |||||
26 | 1 | 200ns | $VERSION = '0.44'; | ||
27 | |||||
28 | 1 | 100ns | $MaxDepth = 0; | ||
29 | 1 | 100ns | $KeepMode = 1; | ||
30 | 1 | 0s | $CPRFComp = 0; | ||
31 | 4 | 24µs | 1 | 11µs | $CopyLink = eval { local $SIG{'__DIE__'}; symlink '', ''; 1 } || 0; # spent 11µs making 1 call to File::Copy::Recursive::CORE:symlink |
32 | 1 | 100ns | $PFSCheck = 1; | ||
33 | 1 | 100ns | $RemvBase = 0; | ||
34 | 1 | 100ns | $NoFtlPth = 0; | ||
35 | 1 | 100ns | $ForcePth = 0; | ||
36 | 1 | 100ns | $CopyLoop = 0; | ||
37 | 1 | 100ns | $RMTrgFil = 0; | ||
38 | 1 | 100ns | $RMTrgDir = 0; | ||
39 | 1 | 400ns | $CondCopy = {}; | ||
40 | 1 | 200ns | $BdTrgWrn = 0; | ||
41 | 1 | 100ns | $SkipFlop = 0; | ||
42 | 1 | 100ns | $DirPerms = 0777; | ||
43 | |||||
44 | # spent 558µs (419+139) within File::Copy::Recursive::__ANON__[/usr/share/perl5/File/Copy/Recursive.pm:84] which was called 6 times, avg 93µs/call:
# 6 times (419µs+139µs) by File::Copy::Recursive::fcopy at line 140, avg 93µs/call | ||||
45 | 6 | 17µs | return 1 if $^O eq 'MSWin32'; # need better way to check for this on winders... | ||
46 | 6 | 18µs | return if @_ != 2 || !defined $_[0] || !defined $_[1]; | ||
47 | 6 | 5µs | return if $_[0] eq $_[1]; | ||
48 | |||||
49 | 6 | 12µs | my $one = ''; | ||
50 | 6 | 6µs | if ($PFSCheck) { | ||
51 | 6 | 171µs | 6 | 19µs | $one = join( '-', ( stat $_[0] )[ 0, 1 ] ) || ''; # spent 19µs making 6 calls to File::Copy::Recursive::CORE:stat, avg 3µs/call |
52 | 6 | 145µs | 6 | 109µs | my $two = join( '-', ( stat $_[1] )[ 0, 1 ] ) || ''; # spent 109µs making 6 calls to File::Copy::Recursive::CORE:stat, avg 18µs/call |
53 | 6 | 4µs | if ( $one eq $two && $one ) { | ||
54 | carp "$_[0] and $_[1] are identical"; | ||||
55 | return; | ||||
56 | } | ||||
57 | } | ||||
58 | |||||
59 | 6 | 149µs | 6 | 10µs | if ( -d $_[0] && !$CopyLoop ) { # spent 10µs making 6 calls to File::Copy::Recursive::CORE:ftdir, avg 2µs/call |
60 | $one = join( '-', ( stat $_[0] )[ 0, 1 ] ) if !$one; | ||||
61 | my $abs = File::Spec->rel2abs( $_[1] ); | ||||
62 | my @pth = File::Spec->splitdir($abs); | ||||
63 | while (@pth) { | ||||
64 | if ( $pth[-1] eq '..' ) { # cheaper than Cwd::realpath() plus we don't want to resolve symlinks at this point, right? | ||||
65 | pop @pth; | ||||
66 | pop @pth unless -l File::Spec->catdir(@pth); | ||||
67 | next; | ||||
68 | } | ||||
69 | my $cur = File::Spec->catdir(@pth); | ||||
70 | last if !$cur; # probably not necessary, but nice to have just in case :) | ||||
71 | my $two = join( '-', ( stat $cur )[ 0, 1 ] ) || ''; | ||||
72 | if ( $one eq $two && $one ) { | ||||
73 | |||||
74 | # $! = 62; # Too many levels of symbolic links | ||||
75 | carp "Caught Deep Recursion Condition: $_[0] contains $_[1]"; | ||||
76 | return; | ||||
77 | } | ||||
78 | |||||
79 | pop @pth; | ||||
80 | } | ||||
81 | } | ||||
82 | |||||
83 | 6 | 27µs | return 1; | ||
84 | 1 | 4µs | }; | ||
85 | |||||
86 | my $glob = sub { | ||||
87 | my ( $do, $src_glob, @args ) = @_; | ||||
88 | |||||
89 | local $CPRFComp = 1; | ||||
90 | require File::Glob; | ||||
91 | |||||
92 | my @rt; | ||||
93 | for my $path ( File::Glob::bsd_glob($src_glob) ) { | ||||
94 | my @call = [ $do->( $path, @args ) ] or return; | ||||
95 | push @rt, \@call; | ||||
96 | } | ||||
97 | |||||
98 | return @rt; | ||||
99 | 1 | 2µs | }; | ||
100 | |||||
101 | my $move = sub { | ||||
102 | my $fl = shift; | ||||
103 | my @x; | ||||
104 | if ($fl) { | ||||
105 | @x = fcopy(@_) or return; | ||||
106 | } | ||||
107 | else { | ||||
108 | @x = dircopy(@_) or return; | ||||
109 | } | ||||
110 | if (@x) { | ||||
111 | if ($fl) { | ||||
112 | unlink $_[0] or return; | ||||
113 | } | ||||
114 | else { | ||||
115 | pathrmdir( $_[0] ) or return; | ||||
116 | } | ||||
117 | if ($RemvBase) { | ||||
118 | my ( $volm, $path ) = File::Spec->splitpath( $_[0] ); | ||||
119 | pathrm( File::Spec->catpath( $volm, $path, '' ), $ForcePth, $NoFtlPth ) or return; | ||||
120 | } | ||||
121 | } | ||||
122 | return wantarray ? @x : $x[0]; | ||||
123 | 1 | 2µs | }; | ||
124 | |||||
125 | my $ok_todo_asper_condcopy = sub { | ||||
126 | my $org = shift; | ||||
127 | my $copy = 1; | ||||
128 | if ( exists $CondCopy->{$org} ) { | ||||
129 | if ( $CondCopy->{$org}{'md5'} ) { | ||||
130 | |||||
131 | } | ||||
132 | if ($copy) { | ||||
133 | |||||
134 | } | ||||
135 | } | ||||
136 | return $copy; | ||||
137 | 1 | 1µs | }; | ||
138 | |||||
139 | # spent 606ms (466µs+606) within File::Copy::Recursive::fcopy which was called 6 times, avg 101ms/call:
# 6 times (466µs+606ms) by RBM::recursive_copy at line 758 of /root/tor-browser-build/rbm/lib/RBM.pm, avg 101ms/call | ||||
140 | 6 | 36µs | 6 | 558µs | $samecheck->(@_) or return; # spent 558µs making 6 calls to File::Copy::Recursive::__ANON__[File/Copy/Recursive.pm:84], avg 93µs/call |
141 | 6 | 5µs | if ( $RMTrgFil && ( -d $_[1] || -e $_[1] ) ) { | ||
142 | my $trg = $_[1]; | ||||
143 | if ( -d $trg ) { | ||||
144 | my @trgx = File::Spec->splitpath( $_[0] ); | ||||
145 | $trg = File::Spec->catfile( $_[1], $trgx[$#trgx] ); | ||||
146 | } | ||||
147 | $samecheck->( $_[0], $trg ) or return; | ||||
148 | if ( -e $trg ) { | ||||
149 | if ( $RMTrgFil == 1 ) { | ||||
150 | unlink $trg or carp "\$RMTrgFil failed: $!"; | ||||
151 | } | ||||
152 | else { | ||||
153 | unlink $trg or return; | ||||
154 | } | ||||
155 | } | ||||
156 | } | ||||
157 | 6 | 97µs | 6 | 165µs | my ( $volm, $path ) = File::Spec->splitpath( $_[1] ); # spent 165µs making 6 calls to File::Spec::Unix::splitpath, avg 28µs/call |
158 | 6 | 34µs | 6 | 12µs | if ( $path && !-d $path ) { # spent 12µs making 6 calls to File::Copy::Recursive::CORE:ftdir, avg 2µs/call |
159 | pathmk( File::Spec->catpath( $volm, $path, '' ), $NoFtlPth ); | ||||
160 | } | ||||
161 | 6 | 74µs | 12 | 18µs | if ( -l $_[0] && $CopyLink ) { # spent 10µs making 6 calls to File::Copy::Recursive::CORE:ftlink, avg 2µs/call
# spent 8µs making 6 calls to File::Copy::Recursive::CORE:ftdir, avg 1µs/call |
162 | my $target = readlink( shift() ); | ||||
163 | ($target) = $target =~ m/(.*)/; # mass-untaint is OK since we have to allow what the file system does | ||||
164 | carp "Copying a symlink ($_[0]) whose target does not exist" | ||||
165 | if !-e $target && $BdTrgWrn; | ||||
166 | my $new = shift(); | ||||
167 | unlink $new if -l $new; | ||||
168 | symlink( $target, $new ) or return; | ||||
169 | } | ||||
170 | elsif ( -d $_[0] && -f $_[1] ) { | ||||
171 | return; | ||||
172 | } | ||||
173 | else { | ||||
174 | 6 | 23µs | 6 | 7µs | return if -d $_[0]; # address File::Copy::copy() bug outlined in https://rt.perl.org/Public/Bug/Display.html?id=132866 # spent 7µs making 6 calls to File::Copy::Recursive::CORE:ftdir, avg 1µs/call |
175 | 6 | 46µs | 6 | 605ms | copy(@_) or return; # spent 605ms making 6 calls to File::Copy::copy, avg 101ms/call |
176 | |||||
177 | 6 | 70µs | 6 | 127µs | my @base_file = File::Spec->splitpath( $_[0] ); # spent 127µs making 6 calls to File::Spec::Unix::splitpath, avg 21µs/call |
178 | 6 | 128µs | 6 | 101µs | my $mode_trg = -d $_[1] ? File::Spec->catfile( $_[1], $base_file[$#base_file] ) : $_[1]; # spent 101µs making 6 calls to File::Copy::Recursive::CORE:ftdir, avg 17µs/call |
179 | |||||
180 | 6 | 145µs | 12 | 95µs | chmod scalar( ( stat( $_[0] ) )[2] ), $mode_trg if $KeepMode; # spent 58µs making 6 calls to File::Copy::Recursive::CORE:chmod, avg 10µs/call
# spent 37µs making 6 calls to File::Copy::Recursive::CORE:stat, avg 6µs/call |
181 | } | ||||
182 | 6 | 38µs | return wantarray ? ( 1, 0, 0 ) : 1; # use 0's incase they do math on them and in case rcopy() is called in list context = no uninit val warnings | ||
183 | } | ||||
184 | |||||
185 | sub rcopy { | ||||
186 | if ( -l $_[0] && $CopyLink ) { | ||||
187 | goto &fcopy; | ||||
188 | } | ||||
189 | |||||
190 | goto &dircopy if -d $_[0] || substr( $_[0], ( 1 * -1 ), 1 ) eq '*'; | ||||
191 | goto &fcopy; | ||||
192 | } | ||||
193 | |||||
194 | sub rcopy_glob { | ||||
195 | $glob->( \&rcopy, @_ ); | ||||
196 | } | ||||
197 | |||||
198 | sub dircopy { | ||||
199 | if ( $RMTrgDir && -d $_[1] ) { | ||||
200 | if ( $RMTrgDir == 1 ) { | ||||
201 | pathrmdir( $_[1] ) or carp "\$RMTrgDir failed: $!"; | ||||
202 | } | ||||
203 | else { | ||||
204 | pathrmdir( $_[1] ) or return; | ||||
205 | } | ||||
206 | } | ||||
207 | my $globstar = 0; | ||||
208 | my $_zero = $_[0]; | ||||
209 | my $_one = $_[1]; | ||||
210 | if ( substr( $_zero, ( 1 * -1 ), 1 ) eq '*' ) { | ||||
211 | $globstar = 1; | ||||
212 | $_zero = substr( $_zero, 0, ( length($_zero) - 1 ) ); | ||||
213 | } | ||||
214 | |||||
215 | $samecheck->( $_zero, $_[1] ) or return; | ||||
216 | if ( !-d $_zero || ( -e $_[1] && !-d $_[1] ) ) { | ||||
217 | $! = 20; | ||||
218 | return; | ||||
219 | } | ||||
220 | |||||
221 | if ( !-d $_[1] ) { | ||||
222 | pathmk( $_[1], $NoFtlPth ) or return; | ||||
223 | } | ||||
224 | else { | ||||
225 | if ( $CPRFComp && !$globstar ) { | ||||
226 | my @parts = File::Spec->splitdir($_zero); | ||||
227 | while ( $parts[$#parts] eq '' ) { pop @parts; } | ||||
228 | $_one = File::Spec->catdir( $_[1], $parts[$#parts] ); | ||||
229 | } | ||||
230 | } | ||||
231 | my $baseend = $_one; | ||||
232 | my $level = 0; | ||||
233 | my $filen = 0; | ||||
234 | my $dirn = 0; | ||||
235 | |||||
236 | my $recurs; #must be my()ed before sub {} since it calls itself | ||||
237 | $recurs = sub { | ||||
238 | my ( $str, $end, $buf ) = @_; | ||||
239 | $filen++ if $end eq $baseend; | ||||
240 | $dirn++ if $end eq $baseend; | ||||
241 | |||||
242 | $DirPerms = oct($DirPerms) if substr( $DirPerms, 0, 1 ) eq '0'; | ||||
243 | mkdir( $end, $DirPerms ) or return if !-d $end; | ||||
244 | if ( $MaxDepth && $MaxDepth =~ m/^\d+$/ && $level >= $MaxDepth ) { | ||||
245 | chmod scalar( ( stat($str) )[2] ), $end if $KeepMode; | ||||
246 | return ( $filen, $dirn, $level ) if wantarray; | ||||
247 | return $filen; | ||||
248 | } | ||||
249 | |||||
250 | $level++; | ||||
251 | |||||
252 | my @files; | ||||
253 | if ( $] < 5.006 ) { | ||||
254 | opendir( STR_DH, $str ) or return; | ||||
255 | @files = grep( $_ ne '.' && $_ ne '..', readdir(STR_DH) ); | ||||
256 | closedir STR_DH; | ||||
257 | } | ||||
258 | else { | ||||
259 | opendir( my $str_dh, $str ) or return; | ||||
260 | @files = grep( $_ ne '.' && $_ ne '..', readdir($str_dh) ); | ||||
261 | closedir $str_dh; | ||||
262 | } | ||||
263 | |||||
264 | for my $file (@files) { | ||||
265 | my ($file_ut) = $file =~ m{ (.*) }xms; | ||||
266 | my $org = File::Spec->catfile( $str, $file_ut ); | ||||
267 | my $new = File::Spec->catfile( $end, $file_ut ); | ||||
268 | if ( -l $org && $CopyLink ) { | ||||
269 | my $target = readlink($org); | ||||
270 | ($target) = $target =~ m/(.*)/; # mass-untaint is OK since we have to allow what the file system does | ||||
271 | carp "Copying a symlink ($org) whose target does not exist" | ||||
272 | if !-e $target && $BdTrgWrn; | ||||
273 | unlink $new if -l $new; | ||||
274 | symlink( $target, $new ) or return; | ||||
275 | } | ||||
276 | elsif ( -d $org ) { | ||||
277 | my $rc; | ||||
278 | if ( !-w $org && $KeepMode ) { | ||||
279 | local $KeepMode = 0; | ||||
280 | carp "Copying readonly directory ($org); mode of its contents may not be preserved."; | ||||
281 | $rc = $recurs->( $org, $new, $buf ) if defined $buf; | ||||
282 | $rc = $recurs->( $org, $new ) if !defined $buf; | ||||
283 | chmod scalar( ( stat($org) )[2] ), $new; | ||||
284 | } | ||||
285 | else { | ||||
286 | $rc = $recurs->( $org, $new, $buf ) if defined $buf; | ||||
287 | $rc = $recurs->( $org, $new ) if !defined $buf; | ||||
288 | } | ||||
289 | if ( !$rc ) { | ||||
290 | if ($SkipFlop) { | ||||
291 | next; | ||||
292 | } | ||||
293 | else { | ||||
294 | return; | ||||
295 | } | ||||
296 | } | ||||
297 | $filen++; | ||||
298 | $dirn++; | ||||
299 | } | ||||
300 | else { | ||||
301 | if ( $ok_todo_asper_condcopy->($org) ) { | ||||
302 | if ($SkipFlop) { | ||||
303 | fcopy( $org, $new, $buf ) or next if defined $buf; | ||||
304 | fcopy( $org, $new ) or next if !defined $buf; | ||||
305 | } | ||||
306 | else { | ||||
307 | fcopy( $org, $new, $buf ) or return if defined $buf; | ||||
308 | fcopy( $org, $new ) or return if !defined $buf; | ||||
309 | } | ||||
310 | chmod scalar( ( stat($org) )[2] ), $new if $KeepMode; | ||||
311 | $filen++; | ||||
312 | } | ||||
313 | } | ||||
314 | } | ||||
315 | $level--; | ||||
316 | chmod scalar( ( stat($str) )[2] ), $end if $KeepMode; | ||||
317 | 1; | ||||
318 | |||||
319 | }; | ||||
320 | |||||
321 | $recurs->( $_zero, $_one, $_[2] ) or return; | ||||
322 | return wantarray ? ( $filen, $dirn, $level ) : $filen; | ||||
323 | } | ||||
324 | |||||
325 | sub fmove { $move->( 1, @_ ) } | ||||
326 | |||||
327 | sub rmove { | ||||
328 | if ( -l $_[0] && $CopyLink ) { | ||||
329 | goto &fmove; | ||||
330 | } | ||||
331 | |||||
332 | goto &dirmove if -d $_[0] || substr( $_[0], ( 1 * -1 ), 1 ) eq '*'; | ||||
333 | goto &fmove; | ||||
334 | } | ||||
335 | |||||
336 | sub rmove_glob { | ||||
337 | $glob->( \&rmove, @_ ); | ||||
338 | } | ||||
339 | |||||
340 | sub dirmove { $move->( 0, @_ ) } | ||||
341 | |||||
342 | sub pathmk { | ||||
343 | my ( $vol, $dir, $file ) = File::Spec->splitpath( shift() ); | ||||
344 | my $nofatal = shift; | ||||
345 | |||||
346 | $DirPerms = oct($DirPerms) if substr( $DirPerms, 0, 1 ) eq '0'; | ||||
347 | |||||
348 | if ( defined($dir) ) { | ||||
349 | my (@dirs) = File::Spec->splitdir($dir); | ||||
350 | |||||
351 | for ( my $i = 0; $i < scalar(@dirs); $i++ ) { | ||||
352 | my $newdir = File::Spec->catdir( @dirs[ 0 .. $i ] ); | ||||
353 | my $newpth = File::Spec->catpath( $vol, $newdir, "" ); | ||||
354 | |||||
355 | mkdir( $newpth, $DirPerms ) or return if !-d $newpth && !$nofatal; | ||||
356 | mkdir( $newpth, $DirPerms ) if !-d $newpth && $nofatal; | ||||
357 | } | ||||
358 | } | ||||
359 | |||||
360 | if ( defined($file) ) { | ||||
361 | my $newpth = File::Spec->catpath( $vol, $dir, $file ); | ||||
362 | |||||
363 | mkdir( $newpth, $DirPerms ) or return if !-d $newpth && !$nofatal; | ||||
364 | mkdir( $newpth, $DirPerms ) if !-d $newpth && $nofatal; | ||||
365 | } | ||||
366 | |||||
367 | 1; | ||||
368 | } | ||||
369 | |||||
370 | sub pathempty { | ||||
371 | my $pth = shift; | ||||
372 | |||||
373 | my ( $orig_dev, $orig_ino ) = ( lstat $pth )[ 0, 1 ]; | ||||
374 | return 2 if !-d _ || !$orig_dev || ( $^O ne 'MSWin32' && !$orig_ino ); #stat.inode is 0 on Windows | ||||
375 | |||||
376 | my $starting_point = Cwd::cwd(); | ||||
377 | my ( $starting_dev, $starting_ino ) = ( lstat $starting_point )[ 0, 1 ]; | ||||
378 | chdir($pth) or Carp::croak("Failed to change directory to “$pth”: $!"); | ||||
379 | $pth = '.'; | ||||
380 | _bail_if_changed( $pth, $orig_dev, $orig_ino ); | ||||
381 | |||||
382 | my @names; | ||||
383 | my $pth_dh; | ||||
384 | if ( $] < 5.006 ) { | ||||
385 | opendir( PTH_DH, $pth ) or return; | ||||
386 | @names = grep !/^\.\.?$/, readdir(PTH_DH); | ||||
387 | closedir PTH_DH; | ||||
388 | } | ||||
389 | else { | ||||
390 | opendir( $pth_dh, $pth ) or return; | ||||
391 | @names = grep !/^\.\.?$/, readdir($pth_dh); | ||||
392 | closedir $pth_dh; | ||||
393 | } | ||||
394 | _bail_if_changed( $pth, $orig_dev, $orig_ino ); | ||||
395 | |||||
396 | for my $name (@names) { | ||||
397 | my ($name_ut) = $name =~ m{ (.*) }xms; | ||||
398 | my $flpth = File::Spec->catdir( $pth, $name_ut ); | ||||
399 | |||||
400 | if ( -l $flpth ) { | ||||
401 | _bail_if_changed( $pth, $orig_dev, $orig_ino ); | ||||
402 | unlink $flpth or return; | ||||
403 | } | ||||
404 | elsif ( -d $flpth ) { | ||||
405 | _bail_if_changed( $pth, $orig_dev, $orig_ino ); | ||||
406 | pathrmdir($flpth) or return; | ||||
407 | } | ||||
408 | else { | ||||
409 | _bail_if_changed( $pth, $orig_dev, $orig_ino ); | ||||
410 | unlink $flpth or return; | ||||
411 | } | ||||
412 | } | ||||
413 | |||||
414 | chdir($starting_point) or Carp::croak("Failed to change directory to “$starting_point”: $!"); | ||||
415 | _bail_if_changed( ".", $starting_dev, $starting_ino ); | ||||
416 | |||||
417 | return 1; | ||||
418 | } | ||||
419 | |||||
420 | sub pathrm { | ||||
421 | my ( $path, $force, $nofail ) = @_; | ||||
422 | |||||
423 | my ( $orig_dev, $orig_ino ) = ( lstat $path )[ 0, 1 ]; | ||||
424 | return 2 if !-d _ || !$orig_dev || !$orig_ino; | ||||
425 | |||||
426 | # Manual test (I hate this function :/): | ||||
427 | # sudo mkdir /foo && perl -MFile::Copy::Recursive=pathrm -le 'print pathrm("/foo",1)' && sudo rm -rf /foo | ||||
428 | if ( $force && File::Spec->file_name_is_absolute($path) ) { | ||||
429 | Carp::croak("pathrm() w/ force on abspath is not allowed"); | ||||
430 | } | ||||
431 | |||||
432 | my @pth = File::Spec->splitdir($path); | ||||
433 | |||||
434 | my %fs_check; | ||||
435 | my $aggregate_path; | ||||
436 | for my $part (@pth) { | ||||
437 | $aggregate_path = defined $aggregate_path ? File::Spec->catdir( $aggregate_path, $part ) : $part; | ||||
438 | $fs_check{$aggregate_path} = [ ( lstat $aggregate_path )[ 0, 1 ] ]; | ||||
439 | } | ||||
440 | |||||
441 | while (@pth) { | ||||
442 | my $cur = File::Spec->catdir(@pth); | ||||
443 | last if !$cur; # necessary ??? | ||||
444 | |||||
445 | if ($force) { | ||||
446 | _bail_if_changed( $cur, $fs_check{$cur}->[0], $fs_check{$cur}->[1] ); | ||||
447 | if ( !pathempty($cur) ) { | ||||
448 | return unless $nofail; | ||||
449 | } | ||||
450 | } | ||||
451 | _bail_if_changed( $cur, $fs_check{$cur}->[0], $fs_check{$cur}->[1] ); | ||||
452 | if ($nofail) { | ||||
453 | rmdir $cur; | ||||
454 | } | ||||
455 | else { | ||||
456 | rmdir $cur or return; | ||||
457 | } | ||||
458 | pop @pth; | ||||
459 | } | ||||
460 | |||||
461 | return 1; | ||||
462 | } | ||||
463 | |||||
464 | sub pathrmdir { | ||||
465 | my $dir = shift; | ||||
466 | if ( -e $dir ) { | ||||
467 | return if !-d $dir; | ||||
468 | } | ||||
469 | else { | ||||
470 | return 2; | ||||
471 | } | ||||
472 | |||||
473 | my ( $orig_dev, $orig_ino ) = ( lstat $dir )[ 0, 1 ]; | ||||
474 | return 2 if !$orig_dev || ( $^O ne 'MSWin32' && !$orig_ino ); | ||||
475 | |||||
476 | pathempty($dir) or return; | ||||
477 | _bail_if_changed( $dir, $orig_dev, $orig_ino ); | ||||
478 | rmdir $dir or return; | ||||
479 | |||||
480 | return 1; | ||||
481 | } | ||||
482 | |||||
483 | sub _bail_if_changed { | ||||
484 | my ( $path, $orig_dev, $orig_ino ) = @_; | ||||
485 | |||||
486 | my ( $cur_dev, $cur_ino ) = ( lstat $path )[ 0, 1 ]; | ||||
487 | |||||
488 | if ( !defined $cur_dev || !defined $cur_ino ) { | ||||
489 | $cur_dev ||= "undef(path went away?)"; | ||||
490 | $cur_ino ||= "undef(path went away?)"; | ||||
491 | } | ||||
492 | else { | ||||
493 | $path = Cwd::abs_path($path); | ||||
494 | } | ||||
495 | |||||
496 | if ( $orig_dev ne $cur_dev || $orig_ino ne $cur_ino ) { | ||||
497 | local $Carp::CarpLevel += 1; | ||||
498 | Carp::croak("directory $path changed: expected dev=$orig_dev ino=$orig_ino, actual dev=$cur_dev ino=$cur_ino, aborting"); | ||||
499 | } | ||||
500 | } | ||||
501 | |||||
502 | 1 | 11µs | 1; | ||
503 | |||||
504 | __END__ | ||||
# spent 58µs within File::Copy::Recursive::CORE:chmod which was called 6 times, avg 10µs/call:
# 6 times (58µs+0s) by File::Copy::Recursive::fcopy at line 180, avg 10µs/call | |||||
# spent 139µs within File::Copy::Recursive::CORE:ftdir which was called 30 times, avg 5µs/call:
# 6 times (101µs+0s) by File::Copy::Recursive::fcopy at line 178, avg 17µs/call
# 6 times (12µs+0s) by File::Copy::Recursive::fcopy at line 158, avg 2µs/call
# 6 times (10µs+0s) by File::Copy::Recursive::__ANON__[/usr/share/perl5/File/Copy/Recursive.pm:84] at line 59, avg 2µs/call
# 6 times (8µs+0s) by File::Copy::Recursive::fcopy at line 161, avg 1µs/call
# 6 times (7µs+0s) by File::Copy::Recursive::fcopy at line 174, avg 1µs/call | |||||
# spent 10µs within File::Copy::Recursive::CORE:ftlink which was called 6 times, avg 2µs/call:
# 6 times (10µs+0s) by File::Copy::Recursive::fcopy at line 161, avg 2µs/call | |||||
# spent 166µs within File::Copy::Recursive::CORE:stat which was called 18 times, avg 9µs/call:
# 6 times (109µs+0s) by File::Copy::Recursive::__ANON__[/usr/share/perl5/File/Copy/Recursive.pm:84] at line 52, avg 18µs/call
# 6 times (37µs+0s) by File::Copy::Recursive::fcopy at line 180, avg 6µs/call
# 6 times (19µs+0s) by File::Copy::Recursive::__ANON__[/usr/share/perl5/File/Copy/Recursive.pm:84] at line 51, avg 3µs/call | |||||
# spent 11µs within File::Copy::Recursive::CORE:symlink which was called:
# once (11µs+0s) by RBM::BEGIN@15 at line 31 | |||||
# spent 600ns within File::Copy::Recursive::__ANON__ which was called:
# once (600ns+0s) by File::Copy::Recursive::BEGIN@13 at line 13 |