Merge pull request #8399 from owncloud/server-server-sharing

Add server<->server sharing
This commit is contained in:
icewind1991 2014-06-17 17:40:05 +02:00
commit 8d1cf79152
45 changed files with 1222 additions and 106 deletions

View File

@ -49,8 +49,9 @@ $server->subscribeEvent('beforeMethod', function () use ($server, $objectTree) {
$rootInfo = $view->getFileInfo('');
// Create ownCloud Dir
$mountManager = \OC\Files\Filesystem::getMountManager();
$rootDir = new OC_Connector_Sabre_Directory($view, $rootInfo);
$objectTree->init($rootDir, $view);
$objectTree->init($rootDir, $view, $mountManager);
$server->addPlugin(new OC_Connector_Sabre_AbortedUploadDetectionPlugin($view));
$server->addPlugin(new OC_Connector_Sabre_QuotaPlugin($view));

View File

@ -41,6 +41,39 @@ class Proxy extends \OC_FileProxy {
private static $fopenMode = array(); // remember the fopen mode
private static $enableEncryption = false; // Enable encryption for the given path
/**
* check if path is excluded from encryption
*
* @param string $path relative to data/
* @param string $uid user
* @return boolean
*/
private function isExcludedPath($path, $uid) {
$view = new \OC\Files\View();
// files outside of the files-folder are excluded
if(strpos($path, '/' . $uid . '/files') !== 0) {
return true;
}
if (!$view->file_exists($path)) {
$path = dirname($path);
}
// we don't encrypt server-to-server shares
list($storage, ) = \OC\Files\Filesystem::resolvePath($path);
/**
* @var \OCP\Files\Storage $storage
*/
if ($storage->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
return true;
}
return false;
}
/**
* Check if a file requires encryption
* @param string $path
@ -50,7 +83,7 @@ class Proxy extends \OC_FileProxy {
* Tests if server side encryption is enabled, and if we should call the
* crypt stream wrapper for the given file
*/
private static function shouldEncrypt($path, $mode = 'w') {
private function shouldEncrypt($path, $mode = 'w') {
$userId = Helper::getUser($path);
$session = new Session(new \OC\Files\View());
@ -59,7 +92,7 @@ class Proxy extends \OC_FileProxy {
if (
$session->getInitialized() !== Session::INIT_SUCCESSFUL // encryption successful initialized
|| Crypt::mode() !== 'server' // we are not in server-side-encryption mode
|| strpos($path, '/' . $userId . '/files') !== 0 // path is not in files/
|| $this->isExcludedPath($path, $userId) // if path is excluded from encryption
|| substr($path, 0, 8) === 'crypt://' // we are already in crypt mode
) {
return false;
@ -85,7 +118,7 @@ class Proxy extends \OC_FileProxy {
*/
public function preFile_put_contents($path, &$data) {
if (self::shouldEncrypt($path)) {
if ($this->shouldEncrypt($path)) {
if (!is_resource($data)) {
@ -219,7 +252,7 @@ class Proxy extends \OC_FileProxy {
public function preFopen($path, $mode) {
self::$fopenMode[$path] = $mode;
self::$enableEncryption = self::shouldEncrypt($path, $mode);
self::$enableEncryption = $this->shouldEncrypt($path, $mode);
}

View File

@ -100,6 +100,8 @@ class Session {
$privateKey = Crypt::decryptPrivateKey($encryptedKey, '');
$this->setPublicSharePrivateKey($privateKey);
$this->setInitialized(\OCA\Encryption\Session::INIT_SUCCESSFUL);
\OC_FileProxy::$enabled = $proxyStatus;
}
}

View File

@ -235,7 +235,8 @@ class Test_Encryption_Webdav extends \PHPUnit_Framework_TestCase {
$view = new \OC\Files\View($root);
$publicDir = new OC_Connector_Sabre_Directory($view, $view->getFileInfo(''));
$objectTree = new \OC\Connector\Sabre\ObjectTree();
$objectTree->init($publicDir, $view);
$mountManager = \OC\Files\Filesystem::getMountManager();
$objectTree->init($publicDir, $view, $mountManager);
// Fire up server
$server = new \Sabre\DAV\Server($publicDir);

View File

@ -9,13 +9,13 @@
namespace OC\Files\Storage;
class DAV extends \OC\Files\Storage\Common {
private $password;
private $user;
private $host;
private $secure;
private $root;
private $certPath;
private $ready;
protected $password;
protected $user;
protected $host;
protected $secure;
protected $root;
protected $certPath;
protected $ready;
/**
* @var \Sabre\DAV\Client
*/
@ -355,6 +355,9 @@ class DAV extends \OC\Files\Storage\Common {
* @param string $path
*/
public function cleanPath($path) {
if ($path === "") {
return $path;
}
$path = \OC\Files\Filesystem::normalizePath($path);
// remove leading slash
return substr($path, 1);
@ -397,11 +400,27 @@ class DAV extends \OC\Files\Storage\Common {
}
}
public function isUpdatable($path) {
return (bool)($this->getPermissions($path) & \OCP\PERMISSION_UPDATE);
}
public function isCreatable($path) {
return (bool)($this->getPermissions($path) & \OCP\PERMISSION_CREATE);
}
public function isSharable($path) {
return (bool)($this->getPermissions($path) & \OCP\PERMISSION_SHARE);
}
public function isDeletable($path) {
return (bool)($this->getPermissions($path) & \OCP\PERMISSION_DELETE);
}
public function getPermissions($path) {
$this->init();
$response = $this->client->propfind($this->encodePath($path), array('{http://owncloud.org/ns}permissions'));
if (isset($response['{http://owncloud.org/ns}permissions'])) {
$permissions = 0;
$permissions = \OCP\PERMISSION_READ;
$permissionsString = $response['{http://owncloud.org/ns}permissions'];
if (strpos($permissionsString, 'R') !== false) {
$permissions |= \OCP\PERMISSION_SHARE;
@ -416,8 +435,12 @@ class DAV extends \OC\Files\Storage\Common {
$permissions |= \OCP\PERMISSION_CREATE;
}
return $permissions;
} else if ($this->is_dir($path)) {
return \OCP\PERMISSION_ALL;
} else if ($this->file_exists($path)) {
return \OCP\PERMISSION_ALL - \OCP\PERMISSION_CREATE;
} else {
return parent::getPermissions($path);
return 0;
}
}
}

View File

@ -0,0 +1,51 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
OCP\JSON::callCheck();
OCP\JSON::checkLoggedIn();
OCP\JSON::checkAppEnabled('files_sharing');
$l = OC_L10N::get('files_sharing');
// check if server admin allows to mount public links from other servers
// check if files_external is enabled
// FIXME file_external check no longer needed if we use the webdav implementation from core
if (OCA\Files_Sharing\Helper::isIncomingServer2serverShareEnabled() === false ||
\OC_App::isEnabled('files_external') === false) {
\OCP\JSON::error(array('data' => array('message' => $l->t('Server to server sharing is not enabled on this server'))));
exit();
}
$token = $_POST['token'];
$remote = $_POST['remote'];
$owner = $_POST['owner'];
$name = $_POST['name'];
$password = $_POST['password'];
$externalManager = new \OCA\Files_Sharing\External\Manager(
\OC::$server->getDatabaseConnection(),
\OC\Files\Filesystem::getMountManager(),
\OC\Files\Filesystem::getLoader(),
\OC::$server->getUserSession()
);
$name = OCP\Files::buildNotExistingFileName('/', $name);
$mount = $externalManager->addShare($remote, $token, $password, $name, $owner);
/**
* @var \OCA\Files_Sharing\External\Storage $storage
*/
$storage = $mount->getStorage();
$result = $storage->file_exists('');
if($result){
$storage->getScanner()->scanAll();
\OCP\JSON::success();
} else {
$externalManager->removeShare($mount->getMountPoint());
\OCP\JSON::error(array('data' => array('message' => $l->t("Couldn't add remote share"))));
}

View File

@ -0,0 +1,69 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
OCP\JSON::checkAppEnabled('files_sharing');
if (!isset($_GET['t'])) {
\OC_Response::setStatus(400); //400 Bad Request
exit;
}
$token = $_GET['t'];
$password = null;
if (isset($_POST['password'])) {
$password = $_POST['password'];
}
$relativePath = null;
if (isset($_GET['dir'])) {
$relativePath = $_GET['dir'];
}
$data = \OCA\Files_Sharing\Helper::setupFromToken($token, $relativePath, $password);
$linkItem = $data['linkItem'];
// Load the files
$path = $data['realPath'];
$isWritable = $linkItem['permissions'] & (\OCP\PERMISSION_UPDATE | \OCP\PERMISSION_CREATE);
if (!$isWritable) {
\OC\Files\Filesystem::addStorageWrapper('readonly', function ($mountPoint, $storage) {
return new \OCA\Files_Sharing\ReadOnlyWrapper(array('storage' => $storage));
});
}
$rootInfo = \OC\Files\Filesystem::getFileInfo($path);
$rootView = new \OC\Files\View('');
/**
* @param \OCP\Files\FileInfo $dir
* @param \OC\Files\View $view
* @return array
*/
function getChildInfo($dir, $view) {
$children = $view->getDirectoryContent($dir->getPath());
$result = array();
foreach ($children as $child) {
$formated = \OCA\Files\Helper::formatFileInfo($child);
if ($child->getType() === 'dir') {
$formated['children'] = getChildInfo($child, $view);
}
$formated['mtime'] = $formated['mtime'] / 1000;
$result[] = $formated;
}
return $result;
}
$result = \OCA\Files\Helper::formatFileInfo($rootInfo);
$result['mtime'] = $result['mtime'] / 1000;
if ($rootInfo->getType() === 'dir') {
$result['children'] = getChildInfo($rootInfo, $rootView);
}
OCP\JSON::success(array('data' => $result));

View File

@ -0,0 +1,29 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
OCP\JSON::checkAppEnabled('files_sharing');
$remote = $_GET['remote'];
function testUrl($url) {
try {
$result = file_get_contents($url);
$data = json_decode($result);
return is_object($data) and !empty($data->version);
} catch (Exception $e) {
return false;
}
}
if (testUrl('https://' . $remote . '/status.php')) {
echo 'https';
} elseif (testUrl('http://' . $remote . '/status.php')) {
echo 'http';
} else {
echo 'false';
}

View File

@ -11,10 +11,24 @@ OC::$CLASSPATH['OC\Files\Cache\Shared_Watcher'] = 'files_sharing/lib/watcher.php
OC::$CLASSPATH['OCA\Files\Share\Api'] = 'files_sharing/lib/api.php';
OC::$CLASSPATH['OCA\Files\Share\Maintainer'] = 'files_sharing/lib/maintainer.php';
OC::$CLASSPATH['OCA\Files\Share\Proxy'] = 'files_sharing/lib/proxy.php';
\OCP\App::registerAdmin('files_sharing', 'settings-admin');
$externalManager = new \OCA\Files_Sharing\External\Manager(
\OC::$server->getDatabaseConnection(),
\OC\Files\Filesystem::getMountManager(),
\OC\Files\Filesystem::getLoader(),
\OC::$server->getUserSession()
);
$externalManager->setup();
OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup');
OCP\Share::registerBackend('file', 'OC_Share_Backend_File');
OCP\Share::registerBackend('folder', 'OC_Share_Backend_Folder', 'file');
OCP\Util::addScript('files_sharing', 'share');
OCP\Util::addScript('files_sharing', 'external');
\OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Shared_Updater', 'writeHook');
\OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Shared_Updater', 'postDeleteHook');
\OC_Hook::connect('OC_Filesystem', 'delete', '\OC\Files\Cache\Shared_Updater', 'deleteHook');

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<database>
<name>*dbname*</name>
<create>true</create>
<overwrite>false</overwrite>
<charset>utf8</charset>
<table>
<name>*dbprefix*share_external</name>
<declaration>
<field>
<name>id</name>
<type>integer</type>
<default>0</default>
<notnull>true</notnull>
<autoincrement>1</autoincrement>
<length>4</length>
</field>
<field>
<name>remote</name>
<type>text</type>
<notnull>true</notnull>
<length>512</length>
<comments>Url of the remove owncloud instance</comments>
</field>
<field>
<name>share_token</name>
<type>text</type>
<notnull>true</notnull>
<length>64</length>
<comments>Public share token</comments>
</field>
<field>
<name>password</name>
<type>text</type>
<notnull>true</notnull>
<length>64</length>
<comments>Optional password for the public share</comments>
</field>
<field>
<name>name</name>
<type>text</type>
<notnull>true</notnull>
<length>64</length>
<comments>Original name on the remote server</comments>
</field>
<field>
<name>owner</name>
<type>text</type>
<notnull>true</notnull>
<length>64</length>
<comments>User that owns the public share on the remote server</comments>
</field>
<field>
<name>user</name>
<type>text</type>
<notnull>true</notnull>
<length>64</length>
<comments>Local user which added the external share</comments>
</field>
<field>
<name>mountpoint</name>
<type>text</type>
<notnull>true</notnull>
<length>4000</length>
<comments>Full path where the share is mounted</comments>
</field>
<field>
<name>mountpoint_hash</name>
<type>text</type>
<notnull>true</notnull>
<length>32</length>
<comments>md5 hash of the mountpoint</comments>
</field>
<index>
<name>sh_external_user</name>
<field>
<name>user</name>
<sorting>ascending</sorting>
</field>
</index>
<index>
<name>sh_external_mp</name>
<unique>true</unique>
<field>
<name>user</name>
<sorting>ascending</sorting>
</field>
<field>
<name>mountpoint_hash</name>
<sorting>ascending</sorting>
</field>
</index>
</declaration>
</table>
</database>

View File

@ -5,6 +5,10 @@ $this->create('core_ajax_public_preview', '/publicpreview')->action(
require_once __DIR__ . '/../ajax/publicpreview.php';
});
$this->create('sharing_external_shareinfo', '/shareinfo')->actionInclude('files_sharing/ajax/shareinfo.php');
$this->create('sharing_external_add', '/external')->actionInclude('files_sharing/ajax/external.php');
$this->create('sharing_external_test_remote', '/testremote')->actionInclude('files_sharing/ajax/testremote.php');
// OCS API
//TODO: SET: mail notification, waiting for PR #4689 to be accepted

View File

@ -1 +1 @@
0.5
0.5.2

View File

@ -87,3 +87,38 @@ thead {
width: 300px;
max-width: 90%;
}
.header-right {
transition: opacity 500ms ease 0s;
-moz-transition: opacity 500ms ease 0s;
-ms-transition: opacity 500ms ease 0s;
-o-transition: opacity 500ms ease 0s;
-webkit-transition: opacity 500ms ease 0s;
}
.header-right:hover, .header-right.active {
opacity: 1;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
filter: alpha(opacity=100);
}
/* within #save */
#remote_address {
margin: 0;
height: 14px;
line-height: 16px;
padding: 6px;
}
#save button {
margin: 0 5px;
height: 28px;
padding-bottom: 4px;
line-height: 14px;
}
#save .save-form [type="submit"] {
margin: 0 5px;
height: 28px;
padding-bottom: 4px;
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
*
* This file is licensed under the Affero General Public License version 3
* or later.
*
* See the COPYING-README file.
*
*/
(function () {
var getParameterByName = function (query, name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\#&]" + name + "=([^&#]*)"),
results = regex.exec(query);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
};
var addExternalShare = function (remote, token, owner, name, password) {
return $.post(OC.generateUrl('apps/files_sharing/external'), {
remote: remote,
token: token,
owner: owner,
name: name,
password: password
});
};
var showAddExternalDialog = function (remote, token, owner, name, passwordProtected) {
var remoteClean = (remote.substr(0, 8) === 'https://') ? remote.substr(8) : remote.substr(7);
var callback = function (add, password) {
password = password || '';
if (add) {
addExternalShare(remote, token, owner, name, password).then(function (result) {
if (result.status === 'error') {
OC.Notification.show(result.data.message);
} else {
FileList.reload();
}
});
}
};
if (!passwordProtected) {
OC.dialogs.confirm(t('files_sharing', 'Add {name} from {owner}@{remote}', {name: name, owner: owner, remote: remoteClean})
, 'Add Share', callback, true);
} else {
OC.dialogs.prompt(t('files_sharing', 'Add {name} from {owner}@{remote}', {name: name, owner: owner, remote: remoteClean})
, 'Add Share', callback, true, 'Password', true);
}
};
OCA.Sharing.showAddExternalDialog = function (hash) {
var remote = getParameterByName(hash, 'remote');
var owner = getParameterByName(hash, 'owner');
var name = getParameterByName(hash, 'name');
var token = getParameterByName(hash, 'token');
var passwordProtected = parseInt(getParameterByName(hash, 'protected'), 10);
if (remote && token && owner && name) {
showAddExternalDialog(remote, token, owner, name, passwordProtected);
}
};
})();
$(document).ready(function () {
// FIXME: HACK: do not init when running unit tests, need a better way
if (!window.TESTING && OCA.Files) {// only run in the files app
var hash = location.hash;
location.hash = '';
OCA.Sharing.showAddExternalDialog(hash);
}
});

View File

@ -19,7 +19,7 @@ if (!OCA.Files) {
OCA.Sharing.PublicApp = {
_initialized: false,
initialize: function($el) {
initialize: function ($el) {
var self = this;
var fileActions;
if (this._initialized) {
@ -65,7 +65,7 @@ OCA.Sharing.PublicApp = {
}
// dynamically load image previews
if (mimetype.substr(0, mimetype.indexOf('/')) === 'image' ) {
if (mimetype.substr(0, mimetype.indexOf('/')) === 'image') {
var params = {
x: $(document).width() * window.devicePixelRatio,
@ -82,7 +82,7 @@ OCA.Sharing.PublicApp = {
if (this.fileList) {
// TODO: move this to a separate PublicFileList class that extends OCA.Files.FileList (+ unit tests)
this.fileList.getDownloadUrl = function(filename, dir) {
this.fileList.getDownloadUrl = function (filename, dir) {
if ($.isArray(filename)) {
filename = JSON.stringify(filename);
}
@ -97,13 +97,13 @@ OCA.Sharing.PublicApp = {
return OC.filePath('', '', 'public.php') + '?' + OC.buildQueryString(params);
};
this.fileList.getAjaxUrl = function(action, params) {
this.fileList.getAjaxUrl = function (action, params) {
params = params || {};
params.t = $('#sharingToken').val();
return OC.filePath('files_sharing', 'ajax', action + '.php') + '?' + OC.buildQueryString(params);
};
this.fileList.linkTo = function(dir) {
this.fileList.linkTo = function (dir) {
var params = {
service: 'files',
t: $('#sharingToken').val(),
@ -112,15 +112,15 @@ OCA.Sharing.PublicApp = {
return OC.filePath('', '', 'public.php') + '?' + OC.buildQueryString(params);
};
this.fileList.generatePreviewUrl = function(urlSpec) {
this.fileList.generatePreviewUrl = function (urlSpec) {
urlSpec.t = $('#dirToken').val();
return OC.generateUrl('/apps/files_sharing/ajax/publicpreview.php?') + $.param(urlSpec);
};
var file_upload_start = $('#file_upload_start');
file_upload_start.on('fileuploadadd', function(e, data) {
file_upload_start.on('fileuploadadd', function (e, data) {
var fileDirectory = '';
if(typeof data.files[0].relativePath !== 'undefined') {
if (typeof data.files[0].relativePath !== 'undefined') {
fileDirectory = data.files[0].relativePath;
}
@ -143,16 +143,34 @@ OCA.Sharing.PublicApp = {
OC.Util.History.addOnPopStateHandler(_.bind(this._onUrlChanged, this));
}
$(document).on('click', '#directLink', function() {
$(document).on('click', '#directLink', function () {
$(this).focus();
$(this).select();
});
$('.save-form').submit(function (event) {
event.preventDefault();
var remote = $(this).find('input[type="text"]').val();
var token = $('#sharingToken').val();
var owner = $('#save').data('owner');
var name = $('#save').data('name');
var isProtected = $('#save').data('protected') ? 1 : 0;
OCA.Sharing.PublicApp._saveToOwnCloud(remote, token, owner, name, isProtected);
});
$('#save > button').click(function () {
$(this).hide();
$('.header-right').addClass('active');
$('.save-form').css('display', 'inline');
$('#remote_address').focus();
});
// legacy
window.FileList = this.fileList;
},
_onDirectoryChanged: function(e) {
_onDirectoryChanged: function (e) {
OC.Util.History.pushState({
service: 'files',
t: $('#sharingToken').val(),
@ -161,21 +179,44 @@ OCA.Sharing.PublicApp = {
});
},
_onUrlChanged: function(params) {
_onUrlChanged: function (params) {
this.fileList.changeDirectory(params.path || params.dir, false, true);
},
_saveToOwnCloud: function(remote, token, owner, name, isProtected) {
var location = window.location.protocol + '//' + window.location.host + OC.webroot;
var url = remote + '/index.php/apps/files#' + 'remote=' + encodeURIComponent(location) // our location is the remote for the other server
+ "&token=" + encodeURIComponent(token) + "&owner=" + encodeURIComponent(owner) + "&name=" + encodeURIComponent(name) + "&protected=" + isProtected;
if (remote.indexOf('://') > 0) {
OC.redirect(url);
} else {
// if no protocol is specified, we automatically detect it by testing https and http
// this check needs to happen on the server due to the Content Security Policy directive
$.get(OC.generateUrl('apps/files_sharing/testremote'), {remote: remote}).then(function (protocol) {
if (protocol !== 'http' && protocol !== 'https') {
OC.dialogs.alert(t('files_sharing', 'No ownCloud installation found at {remote}', {remote: remote}),
t('files_sharing', 'Invalid ownCloud url'));
} else {
OC.redirect(protocol + '://' + url);
}
});
}
}
};
$(document).ready(function() {
$(document).ready(function () {
var App = OCA.Sharing.PublicApp;
// defer app init, to give a chance to plugins to register file actions
_.defer(function() {
_.defer(function () {
App.initialize($('#preview'));
});
if (window.Files) {
// HACK: for oc-dialogs previews that depends on Files:
Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) {
Files.lazyLoadPreview = function (path, mime, ready, width, height, etag) {
return App.fileList.lazyLoadPreview({
path: path,
mime: mime,

View File

@ -0,0 +1,11 @@
$(document).ready(function() {
$('#fileSharingSettings input').change(function() {
var value = 'no';
if (this.checked) {
value = 'yes';
}
OC.AppConfig.setValue('files_sharing', $(this).attr('name'), value);
});
});

View File

@ -38,6 +38,7 @@ class PublicAuth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
*/
protected function validateUserPass($username, $password) {
$linkItem = \OCP\Share::getShareByToken($username, false);
\OC_User::setIncognitoMode(true);
$this->share = $linkItem;
if (!$linkItem) {
return false;

View File

@ -0,0 +1,47 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\Files_Sharing\External;
class Cache extends \OC\Files\Cache\Cache {
private $remote;
private $remoteUser;
private $storage;
/**
* @param \OCA\Files_Sharing\External\Storage $storage
* @param string $remote
* @param string $remoteUser
*/
public function __construct($storage, $remote, $remoteUser) {
$this->storage = $storage;
list(, $remote) = explode('://', $remote, 2);
$this->remote = $remote;
$this->remoteUser = $remoteUser;
parent::__construct($storage);
}
public function get($file) {
$result = parent::get($file);
$result['displayname_owner'] = $this->remoteUser . '@' . $this->remote;
if (!$file || $file === '') {
$result['is_share_mount_point'] = true;
$mountPoint = rtrim($this->storage->getMountPoint());
$result['name'] = basename($mountPoint);
}
return $result;
}
public function getFolderContentsById($id) {
$results = parent::getFolderContentsById($id);
foreach ($results as &$file) {
$file['displayname_owner'] = $this->remoteUser . '@' . $this->remote;
}
return $results;
}
}

View File

@ -0,0 +1,140 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\Files_Sharing\External;
use OC\Files\Filesystem;
class Manager {
const STORAGE = '\OCA\Files_Sharing\External\Storage';
/**
* @var \OCP\IDBConnection
*/
private $connection;
/**
* @var \OC\Files\Mount\Manager
*/
private $mountManager;
/**
* @var \OC\Files\Storage\Loader
*/
private $storageLoader;
/**
* @var \OC\User\Session
*/
private $userSession;
/**
* @param \OCP\IDBConnection $connection
* @param \OC\Files\Mount\Manager $mountManager
* @param \OC\User\Session $userSession
* @param \OC\Files\Storage\Loader $storageLoader
*/
public function __construct(\OCP\IDBConnection $connection, \OC\Files\Mount\Manager $mountManager,
\OC\Files\Storage\Loader $storageLoader, \OC\User\Session $userSession) {
$this->connection = $connection;
$this->mountManager = $mountManager;
$this->userSession = $userSession;
$this->storageLoader = $storageLoader;
}
public function addShare($remote, $token, $password, $name, $owner) {
$user = $this->userSession->getUser();
if ($user) {
$query = $this->connection->prepare('INSERT INTO *PREFIX*share_external(`remote`, `share_token`, `password`,
`name`, `owner`, `user`, `mountpoint`, `mountpoint_hash`) VALUES(?, ?, ?, ?, ?, ?, ?, ?)');
$mountPoint = Filesystem::normalizePath('/' . $name);
$hash = md5($mountPoint);
$query->execute(array($remote, $token, $password, $name, $owner, $user->getUID(), $mountPoint, $hash));
$options = array(
'remote' => $remote,
'token' => $token,
'password' => $password,
'mountpoint' => $mountPoint,
'owner' => $owner
);
return $this->mountShare($options);
}
}
public function setup() {
// don't setup server-to-server shares if the file_external app is disabled
// FIXME no longer needed if we use the webdav implementation from core
if (\OC_App::isEnabled('files_external') === false) {
return false;
}
$user = $this->userSession->getUser();
if ($user) {
$query = $this->connection->prepare('SELECT `remote`, `share_token`, `password`, `mountpoint`, `owner`
FROM *PREFIX*share_external WHERE `user` = ?');
$query->execute(array($user->getUID()));
while ($row = $query->fetch()) {
$row['manager'] = $this;
$row['token'] = $row['share_token'];
$this->mountShare($row);
}
}
}
protected function stripPath($path) {
$prefix = '/' . $this->userSession->getUser()->getUID() . '/files';
return rtrim(substr($path, strlen($prefix)), '/');
}
/**
* @param array $data
* @return Mount
*/
protected function mountShare($data) {
$mountPoint = '/' . $this->userSession->getUser()->getUID() . '/files' . $data['mountpoint'];
$mount = new Mount(self::STORAGE, $mountPoint, $data, $this, $this->storageLoader);
$this->mountManager->addMount($mount);
return $mount;
}
/**
* @return \OC\Files\Mount\Manager
*/
public function getMountManager() {
return $this->mountManager;
}
/**
* @param string $source
* @param string $target
* @return bool
*/
public function setMountPoint($source, $target) {
$user = $this->userSession->getUser();
$source = $this->stripPath($source);
$target = $this->stripPath($target);
$sourceHash = md5($source);
$targetHash = md5($target);
$query = $this->connection->prepare('UPDATE *PREFIX*share_external SET
`mountpoint` = ?, `mountpoint_hash` = ? WHERE `mountpoint_hash` = ? AND `user` = ?');
$result = (bool)$query->execute(array($target, $targetHash, $sourceHash, $user->getUID()));
return $result;
}
public function removeShare($mountPoint) {
$user = $this->userSession->getUser();
$mountPoint = $this->stripPath($mountPoint);
$hash = md5($mountPoint);
$query = $this->connection->prepare('DELETE FROM *PREFIX*share_external WHERE `mountpoint_hash` = ? AND `user` = ?');
return (bool)$query->execute(array($hash, $user->getUID()));
}
}

View File

@ -0,0 +1,53 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\Files_Sharing\External;
use OC\Files\Mount\MoveableMount;
class Mount extends \OC\Files\Mount\Mount implements MoveableMount {
/**
* @var \OCA\Files_Sharing\External\Manager
*/
protected $manager;
/**
* @param string|\OC\Files\Storage\Storage $storage
* @param string $mountpoint
* @param array $options
* @param \OCA\Files_Sharing\External\Manager $manager
* @param \OC\Files\Storage\Loader $loader
*/
public function __construct($storage, $mountpoint, $options, $manager, $loader = null) {
parent::__construct($storage, $mountpoint, $options, $loader);
$this->manager = $manager;
}
/**
* Move the mount point to $target
*
* @param string $target the target mount point
* @return bool
*/
public function moveMount($target) {
$result = $this->manager->setMountPoint($this->mountPoint, $target);
$this->setMountPoint($target);
return $result;
}
/**
* Remove the mount points
*
* @return mixed
* @return bool
*/
public function removeMount() {
return $this->manager->removeShare($this->mountPoint);
}
}

View File

@ -0,0 +1,54 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\Files_Sharing\External;
class Scanner extends \OC\Files\Cache\Scanner {
/**
* @var \OCA\Files_Sharing\External\Storage
*/
protected $storage;
public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1) {
$this->scanAll();
}
public function scanAll() {
$remote = $this->storage->getRemote();
$token = $this->storage->getToken();
$password = $this->storage->getPassword();
$url = $remote . '/index.php/apps/files_sharing/shareinfo?t=' . $token;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
http_build_query(array('password' => $password)));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
$data = json_decode($result, true);
if ($data['status'] === 'success') {
$this->addResult($data['data'], '');
} else {
throw new \Exception('Error while scanning remote share');
}
}
private function addResult($data, $path) {
$this->cache->put($path, $data);
if (isset($data['children'])) {
foreach ($data['children'] as $child) {
$this->addResult($child, ltrim($path . '/' . $child['name'], '/'));
}
}
}
}

View File

@ -0,0 +1,103 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\Files_Sharing\External;
use OC\Files\Filesystem;
use OC\Files\Storage\DAV;
use OCA\Files_Sharing\ISharedStorage;
class Storage extends DAV implements ISharedStorage {
/**
* @var string
*/
private $remoteUser;
/**
* @var string
*/
private $remote;
/**
* @var string
*/
private $mountPoint;
/**
* @var string
*/
private $token;
public function __construct($options) {
$this->remote = $options['remote'];
$this->remoteUser = $options['owner'];
list($protocol, $remote) = explode('://', $this->remote);
list($host, $root) = explode('/', $remote);
$secure = $protocol === 'https';
$root .= '/public.php/webdav';
$this->mountPoint = $options['mountpoint'];
$this->token = $options['token'];
parent::__construct(array(
'secure' => $secure,
'host' => $host,
'root' => $root,
'user' => $options['token'],
'password' => $options['password']
));
}
public function getRemoteUser() {
return $this->remoteUser;
}
public function getRemote() {
return $this->remote;
}
public function getMountPoint() {
return $this->mountPoint;
}
public function getToken() {
return $this->token;
}
public function getPassword() {
return $this->password;
}
/**
* @brief get id of the mount point
* @return string
*/
public function getId() {
return 'shared::' . md5($this->token . '@' . $this->remote);
}
public function getCache($path = '', $storage = null) {
if (!$storage) {
$this->cache = new Cache($this, $this->remote, $this->remoteUser);
}
return $this->cache;
}
/**
* @param string $path
* @param \OC\Files\Storage\Storage $storage
* @return \OCA\Files_Sharing\External\Scanner
*/
public function getScanner($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
if (!isset($this->scanner)) {
$this->scanner = new Scanner($storage);
}
return $this->scanner;
}
}

View File

@ -16,7 +16,7 @@ class Helper {
public static function setupFromToken($token, $relativePath = null, $password = null) {
\OC_User::setIncognitoMode(true);
$linkItem = \OCP\Share::getShareByToken($token);
$linkItem = \OCP\Share::getShareByToken($token, !$password);
if($linkItem === false || ($linkItem['item_type'] !== 'file' && $linkItem['item_type'] !== 'folder')) {
\OC_Response::setStatus(404);
\OC_Log::write('core-preview', 'Passed token parameter is not valid', \OC_Log::DEBUG);
@ -202,4 +202,24 @@ class Helper {
return $path;
}
/**
* allow users from other ownCloud instances to mount public links share by this instance
* @return bool
*/
public static function isOutgoingServer2serverShareEnabled() {
$appConfig = \OC::$server->getAppConfig();
$result = $appConfig->getValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes');
return ($result === 'yes') ? true : false;
}
/**
* allow user to mount public links from onther ownClouds
* @return bool
*/
public static function isIncomingServer2serverShareEnabled() {
$appConfig = \OC::$server->getAppConfig();
$result = $appConfig->getValue('files_sharing', 'incoming_server2server_share_enabled', 'yes');
return ($result === 'yes') ? true : false;
}
}

View File

@ -0,0 +1,13 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\Files_Sharing;
interface ISharedStorage{
}

View File

@ -0,0 +1,27 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\Files_Sharing;
use OC\Files\Cache\Cache;
class ReadOnlyCache extends Cache {
public function get($path) {
$data = parent::get($path);
$data['permissions'] &= (\OCP\PERMISSION_READ | \OCP\PERMISSION_SHARE);
return $data;
}
public function getFolderContents($path) {
$content = parent::getFolderContents($path);
foreach ($content as &$data) {
$data['permissions'] &= (\OCP\PERMISSION_READ | \OCP\PERMISSION_SHARE);
}
return $content;
}
}

View File

@ -0,0 +1,56 @@
<?php
/**
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
namespace OCA\Files_Sharing;
use OC\Files\Storage\Wrapper\Wrapper;
class ReadOnlyWrapper extends Wrapper {
public function isUpdatable($path) {
return false;
}
public function isCreatable($path) {
return false;
}
public function isDeletable($path) {
return false;
}
public function getPermissions($path) {
return $this->storage->getPermissions($path) & (\OCP\PERMISSION_READ | \OCP\PERMISSION_SHARE);
}
public function rename($path1, $path2) {
return false;
}
public function touch($path, $mtime = null) {
return false;
}
public function mkdir($path) {
return false;
}
public function rmdir($path) {
return false;
}
public function unlink($path) {
return false;
}
public function getCache($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
return new ReadOnlyCache($storage);
}
}

View File

@ -23,12 +23,13 @@
namespace OC\Files\Storage;
use OC\Files\Filesystem;
use OCA\Files_Sharing\ISharedStorage;
use OCA\Files_Sharing\SharedMount;
/**
* Convert target path to source path and pass the function call to the correct storage provider
*/
class Shared extends \OC\Files\Storage\Common {
class Shared extends \OC\Files\Storage\Common implements ISharedStorage {
private $share; // the shared resource
private $files = array();
@ -488,16 +489,25 @@ class Shared extends \OC\Files\Storage\Common {
return $this->filemtime($path) > $time;
}
public function getCache($path = '') {
return new \OC\Files\Cache\Shared_Cache($this);
public function getCache($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
return new \OC\Files\Cache\Shared_Cache($storage);
}
public function getScanner($path = '') {
return new \OC\Files\Cache\Scanner($this);
public function getScanner($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
return new \OC\Files\Cache\Scanner($storage);
}
public function getWatcher($path = '') {
return new \OC\Files\Cache\Shared_Watcher($this);
public function getWatcher($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
return new \OC\Files\Cache\Shared_Watcher($storage);
}
public function getOwner($path) {

View File

@ -128,6 +128,7 @@ if (isset($path)) {
$tmpl->assign('mimetype', \OC\Files\Filesystem::getMimeType($path));
$tmpl->assign('dirToken', $linkItem['token']);
$tmpl->assign('sharingToken', $token);
$tmpl->assign('protected', isset($linkItem['share_with']) ? 'true' : 'false');
$urlLinkIdentifiers= (isset($token)?'&t='.$token:'')
.(isset($_GET['dir'])?'&dir='.$_GET['dir']:'')

View File

@ -6,6 +6,10 @@
* See the COPYING-README file.
*/
if (OCA\Files_Sharing\Helper::isOutgoingServer2serverShareEnabled() === false) {
return false;
}
// load needed apps
$RUNTIME_APPTYPES = array('filesystem', 'authentication', 'logging');
@ -37,7 +41,15 @@ $server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav'));
$server->subscribeEvent('beforeMethod', function () use ($server, $objectTree, $authBackend) {
$share = $authBackend->getShare();
$owner = $share['uid_owner'];
$isWritable = $share['permissions'] & (\OCP\PERMISSION_UPDATE | \OCP\PERMISSION_CREATE);
$fileId = $share['file_source'];
if (!$isWritable) {
\OC\Files\Filesystem::addStorageWrapper('readonly', function ($mountPoint, $storage) {
return new \OCA\Files_Sharing\ReadOnlyWrapper(array('storage' => $storage));
});
}
OC_Util::setupFS($owner);
$ownerView = \OC\Files\Filesystem::getView();
$path = $ownerView->getPath($fileId);
@ -47,8 +59,13 @@ $server->subscribeEvent('beforeMethod', function () use ($server, $objectTree, $
$rootInfo = $view->getFileInfo('');
// Create ownCloud Dir
$rootDir = new OC_Connector_Sabre_Directory($view, $rootInfo);
$objectTree->init($rootDir, $view);
if ($rootInfo->getType() === 'dir') {
$root = new OC_Connector_Sabre_Directory($view, $rootInfo);
} else {
$root = new OC_Connector_Sabre_File($view, $rootInfo);
}
$mountManager = \OC\Files\Filesystem::getMountManager();
$objectTree->init($root, $view, $mountManager);
$server->addPlugin(new OC_Connector_Sabre_AbortedUploadDetectionPlugin($view));
$server->addPlugin(new OC_Connector_Sabre_QuotaPlugin($view));

View File

@ -0,0 +1,17 @@
<?php
/**
* Copyright (c) 2011 Robin Appelman <icewind@owncloud.com>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
\OC_Util::checkAdminUser();
\OCP\Util::addScript('files_sharing', 'settings-admin');
$tmpl = new OCP\Template('files_sharing', 'settings-admin');
$tmpl->assign('outgoingServer2serverShareEnabled', OCA\Files_Sharing\Helper::isOutgoingServer2serverShareEnabled());
$tmpl->assign('incomingServer2serverShareEnabled', OCA\Files_Sharing\Helper::isIncomingServer2serverShareEnabled());
return $tmpl->fetchPage();

View File

@ -15,10 +15,19 @@
src="<?php print_unescaped(image_path('', 'logo-wide.svg')); ?>" alt="<?php p($theme->getName()); ?>" /></a>
<div id="logo-claim" style="display:none;"><?php p($theme->getLogoClaim()); ?></div>
<div class="header-right">
<a href="<?php p($_['downloadURL']); ?>" id="download" class="button">
<img class="svg" alt="" src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>"/>
<?php p($l->t('Download'))?>
</a>
<span id="details">
<span id="save" data-protected="<?php p($_['protected'])?>" data-owner="<?php p($_['displayName'])?>" data-name="<?php p($_['filename'])?>">
<button><?php p($l->t('Save to ownCloud')) ?></button>
<form class="save-form hidden" action="#">
<input type="text" id="remote_address" placeholder="<?php p($l->t('example.com/owncloud')) ?>"/>
<input type="submit" value="<?php p($l->t('Save')) ?>"/>
</form>
</span>
<a href="<?php p($_['downloadURL']); ?>" id="download" class="button">
<img class="svg" alt="" src="<?php print_unescaped(OCP\image_path("core", "actions/download.svg")); ?>"/>
<?php p($l->t('Download'))?>
</a>
</span>
</div>
</div></header>
<div id="content">

View File

@ -0,0 +1,13 @@
<div class="section" id="fileSharingSettings" >
<h2><?php p($l->t('File Sharing'));?></h2>
<input type="checkbox" name="outgoing_server2server_share_enabled" id="outgoingServer2serverShareEnabled"
value="1" <?php if ($_['outgoingServer2serverShareEnabled']) print_unescaped('checked="checked"'); ?> />
<label for="outgoingServer2serverShareEnabled"><?php p($l->t('Allow other instances to mount public links shared from this server'));?></label><br/>
<input type="checkbox" name="incoming_server2server_share_enabled" id="incomingServer2serverShareEnabled"
value="1" <?php if ($_['incomingServer2serverShareEnabled']) print_unescaped('checked="checked"'); ?> />
<label for="incomingServer2serverShareEnabled"><?php p($l->t('Allow users to mount public link shares'));?></label><br/>
</div>

0
config/.htaccess Normal file → Executable file
View File

View File

@ -202,7 +202,8 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
* @return array
*/
public function getQuotaInfo() {
$storageInfo = OC_Helper::getStorageInfo($this->path);
$path = \OC\Files\Filesystem::getView()->getRelativePath($this->info->getPath());
$storageInfo = OC_Helper::getStorageInfo($path);
return array(
$storageInfo['used'],
$storageInfo['free']

View File

@ -140,7 +140,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
if (\OC_Util::encryptedFiles()) {
throw new \Sabre\DAV\Exception\ServiceUnavailable();
} else {
return $this->fileView->fopen($this->path, 'rb');
return $this->fileView->fopen(ltrim($this->path, '/'), 'rb');
}
}

View File

@ -10,6 +10,7 @@ namespace OC\Connector\Sabre;
use OC\Files\FileInfo;
use OC\Files\Filesystem;
use OC\Files\Mount\MoveableMount;
class ObjectTree extends \Sabre\DAV\ObjectTree {
@ -18,6 +19,11 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
*/
protected $fileView;
/**
* @var \OC\Files\Mount\Manager
*/
protected $mountManager;
/**
* Creates the object
*
@ -29,10 +35,12 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
/**
* @param \Sabre\DAV\ICollection $rootNode
* @param \OC\Files\View $view
* @param \OC\Files\Mount\Manager $mountManager
*/
public function init(\Sabre\DAV\ICollection $rootNode, \OC\Files\View $view) {
public function init(\Sabre\DAV\ICollection $rootNode, \OC\Files\View $view, \OC\Files\Mount\Manager $mountManager) {
$this->rootNode = $rootNode;
$this->fileView = $view;
$this->mountManager = $mountManager;
}
/**
@ -115,14 +123,15 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
list($sourceDir,) = \Sabre\DAV\URLUtil::splitPath($sourcePath);
list($destinationDir,) = \Sabre\DAV\URLUtil::splitPath($destinationPath);
$isShareMountPoint = false;
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath( '/' . \OCP\User::getUser() . '/files/' . $sourcePath);
if ($storage instanceof \OC\Files\Storage\Shared && !$internalPath) {
$isShareMountPoint = true;
$isMovableMount = false;
$sourceMount = $this->mountManager->find($this->fileView->getAbsolutePath($sourcePath));
$internalPath = $sourceMount->getInternalPath($this->fileView->getAbsolutePath($sourcePath));
if ($sourceMount instanceof MoveableMount && $internalPath === '') {
$isMovableMount = true;
}
// check update privileges
if (!$this->fileView->isUpdatable($sourcePath) && !$isShareMountPoint) {
if (!$this->fileView->isUpdatable($sourcePath) && !$isMovableMount) {
throw new \Sabre\DAV\Exception\Forbidden();
}
if ($sourceDir !== $destinationDir) {
@ -132,7 +141,7 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
if (!$this->fileView->isUpdatable($destinationDir)) {
throw new \Sabre\DAV\Exception\Forbidden();
}
if (!$this->fileView->isDeletable($sourcePath)) {
if (!$this->fileView->isDeletable($sourcePath) && !$isMovableMount) {
throw new \Sabre\DAV\Exception\Forbidden();
}
}

View File

@ -22,20 +22,20 @@ class Cache {
/**
* @var array partial data for the cache
*/
private $partial = array();
protected $partial = array();
/**
* @var string
*/
private $storageId;
protected $storageId;
/**
* @var Storage $storageCache
*/
private $storageCache;
protected $storageCache;
private static $mimetypeIds = array();
private static $mimetypes = array();
protected static $mimetypeIds = array();
protected static $mimetypes = array();
/**
* @param \OC\Files\Storage\Storage|string $storage

View File

@ -287,31 +287,43 @@ abstract class Common implements \OC\Files\Storage\Storage {
return $this->filemtime($path) > $time;
}
public function getCache($path = '') {
public function getCache($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
if (!isset($this->cache)) {
$this->cache = new \OC\Files\Cache\Cache($this);
$this->cache = new \OC\Files\Cache\Cache($storage);
}
return $this->cache;
}
public function getScanner($path = '') {
public function getScanner($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
if (!isset($this->scanner)) {
$this->scanner = new \OC\Files\Cache\Scanner($this);
$this->scanner = new \OC\Files\Cache\Scanner($storage);
}
return $this->scanner;
}
public function getWatcher($path = '') {
public function getWatcher($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
if (!isset($this->watcher)) {
$this->watcher = new \OC\Files\Cache\Watcher($this);
$this->watcher = new \OC\Files\Cache\Watcher($storage);
$this->watcher->setPolicy(\OC::$server->getConfig()->getSystemValue('filesystem_check_changes', Watcher::CHECK_ONCE));
}
return $this->watcher;
}
public function getStorageCache() {
public function getStorageCache($storage = null) {
if (!$storage) {
$storage = $this;
}
if (!isset($this->storageCache)) {
$this->storageCache = new \OC\Files\Cache\Storage($this);
$this->storageCache = new \OC\Files\Cache\Storage($storage);
}
return $this->storageCache;
}

View File

@ -49,9 +49,12 @@ class Home extends Local {
/**
* @return \OC\Files\Cache\HomeCache
*/
public function getCache($path = '') {
public function getCache($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
if (!isset($this->cache)) {
$this->cache = new \OC\Files\Cache\HomeCache($this);
$this->cache = new \OC\Files\Cache\HomeCache($storage);
}
return $this->cache;
}

View File

@ -19,17 +19,19 @@ interface Storage extends \OCP\Files\Storage {
* get a cache instance for the storage
*
* @param string $path
* @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache
* @return \OC\Files\Cache\Cache
*/
public function getCache($path = '');
public function getCache($path = '', $storage = null);
/**
* get a scanner instance for the storage
*
* @param string $path
* @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
* @return \OC\Files\Cache\Scanner
*/
public function getScanner($path = '');
public function getScanner($path = '', $storage = null);
/**
@ -44,9 +46,10 @@ interface Storage extends \OCP\Files\Storage {
* get a watcher instance for the cache
*
* @param string $path
* @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
* @return \OC\Files\Cache\Watcher
*/
public function getWatcher($path = '');
public function getWatcher($path = '', $storage = null);
/**
* @return \OC\Files\Cache\Storage

View File

@ -361,20 +361,28 @@ class Wrapper implements \OC\Files\Storage\Storage {
* get a cache instance for the storage
*
* @param string $path
* @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache
* @return \OC\Files\Cache\Cache
*/
public function getCache($path = '') {
return $this->storage->getCache($path);
public function getCache($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
return $this->storage->getCache($path, $storage);
}
/**
* get a scanner instance for the storage
*
* @param string $path
* @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
* @return \OC\Files\Cache\Scanner
*/
public function getScanner($path = '') {
return $this->storage->getScanner($path);
public function getScanner($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
return $this->storage->getScanner($path, $storage);
}
@ -392,10 +400,14 @@ class Wrapper implements \OC\Files\Storage\Storage {
* get a watcher instance for the cache
*
* @param string $path
* @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher
* @return \OC\Files\Cache\Watcher
*/
public function getWatcher($path = '') {
return $this->storage->getWatcher($path);
public function getWatcher($path = '', $storage = null) {
if (!$storage) {
$storage = $this;
}
return $this->storage->getWatcher($path, $storage);
}
/**
@ -417,6 +429,7 @@ class Wrapper implements \OC\Files\Storage\Storage {
/**
* Returns true
*
* @return true
*/
public function test() {
@ -425,6 +438,7 @@ class Wrapper implements \OC\Files\Storage\Storage {
/**
* Returns the wrapped storage's value for isLocal()
*
* @return bool wrapped storage's isLocal() value
*/
public function isLocal() {

View File

@ -161,7 +161,34 @@ class View {
return $this->basicOperation('mkdir', $path, array('create', 'write'));
}
protected function removeMount($mount, $path){
if ($mount instanceof MoveableMount) {
\OC_Hook::emit(
Filesystem::CLASSNAME, "umount",
array(Filesystem::signal_param_path => $path)
);
$result = $mount->removeMount();
if ($result) {
\OC_Hook::emit(
Filesystem::CLASSNAME, "post_umount",
array(Filesystem::signal_param_path => $path)
);
}
return $result;
} else {
// do not allow deleting the storage's root / the mount point
// because for some storages it might delete the whole contents
// but isn't supposed to work that way
return false;
}
}
public function rmdir($path) {
$absolutePath= $this->getAbsolutePath($path);
$mount = Filesystem::getMountManager()->find($absolutePath);
if ($mount->getInternalPath($absolutePath) === '') {
return $this->removeMount($mount, $path);
}
if ($this->is_dir($path)) {
return $this->basicOperation('rmdir', $path, array('delete'));
} else {
@ -360,25 +387,7 @@ class View {
$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
$mount = Filesystem::getMountManager()->find($absolutePath . $postFix);
if ($mount->getInternalPath($absolutePath) === '') {
if ($mount instanceof MoveableMount) {
\OC_Hook::emit(
Filesystem::CLASSNAME, "umount",
array(Filesystem::signal_param_path => $path)
);
$result = $mount->removeMount();
if ($result) {
\OC_Hook::emit(
Filesystem::CLASSNAME, "post_umount",
array(Filesystem::signal_param_path => $path)
);
}
return $result;
} else {
// do not allow deleting the storage's root / the mount point
// because for some storages it might delete the whole contents
// but isn't supposed to work that way
return false;
}
return $this->removeMount($mount, $path);
}
return $this->basicOperation('unlink', $path, array('delete'));
}
@ -836,11 +845,10 @@ class View {
return $data;
}
$path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
/**
* @var \OC\Files\Storage\Storage $storage
* @var string $internalPath
*/
list($storage, $internalPath) = Filesystem::resolvePath($path);
$mount = Filesystem::getMountManager()->find($path);
$storage = $mount->getStorage();
$internalPath = $mount->getInternalPath($path);
$data = null;
if ($storage) {
$cache = $storage->getCache($internalPath);
@ -888,6 +896,10 @@ class View {
return false;
}
if ($mount instanceof MoveableMount) {
$data['permissions'] |= \OCP\PERMISSION_DELETE | \OCP\PERMISSION_UPDATE;
}
$data = \OC_FileProxy::runPostProxies('getFileInfo', $path, $data);
return new FileInfo($path, $storage, $internalPath, $data);

View File

@ -940,7 +940,7 @@ class OC_Helper {
// return storage info without adding mount points
$includeExtStorage = \OC_Config::getValue('quota_include_external_storage', false);
if (is_null($rootInfo)) {
if (!$rootInfo) {
$rootInfo = \OC\Files\Filesystem::getFileInfo($path, false);
}
$used = $rootInfo->getSize();

View File

@ -508,9 +508,9 @@ class Share extends \OC\Share\Constants {
if ($itemType === 'folder') {
$path = '/' . $uidOwner . '/files' . \OC\Files\Filesystem::getPath($itemSource) . '/';
$mountManager = \OC\Files\Filesystem::getMountManager();
$mounts = $mountManager->getAll();
foreach ($mounts as $mountPoint => $mount) {
if ($mount->getStorage() instanceof \OC\Files\Storage\Shared && strpos($mountPoint, $path) === 0) {
$mounts = $mountManager->findIn($path);
foreach ($mounts as $mount) {
if ($mount->getStorage()->instanceOfStorage('\OCA\Files_Sharing\ISharedStorage')) {
$message = 'Sharing "' . $itemSourceName . '" failed, because it contains files shared with you!';
\OC_Log::write('OCP\Share', $message, \OC_Log::ERROR);
throw new \Exception($message);

View File

@ -110,7 +110,8 @@ class ObjectTree extends PHPUnit_Framework_TestCase {
->will($this->returnValue(false));
/** @var $objectTree \OC\Connector\Sabre\ObjectTree */
$objectTree->init($rootDir, $view);
$mountManager = \OC\Files\Filesystem::getMountManager();
$objectTree->init($rootDir, $view, $mountManager);
$objectTree->move($source, $dest);
}