SFTP: add more stat functions

also don't use stat cache for SFTP/Stream.php
This commit is contained in:
terrafrost 2014-05-26 15:39:30 -05:00
parent 69e15b3855
commit a7fa4cc4ff
2 changed files with 157 additions and 50 deletions

View File

@ -538,7 +538,7 @@ class Net_SFTP extends Net_SSH2
} }
/** /**
* Disable the cache * Disable the stat cache
* *
* @access public * @access public
*/ */
@ -548,7 +548,7 @@ class Net_SFTP extends Net_SSH2
} }
/** /**
* Enable the cache * Enable the stat cache
* *
* @access public * @access public
*/ */
@ -557,6 +557,16 @@ class Net_SFTP extends Net_SSH2
$this->use_stat_cache = true; $this->use_stat_cache = true;
} }
/**
* Clear the stat cache
*
* @access public
*/
function clearStatCache()
{
$this->stat_cache = array();
}
/** /**
* Returns the current directory name * Returns the current directory name
* *
@ -934,7 +944,7 @@ class Net_SFTP extends Net_SSH2
* Save files / directories to cache * Save files / directories to cache
* *
* @param String $path * @param String $path
* @param optional Boolean $file * @param Mixed $value
* @access private * @access private
*/ */
function _update_stat_cache($path, $value) function _update_stat_cache($path, $value)
@ -942,7 +952,7 @@ class Net_SFTP extends Net_SSH2
// preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($path, '/')) // preg_replace('#^/|/(?=/)|/$#', '', $dir) == str_replace('//', '/', trim($path, '/'))
$dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
$temp = &$this->cache; $temp = &$this->stat_cache;
foreach ($dirs as $dir) { foreach ($dirs as $dir) {
if (!isset($temp[$dir])) { if (!isset($temp[$dir])) {
$temp[$dir] = array(); $temp[$dir] = array();
@ -958,14 +968,14 @@ class Net_SFTP extends Net_SSH2
* Remove files / directories from cache * Remove files / directories from cache
* *
* @param String $path * @param String $path
* @param optional Boolean $file * @return Boolean
* @access private * @access private
*/ */
function _remove_from_stat_cache($path) function _remove_from_stat_cache($path)
{ {
$dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
$temp = &$this->cache; $temp = &$this->stat_cache;
foreach ($dirs as $dir) { foreach ($dirs as $dir) {
if ($dir == end($dirs)) { if ($dir == end($dirs)) {
unset($temp[$dir]); unset($temp[$dir]);
@ -991,10 +1001,10 @@ class Net_SFTP extends Net_SSH2
{ {
$dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path)); $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
$temp = &$this->cache; $temp = &$this->stat_cache;
foreach ($dirs as $dir) { foreach ($dirs as $dir) {
if (!isset($temp[$dir])) { if (!isset($temp[$dir])) {
return false; return NULL;
} }
$temp = &$temp[$dir]; $temp = &$temp[$dir];
} }
@ -1033,10 +1043,13 @@ class Net_SFTP extends Net_SSH2
$stat = $this->_stat($filename, NET_SFTP_STAT); $stat = $this->_stat($filename, NET_SFTP_STAT);
if ($stat === false) { if ($stat === false) {
$this->_update_stat_cache($filename, 0); $this->_remove_from_stat_cache($filename);
return false; return false;
} }
if (isset($stat['type'])) { if (isset($stat['type'])) {
if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.';
}
$this->_update_stat_cache($filename, (object) $stat); $this->_update_stat_cache($filename, (object) $stat);
return $stat; return $stat;
} }
@ -1047,6 +1060,9 @@ class Net_SFTP extends Net_SSH2
NET_SFTP_TYPE_REGULAR; NET_SFTP_TYPE_REGULAR;
$this->pwd = $pwd; $this->pwd = $pwd;
if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.';
}
$this->_update_stat_cache($filename, (object) $stat); $this->_update_stat_cache($filename, (object) $stat);
return $stat; return $stat;
@ -1084,9 +1100,13 @@ class Net_SFTP extends Net_SSH2
$lstat = $this->_stat($filename, NET_SFTP_LSTAT); $lstat = $this->_stat($filename, NET_SFTP_LSTAT);
if ($lstat === false) { if ($lstat === false) {
$this->_remove_from_stat_cache($filename);
return false; return false;
} }
if (isset($lstat['type'])) { if (isset($lstat['type'])) {
if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.';
}
$this->_update_stat_cache($filename, (object) $lstat); $this->_update_stat_cache($filename, (object) $lstat);
return $lstat; return $lstat;
} }
@ -1105,6 +1125,9 @@ class Net_SFTP extends Net_SSH2
NET_SFTP_TYPE_REGULAR; NET_SFTP_TYPE_REGULAR;
$this->pwd = $pwd; $this->pwd = $pwd;
if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
$filename.= '/.';
}
$this->_update_stat_cache($filename, (object) $lstat); $this->_update_stat_cache($filename, (object) $lstat);
return $lstat; return $lstat;
@ -1530,7 +1553,7 @@ class Net_SFTP extends Net_SSH2
// the following will do a soft delete, which would be useful if you deleted a file // the following will do a soft delete, which would be useful if you deleted a file
// and then tried to do a stat on the deleted file. the above, in contrast, does // and then tried to do a stat on the deleted file. the above, in contrast, does
// a hard delete // a hard delete
//$this->_update_stat_cache($dir, 0); //$this->_update_stat_cache($dir, false);
return true; return true;
} }
@ -1586,6 +1609,8 @@ class Net_SFTP extends Net_SSH2
return false; return false;
} }
$this->_remove_from_stat_cache($remote_file);
$flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE; $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE;
// according to the SFTP specs, NET_SFTP_OPEN_APPEND should "force all writes to append data at the end of the file." // according to the SFTP specs, NET_SFTP_OPEN_APPEND should "force all writes to append data at the end of the file."
// in practice, it doesn't seem to do that. // in practice, it doesn't seem to do that.
@ -1991,9 +2016,9 @@ class Net_SFTP extends Net_SSH2
$result = $this->_query_stat_cache($path); $result = $this->_query_stat_cache($path);
if ($result !== false) { if (isset($result)) {
// return true if $result is an array or if it's int(1) // return true if $result is an array or if it's int(1)
return $result !== 0; return $result !== false;
} }
} }
@ -2009,19 +2034,11 @@ class Net_SFTP extends Net_SSH2
*/ */
function is_dir($path) function is_dir($path)
{ {
if ($this->use_stat_cache) { $result = $this->_get_stat_cache_prop($path, 'type');
$path = $this->_realpath($path); if ($result === false) {
return false;
$result = $this->_query_stat_cache($path);
if (is_object($result) && isset($result->type)) {
return $result->type === NET_SFTP_TYPE_DIRECTORY;
} }
} return $result === NET_SFTP_TYPE_DIRECTORY;
$result = $this->stat($path);
return $result['type'] === NET_SFTP_TYPE_DIRECTORY;
} }
/** /**
@ -2033,19 +2050,11 @@ class Net_SFTP extends Net_SSH2
*/ */
function is_file($path) function is_file($path)
{ {
if ($this->use_stat_cache) { $result = $this->_get_stat_cache_prop($path, 'type');
$path = $this->_realpath($path); if ($result === false) {
return false;
$result = $this->_query_stat_cache($path);
if (is_object($result) && isset($result->type)) {
return $result->type === NET_SFTP_TYPE_REGULAR;
} }
} return $result === NET_SFTP_TYPE_REGULAR;
$result = $this->stat($path);
return $result['type'] === NET_SFTP_TYPE_REGULAR;
} }
/** /**
@ -2057,43 +2066,139 @@ class Net_SFTP extends Net_SSH2
*/ */
function is_link($path) function is_link($path)
{ {
if ($this->use_stat_cache) { $result = $this->_get_stat_cache_prop($path, 'type');
$path = $this->_realpath($path); if ($result === false) {
return false;
$result = $this->_query_stat_cache($path);
if (is_object($result) && isset($result->type)) {
return $result->type === NET_SFTP_TYPE_SYMLINK;
} }
return $result === NET_SFTP_TYPE_SYMLINK;
} }
$result = $this->stat($path); /**
* Gets last access time of file
*
* @param String $path
* @return Mixed
* @access public
*/
function fileatime($path)
{
return $this->_get_stat_cache_prop($path, 'atime');
}
return $result['type'] === NET_SFTP_TYPE_SYMLINK; /**
* Gets file modification time
*
* @param String $path
* @return Mixed
* @access public
*/
function filemtime($path)
{
return $this->_get_stat_cache_prop($path, 'mtime');
}
/**
* Gets file permissions
*
* @param String $path
* @return Mixed
* @access public
*/
function fileperms($path)
{
return $this->_get_stat_cache_prop($path, 'permissions');
}
/**
* Gets file owner
*
* @param String $path
* @return Mixed
* @access public
*/
function fileowner($path)
{
return $this->_get_stat_cache_prop($path, 'uid');
}
/**
* Gets file group
*
* @param String $path
* @return Mixed
* @access public
*/
function filegroup($path)
{
return $this->_get_stat_cache_prop($path, 'gid');
} }
/** /**
* Gets file size * Gets file size
* *
* @param String $path * @param String $path
* @return Boolean * @return Mixed
* @access public * @access public
*/ */
function filesize($path) function filesize($path)
{
return $this->_get_stat_cache_prop($path, 'size');
}
/**
* Gets file type
*
* @param String $path
* @return Mixed
* @access public
*/
function filetype($path)
{
$type = $this->_get_stat_cache_prop($path, 'type');
if ($type === false) {
return false;
}
switch ($type) {
case NET_SFTP_BLOCK_DEVICE: return 'block';
case NET_SFTP_TYPE_CHAR_DEVICE: return 'char';
case NET_SFTP_TYPE_DIRECTORY: return 'dir';
case NET_SFTP_TYPE_FIFO: return 'fifo';
case NET_SFTP_TYPE_REGULAR: return 'file';
case NET_SFTP_TYPE_SYMLINK: return 'link';
default: return false;
}
}
/**
* Return a stat properity
*
* Uses cache if appropriate.
*
* @param String $path
* @param String $prop
* @return Mixed
* @access private
*/
function _get_stat_cache_prop($path, $prop)
{ {
if ($this->use_stat_cache) { if ($this->use_stat_cache) {
$path = $this->_realpath($path); $path = $this->_realpath($path);
$result = $this->_query_stat_cache($path); $result = $this->_query_stat_cache($path);
if (is_object($result) && isset($result->size)) { if (is_object($result) && isset($result->$prop)) {
return $result->size; return $result->$prop;
} }
} }
$result = $this->stat($path); $result = $this->stat($path);
return $result['size']; if ($result === false || !isset($result[$prop])) {
return false;
}
return $result[$prop];
} }
/** /**
@ -2139,6 +2244,7 @@ class Net_SFTP extends Net_SSH2
// atime and mtime attributes // atime and mtime attributes
//$this->_update_stat_cache($newname, $this->_query_stat_cache($oldname)); //$this->_update_stat_cache($newname, $this->_query_stat_cache($oldname));
$this->_remove_from_stat_cache($oldname); $this->_remove_from_stat_cache($oldname);
$this->_remove_from_stat_cache($newname);
return true; return true;
} }

View File

@ -209,6 +209,7 @@ class Net_SFTP_Stream
$this->sftp = self::$instances[$host][$port][$user][(string) $pass]; $this->sftp = self::$instances[$host][$port][$user][(string) $pass];
} else { } else {
$this->sftp = new Net_SFTP($host, $port); $this->sftp = new Net_SFTP($host, $port);
$this->disableStatCache();
if (isset($this->notification) && is_callable($this->notification)) { if (isset($this->notification) && is_callable($this->notification)) {
/* if !is_callable($this->notification) we could do this: /* if !is_callable($this->notification) we could do this: