Spaces:
Sleeping
Sleeping
File size: 23,041 Bytes
07c3cdd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 | <?php
/*
* $Id: FileSystem.php 3076 2006-12-18 08:52:12Z fabien $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://phing.info>.
*/
/**
* This is an abstract class for platform specific filesystem implementations
* you have to implement each method in the platform specific filesystem implementation
* classes Your local filesytem implementation must extend this class.
* You should also use this class as a template to write your local implementation
* Some native PHP filesystem specific methods are abstracted here as well. Anyway
* you _must_ always use this methods via a PhingFile object (that by nature uses the
* *FileSystem drivers to access the real filesystem via this class using natives.
*
* FIXME:
* - Error handling reduced to min fallthrough runtime excetions
* more precise errorhandling is done by the PhingFile class
*
* @author Charlie Killian <charlie@tizac.com>
* @author Hans Lellelid <hans@xmpl.org>
* @version $Revision: 1.11 $
* @package phing.system.io
*/
abstract class FileSystem {
/* properties for simple boolean attributes */
const BA_EXISTS = 0x01;
const BA_REGULAR = 0x02;
const BA_DIRECTORY = 0x04;
const BA_HIDDEN = 0x08;
/** Instance for getFileSystem() method. */
private static $fs;
/**
* Static method to return the FileSystem singelton representing
* this platform's local filesystem driver.
*/
public static function getFileSystem() {
if (self::$fs === null) {
switch(Phing::getProperty('host.fstype')) {
case 'UNIX':
include_once 'phing/system/io/UnixFileSystem.php';
self::$fs = new UnixFileSystem();
break;
case 'WIN32':
include_once 'phing/system/io/Win32FileSystem.php';
self::$fs = new Win32FileSystem();
break;
case 'WINNT':
include_once 'phing/system/io/WinNTFileSystem.php';
self::$fs = new WinNTFileSystem();
break;
default:
throw new Exception("Host uses unsupported filesystem, unable to proceed");
}
}
return self::$fs;
}
/* -- Normalization and construction -- */
/**
* Return the local filesystem's name-separator character.
*/
abstract function getSeparator();
/**
* Return the local filesystem's path-separator character.
*/
abstract function getPathSeparator();
/**
* Convert the given pathname string to normal form. If the string is
* already in normal form then it is simply returned.
*/
abstract function normalize($strPath);
/**
* Compute the length of this pathname string's prefix. The pathname
* string must be in normal form.
*/
abstract function prefixLength($pathname);
/**
* Resolve the child pathname string against the parent.
* Both strings must be in normal form, and the result
* will be a string in normal form.
*/
abstract function resolve($parent, $child);
/**
* Resolve the given abstract pathname into absolute form. Invoked by the
* getAbsolutePath and getCanonicalPath methods in the PhingFile class.
*/
abstract function resolveFile(PhingFile $f);
/**
* Return the parent pathname string to be used when the parent-directory
* argument in one of the two-argument PhingFile constructors is the empty
* pathname.
*/
abstract function getDefaultParent();
/**
* Post-process the given URI path string if necessary. This is used on
* win32, e.g., to transform "/c:/foo" into "c:/foo". The path string
* still has slash separators; code in the PhingFile class will translate them
* after this method returns.
*/
abstract function fromURIPath($path);
/* -- Path operations -- */
/**
* Tell whether or not the given abstract pathname is absolute.
*/
abstract function isAbsolute(PhingFile $f);
/**
* canonicalize filename by checking on disk
* @return mixed Canonical path or false if the file doesn't exist.
*/
function canonicalize($strPath) {
return @realpath($strPath);
}
/* -- Attribute accessors -- */
/**
* Return the simple boolean attributes for the file or directory denoted
* by the given abstract pathname, or zero if it does not exist or some
* other I/O error occurs.
*/
function getBooleanAttributes(&$f = null) {
throw new Exception("SYSTEM ERROR method getBooleanAttributes() not implemented by fs driver");
}
/**
* Check whether the file or directory denoted by the given abstract
* pathname may be accessed by this process. If the second argument is
* false, then a check for read access is made; if the second
* argument is true, then a check for write (not read-write)
* access is made. Return false if access is denied or an I/O error
* occurs.
*/
function checkAccess(PhingFile $f, $write = false) {
// we clear stat cache, its expensive to look up from scratch,
// but we need to be sure
@clearstatcache();
// Shouldn't this be $f->GetAbsolutePath() ?
// And why doesn't GetAbsolutePath() work?
$strPath = (string) $f->getPath();
// FIXME
// if file object does denote a file that yet not existst
// path rights are checked
if (!@file_exists($strPath) && !is_dir($strPath)) {
$strPath = $f->getParent();
if ($strPath === null || !is_dir($strPath)) {
$strPath = Phing::getProperty("user.dir");
}
//$strPath = dirname($strPath);
}
if (!$write) {
return (boolean) @is_readable($strPath);
} else {
return (boolean) @is_writable($strPath);
}
}
/**
* Return the time at which the file or directory denoted by the given
* abstract pathname was last modified, or zero if it does not exist or
* some other I/O error occurs.
*/
function getLastModifiedTime(PhingFile $f) {
if (!$f->exists()) {
return 0;
}
@clearstatcache();
$strPath = (string) $f->getPath();
$mtime = @filemtime($strPath);
if (false === $mtime) {
// FAILED. Log and return err.
$msg = "FileSystem::Filemtime() FAILED. Cannot can not get modified time of $strPath. $php_errormsg";
throw new Exception($msg);
} else {
return (int) $mtime;
}
}
/**
* Return the length in bytes of the file denoted by the given abstract
* pathname, or zero if it does not exist, is a directory, or some other
* I/O error occurs.
*/
function getLength(PhingFile $f) {
$strPath = (string) $f->getAbsolutePath();
$fs = filesize((string) $strPath);
if ($fs !== false) {
return $fs;
} else {
$msg = "FileSystem::Read() FAILED. Cannot get filesize of $strPath. $php_errormsg";
throw new Exception($msg);
}
}
/* -- File operations -- */
/**
* Create a new empty file with the given pathname. Return
* true if the file was created and false if a
* file or directory with the given pathname already exists. Throw an
* IOException if an I/O error occurs.
*
* @param string Path of the file to be created.
*
* @throws IOException
*/
function createNewFile($strPathname) {
if (@file_exists($strPathname))
return false;
// Create new file
$fp = @fopen($strPathname, "w");
if ($fp === false) {
throw new IOException("The file \"$strPathname\" could not be created");
}
@fclose($fp);
return true;
}
/**
* Delete the file or directory denoted by the given abstract pathname,
* returning true if and only if the operation succeeds.
*/
function delete(PhingFile $f) {
if ($f->isDirectory()) {
return $this->rmdir($f->getPath());
} else {
return $this->unlink($f->getPath());
}
}
/**
* Arrange for the file or directory denoted by the given abstract
* pathname to be deleted when Phing::shutdown is called, returning
* true if and only if the operation succeeds.
*/
function deleteOnExit($f) {
throw new Exception("deleteOnExit() not implemented by local fs driver");
}
/**
* List the elements of the directory denoted by the given abstract
* pathname. Return an array of strings naming the elements of the
* directory if successful; otherwise, return <code>null</code>.
*/
function listDir(PhingFile $f) {
$strPath = (string) $f->getAbsolutePath();
$d = @dir($strPath);
if (!$d) {
return null;
}
$list = array();
while($entry = $d->read()) {
if ($entry != "." && $entry != "..") {
array_push($list, $entry);
}
}
$d->close();
unset($d);
return $list;
}
/**
* Create a new directory denoted by the given abstract pathname,
* returning true if and only if the operation succeeds.
*/
function createDirectory(&$f) {
return @mkdir($f->getAbsolutePath(),0755);
}
/**
* Rename the file or directory denoted by the first abstract pathname to
* the second abstract pathname, returning true if and only if
* the operation succeeds.
*
* @param PhingFile $f1 abstract source file
* @param PhingFile $f2 abstract destination file
* @return void
* @throws Exception if rename cannot be performed
*/
function rename(PhingFile $f1, PhingFile $f2) {
// get the canonical paths of the file to rename
$src = $f1->getAbsolutePath();
$dest = $f2->getAbsolutePath();
if (false === @rename($src, $dest)) {
$msg = "Rename FAILED. Cannot rename $src to $dest. $php_errormsg";
throw new Exception($msg);
}
}
/**
* Set the last-modified time of the file or directory denoted by the
* given abstract pathname returning true if and only if the
* operation succeeds.
* @return void
* @throws Exception
*/
function setLastModifiedTime(PhingFile $f, $time) {
$path = $f->getPath();
$success = @touch($path, $time);
if (!$success) {
throw new Exception("Could not create directory due to: $php_errormsg");
}
}
/**
* Mark the file or directory denoted by the given abstract pathname as
* read-only, returning <code>true</code> if and only if the operation
* succeeds.
*/
function setReadOnly($f) {
throw new Exception("setReadonle() not implemented by local fs driver");
}
/* -- Filesystem interface -- */
/**
* List the available filesystem roots, return array of PhingFile objects
*/
function listRoots() {
throw new Exception("SYSTEM ERROR [listRoots() not implemented by local fs driver]");
}
/* -- Basic infrastructure -- */
/**
* Compare two abstract pathnames lexicographically.
*/
function compare($f1, $f2) {
throw new Exception("SYSTEM ERROR [compare() not implemented by local fs driver]");
}
/**
* Copy a file.
*
* @param PhingFile $src Source path and name file to copy.
* @param PhingFile $dest Destination path and name of new file.
*
* @return void
* @throws Exception if file cannot be copied.
*/
function copy(PhingFile $src, PhingFile $dest) {
global $php_errormsg;
$srcPath = $src->getAbsolutePath();
$destPath = $dest->getAbsolutePath();
if (false === @copy($srcPath, $destPath)) { // Copy FAILED. Log and return err.
// Add error from php to end of log message. $php_errormsg.
$msg = "FileSystem::copy() FAILED. Cannot copy $srcPath to $destPath. $php_errormsg";
throw new Exception($msg);
}
try {
$dest->setMode($src->getMode());
} catch(Exception $exc) {
// [MA] does chmod returns an error on systems that do not support it ?
// eat it up for now.
}
}
/**
* Change the permissions on a file or directory.
*
* @param pathname String. Path and name of file or directory.
* @param mode Int. The mode (permissions) of the file or
* directory. If using octal add leading 0. eg. 0777.
* Mode is affected by the umask system setting.
*
* @return void
* @throws Exception if operation failed.
*/
function chmod($pathname, $mode) {
$str_mode = decoct($mode); // Show octal in messages.
if (false === @chmod($pathname, $mode)) {// FAILED.
$msg = "FileSystem::chmod() FAILED. Cannot chmod $pathname. Mode $str_mode. $php_errormsg";
throw new Exception($msg);
}
}
/**
* Locks a file and throws an Exception if this is not possible.
* @return void
* @throws Exception
*/
function lock(PhingFile $f) {
$filename = $f->getPath();
$fp = @fopen($filename, "w");
$result = @flock($fp, LOCK_EX);
@fclose($fp);
if (!$result) {
throw new Exception("Could not lock file '$filename'");
}
}
/**
* Unlocks a file and throws an IO Error if this is not possible.
*
* @throws Exception
* @return void
*/
function unlock(PhingFile $f) {
$filename = $f->getPath();
$fp = @fopen($filename, "w");
$result = @flock($fp, LOCK_UN);
fclose($fp);
if (!$result) {
throw new Exception("Could not unlock file '$filename'");
}
}
/**
* Delete a file.
*
* @param file String. Path and/or name of file to delete.
*
* @return void
* @throws Exception - if an error is encountered.
*/
function unlink($file) {
global $php_errormsg;
if (false === @unlink($file)) {
$msg = "FileSystem::unlink() FAILED. Cannot unlink '$file'. $php_errormsg";
throw new Exception($msg);
}
}
/**
* Symbolically link a file to another name.
*
* Currently symlink is not implemented on Windows. Don't use if the application is to be portable.
*
* @param string $target Path and/or name of file to link.
* @param string $link Path and/or name of link to be created.
* @return void
*/
function symlink($target, $link) {
// If Windows OS then symlink() will report it is not supported in
// the build. Use this error instead of checking for Windows as the OS.
if (false === @symlink($target, $link)) {
// Add error from php to end of log message. $php_errormsg.
$msg = "FileSystem::Symlink() FAILED. Cannot symlink '$target' to '$link'. $php_errormsg";
throw new Exception($msg);
}
}
/**
* Set the modification and access time on a file to the present time.
*
* @param string $file Path and/or name of file to touch.
* @param int $time
* @return void
*/
function touch($file, $time = null) {
global $php_errormsg;
if (null === $time) {
$error = @touch($file);
} else {
$error = @touch($file, $time);
}
if (false === $error) { // FAILED.
// Add error from php to end of log message. $php_errormsg.
$msg = "FileSystem::touch() FAILED. Cannot touch '$file'. $php_errormsg";
throw new Exception($msg);
}
}
/**
* Delete an empty directory OR a directory and all of its contents.
*
* @param dir String. Path and/or name of directory to delete.
* @param children Boolean. False: don't delete directory contents.
* True: delete directory contents.
*
* @return void
*/
function rmdir($dir, $children = false) {
global $php_errormsg;
// If children=FALSE only delete dir if empty.
if (false === $children) {
if (false === @rmdir($dir)) { // FAILED.
// Add error from php to end of log message. $php_errormsg.
$msg = "FileSystem::rmdir() FAILED. Cannot rmdir $dir. $php_errormsg";
throw new Exception($msg);
}
} else { // delete contents and dir.
$handle = @opendir($dir);
if (false === $handle) { // Error.
$msg = "FileSystem::rmdir() FAILED. Cannot opendir() $dir. $php_errormsg";
throw new Exception($msg);
} else { // Read from handle.
// Don't error on readdir().
while (false !== ($entry = @readdir($handle))) {
if ($entry != '.' && $entry != '..') {
// Only add / if it isn't already the last char.
// This ONLY serves the purpose of making the Logger
// output look nice:)
if (strpos(strrev($dir), DIRECTORY_SEPARATOR) === 0) {// there is a /
$next_entry = $dir . $entry;
} else { // no /
$next_entry = $dir . DIRECTORY_SEPARATOR . $entry;
}
// NOTE: As of php 4.1.1 is_dir doesn't return FALSE it
// returns 0. So use == not ===.
// Don't error on is_dir()
if (false == @is_dir($next_entry)) { // Is file.
try {
self::unlink($next_entry); // Delete.
} catch (Exception $e) {
$msg = "FileSystem::Rmdir() FAILED. Cannot FileSystem::Unlink() $next_entry. ". $e->getMessage();
throw new Exception($msg);
}
} else { // Is directory.
try {
self::rmdir($next_entry, true); // Delete
} catch (Exception $e) {
$msg = "FileSystem::rmdir() FAILED. Cannot FileSystem::rmdir() $next_entry. ". $e->getMessage();
throw new Exception($msg);
}
} // end is_dir else
} // end .. if
} // end while
} // end handle if
// Don't error on closedir()
@closedir($handle);
if (false === @rmdir($dir)) { // FAILED.
// Add error from php to end of log message. $php_errormsg.
$msg = "FileSystem::rmdir() FAILED. Cannot rmdir $dir. $php_errormsg";
throw new Exception($msg);
}
}
}
/**
* Set the umask for file and directory creation.
*
* @param mode Int. Permissions ususally in ocatal. Use leading 0 for
* octal. Number between 0 and 0777.
*
* @return void
* @throws Exception if there is an error performing operation.
*/
function umask($mode) {
global $php_errormsg;
// CONSIDERME:
// Throw a warning if mode is 0. PHP converts illegal octal numbers to
// 0 so 0 might not be what the user intended.
$str_mode = decoct($mode); // Show octal in messages.
if (false === @umask($mode)) { // FAILED.
// Add error from php to end of log message. $php_errormsg.
$msg = "FileSystem::Umask() FAILED. Value $mode. $php_errormsg";
throw new Exception($msg);
}
}
/**
* Compare the modified time of two files.
*
* @param file1 String. Path and name of file1.
* @param file2 String. Path and name of file2.
*
* @return Int. 1 if file1 is newer.
* -1 if file2 is newer.
* 0 if files have the same time.
* Err object on failure.
*
* @throws Exception - if cannot get modified time of either file.
*/
function compareMTimes($file1, $file2) {
$mtime1 = filemtime($file1);
$mtime2 = filemtime($file2);
if ($mtime1 === false) { // FAILED. Log and return err.
// Add error from php to end of log message. $php_errormsg.
$msg = "FileSystem::compareMTimes() FAILED. Cannot can not get modified time of $file1.";
throw new Exception($msg);
} elseif ($mtime2 === false) { // FAILED. Log and return err.
// Add error from php to end of log message. $php_errormsg.
$msg = "FileSystem::compareMTimes() FAILED. Cannot can not get modified time of $file2.";
throw new Exception($msg);
} else { // Worked. Log and return compare.
// Compare mtimes.
if ($mtime1 == $mtime2) {
return 0;
} else {
return ($mtime1 < $mtime2) ? -1 : 1;
} // end compare
}
}
}
|