Gooder English
[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
e2ba98a1 36(defaults to 0777), to be modified by the current umask.
fed7345c 37
38=back
39
037c8c09 40It returns a list of all directories (including intermediates, determined
cc61921f 41using the Unix '/' separator) created. In scalar context it returns
42the number of directories created.
fed7345c 43
070ed461 44If a system error prevents a directory from being created, then the
99c4c5e8 45C<mkpath> function throws a fatal error with C<Carp::croak>. This error
46can be trapped with an C<eval> block:
070ed461 47
48 eval { mkpath($dir) };
49 if ($@) {
50 print "Couldn't create $dir: $@";
51 }
52
fed7345c 53Similarly, the C<rmtree> function provides a convenient way to delete a
54subtree from the directory structure, much like the Unix command C<rm -r>.
55C<rmtree> takes three arguments:
56
57=over 4
58
59=item *
60
61the root of the subtree to delete, or a reference to
62a list of roots. All of the files and directories
63below each root, as well as the roots themselves,
567d72c2 64will be deleted.
fed7345c 65
66=item *
67
68a boolean value, which if TRUE will cause C<rmtree> to
748a9306 69print a message each time it examines a file, giving the
70name of the file, and indicating whether it's using C<rmdir>
71or C<unlink> to remove it, or that it's skipping it.
fed7345c 72(defaults to FALSE)
73
74=item *
75
76a boolean value, which if TRUE will cause C<rmtree> to
748a9306 77skip any files to which you do not have delete access
78(if running under VMS) or write access (if running
79under another OS). This will change in the future when
80a criterion for 'delete permission' under OSs other
96e4d5b1 81than VMS is settled. (defaults to FALSE)
fed7345c 82
83=back
84
cc61921f 85It returns the number of files, directories and symlinks successfully
86deleted. Symlinks are simply deleted and not followed.
fed7345c 87
e2ba98a1 88B<NOTE:> There are race conditions internal to the implementation of
89C<rmtree> making it unsafe to use on directory trees which may be
90altered or moved while C<rmtree> is running, and in particular on any
91directory trees with any path components or subdirectories potentially
92writable by untrusted users.
93
94Additionally, if the third parameter is not TRUE and C<rmtree> is
95interrupted, it may leave files and directories with permissions altered
96to allow deletion (and older versions of this module would even set
97files and directories to world-read/writable!)
98
99Note also that the occurrence of errors in C<rmtree> can be determined I<only>
100by trapping diagnostic messages using C<$SIG{__WARN__}>; it is not apparent
101from the return value.
96e4d5b1 102
b8d5f521 103=head1 DIAGNOSTICS
104
105=over 4
106
107=item *
108
109On Windows, if C<mkpath> gives you the warning: B<No such file or
110directory>, this may mean that you've exceeded your filesystem's
111maximum path length.
112
113=back
114
fed7345c 115=head1 AUTHORS
116
96e4d5b1 117Tim Bunce <F<Tim.Bunce@ig.co.uk>> and
bd3fa61c 118Charles Bailey <F<bailey@newman.upenn.edu>>
fed7345c 119
fed7345c 120=cut
121
3b825e41 122use 5.006;
037c8c09 123use File::Basename ();
037c8c09 124use Exporter ();
125use strict;
b395063c 126use warnings;
68dc0745 127
dde45d8e 128our $VERSION = "1.09";
ff21075d 129our @ISA = qw( Exporter );
130our @EXPORT = qw( mkpath rmtree );
fed7345c 131
68dc0745 132my $Is_VMS = $^O eq 'VMS';
ffb9ee5f 133my $Is_MacOS = $^O eq 'MacOS';
037c8c09 134
135# These OSes complain if you want to remove a file that you have no
136# write permission to:
6d697788 137my $force_writeable = ($^O eq 'os2' || $^O eq 'dos' || $^O eq 'MSWin32' ||
fa6a1c44 138 $^O eq 'amigaos' || $^O eq 'MacOS' || $^O eq 'epoc');
748a9306 139
8878f897 140sub carp {
141 require Carp;
142 goto &Carp::carp;
143}
144
145sub croak {
146 require Carp;
147 goto &Carp::croak;
148}
149
a5f75d66 150sub mkpath {
fed7345c 151 my($paths, $verbose, $mode) = @_;
152 # $paths -- either a path string or ref to list of paths
153 # $verbose -- optional print "mkdir $path" for each directory created
154 # $mode -- optional permissions, defaults to 0777
ffb9ee5f 155 local($")=$Is_MacOS ? ":" : "/";
fed7345c 156 $mode = 0777 unless defined($mode);
157 $paths = [$paths] unless ref $paths;
037c8c09 158 my(@created,$path);
68dc0745 159 foreach $path (@$paths) {
1b1e14d3 160 $path .= '/' if $^O eq 'os2' and $path =~ /^\w:\z/s; # feature of CRT
037c8c09 161 # Logic wants Unix paths, so go with the flow.
e3830a4e 162 if ($Is_VMS) {
163 next if $path eq '/';
164 $path = VMS::Filespec::unixify($path);
491527d0 165 }
e3830a4e 166 next if -d $path;
167 my $parent = File::Basename::dirname($path);
168 unless (-d $parent or $path eq $parent) {
169 push(@created,mkpath($parent, $verbose, $mode));
dde45d8e 170 }
037c8c09 171 print "mkdir $path\n" if $verbose;
67e4c828 172 unless (mkdir($path,$mode)) {
dde45d8e 173 my ($e, $e1) = ($!, $^E);
174 $e .= "; $e1" if $e ne $e1;
c3420933 175 # allow for another process to have created it meanwhile
36beb999 176 $! = $e, croak ("mkdir $path: $e") unless -d $path;
67e4c828 177 }
037c8c09 178 push(@created, $path);
fed7345c 179 }
180 @created;
181}
182
183sub rmtree {
184 my($roots, $verbose, $safe) = @_;
7301ec2d 185 my(@files);
186 my($count) = 0;
037c8c09 187 $verbose ||= 0;
188 $safe ||= 0;
fed7345c 189
ee79a11f 190 if ( defined($roots) && length($roots) ) {
191 $roots = [$roots] unless ref $roots;
192 }
193 else {
8878f897 194 carp ("No root path(s) specified\n");
ee79a11f 195 return 0;
196 }
197
037c8c09 198 my($root);
fed7345c 199 foreach $root (@{$roots}) {
ffb9ee5f 200 if ($Is_MacOS) {
201 $root = ":$root" if $root !~ /:/;
202 $root =~ s#([^:])\z#$1:#;
203 } else {
204 $root =~ s#/\z##;
205 }
7025f710 206 (undef, undef, my $rp) = lstat $root or next;
207 $rp &= 07777; # don't forget setuid, setgid, sticky bits
208 if ( -d _ ) {
e2ba98a1 209 # notabene: 0700 is for making readable in the first place,
037c8c09 210 # it's also intended to change it to writable in case we have
211 # to recurse in which case we are better than rm -rf for
212 # subtrees with strange permissions
e2ba98a1 213 chmod($rp | 0700, ($Is_VMS ? VMS::Filespec::fileify($root) : $root))
8878f897 214 or carp ("Can't make directory $root read+writeable: $!")
037c8c09 215 unless $safe;
216
ff21075d 217 if (opendir my $d, $root) {
7068481f 218 no strict 'refs';
219 if (!defined ${"\cTAINT"} or ${"\cTAINT"}) {
220 # Blindly untaint dir names
221 @files = map { /^(.*)$/s ; $1 } readdir $d;
222 } else {
223 @files = readdir $d;
224 }
ff21075d 225 closedir $d;
226 }
227 else {
8878f897 228 carp ("Can't read $root: $!");
ff21075d 229 @files = ();
230 }
037c8c09 231
232 # Deleting large numbers of files from VMS Files-11 filesystems
233 # is faster if done in reverse ASCIIbetical order
234 @files = reverse @files if $Is_VMS;
1b1e14d3 235 ($root = VMS::Filespec::unixify($root)) =~ s#\.dir\z## if $Is_VMS;
ffb9ee5f 236 if ($Is_MacOS) {
237 @files = map("$root$_", @files);
238 } else {
239 @files = map("$root/$_", grep $_!~/^\.{1,2}\z/s,@files);
240 }
037c8c09 241 $count += rmtree(\@files,$verbose,$safe);
242 if ($safe &&
243 ($Is_VMS ? !&VMS::Filespec::candelete($root) : !-w $root)) {
244 print "skipped $root\n" if $verbose;
245 next;
246 }
e2ba98a1 247 chmod $rp | 0700, $root
8878f897 248 or carp ("Can't make directory $root writeable: $!")
037c8c09 249 if $force_writeable;
250 print "rmdir $root\n" if $verbose;
96e4d5b1 251 if (rmdir $root) {
252 ++$count;
253 }
254 else {
8878f897 255 carp ("Can't remove directory $root: $!");
96e4d5b1 256 chmod($rp, ($Is_VMS ? VMS::Filespec::fileify($root) : $root))
257 or carp("and can't restore permissions to "
258 . sprintf("0%o",$rp) . "\n");
259 }
037c8c09 260 }
261 else {
262 if ($safe &&
64f6ddac 263 ($Is_VMS ? !&VMS::Filespec::candelete($root)
264 : !(-l $root || -w $root)))
265 {
037c8c09 266 print "skipped $root\n" if $verbose;
267 next;
268 }
e2ba98a1 269 chmod $rp | 0600, $root
8878f897 270 or carp ("Can't make file $root writeable: $!")
037c8c09 271 if $force_writeable;
272 print "unlink $root\n" if $verbose;
273 # delete all versions under VMS
94d4f21c 274 for (;;) {
275 unless (unlink $root) {
8878f897 276 carp ("Can't unlink file $root: $!");
96e4d5b1 277 if ($force_writeable) {
278 chmod $rp, $root
279 or carp("and can't restore permissions to "
280 . sprintf("0%o",$rp) . "\n");
281 }
94d4f21c 282 last;
96e4d5b1 283 }
94d4f21c 284 ++$count;
285 last unless $Is_VMS && lstat $root;
037c8c09 286 }
287 }
fed7345c 288 }
289
290 $count;
291}
292
2931;