diff options
Diffstat (limited to 'apps/files_external/lib')
-rwxr-xr-x | apps/files_external/lib/config.php | 339 | ||||
-rw-r--r-- | apps/files_external/lib/smb.php | 2 | ||||
-rw-r--r-- | apps/files_external/lib/smb_oc.php | 93 | ||||
-rw-r--r-- | apps/files_external/lib/swift.php | 6 | ||||
-rw-r--r-- | apps/files_external/lib/webdav.php | 193 |
5 files changed, 490 insertions, 143 deletions
diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php index 43275d36c06..472c3963d51 100755 --- a/apps/files_external/lib/config.php +++ b/apps/files_external/lib/config.php @@ -4,6 +4,8 @@ * * @author Michael Gapczynski * @copyright 2012 Michael Gapczynski mtgap@owncloud.com +* @copyright 2014 Vincent Petry <pvince81@owncloud.com> +* @copyright 2014 Robin McCorkell <rmccorkell@karoshi.org.uk> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE @@ -19,15 +21,24 @@ * License along with this library. If not, see <http://www.gnu.org/licenses/>. */ +set_include_path( + get_include_path() . PATH_SEPARATOR . + \OC_App::getAppPath('files_external') . '/3rdparty/phpseclib/phpseclib' +); + /** -* Class to configure the config/mount.php and data/$user/mount.php files -*/ + * Class to configure mount.json globally and for users + */ class OC_Mount_Config { + // TODO: make this class non-static and give it a proper namespace const MOUNT_TYPE_GLOBAL = 'global'; const MOUNT_TYPE_GROUP = 'group'; const MOUNT_TYPE_USER = 'user'; + // whether to skip backend test (for unit tests, as this static class is not mockable) + public static $skipTest = false; + /** * Get details on each of the external storage backends, used for the mount config UI * If a custom UI is needed, add the key 'custom' and a javascript file with that name will be loaded @@ -39,13 +50,14 @@ class OC_Mount_Config { */ public static function getBackends() { + // FIXME: do not rely on php key order for the options order in the UI $backends['\OC\Files\Storage\Local']=array( 'backend' => 'Local', 'configuration' => array( 'datadir' => 'Location')); $backends['\OC\Files\Storage\AmazonS3']=array( - 'backend' => 'Amazon S3', + 'backend' => 'Amazon S3 and compliant', 'configuration' => array( 'key' => 'Access Key', 'secret' => '*Secret Key', @@ -111,11 +123,18 @@ class OC_Mount_Config { 'password' => '*Password', 'share' => 'Share', 'root' => '&Root')); + $backends['\OC\Files\Storage\SMB_OC'] = array( + 'backend' => 'SMB / CIFS using OC login', + 'configuration' => array( + 'host' => 'URL', + 'username_as_share' => '!Username as share', + 'share' => '&Share', + 'root' => '&Root')); } } if(OC_Mount_Config::checkcurl()){ - $backends['\OC\Files\Storage\DAV']=array( + $backends['\OC\Files\Storage\DAV']=array( 'backend' => 'WebDAV', 'configuration' => array( 'host' => 'URL', @@ -123,7 +142,7 @@ class OC_Mount_Config { 'password' => '*Password', 'root' => '&Root', 'secure' => '!Secure https://')); - $backends['\OC\Files\Storage\OwnCloud']=array( + $backends['\OC\Files\Storage\OwnCloud']=array( 'backend' => 'ownCloud', 'configuration' => array( 'host' => 'URL', @@ -156,6 +175,125 @@ class OC_Mount_Config { } /** + * Hook that mounts the given user's visible mount points + * @param array $data + */ + public static function initMountPointsHook($data) { + $mountPoints = self::getAbsoluteMountPoints($data['user']); + foreach ($mountPoints as $mountPoint => $options) { + \OC\Files\Filesystem::mount($options['class'], $options['options'], $mountPoint); + } + } + + /** + * Returns the mount points for the given user. + * The mount point is relative to the data directory. + * + * @param string $user user + * @return array of mount point string as key, mountpoint config as value + */ + public static function getAbsoluteMountPoints($user) { + $mountPoints = array(); + + $datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data"); + $mount_file = \OC_Config::getValue("mount_file", $datadir . "/mount.json"); + + //move config file to it's new position + if (is_file(\OC::$SERVERROOT . '/config/mount.json')) { + rename(\OC::$SERVERROOT . '/config/mount.json', $mount_file); + } + + // Load system mount points + $mountConfig = self::readData(false); + if (isset($mountConfig[self::MOUNT_TYPE_GLOBAL])) { + foreach ($mountConfig[self::MOUNT_TYPE_GLOBAL] as $mountPoint => $options) { + $options['options'] = self::decryptPasswords($options['options']); + $mountPoints[$mountPoint] = $options; + } + } + if (isset($mountConfig[self::MOUNT_TYPE_GROUP])) { + foreach ($mountConfig[self::MOUNT_TYPE_GROUP] as $group => $mounts) { + if (\OC_Group::inGroup($user, $group)) { + foreach ($mounts as $mountPoint => $options) { + $mountPoint = self::setUserVars($user, $mountPoint); + foreach ($options as &$option) { + $option = self::setUserVars($user, $option); + } + $options['options'] = self::decryptPasswords($options['options']); + $mountPoints[$mountPoint] = $options; + } + } + } + } + if (isset($mountConfig[self::MOUNT_TYPE_USER])) { + foreach ($mountConfig[self::MOUNT_TYPE_USER] as $mountUser => $mounts) { + if ($mountUser === 'all' or strtolower($mountUser) === strtolower($user)) { + foreach ($mounts as $mountPoint => $options) { + $mountPoint = self::setUserVars($user, $mountPoint); + foreach ($options as &$option) { + $option = self::setUserVars($user, $option); + } + $options['options'] = self::decryptPasswords($options['options']); + $mountPoints[$mountPoint] = $options; + } + } + } + } + + // Load personal mount points + $mountConfig = self::readData(true); + if (isset($mountConfig[self::MOUNT_TYPE_USER][$user])) { + foreach ($mountConfig[self::MOUNT_TYPE_USER][$user] as $mountPoint => $options) { + $options['options'] = self::decryptPasswords($options['options']); + $mountPoints[$mountPoint] = $options; + } + } + + return $mountPoints; + } + + /** + * fill in the correct values for $user + * + * @param string $user + * @param string $input + * @return string + */ + private static function setUserVars($user, $input) { + return str_replace('$user', $user, $input); + } + + + /** + * Get details on each of the external storage backends, used for the mount config UI + * Some backends are not available as a personal backend, f.e. Local and such that have + * been disabled by the admin. + * + * If a custom UI is needed, add the key 'custom' and a javascript file with that name will be loaded + * If the configuration parameter should be secret, add a '*' to the beginning of the value + * If the configuration parameter is a boolean, add a '!' to the beginning of the value + * If the configuration parameter is optional, add a '&' to the beginning of the value + * If the configuration parameter is hidden, add a '#' to the beginning of the value + * @return array + */ + public static function getPersonalBackends() { + + $backends = self::getBackends(); + + // Remove local storage and other disabled storages + unset($backends['\OC\Files\Storage\Local']); + + $allowed_backends = explode(',', OCP\Config::getAppValue('files_external', 'user_mounting_backends', '')); + foreach ($backends as $backend => $null) { + if (!in_array($backend, $allowed_backends)) { + unset($backends[$backend]); + } + } + + return $backends; + } + + /** * Get the system mount points * The returned array is not in the same format as getUserMountPoints() * @return array @@ -171,20 +309,26 @@ class OC_Mount_Config { if (strpos($mount['class'], 'OC_Filestorage_') !== false) { $mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15); } + $mount['options'] = self::decryptPasswords($mount['options']); // Remove '/$user/files/' from mount point $mountPoint = substr($mountPoint, 13); - // Merge the mount point into the current mount points - if (isset($system[$mountPoint]) && $system[$mountPoint]['configuration'] == $mount['options']) { - $system[$mountPoint]['applicable']['groups'] - = array_merge($system[$mountPoint]['applicable']['groups'], array($group)); + + $config = array( + 'class' => $mount['class'], + 'mountpoint' => $mountPoint, + 'backend' => $backends[$mount['class']]['backend'], + 'options' => $mount['options'], + 'applicable' => array('groups' => array($group), 'users' => array()), + 'status' => self::getBackendStatus($mount['class'], $mount['options'], false) + ); + $hash = self::makeConfigHash($config); + // If an existing config exists (with same class, mountpoint and options) + if (isset($system[$hash])) { + // add the groups into that config + $system[$hash]['applicable']['groups'] + = array_merge($system[$hash]['applicable']['groups'], array($group)); } else { - $system[$mountPoint] = array( - 'class' => $mount['class'], - 'backend' => $backends[$mount['class']]['backend'], - 'configuration' => $mount['options'], - 'applicable' => array('groups' => array($group), 'users' => array()), - 'status' => self::getBackendStatus($mount['class'], $mount['options']) - ); + $system[$hash] = $config; } } } @@ -196,25 +340,30 @@ class OC_Mount_Config { if (strpos($mount['class'], 'OC_Filestorage_') !== false) { $mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15); } + $mount['options'] = self::decryptPasswords($mount['options']); // Remove '/$user/files/' from mount point $mountPoint = substr($mountPoint, 13); - // Merge the mount point into the current mount points - if (isset($system[$mountPoint]) && $system[$mountPoint]['configuration'] == $mount['options']) { - $system[$mountPoint]['applicable']['users'] - = array_merge($system[$mountPoint]['applicable']['users'], array($user)); + $config = array( + 'class' => $mount['class'], + 'mountpoint' => $mountPoint, + 'backend' => $backends[$mount['class']]['backend'], + 'options' => $mount['options'], + 'applicable' => array('groups' => array(), 'users' => array($user)), + 'status' => self::getBackendStatus($mount['class'], $mount['options'], false) + ); + $hash = self::makeConfigHash($config); + // If an existing config exists (with same class, mountpoint and options) + if (isset($system[$hash])) { + // add the users into that config + $system[$hash]['applicable']['users'] + = array_merge($system[$hash]['applicable']['users'], array($user)); } else { - $system[$mountPoint] = array( - 'class' => $mount['class'], - 'backend' => $backends[$mount['class']]['backend'], - 'configuration' => $mount['options'], - 'applicable' => array('groups' => array(), 'users' => array($user)), - 'status' => self::getBackendStatus($mount['class'], $mount['options']) - ); + $system[$hash] = $config; } } } } - return $system; + return array_values($system); } /** @@ -233,26 +382,37 @@ class OC_Mount_Config { if (strpos($mount['class'], 'OC_Filestorage_') !== false) { $mount['class'] = '\OC\Files\Storage\\'.substr($mount['class'], 15); } - // Remove '/uid/files/' from mount point - $personal[substr($mountPoint, strlen($uid) + 8)] = array( + $mount['options'] = self::decryptPasswords($mount['options']); + $personal[] = array( 'class' => $mount['class'], + // Remove '/uid/files/' from mount point + 'mountpoint' => substr($mountPoint, strlen($uid) + 8), 'backend' => $backends[$mount['class']]['backend'], - 'configuration' => $mount['options'], - 'status' => self::getBackendStatus($mount['class'], $mount['options']) + 'options' => $mount['options'], + 'status' => self::getBackendStatus($mount['class'], $mount['options'], true) ); } } return $personal; } - private static function getBackendStatus($class, $options) { + /** + * Test connecting using the given backend configuration + * @param string $class backend class name + * @param array $options backend configuration options + * @return bool true if the connection succeeded, false otherwise + */ + private static function getBackendStatus($class, $options, $isPersonal) { + if (self::$skipTest) { + return true; + } foreach ($options as &$option) { - $option = str_replace('$user', OCP\User::getUser(), $option); + $option = self::setUserVars(OCP\User::getUser(), $option); } if (class_exists($class)) { try { $storage = new $class($options); - return $storage->test(); + return $storage->test($isPersonal); } catch (Exception $exception) { \OCP\Util::logException('files_external', $exception); return false; @@ -287,18 +447,25 @@ class OC_Mount_Config { if (!isset($backends[$class])) { // invalid backend return false; - } + } if ($isPersonal) { // Verify that the mount point applies for the current user - // Prevent non-admin users from mounting local storage - if ($applicable !== OCP\User::getUser() || strtolower($class) === '\oc\files\storage\local') { + // Prevent non-admin users from mounting local storage and other disabled backends + $allowed_backends = self::getPersonalBackends(); + if ($applicable != OCP\User::getUser() || !isset($allowed_backends[$class])) { return false; } $mountPoint = '/'.$applicable.'/files/'.ltrim($mountPoint, '/'); } else { $mountPoint = '/$user/files/'.ltrim($mountPoint, '/'); } - $mount = array($applicable => array($mountPoint => array('class' => $class, 'options' => $classOptions))); + + $mount = array($applicable => array( + $mountPoint => array( + 'class' => $class, + 'options' => self::encryptPasswords($classOptions)) + ) + ); $mountPoints = self::readData($isPersonal); // Merge the new mount point into the current mount points if (isset($mountPoints[$mountType])) { @@ -312,7 +479,7 @@ class OC_Mount_Config { $mountPoints[$mountType] = $mount; } self::writeData($isPersonal, $mountPoints); - return self::getBackendStatus($class, $classOptions); + return self::getBackendStatus($class, $classOptions, $isPersonal); } /** @@ -389,7 +556,12 @@ class OC_Mount_Config { $datadir = \OC_Config::getValue('datadirectory', \OC::$SERVERROOT . '/data/'); $file = \OC_Config::getValue('mount_file', $datadir . '/mount.json'); } - $content = json_encode($data); + $options = 0; + if (defined('JSON_PRETTY_PRINT')) { + // only for PHP >= 5.4 + $options = JSON_PRETTY_PRINT; + } + $content = json_encode($data, $options); @file_put_contents($file, $content); @chmod($file, 0640); } @@ -446,7 +618,7 @@ class OC_Mount_Config { */ public static function checksmbclient() { if(function_exists('shell_exec')) { - $output=shell_exec('which smbclient 2> /dev/null'); + $output=shell_exec('command -v smbclient 2> /dev/null'); return !empty($output); }else{ return false; @@ -491,4 +663,87 @@ class OC_Mount_Config { return $txt; } + + /** + * Encrypt passwords in the given config options + * @param array $options mount options + * @return array updated options + */ + private static function encryptPasswords($options) { + if (isset($options['password'])) { + $options['password_encrypted'] = self::encryptPassword($options['password']); + // do not unset the password, we want to keep the keys order + // on load... because that's how the UI currently works + $options['password'] = ''; + } + return $options; + } + + /** + * Decrypt passwords in the given config options + * @param array $options mount options + * @return array updated options + */ + private static function decryptPasswords($options) { + // note: legacy options might still have the unencrypted password in the "password" field + if (isset($options['password_encrypted'])) { + $options['password'] = self::decryptPassword($options['password_encrypted']); + unset($options['password_encrypted']); + } + return $options; + } + + /** + * Encrypt a single password + * @param string $password plain text password + * @return encrypted password + */ + private static function encryptPassword($password) { + $cipher = self::getCipher(); + $iv = \OCP\Util::generateRandomBytes(16); + $cipher->setIV($iv); + return base64_encode($iv . $cipher->encrypt($password)); + } + + /** + * Decrypts a single password + * @param string $encryptedPassword encrypted password + * @return plain text password + */ + private static function decryptPassword($encryptedPassword) { + $cipher = self::getCipher(); + $binaryPassword = base64_decode($encryptedPassword); + $iv = substr($binaryPassword, 0, 16); + $cipher->setIV($iv); + $binaryPassword = substr($binaryPassword, 16); + return $cipher->decrypt($binaryPassword); + } + + /** + * Returns the encryption cipher + */ + private static function getCipher() { + if (!class_exists('Crypt_AES', false)) { + include('Crypt/AES.php'); + } + $cipher = new Crypt_AES(CRYPT_AES_MODE_CBC); + $cipher->setKey(\OCP\Config::getSystemValue('passwordsalt')); + return $cipher; + } + + /** + * Computes a hash based on the given configuration. + * This is mostly used to find out whether configurations + * are the same. + */ + private static function makeConfigHash($config) { + $data = json_encode( + array( + 'c' => $config['class'], + 'm' => $config['mountpoint'], + 'o' => $config['options'] + ) + ); + return hash('md5', $data); + } } diff --git a/apps/files_external/lib/smb.php b/apps/files_external/lib/smb.php index c5fba92ee68..f3f3b3ed7f3 100644 --- a/apps/files_external/lib/smb.php +++ b/apps/files_external/lib/smb.php @@ -37,7 +37,7 @@ class SMB extends \OC\Files\Storage\StreamWrapper{ $this->share = substr($this->share, 0, -1); } } else { - throw new \Exception(); + throw new \Exception('Invalid configuration'); } } diff --git a/apps/files_external/lib/smb_oc.php b/apps/files_external/lib/smb_oc.php new file mode 100644 index 00000000000..0c79c06c5df --- /dev/null +++ b/apps/files_external/lib/smb_oc.php @@ -0,0 +1,93 @@ +<?php +/** + * Copyright (c) 2014 Robin McCorkell <rmccorkell@karoshi.org.uk> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Storage; + +require_once __DIR__ . '/../3rdparty/smb4php/smb.php'; + +class SMB_OC extends \OC\Files\Storage\SMB { + private $username_as_share; + + public function __construct($params) { + if (isset($params['host']) && \OC::$session->exists('smb-credentials')) { + $host=$params['host']; + $this->username_as_share = ($params['username_as_share'] === 'true'); + + $params_auth = \OC::$session->get('smb-credentials'); + $user = \OC::$session->get('loginname'); + $password = $params_auth['password']; + + $root=isset($params['root'])?$params['root']:'/'; + $share = ''; + + if ($this->username_as_share) { + $share = '/'.$user; + } elseif (isset($params['share'])) { + $share = $params['share']; + } else { + throw new \Exception(); + } + parent::__construct(array( + "user" => $user, + "password" => $password, + "host" => $host, + "share" => $share, + "root" => $root + )); + } else { + throw new \Exception(); + } + } + + public static function login( $params ) { + \OC::$session->set('smb-credentials', $params); + } + + public function isSharable($path) { + return false; + } + + public function test($isPersonal = true) { + if ($isPersonal) { + if ($this->stat('')) { + return true; + } + return false; + } else { + $smb = new \smb(); + $pu = $smb->parse_url($this->constructUrl('')); + + // Attempt to connect anonymously + $pu['user'] = ''; + $pu['pass'] = ''; + + // Share cannot be checked if dynamic + if ($this->username_as_share) { + if ($smb->look($pu)) { + return true; + } else { + return false; + } + } + if (!$pu['share']) { + return false; + } + + // The following error messages are expected due to anonymous login + $regexp = array( + '(NT_STATUS_ACCESS_DENIED)' => 'skip' + ) + $smb->getRegexp(); + + if ($smb->client("-d 0 " . escapeshellarg('//' . $pu['host'] . '/' . $pu['share']) . " -c exit", $pu, $regexp)) { + return true; + } else { + return false; + } + } + } +} diff --git a/apps/files_external/lib/swift.php b/apps/files_external/lib/swift.php index 7a56fcfc8b7..1337d9f581d 100644 --- a/apps/files_external/lib/swift.php +++ b/apps/files_external/lib/swift.php @@ -251,6 +251,10 @@ class Swift extends \OC\Files\Storage\Common { $mtime = $object->extra_headers['X-Object-Meta-Timestamp']; } + if (!empty($mtime)) { + $mtime = floor($mtime); + } + $stat = array(); $stat['size'] = $object->content_length; $stat['mtime'] = $mtime; @@ -370,7 +374,7 @@ class Swift extends \OC\Files\Storage\Common { 'X-Object-Meta-Timestamp' => $mtime ) ); - return $object->Update($settings); + return $object->UpdateMetadata($settings); } else { $object = $this->container->DataObject(); if (is_null($mtime)) { diff --git a/apps/files_external/lib/webdav.php b/apps/files_external/lib/webdav.php index 9afe73aebd7..279ae716935 100644 --- a/apps/files_external/lib/webdav.php +++ b/apps/files_external/lib/webdav.php @@ -8,7 +8,7 @@ namespace OC\Files\Storage; -class DAV extends \OC\Files\Storage\Common{ +class DAV extends \OC\Files\Storage\Common { private $password; private $user; private $host; @@ -21,7 +21,7 @@ class DAV extends \OC\Files\Storage\Common{ */ private $client; - private static $tempFiles=array(); + private static $tempFiles = array(); public function __construct($params) { if (isset($params['host']) && isset($params['user']) && isset($params['password'])) { @@ -29,9 +29,9 @@ class DAV extends \OC\Files\Storage\Common{ //remove leading http[s], will be generated in createBaseUri() if (substr($host, 0, 8) == "https://") $host = substr($host, 8); else if (substr($host, 0, 7) == "http://") $host = substr($host, 7); - $this->host=$host; - $this->user=$params['user']; - $this->password=$params['password']; + $this->host = $host; + $this->user = $params['user']; + $this->password = $params['password']; if (isset($params['secure'])) { if (is_string($params['secure'])) { $this->secure = ($params['secure'] === 'true'); @@ -42,25 +42,25 @@ class DAV extends \OC\Files\Storage\Common{ $this->secure = false; } if ($this->secure === true) { - $certPath=\OC_User::getHome(\OC_User::getUser()) . '/files_external/rootcerts.crt'; + $certPath = \OC_User::getHome(\OC_User::getUser()) . '/files_external/rootcerts.crt'; if (file_exists($certPath)) { - $this->certPath=$certPath; + $this->certPath = $certPath; } } - $this->root=isset($params['root'])?$params['root']:'/'; - if ( ! $this->root || $this->root[0]!='/') { - $this->root='/'.$this->root; + $this->root = isset($params['root']) ? $params['root'] : '/'; + if (!$this->root || $this->root[0] != '/') { + $this->root = '/' . $this->root; } - if (substr($this->root, -1, 1)!='/') { - $this->root.='/'; + if (substr($this->root, -1, 1) != '/') { + $this->root .= '/'; } } else { throw new \Exception(); } } - private function init(){ - if($this->ready) { + private function init() { + if ($this->ready) { return; } $this->ready = true; @@ -78,28 +78,28 @@ class DAV extends \OC\Files\Storage\Common{ } } - public function getId(){ + public function getId() { return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root; } protected function createBaseUri() { - $baseUri='http'; + $baseUri = 'http'; if ($this->secure) { - $baseUri.='s'; + $baseUri .= 's'; } - $baseUri.='://'.$this->host.$this->root; + $baseUri .= '://' . $this->host . $this->root; return $baseUri; } public function mkdir($path) { $this->init(); - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); return $this->simpleResponse('MKCOL', $path, null, 201); } public function rmdir($path) { $this->init(); - $path=$this->cleanPath($path) . '/'; + $path = $this->cleanPath($path) . '/'; // FIXME: some WebDAV impl return 403 when trying to DELETE // a non-empty folder return $this->simpleResponse('DELETE', $path, null, 204); @@ -107,35 +107,35 @@ class DAV extends \OC\Files\Storage\Common{ public function opendir($path) { $this->init(); - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); try { - $response=$this->client->propfind($this->encodePath($path), array(), 1); - $id=md5('webdav'.$this->root.$path); + $response = $this->client->propfind($this->encodePath($path), array(), 1); + $id = md5('webdav' . $this->root . $path); $content = array(); - $files=array_keys($response); - array_shift($files);//the first entry is the current directory + $files = array_keys($response); + array_shift($files); //the first entry is the current directory foreach ($files as $file) { $file = urldecode(basename($file)); - $content[]=$file; + $content[] = $file; } \OC\Files\Stream\Dir::register($id, $content); - return opendir('fakedir://'.$id); - } catch(\Exception $e) { + return opendir('fakedir://' . $id); + } catch (\Exception $e) { return false; } } public function filetype($path) { $this->init(); - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); try { - $response=$this->client->propfind($this->encodePath($path), array('{DAV:}resourcetype')); + $response = $this->client->propfind($this->encodePath($path), array('{DAV:}resourcetype')); $responseType = array(); if (isset($response["{DAV:}resourcetype"])) { - $responseType=$response["{DAV:}resourcetype"]->resourceType; + $responseType = $response["{DAV:}resourcetype"]->resourceType; } - return (count($responseType)>0 and $responseType[0]=="{DAV:}collection")?'dir':'file'; - } catch(\Exception $e) { + return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file'; + } catch (\Exception $e) { error_log($e->getMessage()); \OCP\Util::writeLog("webdav client", \OCP\Util::sanitizeHTML($e->getMessage()), \OCP\Util::ERROR); return false; @@ -144,11 +144,11 @@ class DAV extends \OC\Files\Storage\Common{ public function file_exists($path) { $this->init(); - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); try { $this->client->propfind($this->encodePath($path), array('{DAV:}resourcetype')); - return true;//no 404 exception - } catch(\Exception $e) { + return true; //no 404 exception + } catch (\Exception $e) { return false; } } @@ -160,34 +160,34 @@ class DAV extends \OC\Files\Storage\Common{ public function fopen($path, $mode) { $this->init(); - $path=$this->cleanPath($path); - switch($mode) { + $path = $this->cleanPath($path); + switch ($mode) { case 'r': case 'rb': - if ( ! $this->file_exists($path)) { + if (!$this->file_exists($path)) { return false; } //straight up curl instead of sabredav here, sabredav put's the entire get result in memory $curl = curl_init(); $fp = fopen('php://temp', 'r+'); - curl_setopt($curl, CURLOPT_USERPWD, $this->user.':'.$this->password); - curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().$this->encodePath($path)); + curl_setopt($curl, CURLOPT_USERPWD, $this->user . ':' . $this->password); + curl_setopt($curl, CURLOPT_URL, $this->createBaseUri() . $this->encodePath($path)); curl_setopt($curl, CURLOPT_FILE, $fp); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); if ($this->secure === true) { curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); - if($this->certPath){ + if ($this->certPath) { curl_setopt($curl, CURLOPT_CAINFO, $this->certPath); } } - - curl_exec ($curl); + + curl_exec($curl); $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); if ($statusCode !== 200) { \OCP\Util::writeLog("webdav client", 'curl GET ' . curl_getinfo($curl, CURLINFO_EFFECTIVE_URL) . ' returned status code ' . $statusCode, \OCP\Util::ERROR); } - curl_close ($curl); + curl_close($curl); rewind($fp); return $fp; case 'w': @@ -203,18 +203,19 @@ class DAV extends \OC\Files\Storage\Common{ case 'c': case 'c+': //emulate these - if (strrpos($path, '.')!==false) { - $ext=substr($path, strrpos($path, '.')); + if (strrpos($path, '.') !== false) { + $ext = substr($path, strrpos($path, '.')); } else { - $ext=''; + $ext = ''; } - $tmpFile = \OCP\Files::tmpFile($ext); - \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); - if($this->file_exists($path)) { - $this->getFile($path, $tmpFile); + if ($this->file_exists($path)) { + $tmpFile = $this->getCachedFile($path); + } else { + $tmpFile = \OCP\Files::tmpFile($ext); } - self::$tempFiles[$tmpFile]=$path; - return fopen('close://'.$tmpFile, $mode); + \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack')); + self::$tempFiles[$tmpFile] = $path; + return fopen('close://' . $tmpFile, $mode); } } @@ -227,32 +228,31 @@ class DAV extends \OC\Files\Storage\Common{ public function free_space($path) { $this->init(); - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); try { - $response=$this->client->propfind($this->encodePath($path), array('{DAV:}quota-available-bytes')); + $response = $this->client->propfind($this->encodePath($path), array('{DAV:}quota-available-bytes')); if (isset($response['{DAV:}quota-available-bytes'])) { return (int)$response['{DAV:}quota-available-bytes']; } else { return \OC\Files\SPACE_UNKNOWN; } - } catch(\Exception $e) { + } catch (\Exception $e) { return \OC\Files\SPACE_UNKNOWN; } } - public function touch($path, $mtime=null) { + public function touch($path, $mtime = null) { $this->init(); if (is_null($mtime)) { - $mtime=time(); + $mtime = time(); } - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); // if file exists, update the mtime, else create a new empty file if ($this->file_exists($path)) { try { $this->client->proppatch($this->encodePath($path), array('{DAV:}lastmodified' => $mtime)); - } - catch (\Sabre_DAV_Exception_NotImplemented $e) { + } catch (\Sabre_DAV_Exception_NotImplemented $e) { return false; } } else { @@ -261,23 +261,13 @@ class DAV extends \OC\Files\Storage\Common{ return true; } - /** - * @param string $path - * @param string $target - */ - public function getFile($path, $target) { - $this->init(); - $source=$this->fopen($path, 'r'); - file_put_contents($target, $source); - } - - public function uploadFile($path, $target) { + protected function uploadFile($path, $target) { $this->init(); - $source=fopen($path, 'r'); + $source = fopen($path, 'r'); $curl = curl_init(); - curl_setopt($curl, CURLOPT_USERPWD, $this->user.':'.$this->password); - curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().str_replace(' ', '%20', $target)); + curl_setopt($curl, CURLOPT_USERPWD, $this->user . ':' . $this->password); + curl_setopt($curl, CURLOPT_URL, $this->createBaseUri() . str_replace(' ', '%20', $target)); curl_setopt($curl, CURLOPT_BINARYTRANSFER, true); curl_setopt($curl, CURLOPT_INFILE, $source); // file pointer curl_setopt($curl, CURLOPT_INFILESIZE, filesize($path)); @@ -285,26 +275,29 @@ class DAV extends \OC\Files\Storage\Common{ if ($this->secure === true) { curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); - if($this->certPath){ + if ($this->certPath) { curl_setopt($curl, CURLOPT_CAINFO, $this->certPath); } } - curl_exec ($curl); + curl_exec($curl); $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); if ($statusCode !== 200) { \OCP\Util::writeLog("webdav client", 'curl GET ' . curl_getinfo($curl, CURLINFO_EFFECTIVE_URL) . ' returned status code ' . $statusCode, \OCP\Util::ERROR); } - curl_close ($curl); + curl_close($curl); + $this->removeCachedFile($target); } public function rename($path1, $path2) { $this->init(); $path1 = $this->encodePath($this->cleanPath($path1)); - $path2 = $this->createBaseUri().$this->encodePath($this->cleanPath($path2)); + $path2 = $this->createBaseUri() . $this->encodePath($this->cleanPath($path2)); try { - $this->client->request('MOVE', $path1, null, array('Destination'=>$path2)); + $this->client->request('MOVE', $path1, null, array('Destination' => $path2)); + $this->removeCachedFile($path1); + $this->removeCachedFile($path2); return true; - } catch(\Exception $e) { + } catch (\Exception $e) { return false; } } @@ -312,47 +305,48 @@ class DAV extends \OC\Files\Storage\Common{ public function copy($path1, $path2) { $this->init(); $path1 = $this->encodePath($this->cleanPath($path1)); - $path2 = $this->createBaseUri().$this->encodePath($this->cleanPath($path2)); + $path2 = $this->createBaseUri() . $this->encodePath($this->cleanPath($path2)); try { - $this->client->request('COPY', $path1, null, array('Destination'=>$path2)); + $this->client->request('COPY', $path1, null, array('Destination' => $path2)); + $this->removeCachedFile($path2); return true; - } catch(\Exception $e) { + } catch (\Exception $e) { return false; } } public function stat($path) { $this->init(); - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); try { $response = $this->client->propfind($this->encodePath($path), array('{DAV:}getlastmodified', '{DAV:}getcontentlength')); return array( - 'mtime'=>strtotime($response['{DAV:}getlastmodified']), - 'size'=>(int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0, + 'mtime' => strtotime($response['{DAV:}getlastmodified']), + 'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0, ); - } catch(\Exception $e) { + } catch (\Exception $e) { return array(); } } public function getMimeType($path) { $this->init(); - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); try { - $response=$this->client->propfind($this->encodePath($path), array('{DAV:}getcontenttype', '{DAV:}resourcetype')); + $response = $this->client->propfind($this->encodePath($path), array('{DAV:}getcontenttype', '{DAV:}resourcetype')); $responseType = array(); if (isset($response["{DAV:}resourcetype"])) { - $responseType=$response["{DAV:}resourcetype"]->resourceType; + $responseType = $response["{DAV:}resourcetype"]->resourceType; } - $type=(count($responseType)>0 and $responseType[0]=="{DAV:}collection")?'dir':'file'; - if ($type=='dir') { + $type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file'; + if ($type == 'dir') { return 'httpd/unix-directory'; } elseif (isset($response['{DAV:}getcontenttype'])) { return $response['{DAV:}getcontenttype']; } else { return false; } - } catch(\Exception $e) { + } catch (\Exception $e) { return false; } } @@ -368,6 +362,7 @@ class DAV extends \OC\Files\Storage\Common{ /** * URL encodes the given path but keeps the slashes + * * @param string $path to encode * @return string encoded path */ @@ -382,11 +377,11 @@ class DAV extends \OC\Files\Storage\Common{ * @param integer $expected */ private function simpleResponse($method, $path, $body, $expected) { - $path=$this->cleanPath($path); + $path = $this->cleanPath($path); try { - $response=$this->client->request($method, $this->encodePath($path), $body); - return $response['statusCode']==$expected; - } catch(\Exception $e) { + $response = $this->client->request($method, $this->encodePath($path), $body); + return $response['statusCode'] == $expected; + } catch (\Exception $e) { return false; } } |