ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/staticperl/perl/lib/Cwd.pm
Revision: 1.1
Committed: Thu Jun 30 14:27:08 2005 UTC (21 years, 4 months ago) by root
Branch: MAIN
CVS Tags: PERL-5-8-7, HEAD
Branch point for: PERL
Log Message:
*** empty log message ***

File Contents

# Content
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.05';
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 # If loading the XS stuff doesn't work, we can fall back to pure perl
203 eval {
204 if ( $] >= 5.006 ) {
205 require XSLoader;
206 XSLoader::load( __PACKAGE__, $VERSION );
207 } else {
208 require DynaLoader;
209 push @ISA, 'DynaLoader';
210 __PACKAGE__->bootstrap( $VERSION );
211 }
212 };
213
214 # Must be after the DynaLoader stuff:
215 $VERSION = eval $VERSION;
216
217 # Big nasty table of function aliases
218 my %METHOD_MAP =
219 (
220 VMS =>
221 {
222 cwd => '_vms_cwd',
223 getcwd => '_vms_cwd',
224 fastcwd => '_vms_cwd',
225 fastgetcwd => '_vms_cwd',
226 abs_path => '_vms_abs_path',
227 fast_abs_path => '_vms_abs_path',
228 },
229
230 MSWin32 =>
231 {
232 # We assume that &_NT_cwd is defined as an XSUB or in the core.
233 cwd => '_NT_cwd',
234 getcwd => '_NT_cwd',
235 fastcwd => '_NT_cwd',
236 fastgetcwd => '_NT_cwd',
237 abs_path => 'fast_abs_path',
238 realpath => 'fast_abs_path',
239 },
240
241 dos =>
242 {
243 cwd => '_dos_cwd',
244 getcwd => '_dos_cwd',
245 fastgetcwd => '_dos_cwd',
246 fastcwd => '_dos_cwd',
247 abs_path => 'fast_abs_path',
248 },
249
250 qnx =>
251 {
252 cwd => '_qnx_cwd',
253 getcwd => '_qnx_cwd',
254 fastgetcwd => '_qnx_cwd',
255 fastcwd => '_qnx_cwd',
256 abs_path => '_qnx_abs_path',
257 fast_abs_path => '_qnx_abs_path',
258 },
259
260 cygwin =>
261 {
262 getcwd => 'cwd',
263 fastgetcwd => 'cwd',
264 fastcwd => 'cwd',
265 abs_path => 'fast_abs_path',
266 realpath => 'fast_abs_path',
267 },
268
269 epoc =>
270 {
271 cwd => '_epoc_cwd',
272 getcwd => '_epoc_cwd',
273 fastgetcwd => '_epoc_cwd',
274 fastcwd => '_epoc_cwd',
275 abs_path => 'fast_abs_path',
276 },
277
278 MacOS =>
279 {
280 getcwd => 'cwd',
281 fastgetcwd => 'cwd',
282 fastcwd => 'cwd',
283 abs_path => 'fast_abs_path',
284 },
285 );
286
287 $METHOD_MAP{NT} = $METHOD_MAP{MSWin32};
288 $METHOD_MAP{nto} = $METHOD_MAP{qnx};
289
290
291 # Find the pwd command in the expected locations. We assume these
292 # are safe. This prevents _backtick_pwd() consulting $ENV{PATH}
293 # so everything works under taint mode.
294 my $pwd_cmd;
295 foreach my $try ('/bin/pwd',
296 '/usr/bin/pwd',
297 '/QOpenSys/bin/pwd', # OS/400 PASE.
298 ) {
299
300 if( -x $try ) {
301 $pwd_cmd = $try;
302 last;
303 }
304 }
305 unless ($pwd_cmd) {
306 # Isn't this wrong? _backtick_pwd() will fail if somenone has
307 # pwd in their path but it is not /bin/pwd or /usr/bin/pwd?
308 # See [perl #16774]. --jhi
309 $pwd_cmd = 'pwd';
310 }
311
312 # Lazy-load Carp
313 sub _carp { require Carp; Carp::carp(@_) }
314 sub _croak { require Carp; Carp::croak(@_) }
315
316 # The 'natural and safe form' for UNIX (pwd may be setuid root)
317 sub _backtick_pwd {
318 local @ENV{qw(PATH IFS CDPATH ENV BASH_ENV)};
319 my $cwd = `$pwd_cmd`;
320 # Belt-and-suspenders in case someone said "undef $/".
321 local $/ = "\n";
322 # `pwd` may fail e.g. if the disk is full
323 chomp($cwd) if defined $cwd;
324 $cwd;
325 }
326
327 # Since some ports may predefine cwd internally (e.g., NT)
328 # we take care not to override an existing definition for cwd().
329
330 unless ($METHOD_MAP{$^O}{cwd} or defined &cwd) {
331 # The pwd command is not available in some chroot(2)'ed environments
332 my $sep = $Config::Config{path_sep} || ':';
333 if( $^O eq 'MacOS' || (defined $ENV{PATH} &&
334 $^O ne 'MSWin32' && # no pwd on Windows
335 grep { -x "$_/pwd" } split($sep, $ENV{PATH})) )
336 {
337 *cwd = \&_backtick_pwd;
338 }
339 else {
340 *cwd = \&getcwd;
341 }
342 }
343
344 # set a reasonable (and very safe) default for fastgetcwd, in case it
345 # isn't redefined later (20001212 rspier)
346 *fastgetcwd = \&cwd;
347
348 # By Brandon S. Allbery
349 #
350 # Usage: $cwd = getcwd();
351
352 sub getcwd
353 {
354 abs_path('.');
355 }
356
357
358 # By John Bazik
359 #
360 # Usage: $cwd = &fastcwd;
361 #
362 # This is a faster version of getcwd. It's also more dangerous because
363 # you might chdir out of a directory that you can't chdir back into.
364
365 sub fastcwd_ {
366 my($odev, $oino, $cdev, $cino, $tdev, $tino);
367 my(@path, $path);
368 local(*DIR);
369
370 my($orig_cdev, $orig_cino) = stat('.');
371 ($cdev, $cino) = ($orig_cdev, $orig_cino);
372 for (;;) {
373 my $direntry;
374 ($odev, $oino) = ($cdev, $cino);
375 CORE::chdir('..') || return undef;
376 ($cdev, $cino) = stat('.');
377 last if $odev == $cdev && $oino == $cino;
378 opendir(DIR, '.') || return undef;
379 for (;;) {
380 $direntry = readdir(DIR);
381 last unless defined $direntry;
382 next if $direntry eq '.';
383 next if $direntry eq '..';
384
385 ($tdev, $tino) = lstat($direntry);
386 last unless $tdev != $odev || $tino != $oino;
387 }
388 closedir(DIR);
389 return undef unless defined $direntry; # should never happen
390 unshift(@path, $direntry);
391 }
392 $path = '/' . join('/', @path);
393 if ($^O eq 'apollo') { $path = "/".$path; }
394 # At this point $path may be tainted (if tainting) and chdir would fail.
395 # Untaint it then check that we landed where we started.
396 $path =~ /^(.*)\z/s # untaint
397 && CORE::chdir($1) or return undef;
398 ($cdev, $cino) = stat('.');
399 die "Unstable directory path, current directory changed unexpectedly"
400 if $cdev != $orig_cdev || $cino != $orig_cino;
401 $path;
402 }
403 if (not defined &fastcwd) { *fastcwd = \&fastcwd_ }
404
405
406 # Keeps track of current working directory in PWD environment var
407 # Usage:
408 # use Cwd 'chdir';
409 # chdir $newdir;
410
411 my $chdir_init = 0;
412
413 sub chdir_init {
414 if ($ENV{'PWD'} and $^O ne 'os2' and $^O ne 'dos' and $^O ne 'MSWin32') {
415 my($dd,$di) = stat('.');
416 my($pd,$pi) = stat($ENV{'PWD'});
417 if (!defined $dd or !defined $pd or $di != $pi or $dd != $pd) {
418 $ENV{'PWD'} = cwd();
419 }
420 }
421 else {
422 my $wd = cwd();
423 $wd = Win32::GetFullPathName($wd) if $^O eq 'MSWin32';
424 $ENV{'PWD'} = $wd;
425 }
426 # Strip an automounter prefix (where /tmp_mnt/foo/bar == /foo/bar)
427 if ($^O ne 'MSWin32' and $ENV{'PWD'} =~ m|(/[^/]+(/[^/]+/[^/]+))(.*)|s) {
428 my($pd,$pi) = stat($2);
429 my($dd,$di) = stat($1);
430 if (defined $pd and defined $dd and $di == $pi and $dd == $pd) {
431 $ENV{'PWD'}="$2$3";
432 }
433 }
434 $chdir_init = 1;
435 }
436
437 sub chdir {
438 my $newdir = @_ ? shift : ''; # allow for no arg (chdir to HOME dir)
439 $newdir =~ s|///*|/|g unless $^O eq 'MSWin32';
440 chdir_init() unless $chdir_init;
441 my $newpwd;
442 if ($^O eq 'MSWin32') {
443 # get the full path name *before* the chdir()
444 $newpwd = Win32::GetFullPathName($newdir);
445 }
446
447 return 0 unless CORE::chdir $newdir;
448
449 if ($^O eq 'VMS') {
450 return $ENV{'PWD'} = $ENV{'DEFAULT'}
451 }
452 elsif ($^O eq 'MacOS') {
453 return $ENV{'PWD'} = cwd();
454 }
455 elsif ($^O eq 'MSWin32') {
456 $ENV{'PWD'} = $newpwd;
457 return 1;
458 }
459
460 if ($newdir =~ m#^/#s) {
461 $ENV{'PWD'} = $newdir;
462 } else {
463 my @curdir = split(m#/#,$ENV{'PWD'});
464 @curdir = ('') unless @curdir;
465 my $component;
466 foreach $component (split(m#/#, $newdir)) {
467 next if $component eq '.';
468 pop(@curdir),next if $component eq '..';
469 push(@curdir,$component);
470 }
471 $ENV{'PWD'} = join('/',@curdir) || '/';
472 }
473 1;
474 }
475
476
477 sub _perl_abs_path
478 {
479 my $start = @_ ? shift : '.';
480 my($dotdots, $cwd, @pst, @cst, $dir, @tst);
481
482 unless (@cst = stat( $start ))
483 {
484 _carp("stat($start): $!");
485 return '';
486 }
487
488 unless (-d _) {
489 # Make sure we can be invoked on plain files, not just directories.
490 # NOTE that this routine assumes that '/' is the only directory separator.
491
492 my ($dir, $file) = $start =~ m{^(.*)/(.+)$}
493 or return cwd() . '/' . $start;
494
495 # Can't use "-l _" here, because the previous stat was a stat(), not an lstat().
496 if (-l $start) {
497 my $link_target = readlink($start);
498 die "Can't resolve link $start: $!" unless defined $link_target;
499
500 require File::Spec;
501 $link_target = $dir . '/' . $link_target
502 unless File::Spec->file_name_is_absolute($link_target);
503
504 return abs_path($link_target);
505 }
506
507 return $dir ? abs_path($dir) . "/$file" : "/$file";
508 }
509
510 $cwd = '';
511 $dotdots = $start;
512 do
513 {
514 $dotdots .= '/..';
515 @pst = @cst;
516 local *PARENT;
517 unless (opendir(PARENT, $dotdots))
518 {
519 _carp("opendir($dotdots): $!");
520 return '';
521 }
522 unless (@cst = stat($dotdots))
523 {
524 _carp("stat($dotdots): $!");
525 closedir(PARENT);
526 return '';
527 }
528 if ($pst[0] == $cst[0] && $pst[1] == $cst[1])
529 {
530 $dir = undef;
531 }
532 else
533 {
534 do
535 {
536 unless (defined ($dir = readdir(PARENT)))
537 {
538 _carp("readdir($dotdots): $!");
539 closedir(PARENT);
540 return '';
541 }
542 $tst[0] = $pst[0]+1 unless (@tst = lstat("$dotdots/$dir"))
543 }
544 while ($dir eq '.' || $dir eq '..' || $tst[0] != $pst[0] ||
545 $tst[1] != $pst[1]);
546 }
547 $cwd = (defined $dir ? "$dir" : "" ) . "/$cwd" ;
548 closedir(PARENT);
549 } while (defined $dir);
550 chop($cwd) unless $cwd eq '/'; # drop the trailing /
551 $cwd;
552 }
553
554
555 my $Curdir;
556 sub fast_abs_path {
557 local $ENV{PWD} = $ENV{PWD} || ''; # Guard against clobberage
558 my $cwd = getcwd();
559 require File::Spec;
560 my $path = @_ ? shift : ($Curdir ||= File::Spec->curdir);
561
562 # Detaint else we'll explode in taint mode. This is safe because
563 # we're not doing anything dangerous with it.
564 ($path) = $path =~ /(.*)/;
565 ($cwd) = $cwd =~ /(.*)/;
566
567 unless (-e $path) {
568 _croak("$path: No such file or directory");
569 }
570
571 unless (-d _) {
572 # Make sure we can be invoked on plain files, not just directories.
573
574 my ($vol, $dir, $file) = File::Spec->splitpath($path);
575 return File::Spec->catfile($cwd, $path) unless length $dir;
576
577 if (-l $path) {
578 my $link_target = readlink($path);
579 die "Can't resolve link $path: $!" unless defined $link_target;
580
581 $link_target = File::Spec->catpath($vol, $dir, $link_target)
582 unless File::Spec->file_name_is_absolute($link_target);
583
584 return fast_abs_path($link_target);
585 }
586
587 my $tdir = $dir;
588 $tdir =~ s!\\!/!g if $^O eq 'MSWin32';
589 return $tdir eq File::Spec->rootdir
590 ? File::Spec->catpath($vol, $dir, $file)
591 : fast_abs_path(File::Spec->catpath($vol, $dir, '')) . '/' . $file;
592 }
593
594 if (!CORE::chdir($path)) {
595 _croak("Cannot chdir to $path: $!");
596 }
597 my $realpath = getcwd();
598 if (! ((-d $cwd) && (CORE::chdir($cwd)))) {
599 _croak("Cannot chdir back to $cwd: $!");
600 }
601 $realpath;
602 }
603
604 # added function alias to follow principle of least surprise
605 # based on previous aliasing. --tchrist 27-Jan-00
606 *fast_realpath = \&fast_abs_path;
607
608
609 # --- PORTING SECTION ---
610
611 # VMS: $ENV{'DEFAULT'} points to default directory at all times
612 # 06-Mar-1996 Charles Bailey bailey@newman.upenn.edu
613 # Note: Use of Cwd::chdir() causes the logical name PWD to be defined
614 # in the process logical name table as the default device and directory
615 # seen by Perl. This may not be the same as the default device
616 # and directory seen by DCL after Perl exits, since the effects
617 # the CRTL chdir() function persist only until Perl exits.
618
619 sub _vms_cwd {
620 return $ENV{'DEFAULT'};
621 }
622
623 sub _vms_abs_path {
624 return $ENV{'DEFAULT'} unless @_;
625
626 # may need to turn foo.dir into [.foo]
627 my $path = VMS::Filespec::pathify($_[0]);
628 $path = $_[0] unless defined $path;
629
630 return VMS::Filespec::rmsexpand($path);
631 }
632
633 sub _os2_cwd {
634 $ENV{'PWD'} = `cmd /c cd`;
635 chomp $ENV{'PWD'};
636 $ENV{'PWD'} =~ s:\\:/:g ;
637 return $ENV{'PWD'};
638 }
639
640 sub _win32_cwd {
641 $ENV{'PWD'} = Win32::GetCwd();
642 $ENV{'PWD'} =~ s:\\:/:g ;
643 return $ENV{'PWD'};
644 }
645
646 *_NT_cwd = \&_win32_cwd if (!defined &_NT_cwd &&
647 defined &Win32::GetCwd);
648
649 *_NT_cwd = \&_os2_cwd unless defined &_NT_cwd;
650
651 sub _dos_cwd {
652 if (!defined &Dos::GetCwd) {
653 $ENV{'PWD'} = `command /c cd`;
654 chomp $ENV{'PWD'};
655 $ENV{'PWD'} =~ s:\\:/:g ;
656 } else {
657 $ENV{'PWD'} = Dos::GetCwd();
658 }
659 return $ENV{'PWD'};
660 }
661
662 sub _qnx_cwd {
663 local $ENV{PATH} = '';
664 local $ENV{CDPATH} = '';
665 local $ENV{ENV} = '';
666 $ENV{'PWD'} = `/usr/bin/fullpath -t`;
667 chomp $ENV{'PWD'};
668 return $ENV{'PWD'};
669 }
670
671 sub _qnx_abs_path {
672 local $ENV{PATH} = '';
673 local $ENV{CDPATH} = '';
674 local $ENV{ENV} = '';
675 my $path = @_ ? shift : '.';
676 local *REALPATH;
677
678 defined( open(REALPATH, '-|') || exec '/usr/bin/fullpath', '-t', $path ) or
679 die "Can't open /usr/bin/fullpath: $!";
680 my $realpath = <REALPATH>;
681 close REALPATH;
682 chomp $realpath;
683 return $realpath;
684 }
685
686 sub _epoc_cwd {
687 $ENV{'PWD'} = EPOC::getcwd();
688 return $ENV{'PWD'};
689 }
690
691
692 # Now that all the base-level functions are set up, alias the
693 # user-level functions to the right places
694
695 if (exists $METHOD_MAP{$^O}) {
696 my $map = $METHOD_MAP{$^O};
697 foreach my $name (keys %$map) {
698 local $^W = 0; # assignments trigger 'subroutine redefined' warning
699 no strict 'refs';
700 *{$name} = \&{$map->{$name}};
701 }
702 }
703
704 # In case the XS version doesn't load.
705 *abs_path = \&_perl_abs_path unless defined &abs_path;
706
707 # added function alias for those of us more
708 # used to the libc function. --tchrist 27-Jan-00
709 *realpath = \&abs_path;
710
711 1;