mirror of
https://github.com/phpseclib/phpseclib.git
synced 2024-12-29 04:23:34 +00:00
SFTP: Revamp file type detection and add truncate method
Also clean up some code
This commit is contained in:
parent
d4f176b434
commit
51d106b6ec
@ -225,15 +225,6 @@ class Net_SFTP extends Net_SSH2 {
|
|||||||
*/
|
*/
|
||||||
var $sftp_errors = array();
|
var $sftp_errors = array();
|
||||||
|
|
||||||
/**
|
|
||||||
* File Type
|
|
||||||
*
|
|
||||||
* @see Net_SFTP::_parseLongname()
|
|
||||||
* @var Integer
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
var $fileType = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directory Cache
|
* Directory Cache
|
||||||
*
|
*
|
||||||
@ -338,7 +329,14 @@ class Net_SFTP extends Net_SSH2 {
|
|||||||
1 => 'NET_SFTP_TYPE_REGULAR',
|
1 => 'NET_SFTP_TYPE_REGULAR',
|
||||||
2 => 'NET_SFTP_TYPE_DIRECTORY',
|
2 => 'NET_SFTP_TYPE_DIRECTORY',
|
||||||
3 => 'NET_SFTP_TYPE_SYMLINK',
|
3 => 'NET_SFTP_TYPE_SYMLINK',
|
||||||
4 => 'NET_SFTP_TYPE_SPECIAL'
|
4 => 'NET_SFTP_TYPE_SPECIAL',
|
||||||
|
5 => 'NET_SFTP_TYPE_UNKNOWN',
|
||||||
|
// the followin types were first defined for use in SFTPv5+
|
||||||
|
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2
|
||||||
|
6 => 'NET_SFTP_TYPE_SOCKET',
|
||||||
|
7 => 'NET_SFTP_TYPE_CHAR_DEVICE',
|
||||||
|
8 => 'NET_SFTP_TYPE_BLOCK_DEVICE',
|
||||||
|
9 => 'NET_SFTP_TYPE_FIFO'
|
||||||
);
|
);
|
||||||
$this->_define_array(
|
$this->_define_array(
|
||||||
$this->packet_types,
|
$this->packet_types,
|
||||||
@ -587,6 +585,11 @@ class Net_SFTP extends Net_SSH2 {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we could do a stat on the alleged $dir to see if it's a directory but that doesn't tell us
|
||||||
|
// the currently logged in user has the appropriate permissions or not. maybe you could see if
|
||||||
|
// the file's uid / gid match the currently logged in user's uid / gid but how there's no easy
|
||||||
|
// way to get those with SFTP
|
||||||
|
|
||||||
if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
|
if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -716,21 +719,21 @@ class Net_SFTP extends Net_SSH2 {
|
|||||||
$shortname = $this->_string_shift($response, $length);
|
$shortname = $this->_string_shift($response, $length);
|
||||||
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
||||||
$longname = $this->_string_shift($response, $length);
|
$longname = $this->_string_shift($response, $length);
|
||||||
$attributes = $this->_parseAttributes($response); // we also don't care about the attributes
|
$attributes = $this->_parseAttributes($response);
|
||||||
$fileType = $this->_parseLongname($longname);
|
if (!isset($attributes['type'])) {
|
||||||
|
$fileType = $this->_parseLongname($longname);
|
||||||
|
if ($fileType) {
|
||||||
|
$attributes['type'] = $fileType;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!$raw) {
|
if (!$raw) {
|
||||||
$contents[] = $shortname;
|
$contents[] = $shortname;
|
||||||
} else {
|
} else {
|
||||||
$contents[$shortname] = $attributes;
|
$contents[$shortname] = $attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($fileType) {
|
if (isset($attributes['type']) && $attributes['type'] == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) {
|
||||||
if ($fileType == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) {
|
$this->_save_dir($dir . '/' . $shortname);
|
||||||
$this->_save_dir($dir . '/' . $shortname);
|
|
||||||
}
|
|
||||||
if ($raw) {
|
|
||||||
$contents[$shortname]['type'] = $fileType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the
|
// SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the
|
||||||
// final SSH_FXP_STATUS packet should tell us that, already.
|
// final SSH_FXP_STATUS packet should tell us that, already.
|
||||||
@ -883,6 +886,9 @@ class Net_SFTP extends Net_SSH2 {
|
|||||||
if ($stat === false) {
|
if ($stat === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (isset($stat['type'])) {
|
||||||
|
return $stat;
|
||||||
|
}
|
||||||
|
|
||||||
$pwd = $this->pwd;
|
$pwd = $this->pwd;
|
||||||
$stat['type'] = $this->chdir($filename) ?
|
$stat['type'] = $this->chdir($filename) ?
|
||||||
@ -917,6 +923,10 @@ class Net_SFTP extends Net_SSH2 {
|
|||||||
if ($lstat === false) {
|
if ($lstat === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (isset($lstat['type'])) {
|
||||||
|
return $lstat;
|
||||||
|
}
|
||||||
|
|
||||||
$stat = $this->_stat($filename, NET_SFTP_STAT);
|
$stat = $this->_stat($filename, NET_SFTP_STAT);
|
||||||
|
|
||||||
if ($lstat != $stat) {
|
if ($lstat != $stat) {
|
||||||
@ -954,11 +964,7 @@ class Net_SFTP extends Net_SSH2 {
|
|||||||
$response = $this->_get_sftp_packet();
|
$response = $this->_get_sftp_packet();
|
||||||
switch ($this->packet_type) {
|
switch ($this->packet_type) {
|
||||||
case NET_SFTP_ATTRS:
|
case NET_SFTP_ATTRS:
|
||||||
$attributes = $this->_parseAttributes($response);
|
return $this->_parseAttributes($response);
|
||||||
if ($this->fileType) {
|
|
||||||
$attributes['type'] = $this->fileType;
|
|
||||||
}
|
|
||||||
return $attributes;
|
|
||||||
case NET_SFTP_STATUS:
|
case NET_SFTP_STATUS:
|
||||||
$this->_logError($response);
|
$this->_logError($response);
|
||||||
return false;
|
return false;
|
||||||
@ -968,33 +974,6 @@ class Net_SFTP extends Net_SSH2 {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to identify the file type
|
|
||||||
*
|
|
||||||
* @param String $path
|
|
||||||
* @param Array $stat
|
|
||||||
* @param Array $lstat
|
|
||||||
* @return Integer
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
function _identify_type($path, $stat1, $stat2)
|
|
||||||
{
|
|
||||||
$stat1 = $this->_stat($path, $stat1);
|
|
||||||
$stat2 = $this->_stat($path, $stat2);
|
|
||||||
|
|
||||||
if ($stat1 != $stat2) {
|
|
||||||
return array_merge($stat1, array('type' => NET_SFTP_TYPE_SYMLINK));
|
|
||||||
}
|
|
||||||
|
|
||||||
$pwd = $this->pwd;
|
|
||||||
$stat1['type'] = $this->chdir($path) ?
|
|
||||||
NET_SFTP_TYPE_DIRECTORY :
|
|
||||||
NET_SFTP_TYPE_REGULAR;
|
|
||||||
$this->pwd = $pwd;
|
|
||||||
|
|
||||||
return $stat1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the file size, in bytes, or false, on failure
|
* Returns the file size, in bytes, or false, on failure
|
||||||
*
|
*
|
||||||
@ -1013,6 +992,21 @@ class Net_SFTP extends Net_SSH2 {
|
|||||||
return isset($result['size']) ? $result['size'] : -1;
|
return isset($result['size']) ? $result['size'] : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Truncates a file to a given length
|
||||||
|
*
|
||||||
|
* @param String $filename
|
||||||
|
* @param Integer $new_size
|
||||||
|
* @return Boolean
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
function truncate($filename, $new_size)
|
||||||
|
{
|
||||||
|
$attr = pack('N3', NET_SFTP_ATTR_SIZE, 0, $new_size);
|
||||||
|
|
||||||
|
return $this->_setstat($filename, $attr, false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets access and modification time of file.
|
* Sets access and modification time of file.
|
||||||
*
|
*
|
||||||
@ -1079,24 +1073,7 @@ class Net_SFTP extends Net_SSH2 {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $time, $atime);
|
return $this->_setstat($filename, $attr, false);
|
||||||
if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = $this->_get_sftp_packet();
|
|
||||||
if ($this->packet_type != NET_SFTP_STATUS) {
|
|
||||||
user_error('Expected SSH_FXP_STATUS');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
|
||||||
if ($status != NET_SFTP_STATUS_OK) {
|
|
||||||
$this->_logError($response, $status);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1914,6 +1891,10 @@ class Net_SFTP extends Net_SSH2 {
|
|||||||
break;
|
break;
|
||||||
case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004
|
case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004
|
||||||
$attr+= unpack('Npermissions', $this->_string_shift($response, 4));
|
$attr+= unpack('Npermissions', $this->_string_shift($response, 4));
|
||||||
|
$fileType = $this->_parseMode($attr['permissions']);
|
||||||
|
if ($filetype !== false) {
|
||||||
|
$attr+= array('type' => $fileType);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008
|
case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008
|
||||||
$attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8));
|
$attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8));
|
||||||
@ -1931,6 +1912,47 @@ class Net_SFTP extends Net_SSH2 {
|
|||||||
return $attr;
|
return $attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to identify the file type
|
||||||
|
*
|
||||||
|
* Quoting the SFTP RFC, "Implementations MUST NOT send bits that are not defined" but they seem to anyway
|
||||||
|
*
|
||||||
|
* @param Integer $mode
|
||||||
|
* @return Integer
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _parseMode($mode)
|
||||||
|
{
|
||||||
|
// values come from http://lxr.free-electrons.com/source/include/uapi/linux/stat.h#L12
|
||||||
|
// see, also, http://linux.die.net/man/2/stat
|
||||||
|
switch ($mode & 0170000) {// ie. 1111 0000 0000 0000
|
||||||
|
case 0000000: // no file type specified - figure out the file type using alternative means
|
||||||
|
return false;
|
||||||
|
case 0040000:
|
||||||
|
return NET_SFTP_TYPE_DIRECTORY;
|
||||||
|
case 0100000:
|
||||||
|
return NET_SFTP_TYPE_REGULAR;
|
||||||
|
case 0120000:
|
||||||
|
return NET_SFTP_TYPE_SYMLINK;
|
||||||
|
// new types introduced in SFTPv5+
|
||||||
|
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2
|
||||||
|
case 0010000: // named pipe (fifo)
|
||||||
|
return NET_SFTP_TYPE_FIFO;
|
||||||
|
case 0020000: // character special
|
||||||
|
return NET_SFTP_TYPE_CHAR_DEVICE;
|
||||||
|
case 0060000: // block special
|
||||||
|
return NET_SFTP_BLOCK_DEVICE;
|
||||||
|
case 0140000: // socket
|
||||||
|
return NET_SFTP_TYPE_SOCKET;
|
||||||
|
case 0160000: // whiteout
|
||||||
|
// "SPECIAL should be used for files that are of
|
||||||
|
// a known type which cannot be expressed in the protocol"
|
||||||
|
return NET_SFTP_TYPE_SPECIAL;
|
||||||
|
default:
|
||||||
|
return NET_SFTP_TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse Longname
|
* Parse Longname
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user