move startglob out of pp_hot.c
[p5sagit/p5-mst-13.2.git] / lib / Cwd.pm
CommitLineData
a0d0e21e 1package Cwd;
2require 5.000;
a0d0e21e 3
f06db76b 4=head1 NAME
5
6getcwd - get pathname of current working directory
7
8=head1 SYNOPSIS
9
4633a7c4 10 use Cwd;
11 $dir = cwd;
12
13 use Cwd;
14 $dir = getcwd;
f06db76b 15
16 use Cwd;
4633a7c4 17 $dir = fastgetcwd;
f06db76b 18
19 use Cwd 'chdir';
20 chdir "/tmp";
21 print $ENV{'PWD'};
22
e4c51978 23 use Cwd 'abs_path'; # aka realpath()
20408e3c 24 print abs_path($ENV{'PWD'});
25
26 use Cwd 'fast_abs_path';
27 print fast_abs_path($ENV{'PWD'});
28
f06db76b 29=head1 DESCRIPTION
30
31The getcwd() function re-implements the getcwd(3) (or getwd(3)) functions
4633a7c4 32in Perl.
f06db76b 33
20408e3c 34The abs_path() function takes a single argument and returns the
e4c51978 35absolute pathname for that argument. It uses the same algorithm
36as getcwd(). (Actually, getcwd() is abs_path(".")) Symbolic links
37and relative-path components ("." and "..") are resolved to return
38the canonical pathname, just like realpath(3). Also callable as
39realpath().
20408e3c 40
cb1a09d0 41The fastcwd() function looks the same as getcwd(), but runs faster.
fb73857a 42It's also more dangerous because it might conceivably chdir() you out
43of a directory that it can't chdir() you back into. If fastcwd
44encounters a problem it will return undef but will probably leave you
45in a different directory. For a measure of extra security, if
46everything appears to have worked, the fastcwd() function will check
47that it leaves you in the same directory that it started in. If it has
48changed it will C<die> with the message "Unstable directory path,
49current directory changed unexpectedly". That should never happen.
f06db76b 50
20408e3c 51The fast_abs_path() function looks the same as abs_path(), but runs faster.
52And like fastcwd() is more dangerous.
53
4633a7c4 54The cwd() function looks the same as getcwd and fastgetcwd but is
55implemented using the most natural and safe form for the current
56architecture. For most systems it is identical to `pwd` (but without
fb73857a 57the trailing line terminator).
58
59It is recommended that cwd (or another *cwd() function) is used in
60I<all> code to ensure portability.
4633a7c4 61
62If you ask to override your chdir() built-in function, then your PWD
63environment variable will be kept up to date. (See
55497cff 64L<perlsub/Overriding Builtin Functions>.) Note that it will only be
1fef88e7 65kept up to date if all packages which use chdir import it from Cwd.
4633a7c4 66
f06db76b 67=cut
68
b060a406 69use strict;
96e4d5b1 70
71use Carp;
72
b060a406 73our $VERSION = '2.03';
96e4d5b1 74
b060a406 75use base qw/ Exporter /;
76our @EXPORT = qw(cwd getcwd fastcwd fastgetcwd);
77our @EXPORT_OK = qw(chdir abs_path fast_abs_path realpath fast_realpath);
a0d0e21e 78
4633a7c4 79
8b88ae92 80# The 'natural and safe form' for UNIX (pwd may be setuid root)
96e4d5b1 81
8b88ae92 82sub _backtick_pwd {
7e03f963 83 my $cwd = `pwd`;
84 # `pwd` may fail e.g. if the disk is full
85 chomp($cwd) if defined $cwd;
4633a7c4 86 $cwd;
8b88ae92 87}
4633a7c4 88
89# Since some ports may predefine cwd internally (e.g., NT)
90# we take care not to override an existing definition for cwd().
91
ea54c8bd 92unless(defined &cwd) {
93 # The pwd command is not available in some chroot(2)'ed environments
94 if(grep { -x "$_/pwd" } split(':', $ENV{PATH})) {
95 *cwd = \&_backtick_pwd;
96 }
97 else {
98 *cwd = \&getcwd;
99 }
100}
a0d0e21e 101
748a9306 102
a0d0e21e 103# By Brandon S. Allbery
104#
105# Usage: $cwd = getcwd();
106
107sub getcwd
108{
07569ed3 109 abs_path('.');
a0d0e21e 110}
111
a0d0e21e 112# By John Bazik
113#
114# Usage: $cwd = &fastcwd;
115#
116# This is a faster version of getcwd. It's also more dangerous because
117# you might chdir out of a directory that you can't chdir back into.
fb73857a 118
a0d0e21e 119sub fastcwd {
120 my($odev, $oino, $cdev, $cino, $tdev, $tino);
121 my(@path, $path);
122 local(*DIR);
123
fb73857a 124 my($orig_cdev, $orig_cino) = stat('.');
125 ($cdev, $cino) = ($orig_cdev, $orig_cino);
a0d0e21e 126 for (;;) {
40000a8c 127 my $direntry;
a0d0e21e 128 ($odev, $oino) = ($cdev, $cino);
e79e61e4 129 CORE::chdir('..') || return undef;
a0d0e21e 130 ($cdev, $cino) = stat('.');
131 last if $odev == $cdev && $oino == $cino;
fb73857a 132 opendir(DIR, '.') || return undef;
a0d0e21e 133 for (;;) {
40000a8c 134 $direntry = readdir(DIR);
fb73857a 135 last unless defined $direntry;
40000a8c 136 next if $direntry eq '.';
137 next if $direntry eq '..';
a0d0e21e 138
40000a8c 139 ($tdev, $tino) = lstat($direntry);
a0d0e21e 140 last unless $tdev != $odev || $tino != $oino;
141 }
142 closedir(DIR);
fb73857a 143 return undef unless defined $direntry; # should never happen
40000a8c 144 unshift(@path, $direntry);
a0d0e21e 145 }
fb73857a 146 $path = '/' . join('/', @path);
21ac5ced 147 if ($^O eq 'apollo') { $path = "/".$path; }
fb73857a 148 # At this point $path may be tainted (if tainting) and chdir would fail.
149 # To be more useful we untaint it then check that we landed where we started.
392d8ab8 150 $path = $1 if $path =~ /^(.*)\z/s; # untaint
e79e61e4 151 CORE::chdir($path) || return undef;
fb73857a 152 ($cdev, $cino) = stat('.');
153 die "Unstable directory path, current directory changed unexpectedly"
154 if $cdev != $orig_cdev || $cino != $orig_cino;
a0d0e21e 155 $path;
156}
157
158
4633a7c4 159# Keeps track of current working directory in PWD environment var
a0d0e21e 160# Usage:
161# use Cwd 'chdir';
162# chdir $newdir;
163
4633a7c4 164my $chdir_init = 0;
a0d0e21e 165
4633a7c4 166sub chdir_init {
3b8e3443 167 if ($ENV{'PWD'} and $^O ne 'os2' and $^O ne 'dos' and $^O ne 'MSWin32') {
a0d0e21e 168 my($dd,$di) = stat('.');
169 my($pd,$pi) = stat($ENV{'PWD'});
170 if (!defined $dd or !defined $pd or $di != $pi or $dd != $pd) {
4633a7c4 171 $ENV{'PWD'} = cwd();
a0d0e21e 172 }
173 }
174 else {
3b8e3443 175 my $wd = cwd();
176 $wd = Win32::GetFullPathName($wd) if $^O eq 'MSWin32';
177 $ENV{'PWD'} = $wd;
a0d0e21e 178 }
4633a7c4 179 # Strip an automounter prefix (where /tmp_mnt/foo/bar == /foo/bar)
3b8e3443 180 if ($^O ne 'MSWin32' and $ENV{'PWD'} =~ m|(/[^/]+(/[^/]+/[^/]+))(.*)|s) {
a0d0e21e 181 my($pd,$pi) = stat($2);
182 my($dd,$di) = stat($1);
183 if (defined $pd and defined $dd and $di == $pi and $dd == $pd) {
184 $ENV{'PWD'}="$2$3";
185 }
186 }
187 $chdir_init = 1;
188}
189
190sub chdir {
22978713 191 my $newdir = @_ ? shift : ''; # allow for no arg (chdir to HOME dir)
3b8e3443 192 $newdir =~ s|///*|/|g unless $^O eq 'MSWin32';
a0d0e21e 193 chdir_init() unless $chdir_init;
4633a7c4 194 return 0 unless CORE::chdir $newdir;
3b8e3443 195 if ($^O eq 'VMS') {
196 return $ENV{'PWD'} = $ENV{'DEFAULT'}
197 }
198 elsif ($^O eq 'MSWin32') {
199 $ENV{'PWD'} = Win32::GetFullPathName($newdir);
200 return 1;
201 }
748a9306 202
392d8ab8 203 if ($newdir =~ m#^/#s) {
a0d0e21e 204 $ENV{'PWD'} = $newdir;
4633a7c4 205 } else {
206 my @curdir = split(m#/#,$ENV{'PWD'});
207 @curdir = ('') unless @curdir;
208 my $component;
a0d0e21e 209 foreach $component (split(m#/#, $newdir)) {
210 next if $component eq '.';
211 pop(@curdir),next if $component eq '..';
212 push(@curdir,$component);
213 }
214 $ENV{'PWD'} = join('/',@curdir) || '/';
215 }
4633a7c4 216 1;
a0d0e21e 217}
218
d57281c6 219# Taken from Cwd.pm It is really getcwd with an optional
220# parameter instead of '.'
221#
8b88ae92 222
d57281c6 223sub abs_path
224{
225 my $start = @_ ? shift : '.';
226 my($dotdots, $cwd, @pst, @cst, $dir, @tst);
929327b2 227
d57281c6 228 unless (@cst = stat( $start ))
229 {
230 carp "stat($start): $!";
231 return '';
8b88ae92 232 }
d57281c6 233 $cwd = '';
234 $dotdots = $start;
235 do
236 {
237 $dotdots .= '/..';
238 @pst = @cst;
239 unless (opendir(PARENT, $dotdots))
240 {
241 carp "opendir($dotdots): $!";
242 return '';
243 }
244 unless (@cst = stat($dotdots))
245 {
246 carp "stat($dotdots): $!";
247 closedir(PARENT);
248 return '';
249 }
250 if ($pst[0] == $cst[0] && $pst[1] == $cst[1])
251 {
252 $dir = undef;
253 }
254 else
255 {
256 do
257 {
258 unless (defined ($dir = readdir(PARENT)))
259 {
260 carp "readdir($dotdots): $!";
261 closedir(PARENT);
262 return '';
263 }
264 $tst[0] = $pst[0]+1 unless (@tst = lstat("$dotdots/$dir"))
265 }
266 while ($dir eq '.' || $dir eq '..' || $tst[0] != $pst[0] ||
267 $tst[1] != $pst[1]);
268 }
269 $cwd = (defined $dir ? "$dir" : "" ) . "/$cwd" ;
270 closedir(PARENT);
271 } while (defined $dir);
272 chop($cwd) unless $cwd eq '/'; # drop the trailing /
273 $cwd;
8b88ae92 274}
275
e4c51978 276# added function alias for those of us more
277# used to the libc function. --tchrist 27-Jan-00
278*realpath = \&abs_path;
279
96e4d5b1 280sub fast_abs_path {
281 my $cwd = getcwd();
3c65c14b 282 my $path = @_ ? shift : '.';
e79e61e4 283 CORE::chdir($path) || croak "Cannot chdir to $path:$!";
96e4d5b1 284 my $realpath = getcwd();
e79e61e4 285 CORE::chdir($cwd) || croak "Cannot chdir back to $cwd:$!";
96e4d5b1 286 $realpath;
8b88ae92 287}
288
e4c51978 289# added function alias to follow principle of least surprise
290# based on previous aliasing. --tchrist 27-Jan-00
291*fast_realpath = \&fast_abs_path;
292
4633a7c4 293
294# --- PORTING SECTION ---
295
296# VMS: $ENV{'DEFAULT'} points to default directory at all times
bd3fa61c 297# 06-Mar-1996 Charles Bailey bailey@newman.upenn.edu
c6538b72 298# Note: Use of Cwd::chdir() causes the logical name PWD to be defined
8b88ae92 299# in the process logical name table as the default device and directory
300# seen by Perl. This may not be the same as the default device
4633a7c4 301# and directory seen by DCL after Perl exits, since the effects
302# the CRTL chdir() function persist only until Perl exits.
4633a7c4 303
304sub _vms_cwd {
96e4d5b1 305 return $ENV{'DEFAULT'};
306}
307
308sub _vms_abs_path {
309 return $ENV{'DEFAULT'} unless @_;
310 my $path = VMS::Filespec::pathify($_[0]);
311 croak("Invalid path name $_[0]") unless defined $path;
312 return VMS::Filespec::rmsexpand($path);
4633a7c4 313}
68dc0745 314
4633a7c4 315sub _os2_cwd {
316 $ENV{'PWD'} = `cmd /c cd`;
317 chop $ENV{'PWD'};
318 $ENV{'PWD'} =~ s:\\:/:g ;
319 return $ENV{'PWD'};
320}
321
96e4d5b1 322sub _win32_cwd {
2d7a9237 323 $ENV{'PWD'} = Win32::GetCwd();
96e4d5b1 324 $ENV{'PWD'} =~ s:\\:/:g ;
325 return $ENV{'PWD'};
326}
327
328*_NT_cwd = \&_win32_cwd if (!defined &_NT_cwd &&
2d7a9237 329 defined &Win32::GetCwd);
96e4d5b1 330
331*_NT_cwd = \&_os2_cwd unless defined &_NT_cwd;
68dc0745 332
39e571d4 333sub _dos_cwd {
334 if (!defined &Dos::GetCwd) {
335 $ENV{'PWD'} = `command /c cd`;
336 chop $ENV{'PWD'};
337 $ENV{'PWD'} =~ s:\\:/:g ;
338 } else {
339 $ENV{'PWD'} = Dos::GetCwd();
340 }
55497cff 341 return $ENV{'PWD'};
342}
343
7fbf1995 344sub _qnx_cwd {
345 $ENV{'PWD'} = `/usr/bin/fullpath -t`;
346 chop $ENV{'PWD'};
347 return $ENV{'PWD'};
348}
349
350sub _qnx_abs_path {
fa921dc6 351 my $path = @_ ? shift : '.';
7fbf1995 352 my $realpath=`/usr/bin/fullpath -t $path`;
353 chop $realpath;
354 return $realpath;
355}
356
ed79a026 357sub _epoc_cwd {
358 $ENV{'PWD'} = EPOC::getcwd();
359 return $ENV{'PWD'};
360}
361
ac1ad7f0 362{
db376a24 363 no warnings; # assignments trigger 'subroutine redefined' warning
4633a7c4 364
ac1ad7f0 365 if ($^O eq 'VMS') {
96e4d5b1 366 *cwd = \&_vms_cwd;
367 *getcwd = \&_vms_cwd;
368 *fastcwd = \&_vms_cwd;
369 *fastgetcwd = \&_vms_cwd;
370 *abs_path = \&_vms_abs_path;
371 *fast_abs_path = \&_vms_abs_path;
ac1ad7f0 372 }
373 elsif ($^O eq 'NT' or $^O eq 'MSWin32') {
374 # We assume that &_NT_cwd is defined as an XSUB or in the core.
96e4d5b1 375 *cwd = \&_NT_cwd;
376 *getcwd = \&_NT_cwd;
377 *fastcwd = \&_NT_cwd;
378 *fastgetcwd = \&_NT_cwd;
379 *abs_path = \&fast_abs_path;
ac1ad7f0 380 }
381 elsif ($^O eq 'os2') {
382 # sys_cwd may keep the builtin command
96e4d5b1 383 *cwd = defined &sys_cwd ? \&sys_cwd : \&_os2_cwd;
384 *getcwd = \&cwd;
385 *fastgetcwd = \&cwd;
386 *fastcwd = \&cwd;
387 *abs_path = \&fast_abs_path;
ac1ad7f0 388 }
39e571d4 389 elsif ($^O eq 'dos') {
390 *cwd = \&_dos_cwd;
391 *getcwd = \&_dos_cwd;
392 *fastgetcwd = \&_dos_cwd;
393 *fastcwd = \&_dos_cwd;
96e4d5b1 394 *abs_path = \&fast_abs_path;
ac1ad7f0 395 }
7fbf1995 396 elsif ($^O eq 'qnx') {
397 *cwd = \&_qnx_cwd;
398 *getcwd = \&_qnx_cwd;
399 *fastgetcwd = \&_qnx_cwd;
400 *fastcwd = \&_qnx_cwd;
401 *abs_path = \&_qnx_abs_path;
402 *fast_abs_path = \&_qnx_abs_path;
403 }
4fabb596 404 elsif ($^O eq 'cygwin') {
1cab015a 405 *getcwd = \&cwd;
406 *fastgetcwd = \&cwd;
407 *fastcwd = \&cwd;
408 *abs_path = \&fast_abs_path;
409 }
ed79a026 410 elsif ($^O eq 'epoc') {
fa6a1c44 411 *cwd = \&_epoc_cwd;
412 *getcwd = \&_epoc_cwd;
ed79a026 413 *fastgetcwd = \&_epoc_cwd;
414 *fastcwd = \&_epoc_cwd;
415 *abs_path = \&fast_abs_path;
416 }
55497cff 417}
4633a7c4 418
419# package main; eval join('',<DATA>) || die $@; # quick test
420
a0d0e21e 4211;
422
4633a7c4 423__END__
424BEGIN { import Cwd qw(:DEFAULT chdir); }
425print join("\n", cwd, getcwd, fastcwd, "");
426chdir('..');
427print join("\n", cwd, getcwd, fastcwd, "");
428print "$ENV{PWD}\n";