[ Index ] |
|
Code source de Symfony 1.0.0 |
1 <?php 2 /* 3 * $Id: Win32FileSystem.php 3076 2006-12-18 08:52:12Z fabien $ 4 * 5 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 6 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 7 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 8 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 9 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 10 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 11 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 12 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 13 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 14 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 15 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 * 17 * This software consists of voluntary contributions made by many individuals 18 * and is licensed under the LGPL. For more information please see 19 * <http://phing.info>. 20 */ 21 22 include_once 'phing/system/io/FileSystem.php'; 23 24 /** 25 * @package phing.system.io 26 */ 27 class Win32FileSystem extends FileSystem { 28 29 protected $slash; 30 protected $altSlash; 31 protected $semicolon; 32 33 private static $driveDirCache = array(); 34 35 function __construct() { 36 $this->slash = self::getSeparator(); 37 $this->semicolon = self::getPathSeparator(); 38 $this->altSlash = ($this->slash === '\\') ? '/' : '\\'; 39 } 40 41 function isSlash($c) { 42 return ($c == '\\') || ($c == '/'); 43 } 44 45 function isLetter($c) { 46 return ((ord($c) >= ord('a')) && (ord($c) <= ord('z'))) 47 || ((ord($c) >= ord('A')) && (ord($c) <= ord('Z'))); 48 } 49 50 function slashify($p) { 51 if ((strlen($p) > 0) && ($p{0} != $this->slash)) { 52 return $this->slash.$p; 53 } 54 else { 55 return $p; 56 } 57 } 58 59 /* -- Normalization and construction -- */ 60 61 function getSeparator() { 62 // the ascii value of is the \ 63 return chr(92); 64 } 65 66 function getPathSeparator() { 67 return ';'; 68 } 69 70 /** 71 * A normal Win32 pathname contains no duplicate slashes, except possibly 72 * for a UNC prefix, and does not end with a slash. It may be the empty 73 * string. Normalized Win32 pathnames have the convenient property that 74 * the length of the prefix almost uniquely identifies the type of the path 75 * and whether it is absolute or relative: 76 * 77 * 0 relative to both drive and directory 78 * 1 drive-relative (begins with '\\') 79 * 2 absolute UNC (if first char is '\\'), else directory-relative (has form "z:foo") 80 * 3 absolute local pathname (begins with "z:\\") 81 */ 82 function normalizePrefix($strPath, $len, $sb) { 83 $src = 0; 84 while (($src < $len) && $this->isSlash($strPath{$src})) { 85 $src++; 86 } 87 $c = ""; 88 if (($len - $src >= 2) 89 && $this->isLetter($c = $strPath{$src}) 90 && $strPath{$src + 1} === ':') { 91 /* Remove leading slashes if followed by drive specifier. 92 * This hack is necessary to support file URLs containing drive 93 * specifiers (e.g., "file://c:/path"). As a side effect, 94 * "/c:/path" can be used as an alternative to "c:/path". */ 95 $sb .= $c; 96 $sb .= ':'; 97 $src += 2; 98 } 99 else { 100 $src = 0; 101 if (($len >= 2) 102 && $this->isSlash($strPath{0}) 103 && $this->isSlash($strPath{1})) { 104 /* UNC pathname: Retain first slash; leave src pointed at 105 * second slash so that further slashes will be collapsed 106 * into the second slash. The result will be a pathname 107 * beginning with "\\\\" followed (most likely) by a host 108 * name. */ 109 $src = 1; 110 $sb.=$this->slash; 111 } 112 } 113 return $src; 114 } 115 116 /** Normalize the given pathname, whose length is len, starting at the given 117 offset; everything before this offset is already normal. */ 118 protected function normalizer($strPath, $len, $offset) { 119 if ($len == 0) { 120 return $strPath; 121 } 122 if ($offset < 3) { 123 $offset = 0; //Avoid fencepost cases with UNC pathnames 124 } 125 $src = 0; 126 $slash = $this->slash; 127 $sb = ""; 128 129 if ($offset == 0) { 130 // Complete normalization, including prefix 131 $src = $this->normalizePrefix($strPath, $len, $sb); 132 } else { 133 // Partial normalization 134 $src = $offset; 135 $sb .= substr($strPath, 0, $offset); 136 } 137 138 // Remove redundant slashes from the remainder of the path, forcing all 139 // slashes into the preferred slash 140 while ($src < $len) { 141 $c = $strPath{$src++}; 142 if ($this->isSlash($c)) { 143 while (($src < $len) && $this->isSlash($strPath{$src})) { 144 $src++; 145 } 146 if ($src === $len) { 147 /* Check for trailing separator */ 148 $sn = (int) strlen($sb); 149 if (($sn == 2) && ($sb{1} === ':')) { 150 // "z:\\" 151 $sb .= $slash; 152 break; 153 } 154 if ($sn === 0) { 155 // "\\" 156 $sb .= $slash; 157 break; 158 } 159 if (($sn === 1) && ($this->isSlash($sb{0}))) { 160 /* "\\\\" is not collapsed to "\\" because "\\\\" marks 161 the beginning of a UNC pathname. Even though it is 162 not, by itself, a valid UNC pathname, we leave it as 163 is in order to be consistent with the win32 APIs, 164 which treat this case as an invalid UNC pathname 165 rather than as an alias for the root directory of 166 the current drive. */ 167 $sb .= $slash; 168 break; 169 } 170 // Path does not denote a root directory, so do not append 171 // trailing slash 172 break; 173 } else { 174 $sb .= $slash; 175 } 176 } else { 177 $sb.=$c; 178 } 179 } 180 $rv = (string) $sb; 181 return $rv; 182 } 183 184 /** 185 * Check that the given pathname is normal. If not, invoke the real 186 * normalizer on the part of the pathname that requires normalization. 187 * This way we iterate through the whole pathname string only once. 188 * @param string $strPath 189 * @return string 190 */ 191 function normalize($strPath) { 192 $n = strlen($strPath); 193 $slash = $this->slash; 194 $altSlash = $this->altSlash; 195 $prev = 0; 196 for ($i = 0; $i < $n; $i++) { 197 $c = $strPath{$i}; 198 if ($c === $altSlash) { 199 return $this->normalizer($strPath, $n, ($prev === $slash) ? $i - 1 : $i); 200 } 201 if (($c === $slash) && ($prev === $slash) && ($i > 1)) { 202 return $this->normalizer($strPath, $n, $i - 1); 203 } 204 if (($c === ':') && ($i > 1)) { 205 return $this->normalizer($strPath, $n, 0); 206 } 207 $prev = $c; 208 } 209 if ($prev === $slash) { 210 return $this->normalizer($strPath, $n, $n - 1); 211 } 212 return $strPath; 213 } 214 215 function prefixLength($strPath) { 216 $path = (string) $strPath; 217 $slash = (string) $this->slash; 218 $n = (int) strlen($path); 219 if ($n === 0) { 220 return 0; 221 } 222 $c0 = $path{0}; 223 $c1 = ($n > 1) ? $path{1} : 224 0; 225 if ($c0 === $slash) { 226 if ($c1 === $slash) { 227 return 2; // absolute UNC pathname "\\\\foo" 228 } 229 return 1; // drive-relative "\\foo" 230 } 231 232 if ($this->isLetter($c0) && ($c1 === ':')) { 233 if (($n > 2) && ($path{2}) === $slash) { 234 return 3; // Absolute local pathname "z:\\foo" */ 235 } 236 return 2; // Directory-relative "z:foo" 237 } 238 return 0; // Completely relative 239 } 240 241 function resolve($parent, $child) { 242 $parent = (string) $parent; 243 $child = (string) $child; 244 $slash = (string) $this->slash; 245 246 $pn = (int) strlen($parent); 247 if ($pn === 0) { 248 return $child; 249 } 250 $cn = (int) strlen($child); 251 if ($cn === 0) { 252 return $parent; 253 } 254 255 $c = $child; 256 if (($cn > 1) && ($c{0} === $slash)) { 257 if ($c{1} === $slash) { 258 // drop prefix when child is a UNC pathname 259 $c = substr($c, 2); 260 } 261 else { 262 //Drop prefix when child is drive-relative */ 263 $c = substr($c, 1); 264 } 265 } 266 267 $p = $parent; 268 if ($p{$pn - 1} === $slash) { 269 $p = substr($p, 0, $pn - 1); 270 } 271 return $p.$this->slashify($c); 272 } 273 274 function getDefaultParent() { 275 return (string) ("".$this->slash); 276 } 277 278 function fromURIPath($strPath) { 279 $p = (string) $strPath; 280 if ((strlen($p) > 2) && ($p{2} === ':')) { 281 282 // "/c:/foo" --> "c:/foo" 283 $p = substr($p,1); 284 285 // "c:/foo/" --> "c:/foo", but "c:/" --> "c:/" 286 if ((strlen($p) > 3) && StringHelper::endsWith('/', $p)) { 287 $p = substr($p, 0, strlen($p) - 1); 288 } 289 } elseif ((strlen($p) > 1) && StringHelper::endsWith('/', $p)) { 290 // "/foo/" --> "/foo" 291 $p = substr($p, 0, strlen($p) - 1); 292 } 293 return (string) $p; 294 } 295 296 297 /* -- Path operations -- */ 298 299 function isAbsolute(PhingFile $f) { 300 $pl = (int) $f->getPrefixLength(); 301 $p = (string) $f->getPath(); 302 return ((($pl === 2) && ($p{0} === $this->slash)) || ($pl === 3) || ($pl === 1 && $p{0} === $this->slash)); 303 } 304 305 /** private */ 306 function _driveIndex($d) { 307 $d = (string) $d{0}; 308 if ((ord($d) >= ord('a')) && (ord($d) <= ord('z'))) { 309 return ord($d) - ord('a'); 310 } 311 if ((ord($d) >= ord('A')) && (ord($d) <= ord('Z'))) { 312 return ord($d) - ord('A'); 313 } 314 return -1; 315 } 316 317 /** private */ 318 function _getDriveDirectory($drive) { 319 $drive = (string) $drive{0}; 320 $i = (int) $this->_driveIndex($drive); 321 if ($i < 0) { 322 return null; 323 } 324 325 $s = (isset(self::$driveDirCache[$i]) ? self::$driveDirCache[$i] : null); 326 327 if ($s !== null) { 328 return $s; 329 } 330 331 $s = $this->_getDriveDirectory($i + 1); 332 self::$driveDirCache[$i] = $s; 333 return $s; 334 } 335 336 function _getUserPath() { 337 //For both compatibility and security, we must look this up every time 338 return (string) $this->normalize(Phing::getProperty("user.dir")); 339 } 340 341 function _getDrive($path) { 342 $path = (string) $path; 343 $pl = $this->prefixLength($path); 344 return ($pl === 3) ? substr($path, 0, 2) : null; 345 } 346 347 function resolveFile(PhingFile $f) { 348 $path = $f->getPath(); 349 $pl = (int) $f->getPrefixLength(); 350 351 if (($pl === 2) && ($path{0} === $this->slash)) { 352 return path; // UNC 353 } 354 355 if ($pl === 3) { 356 return $path; // Absolute local 357 } 358 359 if ($pl === 0) { 360 return (string) ($this->_getUserPath().$this->slashify($path)); //Completely relative 361 } 362 363 if ($pl === 1) { // Drive-relative 364 $up = (string) $this->_getUserPath(); 365 $ud = (string) $this->_getDrive($up); 366 if ($ud !== null) { 367 return (string) $ud.$path; 368 } 369 return (string) $up.$path; //User dir is a UNC path 370 } 371 372 if ($pl === 2) { // Directory-relative 373 $up = (string) $this->_getUserPath(); 374 $ud = (string) $this->_getDrive($up); 375 if (($ud !== null) && StringHelper::startsWith($ud, $path)) { 376 return (string) ($up . $this->slashify(substr($path,2))); 377 } 378 $drive = (string) $path{0}; 379 $dir = (string) $this->_getDriveDirectory($drive); 380 381 $np = (string) ""; 382 if ($dir !== null) { 383 /* When resolving a directory-relative path that refers to a 384 drive other than the current drive, insist that the caller 385 have read permission on the result */ 386 $p = (string) $drive . (':'.$dir.$this->slashify(substr($path,2))); 387 388 if (!$this->checkAccess($p, false)) { 389 // FIXME 390 // throw security error 391 die("Can't resolve path $p"); 392 } 393 return $p; 394 } 395 return (string) $drive.':'.$this->slashify(substr($path,2)); //fake it 396 } 397 398 throw new Exception("Unresolvable path: " . $path); 399 } 400 401 /* -- most of the following is mapped to the functions mapped th php natives in FileSystem */ 402 403 /* -- Attribute accessors -- */ 404 405 function setReadOnly($f) { 406 // dunno how to do this on win 407 throw new Exception("WIN32FileSystem doesn't support read-only yet."); 408 } 409 410 /* -- Filesystem interface -- */ 411 412 protected function _access($path) { 413 if (!$this->checkAccess($path, false)) { 414 throw new Exception("Can't resolve path $p"); 415 } 416 return true; 417 } 418 419 function _nativeListRoots() { 420 // FIXME 421 } 422 423 function listRoots() { 424 $ds = _nativeListRoots(); 425 $n = 0; 426 for ($i = 0; $i < 26; $i++) { 427 if ((($ds >> $i) & 1) !== 0) { 428 if (!$this->access((string)( chr(ord('A') + $i) . ':' . $this->slash))) { 429 $ds &= ~(1 << $i); 430 } else { 431 $n++; 432 } 433 } 434 } 435 $fs = array(); 436 $j = (int) 0; 437 $slash = (string) $this->slash; 438 for ($i = 0; $i < 26; $i++) { 439 if ((($ds >> $i) & 1) !== 0) { 440 $fs[$j++] = new PhingFile(chr(ord('A') + $i) . ':' . $this->slash); 441 } 442 } 443 return $fs; 444 } 445 446 /* -- Basic infrastructure -- */ 447 448 /** compares file paths lexicographically */ 449 function compare(PhingFile $f1, PhingFile $f2) { 450 $f1Path = $f1->getPath(); 451 $f2Path = $f2->getPath(); 452 return (boolean) strcasecmp((string) $f1Path, (string) $f2Path); 453 } 454 455 456 /** 457 * returns the contents of a directory in an array 458 */ 459 function lister($f) { 460 $dir = @opendir($f->getAbsolutePath()); 461 if (!$dir) { 462 throw new Exception("Can't open directory " . $f->__toString()); 463 } 464 $vv = array(); 465 while (($file = @readdir($dir)) !== false) { 466 if ($file == "." || $file == "..") { 467 continue; 468 } 469 $vv[] = (string) $file; 470 } 471 @closedir($dir); 472 return $vv; 473 } 474 475 } 476 477 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Fri Mar 16 22:42:14 2007 | par Balluche grâce à PHPXref 0.7 |