Filename | /usr/lib/perl5/5.14/File/Path.pm |
Statements | Executed 199722 statements in 2.41s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
11624 | 2 | 1 | 1.18s | 1.18s | CORE:ftdir (opcode) | File::Path::
1580 | 1 | 1 | 713ms | 713ms | CORE:mkdir (opcode) | File::Path::
9982 | 2 | 2 | 252ms | 2.53s | mkpath | File::Path::
10044 | 2 | 1 | 187ms | 2.23s | _mkpath (recurses: max depth 4, inclusive time 86.4ms) | File::Path::
1 | 1 | 1 | 5.42ms | 5.97ms | BEGIN@7 | File::Path::
1 | 1 | 1 | 283µs | 283µs | BEGIN@3 | File::Path::
1 | 1 | 1 | 17µs | 112µs | BEGIN@6 | File::Path::
1 | 1 | 1 | 15µs | 40µs | BEGIN@329 | File::Path::
1 | 1 | 1 | 14µs | 18µs | BEGIN@4 | File::Path::
1 | 1 | 1 | 13µs | 129µs | BEGIN@19 | File::Path::
1 | 1 | 1 | 9µs | 9µs | BEGIN@10 | File::Path::
1 | 1 | 1 | 7µs | 7µs | BEGIN@8 | File::Path::
1 | 1 | 1 | 7µs | 7µs | BEGIN@18 | File::Path::
0 | 0 | 0 | 0s | 0s | _carp | File::Path::
0 | 0 | 0 | 0s | 0s | _croak | File::Path::
0 | 0 | 0 | 0s | 0s | _error | File::Path::
0 | 0 | 0 | 0s | 0s | _is_subdir | File::Path::
0 | 0 | 0 | 0s | 0s | _rmtree | File::Path::
0 | 0 | 0 | 0s | 0s | _slash_lc | File::Path::
0 | 0 | 0 | 0s | 0s | make_path | File::Path::
0 | 0 | 0 | 0s | 0s | remove_tree | File::Path::
0 | 0 | 0 | 0s | 0s | rmtree | File::Path::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package File::Path; | ||||
2 | |||||
3 | 2 | 186µs | 1 | 283µs | # spent 283µs within File::Path::BEGIN@3 which was called:
# once (283µs+0s) by File::Temp::BEGIN@145 at line 3 # spent 283µs making 1 call to File::Path::BEGIN@3 |
4 | 2 | 60µs | 2 | 23µs | # spent 18µs (14+5) within File::Path::BEGIN@4 which was called:
# once (14µs+5µs) by File::Temp::BEGIN@145 at line 4 # spent 18µs making 1 call to File::Path::BEGIN@4
# spent 5µs making 1 call to strict::import |
5 | |||||
6 | 2 | 55µs | 2 | 206µs | # spent 112µs (17+94) within File::Path::BEGIN@6 which was called:
# once (17µs+94µs) by File::Temp::BEGIN@145 at line 6 # spent 112µs making 1 call to File::Path::BEGIN@6
# spent 94µs making 1 call to Exporter::import |
7 | 2 | 3.13ms | 1 | 5.97ms | # spent 5.97ms (5.42+542µs) within File::Path::BEGIN@7 which was called:
# once (5.42ms+542µs) by File::Temp::BEGIN@145 at line 7 # spent 5.97ms making 1 call to File::Path::BEGIN@7 |
8 | 2 | 68µs | 1 | 7µs | # spent 7µs within File::Path::BEGIN@8 which was called:
# once (7µs+0s) by File::Temp::BEGIN@145 at line 8 # spent 7µs making 1 call to File::Path::BEGIN@8 |
9 | |||||
10 | # spent 9µs within File::Path::BEGIN@10 which was called:
# once (9µs+0s) by File::Temp::BEGIN@145 at line 16 | ||||
11 | 1 | 8µs | if ($] < 5.006) { | ||
12 | # can't say 'opendir my $dh, $dirname' | ||||
13 | # need to initialise $dh | ||||
14 | eval "use Symbol"; | ||||
15 | } | ||||
16 | 1 | 40µs | 1 | 9µs | } # spent 9µs making 1 call to File::Path::BEGIN@10 |
17 | |||||
18 | 2 | 52µs | 1 | 7µs | # spent 7µs within File::Path::BEGIN@18 which was called:
# once (7µs+0s) by File::Temp::BEGIN@145 at line 18 # spent 7µs making 1 call to File::Path::BEGIN@18 |
19 | 2 | 3.19ms | 2 | 244µs | # spent 129µs (13+115) within File::Path::BEGIN@19 which was called:
# once (13µs+115µs) by File::Temp::BEGIN@145 at line 19 # spent 129µs making 1 call to File::Path::BEGIN@19
# spent 115µs making 1 call to vars::import |
20 | 1 | 1µs | $VERSION = '2.08_01'; | ||
21 | 1 | 8µs | @ISA = qw(Exporter); | ||
22 | 1 | 2µs | @EXPORT = qw(mkpath rmtree); | ||
23 | 1 | 2µs | @EXPORT_OK = qw(make_path remove_tree); | ||
24 | |||||
25 | 1 | 2µs | my $Is_VMS = $^O eq 'VMS'; | ||
26 | 1 | 1µs | my $Is_MacOS = $^O eq 'MacOS'; | ||
27 | |||||
28 | # These OSes complain if you want to remove a file that you have no | ||||
29 | # write permission to: | ||||
30 | 1 | 4µs | my $Force_Writeable = grep {$^O eq $_} qw(amigaos dos epoc MSWin32 MacOS os2); | ||
31 | |||||
32 | # Unix-like systems need to stat each directory in order to detect | ||||
33 | # race condition. MS-Windows is immune to this particular attack. | ||||
34 | 1 | 1µs | my $Need_Stat_Check = !($^O eq 'MSWin32'); | ||
35 | |||||
36 | sub _carp { | ||||
37 | require Carp; | ||||
38 | goto &Carp::carp; | ||||
39 | } | ||||
40 | |||||
41 | sub _croak { | ||||
42 | require Carp; | ||||
43 | goto &Carp::croak; | ||||
44 | } | ||||
45 | |||||
46 | sub _error { | ||||
47 | my $arg = shift; | ||||
48 | my $message = shift; | ||||
49 | my $object = shift; | ||||
50 | |||||
51 | if ($arg->{error}) { | ||||
52 | $object = '' unless defined $object; | ||||
53 | $message .= ": $!" if $!; | ||||
54 | push @{${$arg->{error}}}, {$object => $message}; | ||||
55 | } | ||||
56 | else { | ||||
57 | _carp(defined($object) ? "$message for $object: $!" : "$message: $!"); | ||||
58 | } | ||||
59 | } | ||||
60 | |||||
61 | sub make_path { | ||||
62 | push @_, {} unless @_ and UNIVERSAL::isa($_[-1],'HASH'); | ||||
63 | goto &mkpath; | ||||
64 | } | ||||
65 | |||||
66 | # spent 2.53s (252ms+2.28) within File::Path::mkpath which was called 9982 times, avg 254µs/call:
# 8601 times (217ms+1.10s) by Archive::Zip::Member::extractToFileNamed at line 485 of Archive/Zip/Member.pm, avg 153µs/call
# 1381 times (35.2ms+1.18s) by Archive::Zip::DirectoryMember::extractToFileNamed at line 62 of Archive/Zip/DirectoryMember.pm, avg 879µs/call | ||||
67 | 49910 | 171ms | 9982 | 28.3ms | my $old_style = !(@_ and UNIVERSAL::isa($_[-1],'HASH')); # spent 28.3ms making 9982 calls to UNIVERSAL::isa, avg 3µs/call |
68 | |||||
69 | my $arg; | ||||
70 | my $paths; | ||||
71 | |||||
72 | 49910 | 131ms | if ($old_style) { | ||
73 | my ($verbose, $mode); | ||||
74 | ($paths, $verbose, $mode) = @_; | ||||
75 | 9982 | 24.9ms | $paths = [$paths] unless UNIVERSAL::isa($paths,'ARRAY'); # spent 24.9ms making 9982 calls to UNIVERSAL::isa, avg 2µs/call | ||
76 | $arg->{verbose} = $verbose; | ||||
77 | $arg->{mode} = defined $mode ? $mode : 0777; | ||||
78 | } | ||||
79 | else { | ||||
80 | $arg = pop @_; | ||||
81 | $arg->{mode} = delete $arg->{mask} if exists $arg->{mask}; | ||||
82 | $arg->{mode} = 0777 unless exists $arg->{mode}; | ||||
83 | ${$arg->{error}} = [] if exists $arg->{error}; | ||||
84 | $arg->{owner} = delete $arg->{user} if exists $arg->{user}; | ||||
85 | $arg->{owner} = delete $arg->{uid} if exists $arg->{uid}; | ||||
86 | if (exists $arg->{owner} and $arg->{owner} =~ /\D/) { | ||||
87 | my $uid = (getpwnam $arg->{owner})[2]; | ||||
88 | if (defined $uid) { | ||||
89 | $arg->{owner} = $uid; | ||||
90 | } | ||||
91 | else { | ||||
92 | _error($arg, "unable to map $arg->{owner} to a uid, ownership not changed"); | ||||
93 | delete $arg->{owner}; | ||||
94 | } | ||||
95 | } | ||||
96 | if (exists $arg->{group} and $arg->{group} =~ /\D/) { | ||||
97 | my $gid = (getgrnam $arg->{group})[2]; | ||||
98 | if (defined $gid) { | ||||
99 | $arg->{group} = $gid; | ||||
100 | } | ||||
101 | else { | ||||
102 | _error($arg, "unable to map $arg->{group} to a gid, group ownership not changed"); | ||||
103 | delete $arg->{group}; | ||||
104 | } | ||||
105 | } | ||||
106 | if (exists $arg->{owner} and not exists $arg->{group}) { | ||||
107 | $arg->{group} = -1; # chown will leave group unchanged | ||||
108 | } | ||||
109 | if (exists $arg->{group} and not exists $arg->{owner}) { | ||||
110 | $arg->{owner} = -1; # chown will leave owner unchanged | ||||
111 | } | ||||
112 | $paths = [@_]; | ||||
113 | } | ||||
114 | 9982 | 2.23s | return _mkpath($arg, $paths); # spent 2.23s making 9982 calls to File::Path::_mkpath, avg 223µs/call | ||
115 | } | ||||
116 | |||||
117 | sub _mkpath { | ||||
118 | 50220 | 78.0ms | my $arg = shift; | ||
119 | my $paths = shift; | ||||
120 | |||||
121 | my(@created,$path); | ||||
122 | foreach $path (@$paths) { | ||||
123 | 46496 | 2.01s | next unless defined($path) and length($path); | ||
124 | $path .= '/' if $^O eq 'os2' and $path =~ /^\w:\z/s; # feature of CRT | ||||
125 | # Logic wants Unix paths, so go with the flow. | ||||
126 | if ($Is_VMS) { | ||||
127 | next if $path eq '/'; | ||||
128 | $path = VMS::Filespec::unixify($path); | ||||
129 | } | ||||
130 | 10044 | 1.05s | next if -d $path; # spent 1.05s making 10044 calls to File::Path::CORE:ftdir, avg 104µs/call | ||
131 | 1580 | 146ms | my $parent = File::Basename::dirname($path); # spent 146ms making 1580 calls to File::Basename::dirname, avg 92µs/call | ||
132 | 1642 | 135ms | unless (-d $parent or $path eq $parent) { # spent 135ms making 1580 calls to File::Path::CORE:ftdir, avg 85µs/call
# spent 86.4ms making 62 calls to File::Path::_mkpath, avg 1.39ms/call, recursion: max depth 4, sum of overlapping time 86.4ms | ||
133 | push(@created,_mkpath($arg, [$parent])); | ||||
134 | } | ||||
135 | print "mkdir $path\n" if $arg->{verbose}; | ||||
136 | 3160 | 5.22ms | 1580 | 713ms | if (mkdir($path,$arg->{mode})) { # spent 713ms making 1580 calls to File::Path::CORE:mkdir, avg 452µs/call |
137 | push(@created, $path); | ||||
138 | if (exists $arg->{owner}) { | ||||
139 | # NB: $arg->{group} guaranteed to be set during initialisation | ||||
140 | if (!chown $arg->{owner}, $arg->{group}, $path) { | ||||
141 | _error($arg, "Cannot change ownership of $path to $arg->{owner}:$arg->{group}"); | ||||
142 | } | ||||
143 | } | ||||
144 | } | ||||
145 | else { | ||||
146 | my $save_bang = $!; | ||||
147 | my ($e, $e1) = ($save_bang, $^E); | ||||
148 | $e .= "; $e1" if $e ne $e1; | ||||
149 | # allow for another process to have created it meanwhile | ||||
150 | if (!-d $path) { | ||||
151 | $! = $save_bang; | ||||
152 | if ($arg->{error}) { | ||||
153 | push @{${$arg->{error}}}, {$path => $e}; | ||||
154 | } | ||||
155 | else { | ||||
156 | _croak("mkdir $path: $e"); | ||||
157 | } | ||||
158 | } | ||||
159 | } | ||||
160 | } | ||||
161 | return @created; | ||||
162 | } | ||||
163 | |||||
164 | sub remove_tree { | ||||
165 | push @_, {} unless @_ and UNIVERSAL::isa($_[-1],'HASH'); | ||||
166 | goto &rmtree; | ||||
167 | } | ||||
168 | |||||
169 | sub _is_subdir { | ||||
170 | my($dir, $test) = @_; | ||||
171 | |||||
172 | my($dv, $dd) = File::Spec->splitpath($dir, 1); | ||||
173 | my($tv, $td) = File::Spec->splitpath($test, 1); | ||||
174 | |||||
175 | # not on same volume | ||||
176 | return 0 if $dv ne $tv; | ||||
177 | |||||
178 | my @d = File::Spec->splitdir($dd); | ||||
179 | my @t = File::Spec->splitdir($td); | ||||
180 | |||||
181 | # @t can't be a subdir if it's shorter than @d | ||||
182 | return 0 if @t < @d; | ||||
183 | |||||
184 | return join('/', @d) eq join('/', splice @t, 0, +@d); | ||||
185 | } | ||||
186 | |||||
187 | sub rmtree { | ||||
188 | my $old_style = !(@_ and UNIVERSAL::isa($_[-1],'HASH')); | ||||
189 | |||||
190 | my $arg; | ||||
191 | my $paths; | ||||
192 | |||||
193 | if ($old_style) { | ||||
194 | my ($verbose, $safe); | ||||
195 | ($paths, $verbose, $safe) = @_; | ||||
196 | $arg->{verbose} = $verbose; | ||||
197 | $arg->{safe} = defined $safe ? $safe : 0; | ||||
198 | |||||
199 | if (defined($paths) and length($paths)) { | ||||
200 | $paths = [$paths] unless UNIVERSAL::isa($paths,'ARRAY'); | ||||
201 | } | ||||
202 | else { | ||||
203 | _carp ("No root path(s) specified\n"); | ||||
204 | return 0; | ||||
205 | } | ||||
206 | } | ||||
207 | else { | ||||
208 | $arg = pop @_; | ||||
209 | ${$arg->{error}} = [] if exists $arg->{error}; | ||||
210 | ${$arg->{result}} = [] if exists $arg->{result}; | ||||
211 | $paths = [@_]; | ||||
212 | } | ||||
213 | |||||
214 | $arg->{prefix} = ''; | ||||
215 | $arg->{depth} = 0; | ||||
216 | |||||
217 | my @clean_path; | ||||
218 | $arg->{cwd} = getcwd() or do { | ||||
219 | _error($arg, "cannot fetch initial working directory"); | ||||
220 | return 0; | ||||
221 | }; | ||||
222 | for ($arg->{cwd}) { /\A(.*)\Z/; $_ = $1 } # untaint | ||||
223 | |||||
224 | for my $p (@$paths) { | ||||
225 | # need to fixup case and map \ to / on Windows | ||||
226 | my $ortho_root = $^O eq 'MSWin32' ? _slash_lc($p) : $p; | ||||
227 | my $ortho_cwd = $^O eq 'MSWin32' ? _slash_lc($arg->{cwd}) : $arg->{cwd}; | ||||
228 | my $ortho_root_length = length($ortho_root); | ||||
229 | $ortho_root_length-- if $^O eq 'VMS'; # don't compare '.' with ']' | ||||
230 | if ($ortho_root_length && _is_subdir($ortho_root, $ortho_cwd)) { | ||||
231 | local $! = 0; | ||||
232 | _error($arg, "cannot remove path when cwd is $arg->{cwd}", $p); | ||||
233 | next; | ||||
234 | } | ||||
235 | |||||
236 | if ($Is_MacOS) { | ||||
237 | $p = ":$p" unless $p =~ /:/; | ||||
238 | $p .= ":" unless $p =~ /:\z/; | ||||
239 | } | ||||
240 | elsif ($^O eq 'MSWin32') { | ||||
241 | $p =~ s{[/\\]\z}{}; | ||||
242 | } | ||||
243 | else { | ||||
244 | $p =~ s{/\z}{}; | ||||
245 | } | ||||
246 | push @clean_path, $p; | ||||
247 | } | ||||
248 | |||||
249 | @{$arg}{qw(device inode perm)} = (lstat $arg->{cwd})[0,1] or do { | ||||
250 | _error($arg, "cannot stat initial working directory", $arg->{cwd}); | ||||
251 | return 0; | ||||
252 | }; | ||||
253 | |||||
254 | return _rmtree($arg, \@clean_path); | ||||
255 | } | ||||
256 | |||||
257 | sub _rmtree { | ||||
258 | my $arg = shift; | ||||
259 | my $paths = shift; | ||||
260 | |||||
261 | my $count = 0; | ||||
262 | my $curdir = File::Spec->curdir(); | ||||
263 | my $updir = File::Spec->updir(); | ||||
264 | |||||
265 | my (@files, $root); | ||||
266 | ROOT_DIR: | ||||
267 | foreach $root (@$paths) { | ||||
268 | # since we chdir into each directory, it may not be obvious | ||||
269 | # to figure out where we are if we generate a message about | ||||
270 | # a file name. We therefore construct a semi-canonical | ||||
271 | # filename, anchored from the directory being unlinked (as | ||||
272 | # opposed to being truly canonical, anchored from the root (/). | ||||
273 | |||||
274 | my $canon = $arg->{prefix} | ||||
275 | ? File::Spec->catfile($arg->{prefix}, $root) | ||||
276 | : $root | ||||
277 | ; | ||||
278 | |||||
279 | my ($ldev, $lino, $perm) = (lstat $root)[0,1,2] or next ROOT_DIR; | ||||
280 | |||||
281 | if ( -d _ ) { | ||||
282 | $root = VMS::Filespec::vmspath(VMS::Filespec::pathify($root)) if $Is_VMS; | ||||
283 | |||||
284 | if (!chdir($root)) { | ||||
285 | # see if we can escalate privileges to get in | ||||
286 | # (e.g. funny protection mask such as -w- instead of rwx) | ||||
287 | $perm &= 07777; | ||||
288 | my $nperm = $perm | 0700; | ||||
289 | if (!($arg->{safe} or $nperm == $perm or chmod($nperm, $root))) { | ||||
290 | _error($arg, "cannot make child directory read-write-exec", $canon); | ||||
291 | next ROOT_DIR; | ||||
292 | } | ||||
293 | elsif (!chdir($root)) { | ||||
294 | _error($arg, "cannot chdir to child", $canon); | ||||
295 | next ROOT_DIR; | ||||
296 | } | ||||
297 | } | ||||
298 | |||||
299 | my ($cur_dev, $cur_inode, $perm) = (stat $curdir)[0,1,2] or do { | ||||
300 | _error($arg, "cannot stat current working directory", $canon); | ||||
301 | next ROOT_DIR; | ||||
302 | }; | ||||
303 | |||||
304 | if ($Need_Stat_Check) { | ||||
305 | ($ldev eq $cur_dev and $lino eq $cur_inode) | ||||
306 | or _croak("directory $canon changed before chdir, expected dev=$ldev ino=$lino, actual dev=$cur_dev ino=$cur_inode, aborting."); | ||||
307 | } | ||||
308 | |||||
309 | $perm &= 07777; # don't forget setuid, setgid, sticky bits | ||||
310 | my $nperm = $perm | 0700; | ||||
311 | |||||
312 | # notabene: 0700 is for making readable in the first place, | ||||
313 | # it's also intended to change it to writable in case we have | ||||
314 | # to recurse in which case we are better than rm -rf for | ||||
315 | # subtrees with strange permissions | ||||
316 | |||||
317 | if (!($arg->{safe} or $nperm == $perm or chmod($nperm, $curdir))) { | ||||
318 | _error($arg, "cannot make directory read+writeable", $canon); | ||||
319 | $nperm = $perm; | ||||
320 | } | ||||
321 | |||||
322 | my $d; | ||||
323 | $d = gensym() if $] < 5.006; | ||||
324 | if (!opendir $d, $curdir) { | ||||
325 | _error($arg, "cannot opendir", $canon); | ||||
326 | @files = (); | ||||
327 | } | ||||
328 | else { | ||||
329 | 2 | 1.34ms | 2 | 65µs | # spent 40µs (15+25) within File::Path::BEGIN@329 which was called:
# once (15µs+25µs) by File::Temp::BEGIN@145 at line 329 # spent 40µs making 1 call to File::Path::BEGIN@329
# spent 25µs making 1 call to strict::unimport |
330 | if (!defined ${"\cTAINT"} or ${"\cTAINT"}) { | ||||
331 | # Blindly untaint dir names if taint mode is | ||||
332 | # active, or any perl < 5.006 | ||||
333 | @files = map { /\A(.*)\z/s; $1 } readdir $d; | ||||
334 | } | ||||
335 | else { | ||||
336 | @files = readdir $d; | ||||
337 | } | ||||
338 | closedir $d; | ||||
339 | } | ||||
340 | |||||
341 | if ($Is_VMS) { | ||||
342 | # Deleting large numbers of files from VMS Files-11 | ||||
343 | # filesystems is faster if done in reverse ASCIIbetical order. | ||||
344 | # include '.' to '.;' from blead patch #31775 | ||||
345 | @files = map {$_ eq '.' ? '.;' : $_} reverse @files; | ||||
346 | } | ||||
347 | |||||
348 | @files = grep {$_ ne $updir and $_ ne $curdir} @files; | ||||
349 | |||||
350 | if (@files) { | ||||
351 | # remove the contained files before the directory itself | ||||
352 | my $narg = {%$arg}; | ||||
353 | @{$narg}{qw(device inode cwd prefix depth)} | ||||
354 | = ($cur_dev, $cur_inode, $updir, $canon, $arg->{depth}+1); | ||||
355 | $count += _rmtree($narg, \@files); | ||||
356 | } | ||||
357 | |||||
358 | # restore directory permissions of required now (in case the rmdir | ||||
359 | # below fails), while we are still in the directory and may do so | ||||
360 | # without a race via '.' | ||||
361 | if ($nperm != $perm and not chmod($perm, $curdir)) { | ||||
362 | _error($arg, "cannot reset chmod", $canon); | ||||
363 | } | ||||
364 | |||||
365 | # don't leave the client code in an unexpected directory | ||||
366 | chdir($arg->{cwd}) | ||||
367 | or _croak("cannot chdir to $arg->{cwd} from $canon: $!, aborting."); | ||||
368 | |||||
369 | # ensure that a chdir upwards didn't take us somewhere other | ||||
370 | # than we expected (see CVE-2002-0435) | ||||
371 | ($cur_dev, $cur_inode) = (stat $curdir)[0,1] | ||||
372 | or _croak("cannot stat prior working directory $arg->{cwd}: $!, aborting."); | ||||
373 | |||||
374 | if ($Need_Stat_Check) { | ||||
375 | ($arg->{device} eq $cur_dev and $arg->{inode} eq $cur_inode) | ||||
376 | or _croak("previous directory $arg->{cwd} changed before entering $canon, expected dev=$ldev ino=$lino, actual dev=$cur_dev ino=$cur_inode, aborting."); | ||||
377 | } | ||||
378 | |||||
379 | if ($arg->{depth} or !$arg->{keep_root}) { | ||||
380 | if ($arg->{safe} && | ||||
381 | ($Is_VMS ? !&VMS::Filespec::candelete($root) : !-w $root)) { | ||||
382 | print "skipped $root\n" if $arg->{verbose}; | ||||
383 | next ROOT_DIR; | ||||
384 | } | ||||
385 | if ($Force_Writeable and !chmod $perm | 0700, $root) { | ||||
386 | _error($arg, "cannot make directory writeable", $canon); | ||||
387 | } | ||||
388 | print "rmdir $root\n" if $arg->{verbose}; | ||||
389 | if (rmdir $root) { | ||||
390 | push @{${$arg->{result}}}, $root if $arg->{result}; | ||||
391 | ++$count; | ||||
392 | } | ||||
393 | else { | ||||
394 | _error($arg, "cannot remove directory", $canon); | ||||
395 | if ($Force_Writeable && !chmod($perm, ($Is_VMS ? VMS::Filespec::fileify($root) : $root)) | ||||
396 | ) { | ||||
397 | _error($arg, sprintf("cannot restore permissions to 0%o",$perm), $canon); | ||||
398 | } | ||||
399 | } | ||||
400 | } | ||||
401 | } | ||||
402 | else { | ||||
403 | # not a directory | ||||
404 | $root = VMS::Filespec::vmsify("./$root") | ||||
405 | if $Is_VMS | ||||
406 | && !File::Spec->file_name_is_absolute($root) | ||||
407 | && ($root !~ m/(?<!\^)[\]>]+/); # not already in VMS syntax | ||||
408 | |||||
409 | if ($arg->{safe} && | ||||
410 | ($Is_VMS ? !&VMS::Filespec::candelete($root) | ||||
411 | : !(-l $root || -w $root))) | ||||
412 | { | ||||
413 | print "skipped $root\n" if $arg->{verbose}; | ||||
414 | next ROOT_DIR; | ||||
415 | } | ||||
416 | |||||
417 | my $nperm = $perm & 07777 | 0600; | ||||
418 | if ($Force_Writeable and $nperm != $perm and not chmod $nperm, $root) { | ||||
419 | _error($arg, "cannot make file writeable", $canon); | ||||
420 | } | ||||
421 | print "unlink $canon\n" if $arg->{verbose}; | ||||
422 | # delete all versions under VMS | ||||
423 | for (;;) { | ||||
424 | if (unlink $root) { | ||||
425 | push @{${$arg->{result}}}, $root if $arg->{result}; | ||||
426 | } | ||||
427 | else { | ||||
428 | _error($arg, "cannot unlink file", $canon); | ||||
429 | $Force_Writeable and chmod($perm, $root) or | ||||
430 | _error($arg, sprintf("cannot restore permissions to 0%o",$perm), $canon); | ||||
431 | last; | ||||
432 | } | ||||
433 | ++$count; | ||||
434 | last unless $Is_VMS && lstat $root; | ||||
435 | } | ||||
436 | } | ||||
437 | } | ||||
438 | return $count; | ||||
439 | } | ||||
440 | |||||
441 | sub _slash_lc { | ||||
442 | # fix up slashes and case on MSWin32 so that we can determine that | ||||
443 | # c:\path\to\dir is underneath C:/Path/To | ||||
444 | my $path = shift; | ||||
445 | $path =~ tr{\\}{/}; | ||||
446 | return lc($path); | ||||
447 | } | ||||
448 | |||||
449 | 1 | 37µs | 1; | ||
450 | __END__ | ||||
sub File::Path::CORE:ftdir; # opcode | |||||
# spent 713ms within File::Path::CORE:mkdir which was called 1580 times, avg 452µs/call:
# 1580 times (713ms+0s) by File::Path::_mkpath at line 136, avg 452µs/call |