aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php')
-rw-r--r--vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php141
1 files changed, 116 insertions, 25 deletions
diff --git a/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php
index 0c06c35f4..28b568062 100644
--- a/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php
+++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php
@@ -319,6 +319,38 @@ class SFTP extends SSH2
var $partial_init = false;
/**
+ * http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1
+ * the order, in this case, matters quite a lot - see \phpseclib3\Net\SFTP::_parseAttributes() to understand why
+ *
+ * @var array
+ * @access private
+ */
+ var $attributes = array();
+
+ /**
+ * @var array
+ * @access private
+ */
+ var $open_flags = array();
+
+ /**
+ * SFTPv5+ changed the flags up:
+ * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-8.1.1.3
+ *
+ * @var array
+ * @access private
+ */
+ var $open_flags5 = array();
+
+ /**
+ * http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2
+ * see \phpseclib\Net\SFTP::_parseLongname() for an explanation
+ *
+ * @var array
+ */
+ var $file_types = array();
+
+ /**
* Default Constructor.
*
* Connects to an SFTP server
@@ -422,7 +454,7 @@ class SFTP extends SSH2
// yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in
// two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000.
// that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
- (-1 << 31) & 0xFFFFFFFF => 'NET_SFTP_ATTR_EXTENDED'
+ (PHP_INT_SIZE == 4 ? (-1 << 31) : 0x80000000) => 'NET_SFTP_ATTR_EXTENDED'
);
$this->open_flags = array(
0x00000001 => 'NET_SFTP_OPEN_READ',
@@ -718,7 +750,16 @@ class SFTP extends SSH2
return false;
}
+ $this->pwd = true;
$this->pwd = $this->_realpath('.');
+ if ($this->pwd === false) {
+ if (!$this->canonicalize_paths) {
+ user_error('Unable to canonicalize current working directory');
+ return false;
+ }
+ $this->canonicalize_paths = false;
+ $this->_reset_connection(NET_SSH2_DISCONNECT_CONNECTION_LOST);
+ }
$this->_update_stat_cache($this->pwd, array());
@@ -766,7 +807,9 @@ class SFTP extends SSH2
}
/**
- * Enable path canonicalization
+ * Disable path canonicalization
+ *
+ * If this is enabled then $sftp->pwd() will not return the canonicalized absolute path
*
* @access public
*/
@@ -828,7 +871,7 @@ class SFTP extends SSH2
$error = $this->status_codes[$status];
- if ($this->version > 2 || strlen($response) < 4) {
+ if ($this->version > 2) {
extract(unpack('Nlength', $this->_string_shift($response, 4)));
$this->sftp_errors[] = $error . ': ' . $this->_string_shift($response, $length);
} else {
@@ -872,10 +915,37 @@ class SFTP extends SSH2
function _realpath($path)
{
if (!$this->canonicalize_paths) {
- return $path;
+ if ($this->pwd === true) {
+ return '.';
+ }
+ if (!strlen($path) || $path[0] != '/') {
+ $path = $this->pwd . '/' . $path;
+ }
+
+ $parts = explode('/', $path);
+ $afterPWD = $beforePWD = array();
+ foreach ($parts as $part) {
+ switch ($part) {
+ //case '': // some SFTP servers /require/ double /'s. see https://github.com/phpseclib/phpseclib/pull/1137
+ case '.':
+ break;
+ case '..':
+ if (!empty($afterPWD)) {
+ array_pop($afterPWD);
+ } else {
+ $beforePWD[] = '..';
+ }
+ break;
+ default:
+ $afterPWD[] = $part;
+ }
+ }
+
+ $beforePWD = count($beforePWD) ? implode('/', $beforePWD) : '.';
+ return $beforePWD . '/' . implode('/', $afterPWD);
}
- if ($this->pwd === false) {
+ if ($this->pwd === true) {
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($path), $path))) {
return false;
@@ -897,7 +967,6 @@ class SFTP extends SSH2
$this->_logError($response);
return false;
default:
- user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
return false;
}
}
@@ -1013,6 +1082,12 @@ class SFTP extends SSH2
{
$files = $this->_list($dir, false);
+ // If we get an int back, then that is an "unexpected" status.
+ // We do not have a file list, so return false.
+ if (is_int($files)) {
+ return false;
+ }
+
if (!$recursive || $files === false) {
return $files;
}
@@ -1048,6 +1123,13 @@ class SFTP extends SSH2
function rawlist($dir = '.', $recursive = false)
{
$files = $this->_list($dir, true);
+
+ // If we get an int back, then that is an "unexpected" status.
+ // We do not have a file list, so return false.
+ if (is_int($files)) {
+ return false;
+ }
+
if (!$recursive || $files === false) {
return $files;
}
@@ -1115,8 +1197,12 @@ class SFTP extends SSH2
break;
case NET_SFTP_STATUS:
// presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
- $this->_logError($response);
- return false;
+ if (strlen($response) < 4) {
+ return false;
+ }
+ extract(unpack('Nstatus', $this->_string_shift($response, 4)));
+ $this->_logError($response, $status);
+ return $status;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
@@ -1185,7 +1271,7 @@ class SFTP extends SSH2
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
if ($status != NET_SFTP_STATUS_EOF) {
$this->_logError($response, $status);
- return false;
+ return $status;
}
break 2;
default:
@@ -1861,7 +1947,7 @@ class SFTP extends SSH2
$i = 0;
$entries = $this->_list($path, true);
- if ($entries === false) {
+ if ($entries === false || is_int($entries)) {
return $this->_setstat($path, $attr, false);
}
@@ -2226,7 +2312,7 @@ class SFTP extends SSH2
if ($start >= 0) {
$offset = $start;
- } elseif ($mode & self::RESUME) {
+ } elseif ($mode & (self::RESUME | self::RESUME_START)) {
// if NET_SFTP_OPEN_APPEND worked as it should _size() wouldn't need to be called
$size = $this->size($remote_file);
$offset = $size !== false ? $size : 0;
@@ -2273,7 +2359,7 @@ class SFTP extends SSH2
case is_resource($data):
$mode = $mode & ~self::SOURCE_LOCAL_FILE;
$info = stream_get_meta_data($data);
- if ($info['wrapper_type'] == 'PHP' && $info['stream_type'] == 'Input') {
+ if (isset($info['wrapper_type']) && $info['wrapper_type'] == 'PHP' && $info['stream_type'] == 'Input') {
$fp = fopen('php://memory', 'w+');
stream_copy_to_stream($data, $fp);
rewind($fp);
@@ -2299,7 +2385,11 @@ class SFTP extends SSH2
if ($local_start >= 0) {
fseek($fp, $local_start);
$size-= $local_start;
+ } elseif ($mode & self::RESUME) {
+ fseek($fp, $offset);
+ $size-= $offset;
}
+
} elseif ($dataCallback) {
$size = 0;
} else {
@@ -2603,14 +2693,6 @@ class SFTP extends SSH2
}
}
- if ($length > 0 && $length <= $offset - $start) {
- if ($local_file === false) {
- $content = substr($content, 0, $length);
- } else {
- ftruncate($fp, $length + $res_offset);
- }
- }
-
if ($fclose_check) {
fclose($fp);
@@ -2706,12 +2788,17 @@ class SFTP extends SSH2
$i = 0;
$entries = $this->_list($path, true);
- // normally $entries would have at least . and .. but it might not if the directories
- // permissions didn't allow reading
- if (empty($entries)) {
+ // The folder does not exist at all, so we cannot delete it.
+ if ($entries === NET_SFTP_STATUS_NO_SUCH_FILE) {
return false;
}
+ // Normally $entries would have at least . and .. but it might not if the directories
+ // permissions didn't allow reading. If this happens then default to an empty list of files.
+ if ($entries === false || is_int($entries)) {
+ $entries = array();
+ }
+
unset($entries['.'], $entries['..']);
foreach ($entries as $filename => $props) {
if (!isset($props['type'])) {
@@ -3553,6 +3640,7 @@ class SFTP extends SSH2
$this->use_request_id = false;
$this->pwd = false;
$this->requestBuffer = array();
+ $this->partial_init = false;
}
/**
@@ -3618,6 +3706,9 @@ class SFTP extends SSH2
while ($tempLength > 0) {
$temp = $this->_get_channel_packet(self::CHANNEL, true);
if (is_bool($temp)) {
+ if ($temp && $this->channel_status[self::CHANNEL] === NET_SSH2_MSG_CHANNEL_CLOSE) {
+ $this->channel_close = true;
+ }
$this->packet_type = false;
$this->packet_buffer = '';
return false;
@@ -3698,7 +3789,7 @@ class SFTP extends SSH2
}
/**
- * Returns all errors
+ * Returns all errors on the SFTP layer
*
* @return array
* @access public
@@ -3709,7 +3800,7 @@ class SFTP extends SSH2
}
/**
- * Returns the last error
+ * Returns the last error on the SFTP layer
*
* @return string
* @access public