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