change #31246 unconditionally enabled utf8 cache debugging code
[p5sagit/p5-mst-13.2.git] / lib / File / Path.pm
CommitLineData
1fc4cb55 1package File::Path;
fed7345c 2
3=head1 NAME
4
12c2e016 5File::Path - Create or remove directory trees
6
7=head1 VERSION
8
0b3d36bd 9This document describes version 2.00_11 of File::Path, released
102007-09-08.
fed7345c 11
12=head1 SYNOPSIS
13
8b87c192 14 use File::Path;
fed7345c 15
12c2e016 16 # modern
17 mkpath( 'foo/bar/baz', '/zug/zwang', {verbose => 1} );
18
19 rmtree(
20 'foo/bar/baz', '/zug/zwang',
91c4f65e 21 { verbose => 1, error => \my $err_list }
12c2e016 22 );
23
24 # traditional
8b87c192 25 mkpath(['/foo/bar/baz', 'blurfl/quux'], 1, 0711);
26 rmtree(['foo/bar/baz', 'blurfl/quux'], 1, 1);
fed7345c 27
28=head1 DESCRIPTION
29
0b3d36bd 30The C<mkpath> function provides a convenient way to create directories
31of arbitrary depth. Similarly, the C<rmtree> function provides a
32convenient way to delete an entire directory subtree from the
33filesystem, much like the Unix command C<rm -r>.
12c2e016 34
35Both functions may be called in one of two ways, the traditional,
36compatible with code written since the dawn of time, and modern,
37that offers a more flexible and readable idiom. New code should use
38the modern interface.
39
40=head2 FUNCTIONS
41
0b3d36bd 42The modern way of calling C<mkpath> and C<rmtree> is with a list
43of directories to create, or remove, respectively, followed by an
44optional hash reference containing keys to control the
45function's behaviour.
12c2e016 46
47=head3 C<mkpath>
48
0b3d36bd 49The following keys are recognised as parameters to C<mkpath>.
50The function returns the list of files actually created during the
51call.
12c2e016 52
53 my @created = mkpath(
54 qw(/tmp /flub /home/nobody),
55 {verbose => 1, mode => 0750},
56 );
57 print "created $_\n" for @created;
58
59=over 4
60
61=item mode
62
0b3d36bd 63The numeric permissions mode to apply to each created directory
64(defaults to 0777), to be modified by the current C<umask>. If the
65directory already exists (and thus does not need to be created),
66the permissions will not be modified.
67
68C<mask> is recognised as an alias for this parameter.
12c2e016 69
70=item verbose
71
72If present, will cause C<mkpath> to print the name of each directory
73as it is created. By default nothing is printed.
74
75=item error
76
77If present, will be interpreted as a reference to a list, and will
78be used to store any errors that are encountered. See the ERROR
0b3d36bd 79HANDLING section for more information.
12c2e016 80
0b3d36bd 81If this parameter is not used, certain error conditions may raise
82a fatal error that will cause the program will halt, unless trapped
83in an C<eval> block.
12c2e016 84
85=back
86
87=head3 C<rmtree>
88
89=over 4
90
91=item verbose
92
93If present, will cause C<rmtree> to print the name of each file as
94it is unlinked. By default nothing is printed.
95
96=item skip_others
97
0b3d36bd 98When set to a true value, will cause C<rmtree> to skip the files
99for which the process lacks the required privileges needed to delete
100files, such as delete privileges on VMS.
12c2e016 101
102=item keep_root
103
0b3d36bd 104When set to a true value, will cause all files and subdirectories
105to be removed, except the initially specified directories. This comes
106in handy when cleaning out an application's scratch directory.
12c2e016 107
108 rmtree( '/tmp', {keep_root => 1} );
109
110=item result
111
112If present, will be interpreted as a reference to a list, and will
113be used to store the list of all files and directories unlinked
114during the call. If nothing is unlinked, a reference to an empty
115list is returned (rather than C<undef>).
116
117 rmtree( '/tmp', {result => \my $list} );
118 print "unlinked $_\n" for @$list;
119
0b3d36bd 120This is a useful alternative to the C<verbose> key.
121
12c2e016 122=item error
123
124If present, will be interpreted as a reference to a list,
125and will be used to store any errors that are encountered.
0b3d36bd 126See the ERROR HANDLING section for more information.
12c2e016 127
0b3d36bd 128Removing things is a much more dangerous proposition than
129creating things. As such, there are certain conditions that
130C<rmtree> may encounter that are so dangerous that the only
131sane action left is to kill the program.
132
133Use C<error> to trap all that is reasonable (problems with
134permissions and the like), and let it die if things get out
135of hand. This is the safest course of action.
12c2e016 136
137=back
138
139=head2 TRADITIONAL INTERFACE
140
0b3d36bd 141The old interfaces of C<mkpath> and C<rmtree> take a reference to
142a list of directories (to create or remove), followed by a series
143of positional, numeric, modal parameters that control their behaviour.
144
145This design made it difficult to add additional functionality, as
146well as posed the problem of what to do when the calling code only
147needs to set the last parameter. Even though the code doesn't care
148how the initial positional parameters are set, the programmer is
149forced to learn what the defaults are, and specify them.
12c2e016 150
0b3d36bd 151Worse, if it turns out in the future that it would make more sense
152to change the default behaviour of the first parameter (for example,
153to avoid a security vulnerability), all existing code will remain
154hard-wired to the wrong defaults.
12c2e016 155
0b3d36bd 156Finally, a series of numeric parameters are much less self-documenting
157in terms of communicating to the reader what the code is doing. Named
158parameters do not have this problem.
159
160In the traditional API, C<mkpath> takes three arguments:
fed7345c 161
162=over 4
163
164=item *
165
0b3d36bd 166The name of the path to create, or a reference to a list of paths
167to create,
fed7345c 168
169=item *
170
0b3d36bd 171a boolean value, which if TRUE will cause C<mkpath> to print the
172name of each directory as it is created (defaults to FALSE), and
fed7345c 173
174=item *
175
0b3d36bd 176the numeric mode to use when creating the directories (defaults to
1770777), to be modified by the current umask.
fed7345c 178
179=back
180
037c8c09 181It returns a list of all directories (including intermediates, determined
cc61921f 182using the Unix '/' separator) created. In scalar context it returns
183the number of directories created.
fed7345c 184
070ed461 185If a system error prevents a directory from being created, then the
99c4c5e8 186C<mkpath> function throws a fatal error with C<Carp::croak>. This error
187can be trapped with an C<eval> block:
070ed461 188
189 eval { mkpath($dir) };
190 if ($@) {
191 print "Couldn't create $dir: $@";
192 }
193
0b3d36bd 194In the traditional API, C<rmtree> takes three arguments:
fed7345c 195
196=over 4
197
198=item *
199
0b3d36bd 200the root of the subtree to delete, or a reference to a list of
201roots. All of the files and directories below each root, as well
202as the roots themselves, will be deleted. If you want to keep
203the roots themselves, you must use the modern API.
fed7345c 204
205=item *
206
0b3d36bd 207a boolean value, which if TRUE will cause C<rmtree> to print a
208message each time it examines a file, giving the name of the file,
209and indicating whether it's using C<rmdir> or C<unlink> to remove
210it, or that it's skipping it. (defaults to FALSE)
fed7345c 211
212=item *
213
0b3d36bd 214a boolean value, which if TRUE will cause C<rmtree> to skip any
215files to which you do not have delete access (if running under VMS)
216or write access (if running under another OS). This will change
217in the future when a criterion for 'delete permission' under OSs
218other than VMS is settled. (defaults to FALSE)
fed7345c 219
220=back
221
cc61921f 222It returns the number of files, directories and symlinks successfully
223deleted. Symlinks are simply deleted and not followed.
fed7345c 224
12c2e016 225Note also that the occurrence of errors in C<rmtree> using the
226traditional interface can be determined I<only> by trapping diagnostic
227messages using C<$SIG{__WARN__}>; it is not apparent from the return
228value. (The modern interface may use the C<error> parameter to
0b3d36bd 229record any problems encountered).
12c2e016 230
231=head2 ERROR HANDLING
232
233If C<mkpath> or C<rmtree> encounter an error, a diagnostic message
234will be printed to C<STDERR> via C<carp> (for non-fatal errors),
235or via C<croak> (for fatal errors).
236
237If this behaviour is not desirable, the C<error> attribute may be
238used to hold a reference to a variable, which will be used to store
239the diagnostics. The result is a reference to a list of hash
240references. For each hash reference, the key is the name of the
241file, and the value is the error message (usually the contents of
242C<$!>). An example usage looks like:
243
244 rmpath( 'foo/bar', 'bar/rat', {error => \my $err} );
245 for my $diag (@$err) {
246 my ($file, $message) = each %$diag;
247 print "problem unlinking $file: $message\n";
248 }
249
250If no errors are encountered, C<$err> will point to an empty list
251(thus there is no need to test for C<undef>). If a general error
252is encountered (for instance, C<rmtree> attempts to remove a directory
253tree that does not exist), the diagnostic key will be empty, only
254the value will be set:
255
256 rmpath( '/no/such/path', {error => \my $err} );
257 for my $diag (@$err) {
258 my ($file, $message) = each %$diag;
259 if ($file eq '') {
260 print "general error: $message\n";
261 }
262 }
263
264=head2 NOTES
265
0b3d36bd 266C<File::Path> blindly exports C<mkpath> and C<rmtree> into the
267current namespace. These days, this is considered bad style, but
268to change it now would break too much code. Nonetheless, you are
269invited to specify what it is you are expecting to use:
270
271 use File::Path 'rmtree';
272
12c2e016 273=head3 HEURISTICS
274
275The functions detect (as far as possible) which way they are being
276called and will act appropriately. It is important to remember that
277the heuristic for detecting the old style is either the presence
278of an array reference, or two or three parameters total and second
279and third parameters are numeric. Hence...
280
0b3d36bd 281 mkpath 486, 487, 488;
12c2e016 282
283... will not assume the modern style and create three directories, rather
284it will create one directory verbosely, setting the permission to
2850750 (488 being the decimal equivalent of octal 750). Here, old
286style trumps new. It must, for backwards compatibility reasons.
e2ba98a1 287
12c2e016 288If you want to ensure there is absolutely no ambiguity about which
289way the function will behave, make sure the first parameter is a
290reference to a one-element list, to force the old style interpretation:
e2ba98a1 291
0b3d36bd 292 mkpath [486], 487, 488;
12c2e016 293
294and get only one directory created. Or add a reference to an empty
295parameter hash, to force the new style:
296
0b3d36bd 297 mkpath 486, 487, 488, {};
12c2e016 298
299... and hence create the three directories. If the empty hash
300reference seems a little strange to your eyes, or you suspect a
301subsequent programmer might I<helpfully> optimise it away, you
302can add a parameter set to a default value:
303
0b3d36bd 304 mkpath 486, 487, 488, {verbose => 0};
12c2e016 305
0b3d36bd 306=head3 SECURITY CONSIDERATIONS
12c2e016 307
0b3d36bd 308There were race conditions 1.x implementations of File::Path's
309C<rmtree> function (although sometimes patched depending on the OS
310distribution or platform). The 2.0 version contains code to avoid the
311problem mentioned in CVE-2002-0435.
12c2e016 312
0b3d36bd 313See the following pages for more information:
12c2e016 314
0b3d36bd 315 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=286905
316 http://www.nntp.perl.org/group/perl.perl5.porters/2005/01/msg97623.html
317 http://www.debian.org/security/2005/dsa-696
12c2e016 318
0b3d36bd 319Additionally, unless the C<skip_others> parameter is set (or the
320third parameter in the traditional inferface is TRUE), should a
321C<rmtree> be interrupted, files that were originally in read-only
322mode may now have their permissions set to a read-write (or "delete
323OK") mode.
96e4d5b1 324
b8d5f521 325=head1 DIAGNOSTICS
326
0b3d36bd 327FATAL errors will cause the program to halt (C<croak>), since the
328problem is so severe that it would be dangerous to continue. (This
329can always be trapped with C<eval>, but it's not a good idea. Under
330the circumstances, dying is the best thing to do).
331
332SEVERE errors may be trapped using the modern interface. If the
333they are not trapped, or the old interface is used, such an error
334will cause the program will halt.
335
336All other errors may be trapped using the modern interface, otherwise
337they will be C<carp>ed about. Program execution will not be halted.
338
b8d5f521 339=over 4
340
0b3d36bd 341=item mkdir [ppath]: [errmsg] (SEVERE)
342
343C<mkpath> was unable to create the path. Probably some sort of
344permissions error at the point of departure, or insufficient resources
345(such as free inodes on Unix).
346
347=item No root path(s) specified
348
349C<mkpath> was not given any paths to create. This message is only
350emitted if the routine is called with the traditional interface.
351The modern interface will remain silent if given nothing to do.
352
353=item No such file or directory
354
355On Windows, if C<mkpath> gives you this warning, it may mean that
356you have exceeded your filesystem's maximum path length.
357
358=item cannot fetch initial working directory: [errmsg]
359
360C<rmtree> attempted to determine the initial directory by calling
361C<Cwd::getcwd>, but the call failed for some reason. No attempt
362will be made to delete anything.
363
364=item cannot stat initial working directory: [errmsg]
365
366C<rmtree> attempted to stat the initial directory (after having
367successfully obtained its name via C<getcwd>), however, the call
368failed for some reason. No attempt will be made to delete anything.
369
370=item cannot chdir to [dir]: [errmsg]
371
372C<rmtree> attempted to set the working directory in order to
373begin deleting the objects therein, but was unsuccessful. This is
374usually a permissions issue. The routine will continue to delete
375other things, but this directory will be left intact.
376
377=item directory [dir] changed before chdir, expected dev=[n] inode=[n], actual dev=[n] ino=[n], aborting. (FATAL)
378
379C<rmtree> recorded the device and inode of a directory, and then
380moved into it. It then performed a C<stat> on the current directory
381and detected that the device and inode were no longer the same. As
382this is at the heart of the race condition problem, the program
383will die at this point.
384
385=item cannot make directory [dir] read+writeable: [errmsg]
386
387C<rmtree> attempted to change the permissions on the current directory
388to ensure that subsequent unlinkings would not run into problems,
389but was unable to do so. The permissions remain as they were, and
390the program will carry on, doing the best it can.
391
392=item cannot read [dir]: [errmsg]
393
394C<rmtree> tried to read the contents of the directory in order
395to acquire the names of the directory entries to be unlinked, but
396was unsuccessful. This is usually a permissions issue. The
397program will continue, but the files in this directory will remain
398after the call.
399
400=item cannot reset chmod [dir]: [errmsg]
401
402C<rmtree>, after having deleted everything in a directory, attempted
403to restore its permissions to the original state but failed. The
404directory may wind up being left behind.
405
406=item cannot chdir to [parent-dir] from [child-dir]: [errmsg], aborting. (FATAL)
407
408C<rmtree>, after having deleted everything and restored the permissions
409of a directory, was unable to chdir back to the parent. This is usually
410a sign that something evil this way comes.
411
412=item cannot stat prior working directory [dir]: [errmsg], aborting. (FATAL)
413
414C<rmtree> was unable to stat the parent directory after have returned
415from the child. Since there is no way of knowing if we returned to
416where we think we should be (by comparing device and inode) the only
417way out is to C<croak>.
418
419=item previous directory [parent-dir] changed before entering [child-dir], expected dev=[n] inode=[n], actual dev=[n] ino=[n], aborting. (FATAL)
420
421When C<rmtree> returned from deleting files in a child directory, a
422check revealed that the parent directory it returned to wasn't the one
423it started out from. This is considered a sign of malicious activity.
424
425=item cannot make directory [dir] writeable: [errmsg]
426
427Just before removing a directory (after having successfully removed
428everything it contained), C<rmtree> attempted to set the permissions
429on the directory to ensure it could be removed and failed. Program
430execution continues, but the directory may possibly not be deleted.
431
432=item cannot remove directory [dir]: [errmsg]
433
434C<rmtree> attempted to remove a directory, but failed. This may because
435some objects that were unable to be removed remain in the directory, or
436a permissions issue. The directory will be left behind.
437
438=item cannot restore permissions of [dir] to [0nnn]: [errmsg]
439
440After having failed to remove a directory, C<rmtree> was unable to
441restore its permissions from a permissive state back to a possibly
442more restrictive setting. (Permissions given in octal).
443
444=item cannot make file [file] writeable: [errmsg]
445
446C<rmtree> attempted to force the permissions of a file to ensure it
447could be deleted, but failed to do so. It will, however, still attempt
448to unlink the file.
449
450=item cannot unlink file [file]: [errmsg]
b8d5f521 451
0b3d36bd 452C<rmtree> failed to remove a file. Probably a permissions issue.
453
454=item cannot restore permissions of [file] to [0nnn]: [errmsg]
455
456After having failed to remove a file, C<rmtree> was also unable
457to restore the permissions on the file to a possibily less permissive
458setting. (Permissions given in octal).
b8d5f521 459
460=back
461
12c2e016 462=head1 SEE ALSO
463
464=over 4
465
466=item *
467
468L<Find::File::Rule>
469
0b3d36bd 470When removing directory trees, if you want to examine each file to
471decide whether to delete it (and possibly leaving large swathes
472alone), F<File::Find::Rule> offers a convenient and flexible approach
473to examining directory trees.
12c2e016 474
475=back
476
477=head1 BUGS
478
479Please report all bugs on the RT queue:
480
481L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=File-Path>
482
0b3d36bd 483=head1 ACKNOWLEDGEMENTS
fed7345c 484
0b3d36bd 485Paul Szabo identified the race condition orignially, and Brendan
486O'Dea wrote an implementation for Debian that addressed the problem.
487That code was used as a basis for the current code. Their efforts
488are greatly appreciated.
12c2e016 489
0b3d36bd 490=head1 AUTHORS
491
492Tim Bunce <F<Tim.Bunce@ig.co.uk>> and Charles Bailey
493<F<bailey@newman.upenn.edu>>. Currently maintained by David Landgren
494<F<david@landgren.net>>.
12c2e016 495
496=head1 COPYRIGHT
497
498This module is copyright (C) Charles Bailey, Tim Bunce and
499David Landgren 1995-2007. All rights reserved.
500
501=head1 LICENSE
502
503This library is free software; you can redistribute it and/or modify
504it under the same terms as Perl itself.
fed7345c 505
fed7345c 506=cut
507
12c2e016 508use 5.005_04;
037c8c09 509use strict;
68dc0745 510
0b3d36bd 511use Cwd 'getcwd';
12c2e016 512use File::Basename ();
513use File::Spec ();
0b3d36bd 514
12c2e016 515BEGIN {
91c4f65e 516 if ($] < 5.006) {
12c2e016 517 # can't say 'opendir my $dh, $dirname'
518 # need to initialise $dh
519 eval "use Symbol";
520 }
521}
522
523use Exporter ();
524use vars qw($VERSION @ISA @EXPORT);
0b3d36bd 525$VERSION = '2.00_11';
12c2e016 526@ISA = qw(Exporter);
527@EXPORT = qw(mkpath rmtree);
fed7345c 528
68dc0745 529my $Is_VMS = $^O eq 'VMS';
ffb9ee5f 530my $Is_MacOS = $^O eq 'MacOS';
037c8c09 531
532# These OSes complain if you want to remove a file that you have no
533# write permission to:
12c2e016 534my $Force_Writeable = ($^O eq 'os2' || $^O eq 'dos' || $^O eq 'MSWin32' ||
fa6a1c44 535 $^O eq 'amigaos' || $^O eq 'MacOS' || $^O eq 'epoc');
748a9306 536
12c2e016 537sub _carp {
8878f897 538 require Carp;
539 goto &Carp::carp;
540}
541
12c2e016 542sub _croak {
8878f897 543 require Carp;
544 goto &Carp::croak;
545}
546
0b3d36bd 547sub _error {
548 my $arg = shift;
549 my $message = shift;
550 my $object = shift;
551
552 if ($arg->{error}) {
553 $object = '' unless defined $object;
554 push @{${$arg->{error}}}, {$object => "$message: $!"};
555 }
556 else {
557 _carp(defined($object) ? "$message for $object: $!" : "$message: $!");
558 }
559}
560
a5f75d66 561sub mkpath {
cd117d8b 562 my $old_style = (
3376a30f 563 UNIVERSAL::isa($_[0],'ARRAY')
b92ffa59 564 or (@_ == 2 and (defined $_[1] ? $_[1] =~ /\A\d+\z/ : 1))
565 or (@_ == 3
566 and (defined $_[1] ? $_[1] =~ /\A\d+\z/ : 1)
567 and (defined $_[2] ? $_[2] =~ /\A\d+\z/ : 1)
568 )
cd117d8b 569 ) ? 1 : 0;
12c2e016 570
571 my $arg;
572 my $paths;
573
cd117d8b 574 if ($old_style) {
575 my ($verbose, $mode);
576 ($paths, $verbose, $mode) = @_;
577 $paths = [$paths] unless UNIVERSAL::isa($paths,'ARRAY');
578 $arg->{verbose} = defined $verbose ? $verbose : 0;
579 $arg->{mode} = defined $mode ? $mode : 0777;
580 }
581 else {
3376a30f 582 if (@_ > 0 and UNIVERSAL::isa($_[-1], 'HASH')) {
12c2e016 583 $arg = pop @_;
584 exists $arg->{mask} and $arg->{mode} = delete $arg->{mask};
585 $arg->{mode} = 0777 unless exists $arg->{mode};
586 ${$arg->{error}} = [] if exists $arg->{error};
587 }
588 else {
589 @{$arg}{qw(verbose mode)} = (0, 0777);
590 }
591 $paths = [@_];
592 }
12c2e016 593 return _mkpath($arg, $paths);
594}
595
596sub _mkpath {
597 my $arg = shift;
598 my $paths = shift;
599
ffb9ee5f 600 local($")=$Is_MacOS ? ":" : "/";
037c8c09 601 my(@created,$path);
68dc0745 602 foreach $path (@$paths) {
12c2e016 603 next unless length($path);
1b1e14d3 604 $path .= '/' if $^O eq 'os2' and $path =~ /^\w:\z/s; # feature of CRT
037c8c09 605 # Logic wants Unix paths, so go with the flow.
e3830a4e 606 if ($Is_VMS) {
607 next if $path eq '/';
608 $path = VMS::Filespec::unixify($path);
491527d0 609 }
e3830a4e 610 next if -d $path;
611 my $parent = File::Basename::dirname($path);
612 unless (-d $parent or $path eq $parent) {
12c2e016 613 push(@created,_mkpath($arg, [$parent]));
614 }
615 print "mkdir $path\n" if $arg->{verbose};
616 if (mkdir($path,$arg->{mode})) {
617 push(@created, $path);
dde45d8e 618 }
12c2e016 619 else {
620 my $save_bang = $!;
621 my ($e, $e1) = ($save_bang, $^E);
dde45d8e 622 $e .= "; $e1" if $e ne $e1;
c3420933 623 # allow for another process to have created it meanwhile
12c2e016 624 if (!-d $path) {
625 $! = $save_bang;
626 if ($arg->{error}) {
627 push @{${$arg->{error}}}, {$path => $e};
628 }
629 else {
630 _croak("mkdir $path: $e");
631 }
67e4c828 632 }
fed7345c 633 }
12c2e016 634 }
635 return @created;
fed7345c 636}
637
638sub rmtree {
cd117d8b 639 my $old_style = (
3376a30f 640 UNIVERSAL::isa($_[0],'ARRAY')
b92ffa59 641 or (@_ == 2 and (defined $_[1] ? $_[1] =~ /\A\d+\z/ : 1))
642 or (@_ == 3
643 and (defined $_[1] ? $_[1] =~ /\A\d+\z/ : 1)
644 and (defined $_[2] ? $_[2] =~ /\A\d+\z/ : 1)
645 )
cd117d8b 646 ) ? 1 : 0;
12c2e016 647
648 my $arg;
649 my $paths;
650
cd117d8b 651 if ($old_style) {
12c2e016 652 my ($verbose, $safe);
653 ($paths, $verbose, $safe) = @_;
12c2e016 654 $arg->{verbose} = defined $verbose ? $verbose : 0;
655 $arg->{safe} = defined $safe ? $safe : 0;
fed7345c 656
3376a30f 657 if (defined($paths) and length($paths)) {
658 $paths = [$paths] unless UNIVERSAL::isa($paths,'ARRAY');
659 }
660 else {
cd117d8b 661 _carp ("No root path(s) specified\n");
662 return 0;
663 }
ee79a11f 664 }
665 else {
cd117d8b 666 if (@_ > 0 and UNIVERSAL::isa($_[-1],'HASH')) {
667 $arg = pop @_;
668 ${$arg->{error}} = [] if exists $arg->{error};
669 ${$arg->{result}} = [] if exists $arg->{result};
12c2e016 670 }
cd117d8b 671 else {
672 @{$arg}{qw(verbose safe)} = (0, 0);
ee79a11f 673 }
cd117d8b 674 $paths = [@_];
3376a30f 675 }
0b3d36bd 676
677 $arg->{prefix} = '';
678 $arg->{depth} = 0;
679
680 $arg->{cwd} = getcwd() or do {
681 _error($arg, "cannot fetch initial working directory");
682 return 0;
683 };
684 for ($arg->{cwd}) { /\A(.*)\Z/; $_ = $1 } # untaint
685
686 @{$arg}{qw(device inode)} = (stat $arg->{cwd})[0,1] or do {
687 _error($arg, "cannot stat initial working directory", $arg->{cwd});
688 return 0;
689 };
690
12c2e016 691 return _rmtree($arg, $paths);
692}
ee79a11f 693
12c2e016 694sub _rmtree {
695 my $arg = shift;
696 my $paths = shift;
0b3d36bd 697
698 my $count = 0;
699 my $curdir = File::Spec->curdir();
700 my $updir = File::Spec->updir();
701
12c2e016 702 my (@files, $root);
cd117d8b 703 foreach $root (@$paths) {
ffb9ee5f 704 if ($Is_MacOS) {
0b3d36bd 705 $root = ":$root" unless $root =~ /:/;
706 $root .= ":" unless $root =~ /:\z/;
12c2e016 707 }
708 else {
0b3d36bd 709 $root =~ s{/\z}{};
ffb9ee5f 710 }
0b3d36bd 711 my ($ldev, $lino, $perm) = (lstat $root)[0,1,2] or next;
712
713 # since we chdir into each directory, it may not be obvious
714 # to figure out where we are if we generate a message about
715 # a file name. We therefore construct a semi-canonical
716 # filename, anchored from the directory being unlinked (as
717 # opposed to being truly canonical, anchored from the root (/).
718
719 my $canon = $arg->{prefix}
720 ? File::Spec->catdir($arg->{prefix}, $root)
721 : $root
722 ;
723
7025f710 724 if ( -d _ ) {
0b3d36bd 725 if (!chdir($root)) {
726 # see if we can escalate privileges to get in
727 # (e.g. funny protection mask such as -w- instead of rwx)
728 $perm &= 07777;
729 my $nperm = $perm | 0700;
730 if (!($arg->{safe} or $nperm == $perm or chmod($nperm, $root))) {
731 _error($arg, "cannot make child directory read-write-exec", $canon);
732 next;
733 }
734 elsif (!chdir($root)) {
735 _error($arg, "cannot chdir to child", $canon);
736 next;
737 }
738 }
739
740 my ($device, $inode, $perm) = (stat $curdir)[0,1,2] or do {
741 _error($arg, "cannot stat current working directory", $canon);
742 return $count;
743 };
744
745 ($ldev eq $device and $lino eq $inode)
746 or _croak("directory $canon changed before chdir, expected dev=$ldev inode=$lino, actual dev=$device ino=$inode, aborting.");
747
748 $perm &= 07777; # don't forget setuid, setgid, sticky bits
749 my $nperm = $perm | 0700;
750
e2ba98a1 751 # notabene: 0700 is for making readable in the first place,
037c8c09 752 # it's also intended to change it to writable in case we have
753 # to recurse in which case we are better than rm -rf for
754 # subtrees with strange permissions
0b3d36bd 755
756 if (!($arg->{safe} or $nperm == $perm or chmod($nperm, $curdir))) {
757 _error($arg, "cannot make directory read+writeable", $canon);
758 $nperm = $perm;
12c2e016 759 }
760
761 my $d;
762 $d = gensym() if $] < 5.006;
0b3d36bd 763 if (!opendir $d, $curdir) {
764 _error($arg, "cannot opendir", $canon);
12c2e016 765 @files = ();
766 }
767 else {
7068481f 768 no strict 'refs';
769 if (!defined ${"\cTAINT"} or ${"\cTAINT"}) {
12c2e016 770 # Blindly untaint dir names if taint mode is
771 # active, or any perl < 5.006
772 @files = map { /\A(.*)\z/s; $1 } readdir $d;
773 }
774 else {
7068481f 775 @files = readdir $d;
776 }
ff21075d 777 closedir $d;
778 }
037c8c09 779
463ea4b9 780 if ($Is_VMS) {
0b3d36bd 781 # Deleting large numbers of files from VMS Files-11
782 # filesystems is faster if done in reverse ASCIIbetical order.
783 # include '.' to '.;' from blead patch #31775
784 @files = map {$_ eq '.' ? '.;' : $_} reverse @files;
785 ($root = VMS::Filespec::unixify($root)) =~ s/\.dir\z//;
786 }
787 @files = grep {$_ ne $updir and $_ ne $curdir} @files;
788
789 if (@files) {
790 # remove the contained files before the directory itself
791 my $narg = {%$arg};
792 @{$narg}{qw(device inode cwd prefix depth)}
793 = ($device, $inode, $updir, $canon, $arg->{depth}+1);
794 $count += _rmtree($narg, \@files);
795 }
796
797 # restore directory permissions of required now (in case the rmdir
798 # below fails), while we are still in the directory and may do so
799 # without a race via '.'
800 if ($nperm != $perm and not chmod($perm, $curdir)) {
801 _error($arg, "cannot reset chmod", $canon);
12c2e016 802 }
0b3d36bd 803
804 # don't leave the client code in an unexpected directory
805 chdir($arg->{cwd})
806 or _croak("cannot chdir to $arg->{cwd} from $canon: $!, aborting.");
807
808 # ensure that a chdir upwards didn't take us somewhere other
809 # than we expected (see CVE-2002-0435)
810 ($device, $inode) = (stat $curdir)[0,1]
811 or _croak("cannot stat prior working directory $arg->{cwd}: $!, aborting.");
812
813 ($arg->{device} eq $device and $arg->{inode} eq $inode)
814 or _croak("previous directory $arg->{cwd} changed before entering $canon, expected dev=$ldev inode=$lino, actual dev=$device ino=$inode, aborting.");
815
12c2e016 816 if ($arg->{depth} or !$arg->{keep_root}) {
817 if ($arg->{safe} &&
037c8c09 818 ($Is_VMS ? !&VMS::Filespec::candelete($root) : !-w $root)) {
12c2e016 819 print "skipped $root\n" if $arg->{verbose};
037c8c09 820 next;
821 }
0b3d36bd 822 if (!chmod $perm | 0700, $root) {
12c2e016 823 if ($Force_Writeable) {
0b3d36bd 824 _error($arg, "cannot make directory writeable", $canon);
12c2e016 825 }
826 }
827 print "rmdir $root\n" if $arg->{verbose};
96e4d5b1 828 if (rmdir $root) {
12c2e016 829 push @{${$arg->{result}}}, $root if $arg->{result};
96e4d5b1 830 ++$count;
831 }
832 else {
0b3d36bd 833 _error($arg, "cannot remove directory", $canon);
834 if (!chmod($perm, ($Is_VMS ? VMS::Filespec::fileify($root) : $root))
12c2e016 835 ) {
0b3d36bd 836 _error($arg, sprintf("cannot restore permissions to 0%o",$perm), $canon);
12c2e016 837 }
838 }
839 }
840 }
841 else {
0b3d36bd 842 # not a directory
12c2e016 843 if ($arg->{safe} &&
64f6ddac 844 ($Is_VMS ? !&VMS::Filespec::candelete($root)
845 : !(-l $root || -w $root)))
846 {
12c2e016 847 print "skipped $root\n" if $arg->{verbose};
037c8c09 848 next;
849 }
0b3d36bd 850
851 my $nperm = $perm & 07777 | 0600;
852 if ($nperm != $perm and not chmod $nperm, $root) {
12c2e016 853 if ($Force_Writeable) {
0b3d36bd 854 _error($arg, "cannot make file writeable", $canon);
12c2e016 855 }
856 }
0b3d36bd 857 print "unlink $canon\n" if $arg->{verbose};
037c8c09 858 # delete all versions under VMS
94d4f21c 859 for (;;) {
12c2e016 860 if (unlink $root) {
861 push @{${$arg->{result}}}, $root if $arg->{result};
862 }
863 else {
0b3d36bd 864 _error($arg, "cannot unlink file", $canon);
865 $Force_Writeable and chmod($perm, $root) or
866 _error($arg, sprintf("cannot restore permissions to 0%o",$perm), $canon);
94d4f21c 867 last;
96e4d5b1 868 }
94d4f21c 869 ++$count;
870 last unless $Is_VMS && lstat $root;
037c8c09 871 }
872 }
fed7345c 873 }
874
12c2e016 875 return $count;
fed7345c 876}
877
8781;