Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

355 lines
8.9 KiB

  1. package File::Spec::Win32;
  2. use strict;
  3. use Cwd;
  4. use vars qw(@ISA $VERSION);
  5. require File::Spec::Unix;
  6. $VERSION = '1.2';
  7. @ISA = qw(File::Spec::Unix);
  8. =head1 NAME
  9. File::Spec::Win32 - methods for Win32 file specs
  10. =head1 SYNOPSIS
  11. require File::Spec::Win32; # Done internally by File::Spec if needed
  12. =head1 DESCRIPTION
  13. See File::Spec::Unix for a documentation of the methods provided
  14. there. This package overrides the implementation of these methods, not
  15. the semantics.
  16. =over
  17. =item devnull
  18. Returns a string representation of the null device.
  19. =cut
  20. sub devnull {
  21. return "nul";
  22. }
  23. =item tmpdir
  24. Returns a string representation of the first existing directory
  25. from the following list:
  26. $ENV{TMPDIR}
  27. $ENV{TEMP}
  28. $ENV{TMP}
  29. C:/temp
  30. /tmp
  31. /
  32. =cut
  33. my $tmpdir;
  34. sub tmpdir {
  35. return $tmpdir if defined $tmpdir;
  36. my $self = shift;
  37. foreach (@ENV{qw(TMPDIR TEMP TMP)}, qw(C:/temp /tmp /)) {
  38. next unless defined && -d;
  39. $tmpdir = $_;
  40. last;
  41. }
  42. $tmpdir = '' unless defined $tmpdir;
  43. $tmpdir = $self->canonpath($tmpdir);
  44. return $tmpdir;
  45. }
  46. sub case_tolerant {
  47. return 1;
  48. }
  49. sub file_name_is_absolute {
  50. my ($self,$file) = @_;
  51. return scalar($file =~ m{^([a-z]:)?[\\/]}is);
  52. }
  53. =item catfile
  54. Concatenate one or more directory names and a filename to form a
  55. complete path ending with a filename
  56. =cut
  57. sub catfile {
  58. my $self = shift;
  59. my $file = pop @_;
  60. return $file unless @_;
  61. my $dir = $self->catdir(@_);
  62. $dir .= "\\" unless substr($dir,-1) eq "\\";
  63. return $dir.$file;
  64. }
  65. sub path {
  66. my $path = $ENV{'PATH'} || $ENV{'Path'} || $ENV{'path'};
  67. my @path = split(';',$path);
  68. foreach (@path) { $_ = '.' if $_ eq '' }
  69. return @path;
  70. }
  71. =item canonpath
  72. No physical check on the filesystem, but a logical cleanup of a
  73. path. On UNIX eliminated successive slashes and successive "/.".
  74. =cut
  75. sub canonpath {
  76. my ($self,$path) = @_;
  77. $path =~ s/^([a-z]:)/\u$1/s;
  78. $path =~ s|/|\\|g;
  79. $path =~ s|([^\\])\\+|$1\\|g; # xx////xx -> xx/xx
  80. $path =~ s|(\\\.)+\\|\\|g; # xx/././xx -> xx/xx
  81. $path =~ s|^(\.\\)+||s unless $path eq ".\\"; # ./xx -> xx
  82. $path =~ s|\\\Z(?!\n)||
  83. unless $path =~ m#^([A-Z]:)?\\\Z(?!\n)#s; # xx/ -> xx
  84. return $path;
  85. }
  86. =item splitpath
  87. ($volume,$directories,$file) = File::Spec->splitpath( $path );
  88. ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
  89. Splits a path in to volume, directory, and filename portions. Assumes that
  90. the last file is a path unless the path ends in '\\', '\\.', '\\..'
  91. or $no_file is true. On Win32 this means that $no_file true makes this return
  92. ( $volume, $path, undef ).
  93. Separators accepted are \ and /.
  94. Volumes can be drive letters or UNC sharenames (\\server\share).
  95. The results can be passed to L</catpath> to get back a path equivalent to
  96. (usually identical to) the original path.
  97. =cut
  98. sub splitpath {
  99. my ($self,$path, $nofile) = @_;
  100. my ($volume,$directory,$file) = ('','','');
  101. if ( $nofile ) {
  102. $path =~
  103. m{^( (?:[a-zA-Z]:|(?:\\\\|//)[^\\/]+[\\/][^\\/]+)? )
  104. (.*)
  105. }xs;
  106. $volume = $1;
  107. $directory = $2;
  108. }
  109. else {
  110. $path =~
  111. m{^ ( (?: [a-zA-Z]: |
  112. (?:\\\\|//)[^\\/]+[\\/][^\\/]+
  113. )?
  114. )
  115. ( (?:.*[\\\\/](?:\.\.?\Z(?!\n))?)? )
  116. (.*)
  117. }xs;
  118. $volume = $1;
  119. $directory = $2;
  120. $file = $3;
  121. }
  122. return ($volume,$directory,$file);
  123. }
  124. =item splitdir
  125. The opposite of L</catdir()>.
  126. @dirs = File::Spec->splitdir( $directories );
  127. $directories must be only the directory portion of the path on systems
  128. that have the concept of a volume or that have path syntax that differentiates
  129. files from directories.
  130. Unlike just splitting the directories on the separator, leading empty and
  131. trailing directory entries can be returned, because these are significant
  132. on some OSs. So,
  133. File::Spec->splitdir( "/a/b/c" );
  134. Yields:
  135. ( '', 'a', 'b', '', 'c', '' )
  136. =cut
  137. sub splitdir {
  138. my ($self,$directories) = @_ ;
  139. #
  140. # split() likes to forget about trailing null fields, so here we
  141. # check to be sure that there will not be any before handling the
  142. # simple case.
  143. #
  144. if ( $directories !~ m|[\\/]\Z(?!\n)| ) {
  145. return split( m|[\\/]|, $directories );
  146. }
  147. else {
  148. #
  149. # since there was a trailing separator, add a file name to the end,
  150. # then do the split, then replace it with ''.
  151. #
  152. my( @directories )= split( m|[\\/]|, "${directories}dummy" ) ;
  153. $directories[ $#directories ]= '' ;
  154. return @directories ;
  155. }
  156. }
  157. =item catpath
  158. Takes volume, directory and file portions and returns an entire path. Under
  159. Unix, $volume is ignored, and this is just like catfile(). On other OSs,
  160. the $volume become significant.
  161. =cut
  162. sub catpath {
  163. my ($self,$volume,$directory,$file) = @_;
  164. # If it's UNC, make sure the glue separator is there, reusing
  165. # whatever separator is first in the $volume
  166. $volume .= $1
  167. if ( $volume =~ m@^([\\/])[\\/][^\\/]+[\\/][^\\/]+\Z(?!\n)@s &&
  168. $directory =~ m@^[^\\/]@s
  169. ) ;
  170. $volume .= $directory ;
  171. # If the volume is not just A:, make sure the glue separator is
  172. # there, reusing whatever separator is first in the $volume if possible.
  173. if ( $volume !~ m@^[a-zA-Z]:\Z(?!\n)@s &&
  174. $volume =~ m@[^\\/]\Z(?!\n)@ &&
  175. $file =~ m@[^\\/]@
  176. ) {
  177. $volume =~ m@([\\/])@ ;
  178. my $sep = $1 ? $1 : '\\' ;
  179. $volume .= $sep ;
  180. }
  181. $volume .= $file ;
  182. return $volume ;
  183. }
  184. sub abs2rel {
  185. my($self,$path,$base) = @_;
  186. # Clean up $path
  187. if ( ! $self->file_name_is_absolute( $path ) ) {
  188. $path = $self->rel2abs( $path ) ;
  189. }
  190. else {
  191. $path = $self->canonpath( $path ) ;
  192. }
  193. # Figure out the effective $base and clean it up.
  194. if ( ! $self->file_name_is_absolute( $base ) ) {
  195. $base = $self->rel2abs( $base ) ;
  196. }
  197. elsif ( !defined( $base ) || $base eq '' ) {
  198. $base = cwd() ;
  199. }
  200. else {
  201. $base = $self->canonpath( $base ) ;
  202. }
  203. # Split up paths
  204. my ( $path_volume, $path_directories, $path_file ) =
  205. $self->splitpath( $path, 1 ) ;
  206. my $base_directories = ($self->splitpath( $base, 1 ))[1] ;
  207. # Now, remove all leading components that are the same
  208. my @pathchunks = $self->splitdir( $path_directories );
  209. my @basechunks = $self->splitdir( $base_directories );
  210. while ( @pathchunks &&
  211. @basechunks &&
  212. lc( $pathchunks[0] ) eq lc( $basechunks[0] )
  213. ) {
  214. shift @pathchunks ;
  215. shift @basechunks ;
  216. }
  217. # No need to catdir, we know these are well formed.
  218. $path_directories = CORE::join( '\\', @pathchunks );
  219. $base_directories = CORE::join( '\\', @basechunks );
  220. # $base_directories now contains the directories the resulting relative
  221. # path must ascend out of before it can descend to $path_directory. So,
  222. # replace all names with $parentDir
  223. #FA Need to replace between backslashes...
  224. $base_directories =~ s|[^\\]+|..|g ;
  225. # Glue the two together, using a separator if necessary, and preventing an
  226. # empty result.
  227. #FA Must check that new directories are not empty.
  228. if ( $path_directories ne '' && $base_directories ne '' ) {
  229. $path_directories = "$base_directories\\$path_directories" ;
  230. } else {
  231. $path_directories = "$base_directories$path_directories" ;
  232. }
  233. # It makes no sense to add a relative path to a UNC volume
  234. $path_volume = '' unless $path_volume =~ m{^[A-Z]:}is ;
  235. return $self->canonpath(
  236. $self->catpath($path_volume, $path_directories, $path_file )
  237. ) ;
  238. }
  239. sub rel2abs {
  240. my ($self,$path,$base ) = @_;
  241. if ( ! $self->file_name_is_absolute( $path ) ) {
  242. if ( !defined( $base ) || $base eq '' ) {
  243. $base = cwd() ;
  244. }
  245. elsif ( ! $self->file_name_is_absolute( $base ) ) {
  246. $base = $self->rel2abs( $base ) ;
  247. }
  248. else {
  249. $base = $self->canonpath( $base ) ;
  250. }
  251. my ( $path_directories, $path_file ) =
  252. ($self->splitpath( $path, 1 ))[1,2] ;
  253. my ( $base_volume, $base_directories ) =
  254. $self->splitpath( $base, 1 ) ;
  255. $path = $self->catpath(
  256. $base_volume,
  257. $self->catdir( $base_directories, $path_directories ),
  258. $path_file
  259. ) ;
  260. }
  261. return $self->canonpath( $path ) ;
  262. }
  263. =back
  264. =head1 SEE ALSO
  265. L<File::Spec>
  266. =cut
  267. 1;