From a65b820b54aa12c91c8b5032fd669542d220d18e Mon Sep 17 00:00:00 2001 From: terrafrost Date: Wed, 18 Jun 2014 11:34:50 -0500 Subject: [PATCH 1/5] SFTP: add readlink and symlink functions --- phpseclib/Net/SFTP.php | 82 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php index 7f633eac..4e912098 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -312,6 +312,8 @@ class Net_SFTP extends Net_SSH2 SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3 pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.5 */ 18 => 'NET_SFTP_RENAME', + 19 => 'NET_SFTP_READLINK', + 20 => 'NET_SFTP_SYMLINK', 101=> 'NET_SFTP_STATUS', 102=> 'NET_SFTP_HANDLE', @@ -1557,6 +1559,86 @@ class Net_SFTP extends Net_SSH2 return true; } + /** + * Return the target of a symbolic link + * + * @param String $link + * @return Mixed + * @access public + */ + function readlink($link) + { + if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { + return false; + } + + $link = $this->_realpath($link); + + if (!$this->_send_sftp_packet(NET_SFTP_READLINK, pack('Na*', strlen($link), $link))) { + return false; + } + + $response = $this->_get_sftp_packet(); + switch ($this->packet_type) { + case NET_SFTP_NAME: + break; + case NET_SFTP_STATUS: + $this->_logError($response); + return false; + default: + user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS'); + return false; + } + + extract(unpack('Ncount', $this->_string_shift($response, 4))); + // the file isn't a symlink + if (!$count) { + return false; + } + + extract(unpack('Nlength', $this->_string_shift($response, 4))); + return $this->_string_shift($response, $length); + } + + /** + * Create a symlink + * + * symlink() creates a symbolic link to the existing target with the specified name link. + * + * @param String $target + * @param String $link + * @return Boolean + * @access public + */ + function symlink($target, $link) + { + if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { + return false; + } + + $target = $this->_realpath($target); + $link = $this->_realpath($link); + + $packet = pack('Na*Na*', strlen($target), $target, strlen($link), $link); + if (!$this->_send_sftp_packet(NET_SFTP_SYMLINK, $packet)) { + 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; + } + /** * Creates a directory. * From f95bf8b10be639958bda7781dc327d01078d35e4 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Thu, 19 Jun 2014 09:00:23 -0500 Subject: [PATCH 2/5] SFTP: add unit tests for symlinks --- tests/Functional/Net/SFTPUserStoryTest.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/Functional/Net/SFTPUserStoryTest.php b/tests/Functional/Net/SFTPUserStoryTest.php index c07c7ab7..8e806c3d 100644 --- a/tests/Functional/Net/SFTPUserStoryTest.php +++ b/tests/Functional/Net/SFTPUserStoryTest.php @@ -316,6 +316,27 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase return $sftp; } + /** + * @depends testSortOrder + */ + public function testSymlink($sftp) + { + $this->assertTrue( + $sftp->symlink('symlink', 'file3.txt'), + 'Failed asserting that a symlink could be created' + ); + } + + /** + * @depends testSymlink + */ + public function testReadlink($sftp) + { + $this->assertInternalType('string', $sftp->readlink('symlink'), + 'Failed asserting that a symlink's target could be read' + ); + } + /** * @depends testSortOrder */ From 366410e2e1efb64f9f058eaea875d9b85cb1648b Mon Sep 17 00:00:00 2001 From: terrafrost Date: Thu, 19 Jun 2014 10:42:20 -0500 Subject: [PATCH 3/5] SFTP: syntax error in unit test --- tests/Functional/Net/SFTPUserStoryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Functional/Net/SFTPUserStoryTest.php b/tests/Functional/Net/SFTPUserStoryTest.php index 8e806c3d..e2e5ce83 100644 --- a/tests/Functional/Net/SFTPUserStoryTest.php +++ b/tests/Functional/Net/SFTPUserStoryTest.php @@ -333,7 +333,7 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase public function testReadlink($sftp) { $this->assertInternalType('string', $sftp->readlink('symlink'), - 'Failed asserting that a symlink's target could be read' + 'Failed asserting that a symlink\'s target could be read' ); } From 05baf7b73bc772b645a9de2389f9f16778ab3210 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Thu, 19 Jun 2014 13:57:42 -0500 Subject: [PATCH 4/5] SFTP: fix unit test --- tests/Functional/Net/SFTPUserStoryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Functional/Net/SFTPUserStoryTest.php b/tests/Functional/Net/SFTPUserStoryTest.php index e2e5ce83..92c0263b 100644 --- a/tests/Functional/Net/SFTPUserStoryTest.php +++ b/tests/Functional/Net/SFTPUserStoryTest.php @@ -322,7 +322,7 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase public function testSymlink($sftp) { $this->assertTrue( - $sftp->symlink('symlink', 'file3.txt'), + $sftp->symlink('file3.txt', 'symlink'), 'Failed asserting that a symlink could be created' ); } From 03c315d5466af72d337f0267b4e8a1ecbbda38b7 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Thu, 19 Jun 2014 23:57:32 -0500 Subject: [PATCH 5/5] SFTP: return $sftp object in unit tests --- tests/Functional/Net/SFTPUserStoryTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Functional/Net/SFTPUserStoryTest.php b/tests/Functional/Net/SFTPUserStoryTest.php index 92c0263b..bdf8e7e3 100644 --- a/tests/Functional/Net/SFTPUserStoryTest.php +++ b/tests/Functional/Net/SFTPUserStoryTest.php @@ -325,6 +325,8 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase $sftp->symlink('file3.txt', 'symlink'), 'Failed asserting that a symlink could be created' ); + + return $sftp; } /** @@ -335,6 +337,8 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase $this->assertInternalType('string', $sftp->readlink('symlink'), 'Failed asserting that a symlink\'s target could be read' ); + + return $sftp; } /**