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