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