diff options
Diffstat (limited to 'buildscripts/phing/classes/phing/system/io/FileSystem.php')
-rwxr-xr-x[-rw-r--r--] | buildscripts/phing/classes/phing/system/io/FileSystem.php | 283 |
1 files changed, 233 insertions, 50 deletions
diff --git a/buildscripts/phing/classes/phing/system/io/FileSystem.php b/buildscripts/phing/classes/phing/system/io/FileSystem.php index 2802ddfb..284be830 100644..100755 --- a/buildscripts/phing/classes/phing/system/io/FileSystem.php +++ b/buildscripts/phing/classes/phing/system/io/FileSystem.php @@ -1,7 +1,7 @@ <?php /* - * $Id: FileSystem.php,v 1.11 2005/12/01 20:56:59 hlellelid Exp $ + * $Id: 235081905c0eafcd98da2fec63404fa2ebee090a $ * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -30,30 +30,50 @@ * *FileSystem drivers to access the real filesystem via this class using natives. * * FIXME: - * - Error handling reduced to min fallthrough runtime excetions + * - Error handling reduced to min fallthrough runtime exceptions * 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 $ + * @version $Id$ * @package phing.system.io */ abstract class FileSystem { - /* properties for simple boolean attributes */ + /** + * @var int + */ const BA_EXISTS = 0x01; + + /** + * @var int + */ const BA_REGULAR = 0x02; + + /** + * @var int + */ const BA_DIRECTORY = 0x04; + + /** + * @var int + */ const BA_HIDDEN = 0x08; - /** Instance for getFileSystem() method. */ + /** + * Instance for getFileSystem() method. + * @var FileSystem + */ private static $fs; /** * Static method to return the FileSystem singelton representing * this platform's local filesystem driver. + * + * @return FileSystem + * @throws IOException */ - function getFileSystem() { + public static function getFileSystem() { if (self::$fs === null) { switch(Phing::getProperty('host.fstype')) { case 'UNIX': @@ -69,7 +89,7 @@ abstract class FileSystem { self::$fs = new WinNTFileSystem(); break; default: - throw new Exception("Host uses unsupported filesystem, unable to proceed"); + throw new IOException("Host uses unsupported filesystem, unable to proceed"); } } return self::$fs; @@ -90,12 +110,16 @@ abstract class FileSystem { /** * Convert the given pathname string to normal form. If the string is * already in normal form then it is simply returned. + * + * @param string $strPath */ abstract function normalize($strPath); /** * Compute the length of this pathname string's prefix. The pathname * string must be in normal form. + * + * @param string $pathname */ abstract function prefixLength($pathname); @@ -103,12 +127,17 @@ abstract class FileSystem { * 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. + * + * @param string $parent + * @param string $child */ abstract function resolve($parent, $child); /** * Resolve the given abstract pathname into absolute form. Invoked by the * getAbsolutePath and getCanonicalPath methods in the PhingFile class. + * + * @param PhingFile $f */ abstract function resolveFile(PhingFile $f); @@ -124,18 +153,23 @@ abstract class FileSystem { * 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. + * + * @param string $path */ abstract function fromURIPath($path); - + /* -- Path operations -- */ /** * Tell whether or not the given abstract pathname is absolute. + * + * @param PhingFile $f */ abstract function isAbsolute(PhingFile $f); /** * canonicalize filename by checking on disk + * @param string $strPath * @return mixed Canonical path or false if the file doesn't exist. */ function canonicalize($strPath) { @@ -148,9 +182,11 @@ abstract class FileSystem { * 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. + * + * @param PhingFile $f */ function getBooleanAttributes($f) { - throw new Exception("SYSTEM ERROR method getBooleanAttributes() not implemented by fs driver"); + throw new IOException("getBooleanAttributes() not implemented by fs driver"); } /** @@ -160,6 +196,9 @@ abstract class FileSystem { * 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. + * + * @param PhingFile $f + * @param boolean $write */ function checkAccess(PhingFile $f, $write = false) { // we clear stat cache, its expensive to look up from scratch, @@ -189,11 +228,27 @@ abstract class FileSystem { return (boolean) @is_writable($strPath); } } - + + /** + * Whether file can be deleted. + * @param PhingFile $f + * @return boolean + */ + function canDelete(PhingFile $f) + { + clearstatcache(); + $dir = dirname($f->getAbsolutePath()); + return (bool) @is_writable($dir); + } + /** * 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. + * + * @param PhingFile $f + * @return int + * @throws IOException */ function getLastModifiedTime(PhingFile $f) { @@ -203,20 +258,35 @@ abstract class FileSystem { @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); + + if (@is_link($strPath)) { + $stats = @lstat($strPath); + + if (!isset($stats['mtime'])) { + $mtime = false; + } else { + $mtime = $stats['mtime']; + } } else { - return (int) $mtime; + $mtime = @filemtime($strPath); + } + + if (false === $mtime) { + $msg = "FileSystem::getLastModifiedTime() FAILED. Can not get modified time of $strPath. $php_errormsg"; + throw new IOException($msg); } + + 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. + * + * @param PhingFile $f + * @throws IOException + * @return int */ function getLength(PhingFile $f) { $strPath = (string) $f->getAbsolutePath(); @@ -225,7 +295,7 @@ abstract class FileSystem { return $fs; } else { $msg = "FileSystem::Read() FAILED. Cannot get filesize of $strPath. $php_errormsg"; - throw new Exception($msg); + throw new IOException($msg); } } @@ -237,9 +307,9 @@ abstract class FileSystem { * 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 + * @param string $strPathname Path of the file to be created. + * @throws IOException + * @return boolean */ function createNewFile($strPathname) { if (@file_exists($strPathname)) @@ -257,10 +327,14 @@ abstract class FileSystem { /** * Delete the file or directory denoted by the given abstract pathname, * returning true if and only if the operation succeeds. + * + * @param PhingFile $f + * @param boolean $recursive + * @return void */ - function delete(PhingFile $f) { + function delete(PhingFile $f, $recursive = false) { if ($f->isDirectory()) { - return $this->rmdir($f->getPath()); + return $this->rmdir($f->getPath(), $recursive); } else { return $this->unlink($f->getPath()); } @@ -269,16 +343,21 @@ abstract class FileSystem { /** * 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. + * true if and only if the operation succeeds. + * + * @param PhingFile $f + * @throws IOException */ function deleteOnExit($f) { - throw new Exception("deleteOnExit() not implemented by local fs driver"); + throw new IOException("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>. + * + * @param PhingFile $f */ function listDir(PhingFile $f) { $strPath = (string) $f->getAbsolutePath(); @@ -300,9 +379,18 @@ abstract class FileSystem { /** * 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); + * + * NOTE: umask() is reset to 0 while executing mkdir(), and restored afterwards + * + * @param PhingFile $f + * @param int $mode + * @return boolean + */ + function createDirectory(&$f, $mode = 0755) { + $old_umask = umask(0); + $return = @mkdir($f->getAbsolutePath(), $mode); + umask($old_umask); + return $return; } /** @@ -313,7 +401,7 @@ abstract class FileSystem { * @param PhingFile $f1 abstract source file * @param PhingFile $f2 abstract destination file * @return void - * @throws Exception if rename cannot be performed + * @throws IOException if rename cannot be performed */ function rename(PhingFile $f1, PhingFile $f2) { // get the canonical paths of the file to rename @@ -321,7 +409,7 @@ abstract class FileSystem { $dest = $f2->getAbsolutePath(); if (false === @rename($src, $dest)) { $msg = "Rename FAILED. Cannot rename $src to $dest. $php_errormsg"; - throw new Exception($msg); + throw new IOException($msg); } } @@ -329,14 +417,17 @@ abstract class FileSystem { * 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. + * + * @param PhingFile $f + * @param int $time * @return void - * @throws Exception + * @throws IOException */ 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"); + throw new IOException("Could not touch '" . $path . "' due to: $php_errormsg"); } } @@ -344,27 +435,34 @@ abstract class FileSystem { * 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. + * + * @param PhingFile $f + * @throws IOException */ function setReadOnly($f) { - throw new Exception("setReadonle() not implemented by local fs driver"); + throw new IOException("setReadonly() not implemented by local fs driver"); } /* -- Filesystem interface -- */ /** * List the available filesystem roots, return array of PhingFile objects + * @throws IOException */ function listRoots() { - throw new Exception("SYSTEM ERROR [listRoots() not implemented by local fs driver]"); + throw new IOException("listRoots() not implemented by local fs driver"); } /* -- Basic infrastructure -- */ /** * Compare two abstract pathnames lexicographically. + * + * @param PhingFile $f1 + * @param PhingFile $f2 */ - function compare($f1, $f2) { - throw new Exception("SYSTEM ERROR [compare() not implemented by local fs driver]"); + function compare(PhingFile $f1, PhingFile $f2) { + throw new IOException("compare() not implemented by local fs driver"); } /** @@ -374,17 +472,23 @@ abstract class FileSystem { * @param PhingFile $dest Destination path and name of new file. * * @return void - * @throws Exception if file cannot be copied. + * @throws IOException if file cannot be copied. */ function copy(PhingFile $src, PhingFile $dest) { global $php_errormsg; + + // Recursively copy a directory + if($src->isDirectory()) { + return $this->copyr($src->getAbsolutePath(), $dest->getAbsolutePath()); + } + $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); + throw new IOException($msg); } try { @@ -394,28 +498,106 @@ abstract class FileSystem { // eat it up for now. } } + + /** + * Copy a file, or recursively copy a folder and its contents + * + * @author Aidan Lister <aidan@php.net> + * @version 1.0.1 + * @link http://aidanlister.com/repos/v/function.copyr.php + * @param string $source Source path + * @param string $dest Destination path + * @return bool Returns TRUE on success, FALSE on failure + */ + function copyr($source, $dest) + { + // Check for symlinks + if (is_link($source)) { + return symlink(readlink($source), $dest); + } + + // Simple copy for a file + if (is_file($source)) { + return copy($source, $dest); + } + + // Make destination directory + if (!is_dir($dest)) { + mkdir($dest); + } + + // Loop through the folder + $dir = dir($source); + while (false !== $entry = $dir->read()) { + // Skip pointers + if ($entry == '.' || $entry == '..') { + continue; + } + + // Deep copy directories + $this->copyr("$source/$entry", "$dest/$entry"); + } + + // Clean up + $dir->close(); + return true; + } + + /** + * Change the ownership on a file or directory. + * + * @param string $pathname Path and name of file or directory. + * @param string $user The user name or number of the file or directory. See http://us.php.net/chown + * + * @return void + * @throws Exception if operation failed. + */ + function chown($pathname, $user) { + if (false === @chown($pathname, $user)) {// FAILED. + $msg = "FileSystem::chown() FAILED. Cannot chown $pathname. User $user." . (isset($php_errormsg) ? ' ' . $php_errormsg : ""); + throw new IOException($msg); + } + } + + /** + * Change the group on a file or directory. + * + * @param string $pathname Path and name of file or directory. + * @param string $group The group of the file or directory. See http://us.php.net/chgrp + * + * @return void + * @throws IOException if operation failed. + */ + function chgrp($pathname, $group) { + if (false === @chgrp($pathname, $group)) {// FAILED. + $msg = "FileSystem::chgrp() FAILED. Cannot chown $pathname. Group $group." . (isset($php_errormsg) ? ' ' . $php_errormsg : ""); + throw new IOException($msg); + } + } /** * 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. + * @param string $pathname Path and name of file or directory. + * @param int $mode 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. + * @throws IOException 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); + $msg = "FileSystem::chmod() FAILED. Cannot chmod $pathname. Mode $str_mode." . (isset($php_errormsg) ? ' ' . $php_errormsg : ""); + throw new IOException($msg); } } /** * Locks a file and throws an Exception if this is not possible. + * + * @param PhingFile $f * @return void * @throws Exception */ @@ -425,14 +607,15 @@ abstract class FileSystem { $result = @flock($fp, LOCK_EX); @fclose($fp); if (!$result) { - throw new Exception("Could not lock file '$filename'"); + throw new IOException("Could not lock file '$filename'"); } } /** * Unlocks a file and throws an IO Error if this is not possible. * - * @throws Exception + * @param PhingFile $f + * @throws IOException * @return void */ function unlock(PhingFile $f) { @@ -448,16 +631,16 @@ abstract class FileSystem { /** * Delete a file. * - * @param file String. Path and/or name of file to delete. + * @param string $file Path and/or name of file to delete. * * @return void - * @throws Exception - if an error is encountered. + * @throws IOException - 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); + throw new IOException($msg); } } @@ -478,7 +661,7 @@ abstract class FileSystem { 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); + throw new IOException($msg); } } |