Re: [REPATCH] Re: [PATCH] Re: [ID 20011030.064] File::Temp tempdir(CLEANUP => 1)...
[p5sagit/p5-mst-13.2.git] / lib / File / Path.pm
CommitLineData
1fc4cb55 1package File::Path;
fed7345c 2
3=head1 NAME
4
8b87c192 5File::Path - create or remove directory trees
fed7345c 6
7=head1 SYNOPSIS
8
8b87c192 9 use File::Path;
fed7345c 10
8b87c192 11 mkpath(['/foo/bar/baz', 'blurfl/quux'], 1, 0711);
12 rmtree(['foo/bar/baz', 'blurfl/quux'], 1, 1);
fed7345c 13
14=head1 DESCRIPTION
15
037c8c09 16The C<mkpath> function provides a convenient way to create directories, even
17if your C<mkdir> kernel call won't create more than one level of directory at
18a time. C<mkpath> takes three arguments:
fed7345c 19
20=over 4
21
22=item *
23
24the name of the path to create, or a reference
25to a list of paths to create,
26
27=item *
28
29a boolean value, which if TRUE will cause C<mkpath>
30to print the name of each directory as it is created
31(defaults to FALSE), and
32
33=item *
34
35the numeric mode to use when creating the directories
36(defaults to 0777)
37
38=back
39
037c8c09 40It returns a list of all directories (including intermediates, determined
41using the Unix '/' separator) created.
fed7345c 42
43Similarly, the C<rmtree> function provides a convenient way to delete a
44subtree from the directory structure, much like the Unix command C<rm -r>.
45C<rmtree> takes three arguments:
46
47=over 4
48
49=item *
50
51the root of the subtree to delete, or a reference to
52a list of roots. All of the files and directories
53below each root, as well as the roots themselves,
567d72c2 54will be deleted.
fed7345c 55
56=item *
57
58a boolean value, which if TRUE will cause C<rmtree> to
748a9306 59print a message each time it examines a file, giving the
60name of the file, and indicating whether it's using C<rmdir>
61or C<unlink> to remove it, or that it's skipping it.
fed7345c 62(defaults to FALSE)
63
64=item *
65
66a boolean value, which if TRUE will cause C<rmtree> to
748a9306 67skip any files to which you do not have delete access
68(if running under VMS) or write access (if running
69under another OS). This will change in the future when
70a criterion for 'delete permission' under OSs other
96e4d5b1 71than VMS is settled. (defaults to FALSE)
fed7345c 72
73=back
74
96e4d5b1 75It returns the number of files successfully deleted. Symlinks are
341bd822 76simply deleted and not followed.
fed7345c 77
96e4d5b1 78B<NOTE:> If the third parameter is not TRUE, C<rmtree> is B<unsecure>
79in the face of failure or interruption. Files and directories which
80were not deleted may be left with permissions reset to allow world
81read and write access. Note also that the occurrence of errors in
82rmtree can be determined I<only> by trapping diagnostic messages
83using C<$SIG{__WARN__}>; it is not apparent from the return value.
84Therefore, you must be extremely careful about using C<rmtree($foo,$bar,0>
85in situations where security is an issue.
86
fed7345c 87=head1 AUTHORS
88
96e4d5b1 89Tim Bunce <F<Tim.Bunce@ig.co.uk>> and
bd3fa61c 90Charles Bailey <F<bailey@newman.upenn.edu>>
fed7345c 91
fed7345c 92=cut
93
3b825e41 94use 5.006;
fed7345c 95use Carp;
037c8c09 96use File::Basename ();
037c8c09 97use Exporter ();
98use strict;
b395063c 99use warnings;
68dc0745 100
7068481f 101our $VERSION = "1.05";
ff21075d 102our @ISA = qw( Exporter );
103our @EXPORT = qw( mkpath rmtree );
fed7345c 104
68dc0745 105my $Is_VMS = $^O eq 'VMS';
ffb9ee5f 106my $Is_MacOS = $^O eq 'MacOS';
037c8c09 107
108# These OSes complain if you want to remove a file that you have no
109# write permission to:
6d697788 110my $force_writeable = ($^O eq 'os2' || $^O eq 'dos' || $^O eq 'MSWin32' ||
fa6a1c44 111 $^O eq 'amigaos' || $^O eq 'MacOS' || $^O eq 'epoc');
748a9306 112
a5f75d66 113sub mkpath {
fed7345c 114 my($paths, $verbose, $mode) = @_;
115 # $paths -- either a path string or ref to list of paths
116 # $verbose -- optional print "mkdir $path" for each directory created
117 # $mode -- optional permissions, defaults to 0777
ffb9ee5f 118 local($")=$Is_MacOS ? ":" : "/";
fed7345c 119 $mode = 0777 unless defined($mode);
120 $paths = [$paths] unless ref $paths;
037c8c09 121 my(@created,$path);
68dc0745 122 foreach $path (@$paths) {
1b1e14d3 123 $path .= '/' if $^O eq 'os2' and $path =~ /^\w:\z/s; # feature of CRT
037c8c09 124 # Logic wants Unix paths, so go with the flow.
e3830a4e 125 if ($Is_VMS) {
126 next if $path eq '/';
127 $path = VMS::Filespec::unixify($path);
128 if ($path =~ m:^(/[^/]+)/?\z:) {
129 $path = $1.'/000000';
c3420933 130 }
491527d0 131 }
e3830a4e 132 next if -d $path;
133 my $parent = File::Basename::dirname($path);
134 unless (-d $parent or $path eq $parent) {
135 push(@created,mkpath($parent, $verbose, $mode));
136 }
037c8c09 137 print "mkdir $path\n" if $verbose;
67e4c828 138 unless (mkdir($path,$mode)) {
c3420933 139 my $e = $!;
140 # allow for another process to have created it meanwhile
141 croak "mkdir $path: $e" unless -d $path;
67e4c828 142 }
037c8c09 143 push(@created, $path);
fed7345c 144 }
145 @created;
146}
147
148sub rmtree {
149 my($roots, $verbose, $safe) = @_;
7301ec2d 150 my(@files);
151 my($count) = 0;
037c8c09 152 $verbose ||= 0;
153 $safe ||= 0;
fed7345c 154
ee79a11f 155 if ( defined($roots) && length($roots) ) {
156 $roots = [$roots] unless ref $roots;
157 }
158 else {
159 carp "No root path(s) specified\n";
160 return 0;
161 }
162
037c8c09 163 my($root);
fed7345c 164 foreach $root (@{$roots}) {
ffb9ee5f 165 if ($Is_MacOS) {
166 $root = ":$root" if $root !~ /:/;
167 $root =~ s#([^:])\z#$1:#;
168 } else {
169 $root =~ s#/\z##;
170 }
7025f710 171 (undef, undef, my $rp) = lstat $root or next;
172 $rp &= 07777; # don't forget setuid, setgid, sticky bits
173 if ( -d _ ) {
037c8c09 174 # notabene: 0777 is for making readable in the first place,
175 # it's also intended to change it to writable in case we have
176 # to recurse in which case we are better than rm -rf for
177 # subtrees with strange permissions
96e4d5b1 178 chmod(0777, ($Is_VMS ? VMS::Filespec::fileify($root) : $root))
037c8c09 179 or carp "Can't make directory $root read+writeable: $!"
180 unless $safe;
181
ff21075d 182 if (opendir my $d, $root) {
7068481f 183 no strict 'refs';
184 if (!defined ${"\cTAINT"} or ${"\cTAINT"}) {
185 # Blindly untaint dir names
186 @files = map { /^(.*)$/s ; $1 } readdir $d;
187 } else {
188 @files = readdir $d;
189 }
ff21075d 190 closedir $d;
191 }
192 else {
193 carp "Can't read $root: $!";
194 @files = ();
195 }
037c8c09 196
197 # Deleting large numbers of files from VMS Files-11 filesystems
198 # is faster if done in reverse ASCIIbetical order
199 @files = reverse @files if $Is_VMS;
1b1e14d3 200 ($root = VMS::Filespec::unixify($root)) =~ s#\.dir\z## if $Is_VMS;
ffb9ee5f 201 if ($Is_MacOS) {
202 @files = map("$root$_", @files);
203 } else {
204 @files = map("$root/$_", grep $_!~/^\.{1,2}\z/s,@files);
205 }
037c8c09 206 $count += rmtree(\@files,$verbose,$safe);
207 if ($safe &&
208 ($Is_VMS ? !&VMS::Filespec::candelete($root) : !-w $root)) {
209 print "skipped $root\n" if $verbose;
210 next;
211 }
212 chmod 0777, $root
213 or carp "Can't make directory $root writeable: $!"
214 if $force_writeable;
215 print "rmdir $root\n" if $verbose;
96e4d5b1 216 if (rmdir $root) {
217 ++$count;
218 }
219 else {
220 carp "Can't remove directory $root: $!";
221 chmod($rp, ($Is_VMS ? VMS::Filespec::fileify($root) : $root))
222 or carp("and can't restore permissions to "
223 . sprintf("0%o",$rp) . "\n");
224 }
037c8c09 225 }
226 else {
227 if ($safe &&
64f6ddac 228 ($Is_VMS ? !&VMS::Filespec::candelete($root)
229 : !(-l $root || -w $root)))
230 {
037c8c09 231 print "skipped $root\n" if $verbose;
232 next;
233 }
234 chmod 0666, $root
235 or carp "Can't make file $root writeable: $!"
236 if $force_writeable;
237 print "unlink $root\n" if $verbose;
238 # delete all versions under VMS
94d4f21c 239 for (;;) {
240 unless (unlink $root) {
96e4d5b1 241 carp "Can't unlink file $root: $!";
242 if ($force_writeable) {
243 chmod $rp, $root
244 or carp("and can't restore permissions to "
245 . sprintf("0%o",$rp) . "\n");
246 }
94d4f21c 247 last;
96e4d5b1 248 }
94d4f21c 249 ++$count;
250 last unless $Is_VMS && lstat $root;
037c8c09 251 }
252 }
fed7345c 253 }
254
255 $count;
256}
257
2581;