1package File::Spec::Unix; 2 3use strict; 4use vars qw($VERSION); 5 6$VERSION = '1.5'; 7 8=head1 NAME 9 10File::Spec::Unix - File::Spec for Unix, base for other File::Spec modules 11 12=head1 SYNOPSIS 13 14 require File::Spec::Unix; # Done automatically by File::Spec 15 16=head1 DESCRIPTION 17 18Methods for manipulating file specifications. Other File::Spec 19modules, such as File::Spec::Mac, inherit from File::Spec::Unix and 20override specific methods. 21 22=head1 METHODS 23 24=over 2 25 26=item canonpath() 27 28No physical check on the filesystem, but a logical cleanup of a 29path. On UNIX eliminates successive slashes and successive "/.". 30 31 $cpath = File::Spec->canonpath( $path ) ; 32 33=cut 34 35sub canonpath { 36 my ($self,$path) = @_; 37 38 # Handle POSIX-style node names beginning with double slash (qnx, nto) 39 # Handle network path names beginning with double slash (cygwin) 40 # (POSIX says: "a pathname that begins with two successive slashes 41 # may be interpreted in an implementation-defined manner, although 42 # more than two leading slashes shall be treated as a single slash.") 43 my $node = ''; 44 if ( $^O =~ m/^(?:qnx|nto|cygwin)$/ && $path =~ s:^(//[^/]+)(/|\z):/:s ) { 45 $node = $1; 46 } 47 # This used to be 48 # $path =~ s|/+|/|g unless($^O eq 'cygwin'); 49 # but that made tests 29, 30, 35, 46, and 213 (as of #13272) to fail 50 # (Mainly because trailing "" directories didn't get stripped). 51 # Why would cygwin avoid collapsing multiple slashes into one? --jhi 52 $path =~ s|/+|/|g; # xx////xx -> xx/xx 53 $path =~ s@(/\.)+(/|\Z(?!\n))@/@g; # xx/././xx -> xx/xx 54 $path =~ s|^(\./)+||s unless $path eq "./"; # ./xx -> xx 55 $path =~ s|^/(\.\./)+|/|s; # /../../xx -> xx 56 $path =~ s|/\Z(?!\n)|| unless $path eq "/"; # xx/ -> xx 57 return "$node$path"; 58} 59 60=item catdir() 61 62Concatenate two or more directory names to form a complete path ending 63with a directory. But remove the trailing slash from the resulting 64string, because it doesn't look good, isn't necessary and confuses 65OS2. Of course, if this is the root directory, don't cut off the 66trailing slash :-) 67 68=cut 69 70sub catdir { 71 my $self = shift; 72 73 $self->canonpath(join('/', @_, '')); # '' because need a trailing '/' 74} 75 76=item catfile 77 78Concatenate one or more directory names and a filename to form a 79complete path ending with a filename 80 81=cut 82 83sub catfile { 84 my $self = shift; 85 my $file = $self->canonpath(pop @_); 86 return $file unless @_; 87 my $dir = $self->catdir(@_); 88 $dir .= "/" unless substr($dir,-1) eq "/"; 89 return $dir.$file; 90} 91 92=item curdir 93 94Returns a string representation of the current directory. "." on UNIX. 95 96=cut 97 98sub curdir () { '.' } 99 100=item devnull 101 102Returns a string representation of the null device. "/dev/null" on UNIX. 103 104=cut 105 106sub devnull () { '/dev/null' } 107 108=item rootdir 109 110Returns a string representation of the root directory. "/" on UNIX. 111 112=cut 113 114sub rootdir () { '/' } 115 116=item tmpdir 117 118Returns a string representation of the first writable directory from 119the following list or the current directory if none from the list are 120writable: 121 122 $ENV{TMPDIR} 123 /tmp 124 125Since perl 5.8.0, if running under taint mode, and if $ENV{TMPDIR} 126is tainted, it is not used. 127 128=cut 129 130my $tmpdir; 131sub _tmpdir { 132 return $tmpdir if defined $tmpdir; 133 my $self = shift; 134 my @dirlist = @_; 135 { 136 no strict 'refs'; 137 if (${"\cTAINT"}) { # Check for taint mode on perl >= 5.8.0 138 require Scalar::Util; 139 @dirlist = grep { ! Scalar::Util::tainted($_) } @dirlist; 140 } 141 } 142 foreach (@dirlist) { 143 next unless defined && -d && -w _; 144 $tmpdir = $_; 145 last; 146 } 147 $tmpdir = $self->curdir unless defined $tmpdir; 148 $tmpdir = defined $tmpdir && $self->canonpath($tmpdir); 149 return $tmpdir; 150} 151 152sub tmpdir { 153 return $tmpdir if defined $tmpdir; 154 my $self = shift; 155 $tmpdir = $self->_tmpdir( $ENV{TMPDIR}, "/tmp" ); 156} 157 158=item updir 159 160Returns a string representation of the parent directory. ".." on UNIX. 161 162=cut 163 164sub updir () { '..' } 165 166=item no_upwards 167 168Given a list of file names, strip out those that refer to a parent 169directory. (Does not strip symlinks, only '.', '..', and equivalents.) 170 171=cut 172 173sub no_upwards { 174 my $self = shift; 175 return grep(!/^\.{1,2}\Z(?!\n)/s, @_); 176} 177 178=item case_tolerant 179 180Returns a true or false value indicating, respectively, that alphabetic 181is not or is significant when comparing file specifications. 182 183=cut 184 185sub case_tolerant () { 0 } 186 187=item file_name_is_absolute 188 189Takes as argument a path and returns true if it is an absolute path. 190 191This does not consult the local filesystem on Unix, Win32, OS/2 or Mac 192OS (Classic). It does consult the working environment for VMS (see 193L<File::Spec::VMS/file_name_is_absolute>). 194 195=cut 196 197sub file_name_is_absolute { 198 my ($self,$file) = @_; 199 return scalar($file =~ m:^/:s); 200} 201 202=item path 203 204Takes no argument, returns the environment variable PATH as an array. 205 206=cut 207 208sub path { 209 return () unless exists $ENV{PATH}; 210 my @path = split(':', $ENV{PATH}); 211 foreach (@path) { $_ = '.' if $_ eq '' } 212 return @path; 213} 214 215=item join 216 217join is the same as catfile. 218 219=cut 220 221sub join { 222 my $self = shift; 223 return $self->catfile(@_); 224} 225 226=item splitpath 227 228 ($volume,$directories,$file) = File::Spec->splitpath( $path ); 229 ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file ); 230 231Splits a path into volume, directory, and filename portions. On systems 232with no concept of volume, returns '' for volume. 233 234For systems with no syntax differentiating filenames from directories, 235assumes that the last file is a path unless $no_file is true or a 236trailing separator or /. or /.. is present. On Unix this means that $no_file 237true makes this return ( '', $path, '' ). 238 239The directory portion may or may not be returned with a trailing '/'. 240 241The results can be passed to L</catpath()> to get back a path equivalent to 242(usually identical to) the original path. 243 244=cut 245 246sub splitpath { 247 my ($self,$path, $nofile) = @_; 248 249 my ($volume,$directory,$file) = ('','',''); 250 251 if ( $nofile ) { 252 $directory = $path; 253 } 254 else { 255 $path =~ m|^ ( (?: .* / (?: \.\.?\Z(?!\n) )? )? ) ([^/]*) |xs; 256 $directory = $1; 257 $file = $2; 258 } 259 260 return ($volume,$directory,$file); 261} 262 263 264=item splitdir 265 266The opposite of L</catdir()>. 267 268 @dirs = File::Spec->splitdir( $directories ); 269 270$directories must be only the directory portion of the path on systems 271that have the concept of a volume or that have path syntax that differentiates 272files from directories. 273 274Unlike just splitting the directories on the separator, empty 275directory names (C<''>) can be returned, because these are significant 276on some OSs. 277 278On Unix, 279 280 File::Spec->splitdir( "/a/b//c/" ); 281 282Yields: 283 284 ( '', 'a', 'b', '', 'c', '' ) 285 286=cut 287 288sub splitdir { 289 return split m|/|, $_[1], -1; # Preserve trailing fields 290} 291 292 293=item catpath() 294 295Takes volume, directory and file portions and returns an entire path. Under 296Unix, $volume is ignored, and directory and file are concatenated. A '/' is 297inserted if needed (though if the directory portion doesn't start with 298'/' it is not added). On other OSs, $volume is significant. 299 300=cut 301 302sub catpath { 303 my ($self,$volume,$directory,$file) = @_; 304 305 if ( $directory ne '' && 306 $file ne '' && 307 substr( $directory, -1 ) ne '/' && 308 substr( $file, 0, 1 ) ne '/' 309 ) { 310 $directory .= "/$file" ; 311 } 312 else { 313 $directory .= $file ; 314 } 315 316 return $directory ; 317} 318 319=item abs2rel 320 321Takes a destination path and an optional base path returns a relative path 322from the base path to the destination path: 323 324 $rel_path = File::Spec->abs2rel( $path ) ; 325 $rel_path = File::Spec->abs2rel( $path, $base ) ; 326 327If $base is not present or '', then L<cwd()|Cwd> is used. If $base is 328relative, then it is converted to absolute form using 329L</rel2abs()>. This means that it is taken to be relative to 330L<cwd()|Cwd>. 331 332On systems that have a grammar that indicates filenames, this ignores the 333$base filename. Otherwise all path components are assumed to be 334directories. 335 336If $path is relative, it is converted to absolute form using L</rel2abs()>. 337This means that it is taken to be relative to L<cwd()|Cwd>. 338 339No checks against the filesystem are made. On VMS, there is 340interaction with the working environment, as logicals and 341macros are expanded. 342 343Based on code written by Shigio Yamaguchi. 344 345=cut 346 347sub abs2rel { 348 my($self,$path,$base) = @_; 349 350 # Clean up $path 351 if ( ! $self->file_name_is_absolute( $path ) ) { 352 $path = $self->rel2abs( $path ) ; 353 } 354 else { 355 $path = $self->canonpath( $path ) ; 356 } 357 358 # Figure out the effective $base and clean it up. 359 if ( !defined( $base ) || $base eq '' ) { 360 $base = $self->_cwd(); 361 } 362 elsif ( ! $self->file_name_is_absolute( $base ) ) { 363 $base = $self->rel2abs( $base ) ; 364 } 365 else { 366 $base = $self->canonpath( $base ) ; 367 } 368 369 # Now, remove all leading components that are the same 370 my @pathchunks = $self->splitdir( $path); 371 my @basechunks = $self->splitdir( $base); 372 373 while (@pathchunks && @basechunks && $pathchunks[0] eq $basechunks[0]) { 374 shift @pathchunks ; 375 shift @basechunks ; 376 } 377 378 $path = CORE::join( '/', @pathchunks ); 379 $base = CORE::join( '/', @basechunks ); 380 381 # $base now contains the directories the resulting relative path 382 # must ascend out of before it can descend to $path_directory. So, 383 # replace all names with $parentDir 384 $base =~ s|[^/]+|..|g ; 385 386 # Glue the two together, using a separator if necessary, and preventing an 387 # empty result. 388 if ( $path ne '' && $base ne '' ) { 389 $path = "$base/$path" ; 390 } else { 391 $path = "$base$path" ; 392 } 393 394 return $self->canonpath( $path ) ; 395} 396 397=item rel2abs() 398 399Converts a relative path to an absolute path. 400 401 $abs_path = File::Spec->rel2abs( $path ) ; 402 $abs_path = File::Spec->rel2abs( $path, $base ) ; 403 404If $base is not present or '', then L<cwd()|Cwd> is used. If $base is 405relative, then it is converted to absolute form using 406L</rel2abs()>. This means that it is taken to be relative to 407L<cwd()|Cwd>. 408 409On systems that have a grammar that indicates filenames, this ignores 410the $base filename. Otherwise all path components are assumed to be 411directories. 412 413If $path is absolute, it is cleaned up and returned using L</canonpath()>. 414 415No checks against the filesystem are made. On VMS, there is 416interaction with the working environment, as logicals and 417macros are expanded. 418 419Based on code written by Shigio Yamaguchi. 420 421=cut 422 423sub rel2abs { 424 my ($self,$path,$base ) = @_; 425 426 # Clean up $path 427 if ( ! $self->file_name_is_absolute( $path ) ) { 428 # Figure out the effective $base and clean it up. 429 if ( !defined( $base ) || $base eq '' ) { 430 $base = $self->_cwd(); 431 } 432 elsif ( ! $self->file_name_is_absolute( $base ) ) { 433 $base = $self->rel2abs( $base ) ; 434 } 435 else { 436 $base = $self->canonpath( $base ) ; 437 } 438 439 # Glom them together 440 $path = $self->catdir( $base, $path ) ; 441 } 442 443 return $self->canonpath( $path ) ; 444} 445 446=back 447 448=head1 SEE ALSO 449 450L<File::Spec> 451 452=cut 453 454# Internal routine to File::Spec, no point in making this public since 455# it is the standard Cwd interface. Most of the platform-specific 456# File::Spec subclasses use this. 457sub _cwd { 458 require Cwd; 459 Cwd::cwd(); 460} 461 4621; 463