Perl 5.8.3 patches from the BS2000 port - part 2
[p5sagit/p5-mst-13.2.git] / lib / Cwd.pm
CommitLineData
a0d0e21e 1package Cwd;
a0d0e21e 2
f06db76b 3=head1 NAME
4
902bacac 5Cwd - get pathname of current working directory
f06db76b 6
7=head1 SYNOPSIS
8
4633a7c4 9 use Cwd;
04929354 10 my $dir = getcwd;
4633a7c4 11
04929354 12 use Cwd 'abs_path';
13 my $abs_path = abs_path($file);
f06db76b 14
04929354 15=head1 DESCRIPTION
902bacac 16
04929354 17This module provides functions for determining the pathname of the
18current working directory. It is recommended that getcwd (or another
19*cwd() function) be used in I<all> code to ensure portability.
f06db76b 20
04929354 21By default, it exports the functions cwd(), getcwd(), fastcwd(), and
22fastgetcwd() into the caller's namespace.
f06db76b 23
20408e3c 24
04929354 25=head2 getcwd and friends
20408e3c 26
04929354 27Each of these functions are called without arguments and return the
28absolute path of the current working directory.
f06db76b 29
04929354 30=over 4
31
32=item getcwd
33
34 my $cwd = getcwd();
35
36Returns the current working directory.
37
38Re-implements the getcwd(3) (or getwd(3)) functions in Perl.
39
40=item cwd
41
42 my $cwd = cwd();
43
44The cwd() is the most natural form for the current architecture. For
45most systems it is identical to `pwd` (but without the trailing line
46terminator).
47
04929354 48=item fastcwd
49
50 my $cwd = fastcwd();
51
52A more dangerous version of getcwd(), but potentially faster.
53
54It might conceivably chdir() you out of a directory that it can't
55chdir() you back into. If fastcwd encounters a problem it will return
56undef but will probably leave you in a different directory. For a
57measure of extra security, if everything appears to have worked, the
58fastcwd() function will check that it leaves you in the same directory
59that it started in. If it has changed it will C<die> with the message
60"Unstable directory path, current directory changed
61unexpectedly". That should never happen.
62
63=item fastgetcwd
64
65 my $cwd = fastgetcwd();
f06db76b 66
902bacac 67The fastgetcwd() function is provided as a synonym for cwd().
fb73857a 68
04929354 69=back
70
902bacac 71
04929354 72=head2 abs_path and friends
73
74These functions are exported only on request. They each take a single
3ee63918 75argument and return the absolute pathname for it. If no argument is
76given they'll use the current working directory.
04929354 77
78=over 4
79
80=item abs_path
81
82 my $abs_path = abs_path($file);
83
84Uses the same algorithm as getcwd(). Symbolic links and relative-path
85components ("." and "..") are resolved to return the canonical
86pathname, just like realpath(3).
87
88=item realpath
89
90 my $abs_path = realpath($file);
91
92A synonym for abs_path().
93
94=item fast_abs_path
95
510179aa 96 my $abs_path = fast_abs_path($file);
04929354 97
98A more dangerous, but potentially faster version of abs_path.
99
100=back
101
102=head2 $ENV{PWD}
103
104If you ask to override your chdir() built-in function,
105
106 use Cwd qw(chdir);
107
108then your PWD environment variable will be kept up to date. Note that
109it will only be kept up to date if all packages which use chdir import
110it from Cwd.
4633a7c4 111
4633a7c4 112
4d6b4052 113=head1 NOTES
114
115=over 4
116
117=item *
118
04929354 119Since the path seperators are different on some operating systems ('/'
120on Unix, ':' on MacPerl, etc...) we recommend you use the File::Spec
121modules wherever portability is a concern.
122
04929354 123=item *
4d6b4052 124
125Actually, on Mac OS, the C<getcwd()>, C<fastgetcwd()> and C<fastcwd()>
126functions are all aliases for the C<cwd()> function, which, on Mac OS,
127calls `pwd`. Likewise, the C<abs_path()> function is an alias for
128C<fast_abs_path()>.
129
130=back
131
04929354 132=head1 SEE ALSO
133
134L<File::chdir>
135
f06db76b 136=cut
137
b060a406 138use strict;
a9939470 139use Exporter;
140use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
96e4d5b1 141
a9939470 142$VERSION = '2.12';
96e4d5b1 143
a9939470 144@ISA = qw/ Exporter /;
145@EXPORT = qw(cwd getcwd fastcwd fastgetcwd);
146@EXPORT_OK = qw(chdir abs_path fast_abs_path realpath fast_realpath);
a0d0e21e 147
f5f423e4 148# sys_cwd may keep the builtin command
149
150# All the functionality of this module may provided by builtins,
151# there is no sense to process the rest of the file.
152# The best choice may be to have this in BEGIN, but how to return from BEGIN?
153
a9939470 154if ($^O eq 'os2') {
f5f423e4 155 local $^W = 0;
a9939470 156
157 *cwd = defined &sys_cwd ? \&sys_cwd : \&_os2_cwd;
158 *getcwd = \&cwd;
159 *fastgetcwd = \&cwd;
160 *fastcwd = \&cwd;
161
162 *fast_abs_path = \&sys_abspath if defined &sys_abspath;
163 *abs_path = \&fast_abs_path;
164 *realpath = \&fast_abs_path;
165 *fast_realpath = \&fast_abs_path;
166
f5f423e4 167 return 1;
168}
169
f22d8e4b 170eval {
171 require XSLoader;
46ba3155 172 local $^W = 0;
f22d8e4b 173 XSLoader::load('Cwd');
174};
4633a7c4 175
96e4d5b1 176
3547aa9a 177# Find the pwd command in the expected locations. We assume these
178# are safe. This prevents _backtick_pwd() consulting $ENV{PATH}
179# so everything works under taint mode.
180my $pwd_cmd;
181foreach my $try (qw(/bin/pwd /usr/bin/pwd)) {
182 if( -x $try ) {
183 $pwd_cmd = $try;
184 last;
185 }
186}
522b859a 187unless ($pwd_cmd) {
188 if (-x '/QOpenSys/bin/pwd') { # OS/400 PASE.
189 $pwd_cmd = '/QOpenSys/bin/pwd' ;
190 } else {
191 # Isn't this wrong? _backtick_pwd() will fail if somenone has
192 # pwd in their path but it is not /bin/pwd or /usr/bin/pwd?
193 # See [perl #16774]. --jhi
194 $pwd_cmd = 'pwd';
195 }
196}
3547aa9a 197
a9939470 198# Lazy-load Carp
199sub _carp { require Carp; Carp::carp(@_) }
200sub _croak { require Carp; Carp::croak(@_) }
201
3547aa9a 202# The 'natural and safe form' for UNIX (pwd may be setuid root)
8b88ae92 203sub _backtick_pwd {
db281859 204 local @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)};
3547aa9a 205 my $cwd = `$pwd_cmd`;
ac3b20cb 206 # Belt-and-suspenders in case someone said "undef $/".
5cf6da5f 207 local $/ = "\n";
ac3b20cb 208 # `pwd` may fail e.g. if the disk is full
7e03f963 209 chomp($cwd) if defined $cwd;
4633a7c4 210 $cwd;
8b88ae92 211}
4633a7c4 212
213# Since some ports may predefine cwd internally (e.g., NT)
214# we take care not to override an existing definition for cwd().
215
ea54c8bd 216unless(defined &cwd) {
217 # The pwd command is not available in some chroot(2)'ed environments
73b801a6 218 if( $^O eq 'MacOS' || (defined $ENV{PATH} &&
219 grep { -x "$_/pwd" } split(':', $ENV{PATH})) )
220 {
ea54c8bd 221 *cwd = \&_backtick_pwd;
222 }
223 else {
224 *cwd = \&getcwd;
225 }
226}
a0d0e21e 227
1f4f94f5 228# set a reasonable (and very safe) default for fastgetcwd, in case it
229# isn't redefined later (20001212 rspier)
230*fastgetcwd = \&cwd;
748a9306 231
a0d0e21e 232# By Brandon S. Allbery
233#
234# Usage: $cwd = getcwd();
235
236sub getcwd
237{
07569ed3 238 abs_path('.');
a0d0e21e 239}
240
a0c9c202 241
242# By John Bazik
243#
244# Usage: $cwd = &fastcwd;
245#
246# This is a faster version of getcwd. It's also more dangerous because
247# you might chdir out of a directory that you can't chdir back into.
248
249sub fastcwd {
250 my($odev, $oino, $cdev, $cino, $tdev, $tino);
251 my(@path, $path);
252 local(*DIR);
253
254 my($orig_cdev, $orig_cino) = stat('.');
255 ($cdev, $cino) = ($orig_cdev, $orig_cino);
256 for (;;) {
257 my $direntry;
258 ($odev, $oino) = ($cdev, $cino);
259 CORE::chdir('..') || return undef;
260 ($cdev, $cino) = stat('.');
261 last if $odev == $cdev && $oino == $cino;
262 opendir(DIR, '.') || return undef;
263 for (;;) {
264 $direntry = readdir(DIR);
265 last unless defined $direntry;
266 next if $direntry eq '.';
267 next if $direntry eq '..';
268
269 ($tdev, $tino) = lstat($direntry);
270 last unless $tdev != $odev || $tino != $oino;
271 }
272 closedir(DIR);
273 return undef unless defined $direntry; # should never happen
274 unshift(@path, $direntry);
275 }
276 $path = '/' . join('/', @path);
277 if ($^O eq 'apollo') { $path = "/".$path; }
278 # At this point $path may be tainted (if tainting) and chdir would fail.
248785eb 279 # Untaint it then check that we landed where we started.
280 $path =~ /^(.*)\z/s # untaint
281 && CORE::chdir($1) or return undef;
a0c9c202 282 ($cdev, $cino) = stat('.');
283 die "Unstable directory path, current directory changed unexpectedly"
284 if $cdev != $orig_cdev || $cino != $orig_cino;
285 $path;
286}
287
288
4633a7c4 289# Keeps track of current working directory in PWD environment var
a0d0e21e 290# Usage:
291# use Cwd 'chdir';
292# chdir $newdir;
293
4633a7c4 294my $chdir_init = 0;
a0d0e21e 295
4633a7c4 296sub chdir_init {
3b8e3443 297 if ($ENV{'PWD'} and $^O ne 'os2' and $^O ne 'dos' and $^O ne 'MSWin32') {
a0d0e21e 298 my($dd,$di) = stat('.');
299 my($pd,$pi) = stat($ENV{'PWD'});
300 if (!defined $dd or !defined $pd or $di != $pi or $dd != $pd) {
4633a7c4 301 $ENV{'PWD'} = cwd();
a0d0e21e 302 }
303 }
304 else {
3b8e3443 305 my $wd = cwd();
306 $wd = Win32::GetFullPathName($wd) if $^O eq 'MSWin32';
307 $ENV{'PWD'} = $wd;
a0d0e21e 308 }
4633a7c4 309 # Strip an automounter prefix (where /tmp_mnt/foo/bar == /foo/bar)
3b8e3443 310 if ($^O ne 'MSWin32' and $ENV{'PWD'} =~ m|(/[^/]+(/[^/]+/[^/]+))(.*)|s) {
a0d0e21e 311 my($pd,$pi) = stat($2);
312 my($dd,$di) = stat($1);
313 if (defined $pd and defined $dd and $di == $pi and $dd == $pd) {
314 $ENV{'PWD'}="$2$3";
315 }
316 }
317 $chdir_init = 1;
318}
319
320sub chdir {
22978713 321 my $newdir = @_ ? shift : ''; # allow for no arg (chdir to HOME dir)
3b8e3443 322 $newdir =~ s|///*|/|g unless $^O eq 'MSWin32';
a0d0e21e 323 chdir_init() unless $chdir_init;
4ffa1610 324 my $newpwd;
325 if ($^O eq 'MSWin32') {
326 # get the full path name *before* the chdir()
327 $newpwd = Win32::GetFullPathName($newdir);
328 }
329
4633a7c4 330 return 0 unless CORE::chdir $newdir;
4ffa1610 331
3b8e3443 332 if ($^O eq 'VMS') {
333 return $ENV{'PWD'} = $ENV{'DEFAULT'}
334 }
4aecb5b5 335 elsif ($^O eq 'MacOS') {
336 return $ENV{'PWD'} = cwd();
337 }
3b8e3443 338 elsif ($^O eq 'MSWin32') {
4ffa1610 339 $ENV{'PWD'} = $newpwd;
3b8e3443 340 return 1;
341 }
748a9306 342
392d8ab8 343 if ($newdir =~ m#^/#s) {
a0d0e21e 344 $ENV{'PWD'} = $newdir;
4633a7c4 345 } else {
346 my @curdir = split(m#/#,$ENV{'PWD'});
347 @curdir = ('') unless @curdir;
348 my $component;
a0d0e21e 349 foreach $component (split(m#/#, $newdir)) {
350 next if $component eq '.';
351 pop(@curdir),next if $component eq '..';
352 push(@curdir,$component);
353 }
354 $ENV{'PWD'} = join('/',@curdir) || '/';
355 }
4633a7c4 356 1;
a0d0e21e 357}
358
a0c9c202 359
360# In case the XS version doesn't load.
361*abs_path = \&_perl_abs_path unless defined &abs_path;
362sub _perl_abs_path
363{
364 my $start = @_ ? shift : '.';
365 my($dotdots, $cwd, @pst, @cst, $dir, @tst);
366
367 unless (@cst = stat( $start ))
368 {
a9939470 369 _carp("stat($start): $!");
a0c9c202 370 return '';
371 }
372 $cwd = '';
373 $dotdots = $start;
374 do
375 {
376 $dotdots .= '/..';
377 @pst = @cst;
a25ef67d 378 local *PARENT;
a0c9c202 379 unless (opendir(PARENT, $dotdots))
380 {
a9939470 381 _carp("opendir($dotdots): $!");
a0c9c202 382 return '';
383 }
384 unless (@cst = stat($dotdots))
385 {
a9939470 386 _carp("stat($dotdots): $!");
a0c9c202 387 closedir(PARENT);
388 return '';
389 }
390 if ($pst[0] == $cst[0] && $pst[1] == $cst[1])
391 {
392 $dir = undef;
393 }
394 else
395 {
396 do
397 {
398 unless (defined ($dir = readdir(PARENT)))
399 {
a9939470 400 _carp("readdir($dotdots): $!");
a0c9c202 401 closedir(PARENT);
402 return '';
403 }
404 $tst[0] = $pst[0]+1 unless (@tst = lstat("$dotdots/$dir"))
405 }
406 while ($dir eq '.' || $dir eq '..' || $tst[0] != $pst[0] ||
407 $tst[1] != $pst[1]);
408 }
409 $cwd = (defined $dir ? "$dir" : "" ) . "/$cwd" ;
410 closedir(PARENT);
411 } while (defined $dir);
412 chop($cwd) unless $cwd eq '/'; # drop the trailing /
413 $cwd;
414}
415
416
e4c51978 417# added function alias for those of us more
418# used to the libc function. --tchrist 27-Jan-00
419*realpath = \&abs_path;
420
3ee63918 421my $Curdir;
96e4d5b1 422sub fast_abs_path {
423 my $cwd = getcwd();
4d6b4052 424 require File::Spec;
3ee63918 425 my $path = @_ ? shift : ($Curdir ||= File::Spec->curdir);
426
427 # Detaint else we'll explode in taint mode. This is safe because
428 # we're not doing anything dangerous with it.
429 ($path) = $path =~ /(.*)/;
430 ($cwd) = $cwd =~ /(.*)/;
431
e2ba406b 432 if (!CORE::chdir($path)) {
a9939470 433 _croak("Cannot chdir to $path: $!");
e2ba406b 434 }
96e4d5b1 435 my $realpath = getcwd();
e2ba406b 436 if (! ((-d $cwd) && (CORE::chdir($cwd)))) {
a9939470 437 _croak("Cannot chdir back to $cwd: $!");
e2ba406b 438 }
96e4d5b1 439 $realpath;
8b88ae92 440}
441
e4c51978 442# added function alias to follow principle of least surprise
443# based on previous aliasing. --tchrist 27-Jan-00
444*fast_realpath = \&fast_abs_path;
445
4633a7c4 446
447# --- PORTING SECTION ---
448
449# VMS: $ENV{'DEFAULT'} points to default directory at all times
bd3fa61c 450# 06-Mar-1996 Charles Bailey bailey@newman.upenn.edu
c6538b72 451# Note: Use of Cwd::chdir() causes the logical name PWD to be defined
8b88ae92 452# in the process logical name table as the default device and directory
453# seen by Perl. This may not be the same as the default device
4633a7c4 454# and directory seen by DCL after Perl exits, since the effects
455# the CRTL chdir() function persist only until Perl exits.
4633a7c4 456
457sub _vms_cwd {
96e4d5b1 458 return $ENV{'DEFAULT'};
459}
460
461sub _vms_abs_path {
462 return $ENV{'DEFAULT'} unless @_;
463 my $path = VMS::Filespec::pathify($_[0]);
e2ba406b 464 if (! defined $path)
465 {
a9939470 466 _croak("Invalid path name $_[0]")
e2ba406b 467 }
96e4d5b1 468 return VMS::Filespec::rmsexpand($path);
4633a7c4 469}
68dc0745 470
4633a7c4 471sub _os2_cwd {
472 $ENV{'PWD'} = `cmd /c cd`;
39741d73 473 chomp $ENV{'PWD'};
aa6b7957 474 $ENV{'PWD'} =~ s:\\:/:g ;
4633a7c4 475 return $ENV{'PWD'};
476}
477
96e4d5b1 478sub _win32_cwd {
2d7a9237 479 $ENV{'PWD'} = Win32::GetCwd();
aa6b7957 480 $ENV{'PWD'} =~ s:\\:/:g ;
96e4d5b1 481 return $ENV{'PWD'};
482}
483
484*_NT_cwd = \&_win32_cwd if (!defined &_NT_cwd &&
2d7a9237 485 defined &Win32::GetCwd);
96e4d5b1 486
487*_NT_cwd = \&_os2_cwd unless defined &_NT_cwd;
68dc0745 488
39e571d4 489sub _dos_cwd {
490 if (!defined &Dos::GetCwd) {
491 $ENV{'PWD'} = `command /c cd`;
39741d73 492 chomp $ENV{'PWD'};
aa6b7957 493 $ENV{'PWD'} =~ s:\\:/:g ;
39e571d4 494 } else {
495 $ENV{'PWD'} = Dos::GetCwd();
496 }
55497cff 497 return $ENV{'PWD'};
498}
499
7fbf1995 500sub _qnx_cwd {
35b807ef 501 local $ENV{PATH} = '';
502 local $ENV{CDPATH} = '';
503 local $ENV{ENV} = '';
7fbf1995 504 $ENV{'PWD'} = `/usr/bin/fullpath -t`;
39741d73 505 chomp $ENV{'PWD'};
7fbf1995 506 return $ENV{'PWD'};
507}
508
509sub _qnx_abs_path {
35b807ef 510 local $ENV{PATH} = '';
511 local $ENV{CDPATH} = '';
512 local $ENV{ENV} = '';
fa921dc6 513 my $path = @_ ? shift : '.';
39741d73 514 local *REALPATH;
515
516 open(REALPATH, '-|', '/usr/bin/fullpath', '-t', $path) or
517 die "Can't open /usr/bin/fullpath: $!";
518 my $realpath = <REALPATH>;
519 close REALPATH;
520 chomp $realpath;
7fbf1995 521 return $realpath;
522}
523
ed79a026 524sub _epoc_cwd {
525 $ENV{'PWD'} = EPOC::getcwd();
526 return $ENV{'PWD'};
527}
528
ac1ad7f0 529{
db376a24 530 no warnings; # assignments trigger 'subroutine redefined' warning
4633a7c4 531
ac1ad7f0 532 if ($^O eq 'VMS') {
96e4d5b1 533 *cwd = \&_vms_cwd;
534 *getcwd = \&_vms_cwd;
535 *fastcwd = \&_vms_cwd;
536 *fastgetcwd = \&_vms_cwd;
537 *abs_path = \&_vms_abs_path;
538 *fast_abs_path = \&_vms_abs_path;
ac1ad7f0 539 }
540 elsif ($^O eq 'NT' or $^O eq 'MSWin32') {
541 # We assume that &_NT_cwd is defined as an XSUB or in the core.
96e4d5b1 542 *cwd = \&_NT_cwd;
543 *getcwd = \&_NT_cwd;
544 *fastcwd = \&_NT_cwd;
545 *fastgetcwd = \&_NT_cwd;
546 *abs_path = \&fast_abs_path;
cade0c02 547 *realpath = \&fast_abs_path;
ac1ad7f0 548 }
39e571d4 549 elsif ($^O eq 'dos') {
550 *cwd = \&_dos_cwd;
551 *getcwd = \&_dos_cwd;
552 *fastgetcwd = \&_dos_cwd;
553 *fastcwd = \&_dos_cwd;
96e4d5b1 554 *abs_path = \&fast_abs_path;
ac1ad7f0 555 }
7438b6ad 556 elsif ($^O =~ m/^(?:qnx|nto)$/ ) {
7fbf1995 557 *cwd = \&_qnx_cwd;
558 *getcwd = \&_qnx_cwd;
559 *fastgetcwd = \&_qnx_cwd;
560 *fastcwd = \&_qnx_cwd;
561 *abs_path = \&_qnx_abs_path;
562 *fast_abs_path = \&_qnx_abs_path;
563 }
4fabb596 564 elsif ($^O eq 'cygwin') {
1cab015a 565 *getcwd = \&cwd;
566 *fastgetcwd = \&cwd;
567 *fastcwd = \&cwd;
568 *abs_path = \&fast_abs_path;
a9939470 569 *realpath = \&abs_path;
1cab015a 570 }
ed79a026 571 elsif ($^O eq 'epoc') {
fa6a1c44 572 *cwd = \&_epoc_cwd;
573 *getcwd = \&_epoc_cwd;
ed79a026 574 *fastgetcwd = \&_epoc_cwd;
575 *fastcwd = \&_epoc_cwd;
576 *abs_path = \&fast_abs_path;
577 }
4aecb5b5 578 elsif ($^O eq 'MacOS') {
579 *getcwd = \&cwd;
580 *fastgetcwd = \&cwd;
581 *fastcwd = \&cwd;
582 *abs_path = \&fast_abs_path;
583 }
55497cff 584}
4633a7c4 585
4633a7c4 586
a0d0e21e 5871;