This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
5.004_58 QNX getcwd
[perl5.git] / lib / Cwd.pm
CommitLineData
a0d0e21e
LW
1package Cwd;
2require 5.000;
a0d0e21e 3
f06db76b
AD
4=head1 NAME
5
6getcwd - get pathname of current working directory
7
8=head1 SYNOPSIS
9
4633a7c4
LW
10 use Cwd;
11 $dir = cwd;
12
13 use Cwd;
14 $dir = getcwd;
f06db76b
AD
15
16 use Cwd;
4633a7c4 17 $dir = fastgetcwd;
f06db76b
AD
18
19 use Cwd 'chdir';
20 chdir "/tmp";
21 print $ENV{'PWD'};
22
23=head1 DESCRIPTION
24
25The getcwd() function re-implements the getcwd(3) (or getwd(3)) functions
4633a7c4 26in Perl.
f06db76b 27
cb1a09d0 28The fastcwd() function looks the same as getcwd(), but runs faster.
fb73857a 29It's also more dangerous because it might conceivably chdir() you out
30of a directory that it can't chdir() you back into. If fastcwd
31encounters a problem it will return undef but will probably leave you
32in a different directory. For a measure of extra security, if
33everything appears to have worked, the fastcwd() function will check
34that it leaves you in the same directory that it started in. If it has
35changed it will C<die> with the message "Unstable directory path,
36current directory changed unexpectedly". That should never happen.
f06db76b 37
4633a7c4
LW
38The cwd() function looks the same as getcwd and fastgetcwd but is
39implemented using the most natural and safe form for the current
40architecture. For most systems it is identical to `pwd` (but without
fb73857a 41the trailing line terminator).
42
43It is recommended that cwd (or another *cwd() function) is used in
44I<all> code to ensure portability.
4633a7c4
LW
45
46If you ask to override your chdir() built-in function, then your PWD
47environment variable will be kept up to date. (See
55497cff 48L<perlsub/Overriding Builtin Functions>.) Note that it will only be
1fef88e7 49kept up to date if all packages which use chdir import it from Cwd.
4633a7c4 50
f06db76b
AD
51=cut
52
96e4d5b1 53## use strict;
54
55use Carp;
56
57$VERSION = '2.00';
58
59require Exporter;
a0d0e21e 60@ISA = qw(Exporter);
e7ae0116 61@EXPORT = qw(cwd getcwd fastcwd fastgetcwd);
96e4d5b1 62@EXPORT_OK = qw(chdir abs_path fast_abs_path);
a0d0e21e 63
4633a7c4 64
8b88ae92 65# The 'natural and safe form' for UNIX (pwd may be setuid root)
96e4d5b1 66
8b88ae92 67sub _backtick_pwd {
4633a7c4
LW
68 my $cwd;
69 chop($cwd = `pwd`);
70 $cwd;
8b88ae92 71}
4633a7c4
LW
72
73# Since some ports may predefine cwd internally (e.g., NT)
74# we take care not to override an existing definition for cwd().
75
76*cwd = \&_backtick_pwd unless defined &cwd;
a0d0e21e 77
748a9306 78
a0d0e21e
LW
79# By Brandon S. Allbery
80#
81# Usage: $cwd = getcwd();
82
83sub getcwd
84{
85 my($dotdots, $cwd, @pst, @cst, $dir, @tst);
86
87 unless (@cst = stat('.'))
88 {
89 warn "stat(.): $!";
90 return '';
91 }
92 $cwd = '';
42793c05 93 $dotdots = '';
a0d0e21e
LW
94 do
95 {
96 $dotdots .= '/' if $dotdots;
97 $dotdots .= '..';
98 @pst = @cst;
99 unless (opendir(PARENT, $dotdots))
100 {
101 warn "opendir($dotdots): $!";
102 return '';
103 }
104 unless (@cst = stat($dotdots))
105 {
106 warn "stat($dotdots): $!";
107 closedir(PARENT);
108 return '';
109 }
110 if ($pst[0] == $cst[0] && $pst[1] == $cst[1])
111 {
fb73857a 112 $dir = undef;
a0d0e21e
LW
113 }
114 else
115 {
116 do
117 {
3edbfbe5
TB
118 unless (defined ($dir = readdir(PARENT)))
119 {
a0d0e21e
LW
120 warn "readdir($dotdots): $!";
121 closedir(PARENT);
122 return '';
123 }
124 unless (@tst = lstat("$dotdots/$dir"))
125 {
55497cff 126 # warn "lstat($dotdots/$dir): $!";
37120919
AD
127 # Just because you can't lstat this directory
128 # doesn't mean you'll never find the right one.
129 # closedir(PARENT);
130 # return '';
a0d0e21e
LW
131 }
132 }
133 while ($dir eq '.' || $dir eq '..' || $tst[0] != $pst[0] ||
134 $tst[1] != $pst[1]);
135 }
fb73857a 136 $cwd = (defined $dir ? "$dir" : "" ) . "/$cwd" ;
a0d0e21e 137 closedir(PARENT);
fb73857a 138 } while (defined $dir);
f6c18ff1 139 chop($cwd) unless $cwd eq '/'; # drop the trailing /
a0d0e21e
LW
140 $cwd;
141}
142
143
144
145# By John Bazik
146#
147# Usage: $cwd = &fastcwd;
148#
149# This is a faster version of getcwd. It's also more dangerous because
150# you might chdir out of a directory that you can't chdir back into.
fb73857a 151
152# List of metachars taken from do_exec() in doio.c
153my $quoted_shell_meta = quotemeta('$&*(){}[]";\\|?<>~`'."'\n");
a0d0e21e
LW
154
155sub fastcwd {
156 my($odev, $oino, $cdev, $cino, $tdev, $tino);
157 my(@path, $path);
158 local(*DIR);
159
fb73857a 160 my($orig_cdev, $orig_cino) = stat('.');
161 ($cdev, $cino) = ($orig_cdev, $orig_cino);
a0d0e21e 162 for (;;) {
40000a8c 163 my $direntry;
a0d0e21e 164 ($odev, $oino) = ($cdev, $cino);
fb73857a 165 chdir('..') || return undef;
a0d0e21e
LW
166 ($cdev, $cino) = stat('.');
167 last if $odev == $cdev && $oino == $cino;
fb73857a 168 opendir(DIR, '.') || return undef;
a0d0e21e 169 for (;;) {
40000a8c 170 $direntry = readdir(DIR);
fb73857a 171 last unless defined $direntry;
40000a8c
AD
172 next if $direntry eq '.';
173 next if $direntry eq '..';
a0d0e21e 174
40000a8c 175 ($tdev, $tino) = lstat($direntry);
a0d0e21e
LW
176 last unless $tdev != $odev || $tino != $oino;
177 }
178 closedir(DIR);
fb73857a 179 return undef unless defined $direntry; # should never happen
40000a8c 180 unshift(@path, $direntry);
a0d0e21e 181 }
fb73857a 182 $path = '/' . join('/', @path);
183 # At this point $path may be tainted (if tainting) and chdir would fail.
184 # To be more useful we untaint it then check that we landed where we started.
185 $path = $1 if $path =~ /^(.*)$/; # untaint
186 chdir($path) || return undef;
187 ($cdev, $cino) = stat('.');
188 die "Unstable directory path, current directory changed unexpectedly"
189 if $cdev != $orig_cdev || $cino != $orig_cino;
a0d0e21e
LW
190 $path;
191}
192
193
4633a7c4 194# Keeps track of current working directory in PWD environment var
a0d0e21e
LW
195# Usage:
196# use Cwd 'chdir';
197# chdir $newdir;
198
4633a7c4 199my $chdir_init = 0;
a0d0e21e 200
4633a7c4 201sub chdir_init {
39e571d4 202 if ($ENV{'PWD'} and $^O ne 'os2' and $^O ne 'dos') {
a0d0e21e
LW
203 my($dd,$di) = stat('.');
204 my($pd,$pi) = stat($ENV{'PWD'});
205 if (!defined $dd or !defined $pd or $di != $pi or $dd != $pd) {
4633a7c4 206 $ENV{'PWD'} = cwd();
a0d0e21e
LW
207 }
208 }
209 else {
4633a7c4 210 $ENV{'PWD'} = cwd();
a0d0e21e 211 }
4633a7c4 212 # Strip an automounter prefix (where /tmp_mnt/foo/bar == /foo/bar)
a0d0e21e
LW
213 if ($ENV{'PWD'} =~ m|(/[^/]+(/[^/]+/[^/]+))(.*)|) {
214 my($pd,$pi) = stat($2);
215 my($dd,$di) = stat($1);
216 if (defined $pd and defined $dd and $di == $pi and $dd == $pd) {
217 $ENV{'PWD'}="$2$3";
218 }
219 }
220 $chdir_init = 1;
221}
222
223sub chdir {
4633a7c4
LW
224 my $newdir = shift || ''; # allow for no arg (chdir to HOME dir)
225 $newdir =~ s|///*|/|g;
a0d0e21e 226 chdir_init() unless $chdir_init;
4633a7c4 227 return 0 unless CORE::chdir $newdir;
c6538b72 228 if ($^O eq 'VMS') { return $ENV{'PWD'} = $ENV{'DEFAULT'} }
748a9306 229
a0d0e21e
LW
230 if ($newdir =~ m#^/#) {
231 $ENV{'PWD'} = $newdir;
4633a7c4
LW
232 } else {
233 my @curdir = split(m#/#,$ENV{'PWD'});
234 @curdir = ('') unless @curdir;
235 my $component;
a0d0e21e
LW
236 foreach $component (split(m#/#, $newdir)) {
237 next if $component eq '.';
238 pop(@curdir),next if $component eq '..';
239 push(@curdir,$component);
240 }
241 $ENV{'PWD'} = join('/',@curdir) || '/';
242 }
4633a7c4 243 1;
a0d0e21e
LW
244}
245
8b88ae92
NIS
246# Taken from Cwd.pm It is really getcwd with an optional
247# parameter instead of '.'
248#
249
250sub abs_path
251{
252 my $start = shift || '.';
253 my($dotdots, $cwd, @pst, @cst, $dir, @tst);
254
255 unless (@cst = stat( $start ))
256 {
257 carp "stat($start): $!";
258 return '';
259 }
260 $cwd = '';
261 $dotdots = $start;
262 do
263 {
264 $dotdots .= '/..';
265 @pst = @cst;
266 unless (opendir(PARENT, $dotdots))
267 {
268 carp "opendir($dotdots): $!";
269 return '';
270 }
271 unless (@cst = stat($dotdots))
272 {
273 carp "stat($dotdots): $!";
274 closedir(PARENT);
275 return '';
276 }
277 if ($pst[0] == $cst[0] && $pst[1] == $cst[1])
278 {
279 $dir = '';
280 }
281 else
282 {
283 do
284 {
285 unless (defined ($dir = readdir(PARENT)))
286 {
287 carp "readdir($dotdots): $!";
288 closedir(PARENT);
289 return '';
290 }
291 $tst[0] = $pst[0]+1 unless (@tst = lstat("$dotdots/$dir"))
292 }
293 while ($dir eq '.' || $dir eq '..' || $tst[0] != $pst[0] ||
294 $tst[1] != $pst[1]);
295 }
296 $cwd = "$dir/$cwd";
297 closedir(PARENT);
298 } while ($dir);
299 chop($cwd); # drop the trailing /
300 $cwd;
301}
302
96e4d5b1 303sub fast_abs_path {
304 my $cwd = getcwd();
305 my $path = shift || '.';
306 chdir($path) || croak "Cannot chdir to $path:$!";
307 my $realpath = getcwd();
308 chdir($cwd) || croak "Cannot chdir back to $cwd:$!";
309 $realpath;
8b88ae92
NIS
310}
311
4633a7c4
LW
312
313# --- PORTING SECTION ---
314
315# VMS: $ENV{'DEFAULT'} points to default directory at all times
c6538b72 316# 06-Mar-1996 Charles Bailey bailey@genetics.upenn.edu
317# Note: Use of Cwd::chdir() causes the logical name PWD to be defined
8b88ae92
NIS
318# in the process logical name table as the default device and directory
319# seen by Perl. This may not be the same as the default device
4633a7c4
LW
320# and directory seen by DCL after Perl exits, since the effects
321# the CRTL chdir() function persist only until Perl exits.
4633a7c4
LW
322
323sub _vms_cwd {
96e4d5b1 324 return $ENV{'DEFAULT'};
325}
326
327sub _vms_abs_path {
328 return $ENV{'DEFAULT'} unless @_;
329 my $path = VMS::Filespec::pathify($_[0]);
330 croak("Invalid path name $_[0]") unless defined $path;
331 return VMS::Filespec::rmsexpand($path);
4633a7c4 332}
68dc0745 333
4633a7c4
LW
334sub _os2_cwd {
335 $ENV{'PWD'} = `cmd /c cd`;
336 chop $ENV{'PWD'};
337 $ENV{'PWD'} =~ s:\\:/:g ;
338 return $ENV{'PWD'};
339}
340
96e4d5b1 341sub _win32_cwd {
2d7a9237 342 $ENV{'PWD'} = Win32::GetCwd();
96e4d5b1 343 $ENV{'PWD'} =~ s:\\:/:g ;
344 return $ENV{'PWD'};
345}
346
347*_NT_cwd = \&_win32_cwd if (!defined &_NT_cwd &&
2d7a9237 348 defined &Win32::GetCwd);
96e4d5b1 349
350*_NT_cwd = \&_os2_cwd unless defined &_NT_cwd;
68dc0745 351
39e571d4
LM
352sub _dos_cwd {
353 if (!defined &Dos::GetCwd) {
354 $ENV{'PWD'} = `command /c cd`;
355 chop $ENV{'PWD'};
356 $ENV{'PWD'} =~ s:\\:/:g ;
357 } else {
358 $ENV{'PWD'} = Dos::GetCwd();
359 }
55497cff 360 return $ENV{'PWD'};
361}
362
7fbf1995
NA
363sub _qnx_cwd {
364 $ENV{'PWD'} = `/usr/bin/fullpath -t`;
365 chop $ENV{'PWD'};
366 return $ENV{'PWD'};
367}
368
369sub _qnx_abs_path {
370 my $path = shift || '.';
371 my $realpath=`/usr/bin/fullpath -t $path`;
372 chop $realpath;
373 return $realpath;
374}
375
ac1ad7f0
PM
376{
377 local $^W = 0; # assignments trigger 'subroutine redefined' warning
4633a7c4 378
ac1ad7f0 379 if ($^O eq 'VMS') {
96e4d5b1 380 *cwd = \&_vms_cwd;
381 *getcwd = \&_vms_cwd;
382 *fastcwd = \&_vms_cwd;
383 *fastgetcwd = \&_vms_cwd;
384 *abs_path = \&_vms_abs_path;
385 *fast_abs_path = \&_vms_abs_path;
ac1ad7f0
PM
386 }
387 elsif ($^O eq 'NT' or $^O eq 'MSWin32') {
388 # We assume that &_NT_cwd is defined as an XSUB or in the core.
96e4d5b1 389 *cwd = \&_NT_cwd;
390 *getcwd = \&_NT_cwd;
391 *fastcwd = \&_NT_cwd;
392 *fastgetcwd = \&_NT_cwd;
393 *abs_path = \&fast_abs_path;
ac1ad7f0
PM
394 }
395 elsif ($^O eq 'os2') {
396 # sys_cwd may keep the builtin command
96e4d5b1 397 *cwd = defined &sys_cwd ? \&sys_cwd : \&_os2_cwd;
398 *getcwd = \&cwd;
399 *fastgetcwd = \&cwd;
400 *fastcwd = \&cwd;
401 *abs_path = \&fast_abs_path;
ac1ad7f0 402 }
39e571d4
LM
403 elsif ($^O eq 'dos') {
404 *cwd = \&_dos_cwd;
405 *getcwd = \&_dos_cwd;
406 *fastgetcwd = \&_dos_cwd;
407 *fastcwd = \&_dos_cwd;
96e4d5b1 408 *abs_path = \&fast_abs_path;
ac1ad7f0 409 }
7fbf1995
NA
410 elsif ($^O eq 'qnx') {
411 *cwd = \&_qnx_cwd;
412 *getcwd = \&_qnx_cwd;
413 *fastgetcwd = \&_qnx_cwd;
414 *fastcwd = \&_qnx_cwd;
415 *abs_path = \&_qnx_abs_path;
416 *fast_abs_path = \&_qnx_abs_path;
417 }
55497cff 418}
4633a7c4
LW
419
420# package main; eval join('',<DATA>) || die $@; # quick test
421
a0d0e21e
LW
4221;
423
4633a7c4
LW
424__END__
425BEGIN { import Cwd qw(:DEFAULT chdir); }
426print join("\n", cwd, getcwd, fastcwd, "");
427chdir('..');
428print join("\n", cwd, getcwd, fastcwd, "");
429print "$ENV{PWD}\n";