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