- the file/folder's permission is now stored in the file cache - BackGroundWatcher has been removed - this has meanwhile be replaced by occ files:scan which can be executed in a cron jobs - increase version to trigger database migrationtags/v7.0.0alpha2
OC_Search::registerProvider('OC_Search_Provider_File'); | OC_Search::registerProvider('OC_Search_Provider_File'); | ||||
\OCP\BackgroundJob::addRegularTask('\OC\Files\Cache\BackgroundWatcher', 'checkNext'); | |||||
$templateManager = OC_Helper::getFileTemplateManager(); | $templateManager = OC_Helper::getFileTemplateManager(); | ||||
$templateManager->registerTemplate('text/html', 'core/templates/filetemplates/template.html'); | $templateManager->registerTemplate('text/html', 'core/templates/filetemplates/template.html'); | ||||
$templateManager->registerTemplate('application/vnd.oasis.opendocument.presentation', 'core/templates/filetemplates/template.odp'); | $templateManager->registerTemplate('application/vnd.oasis.opendocument.presentation', 'core/templates/filetemplates/template.odp'); |
return $shares; | return $shares; | ||||
} | } | ||||
$select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `file_source`, `path` , `permissions`, `stime`, `expiration`, `token`, `storage`, `mail_send`, `mail_send`'; | |||||
$select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `file_source`, `path` , `*PREFIX*share`.`permissions`, `stime`, `expiration`, `token`, `storage`, `mail_send`, `mail_send`'; | |||||
$getReshares = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` WHERE `*PREFIX*share`.`file_source` = ? AND `*PREFIX*share`.`item_type` IN (\'file\', \'folder\') AND `uid_owner` != ?'); | $getReshares = \OC_DB::prepare('SELECT ' . $select . ' FROM `*PREFIX*share` INNER JOIN `*PREFIX*filecache` ON `file_source` = `*PREFIX*filecache`.`fileid` WHERE `*PREFIX*share`.`file_source` = ? AND `*PREFIX*share`.`item_type` IN (\'file\', \'folder\') AND `uid_owner` != ?'); | ||||
$reshares = $getReshares->execute(array($itemSource, \OCP\User::getUser()))->fetchAll(); | $reshares = $getReshares->execute(array($itemSource, \OCP\User::getUser()))->fetchAll(); | ||||
} | } | ||||
$query = \OC_DB::prepare( | $query = \OC_DB::prepare( | ||||
'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`,' | 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`,' | ||||
. ' `size`, `mtime`, `encrypted`, `unencrypted_size`, `storage_mtime`, `etag`' | |||||
. ' `size`, `mtime`, `encrypted`, `unencrypted_size`, `storage_mtime`, `etag`, `permissions`' | |||||
. ' FROM `*PREFIX*filecache` WHERE `fileid` = ?'); | . ' FROM `*PREFIX*filecache` WHERE `fileid` = ?'); | ||||
$result = $query->execute(array($sourceId)); | $result = $query->execute(array($sourceId)); | ||||
$data = $result->fetchRow(); | $data = $result->fetchRow(); | ||||
} else { | } else { | ||||
$data['size'] = (int)$data['size']; | $data['size'] = (int)$data['size']; | ||||
} | } | ||||
$data['permissions'] = (int)$data['permissions']; | |||||
if (!is_int($file) || $file === 0) { | if (!is_int($file) || $file === 0) { | ||||
$data['path'] = ''; | $data['path'] = ''; | ||||
$data['name'] = basename($this->storage->getMountPoint()); | $data['name'] = basename($this->storage->getMountPoint()); |
<?php | |||||
/** | |||||
* ownCloud | |||||
* | |||||
* @author Michael Gapczynski | |||||
* @copyright 2012 Michael Gapczynski mtgap@owncloud.com | |||||
* | |||||
* This library is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or any later version. | |||||
* | |||||
* This library is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||||
* | |||||
* You should have received a copy of the GNU Affero General Public | |||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
namespace OC\Files\Cache; | |||||
class Shared_Permissions extends Permissions { | |||||
/** | |||||
* get the permissions for a single file | |||||
* | |||||
* @param int $fileId | |||||
* @param string $user | |||||
* @return int permissions | |||||
*/ | |||||
public function get($fileId, $user) { | |||||
$permissions = $this->storage->getPermissions(); | |||||
return $this->updatePermissions($permissions); | |||||
} | |||||
/** | |||||
* @param integer $fileId | |||||
* @param string $user | |||||
*/ | |||||
private function getFile($fileId, $user) { | |||||
return $this->get($fileId, $user); | |||||
} | |||||
/** | |||||
* set the permissions of a file | |||||
* | |||||
* @param int $fileId | |||||
* @param string $user | |||||
* @param int $permissions | |||||
*/ | |||||
public function set($fileId, $user, $permissions) { | |||||
// Not a valid action for Shared Permissions | |||||
} | |||||
/** | |||||
* get the permissions of multiply files | |||||
* | |||||
* @param int[] $fileIds | |||||
* @param string $user | |||||
* @return int[] | |||||
*/ | |||||
public function getMultiple($fileIds, $user) { | |||||
$filePermissions = array(); | |||||
foreach ($fileIds as $fileId) { | |||||
$filePermissions[$fileId] = $this->get($fileId, $user); | |||||
} | |||||
return $filePermissions; | |||||
} | |||||
/** | |||||
* get the permissions for all files in a folder | |||||
* | |||||
* @param int $parentId | |||||
* @param string $user | |||||
* @return int[] | |||||
*/ | |||||
public function getDirectoryPermissions($parentId, $user) { | |||||
if ($parentId === -1 && $this->storage->instanceOfStorage('\OC\Files\Storage\Shared')) { | |||||
$fileCacheId = $this->storage->getSourceId(); | |||||
} else { | |||||
$fileCacheId = $parentId; | |||||
} | |||||
$query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `parent` = ?'); | |||||
$result = $query->execute(array($fileCacheId)); | |||||
$permissions = $this->get($parentId, $user); | |||||
$filePermissions = array(); | |||||
while ($row = $result->fetchRow()) { | |||||
$filePermissions[$row['fileid']] = $permissions; | |||||
} | |||||
return $filePermissions; | |||||
} | |||||
/** | |||||
* remove the permissions for a file | |||||
* | |||||
* @param int $fileId | |||||
* @param string $user | |||||
*/ | |||||
public function remove($fileId, $user = null) { | |||||
// Not a valid action for Shared Permissions | |||||
} | |||||
public function removeMultiple($fileIds, $user) { | |||||
// Not a valid action for Shared Permissions | |||||
} | |||||
} |
return new \OC\Files\Cache\Scanner($this); | return new \OC\Files\Cache\Scanner($this); | ||||
} | } | ||||
public function getPermissionsCache($path = '') { | |||||
return new \OC\Files\Cache\Shared_Permissions($this); | |||||
} | |||||
public function getWatcher($path = '') { | public function getWatcher($path = '') { | ||||
return new \OC\Files\Cache\Shared_Watcher($this); | return new \OC\Files\Cache\Shared_Watcher($this); | ||||
} | } |
<length>40</length> | <length>40</length> | ||||
</field> | </field> | ||||
<index> | |||||
<field> | |||||
<name>permissions</name> | |||||
<type>integer</type> | |||||
<default>0</default> | |||||
<notnull>false</notnull> | |||||
<length>4</length> | |||||
</field> | |||||
<index> | |||||
<name>fs_storage_path_hash</name> | <name>fs_storage_path_hash</name> | ||||
<unique>true</unique> | <unique>true</unique> | ||||
<field> | <field> | ||||
</table> | </table> | ||||
<table> | |||||
<!-- | |||||
Maps (fileid, user) to an integer which is a permission bitfield. | |||||
- E.g. (4, admin) -> 27 | |||||
--> | |||||
<name>*dbprefix*permissions</name> | |||||
<declaration> | |||||
<!-- Foreign Key filecache::fileid --> | |||||
<field> | |||||
<name>fileid</name> | |||||
<type>integer</type> | |||||
<default>0</default> | |||||
<notnull>true</notnull> | |||||
<length>4</length> | |||||
</field> | |||||
<!-- Foreign Key users::uid --> | |||||
<field> | |||||
<name>user</name> | |||||
<type>text</type> | |||||
<default></default> | |||||
<notnull>false</notnull> | |||||
<length>64</length> | |||||
</field> | |||||
<field> | |||||
<name>permissions</name> | |||||
<type>integer</type> | |||||
<default>0</default> | |||||
<notnull>true</notnull> | |||||
<length>4</length> | |||||
</field> | |||||
<index> | |||||
<name>id_user_index</name> | |||||
<field> | |||||
<name>fileid</name> | |||||
<sorting>ascending</sorting> | |||||
</field> | |||||
<field> | |||||
<name>user</name> | |||||
<sorting>ascending</sorting> | |||||
</field> | |||||
</index> | |||||
</declaration> | |||||
</table> | |||||
<table> | <table> | ||||
<!-- | <!-- |
<?php | |||||
/** | |||||
* Copyright (c) 2013 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 OC\Files\Cache; | |||||
use \OC\Files\Mount; | |||||
use \OC\Files\Filesystem; | |||||
class BackgroundWatcher { | |||||
static $folderMimetype = null; | |||||
static private function getFolderMimetype() { | |||||
if (!is_null(self::$folderMimetype)) { | |||||
return self::$folderMimetype; | |||||
} | |||||
$sql = 'SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?'; | |||||
$result = \OC_DB::executeAudited($sql, array('httpd/unix-directory')); | |||||
$row = $result->fetchRow(); | |||||
return $row['id']; | |||||
} | |||||
/** | |||||
* @param integer $id | |||||
*/ | |||||
static private function checkUpdate($id) { | |||||
$cacheItem = Cache::getById($id); | |||||
if (is_null($cacheItem)) { | |||||
return; | |||||
} | |||||
list($storageId, $internalPath) = $cacheItem; | |||||
$mounts = Filesystem::getMountByStorageId($storageId); | |||||
if (count($mounts) === 0) { | |||||
//if the storage we need isn't mounted on default, try to find a user that has access to the storage | |||||
$permissionsCache = new Permissions($storageId); | |||||
$users = $permissionsCache->getUsers($id); | |||||
if (count($users) === 0) { | |||||
return; | |||||
} | |||||
Filesystem::initMountPoints($users[0]); | |||||
$mounts = Filesystem::getMountByStorageId($storageId); | |||||
if (count($mounts) === 0) { | |||||
return; | |||||
} | |||||
} | |||||
$storage = $mounts[0]->getStorage(); | |||||
$watcher = new Watcher($storage); | |||||
$watcher->checkUpdate($internalPath); | |||||
} | |||||
/** | |||||
* get the next fileid in the cache | |||||
* | |||||
* @param int $previous | |||||
* @param bool $folder | |||||
* @return int | |||||
*/ | |||||
static private function getNextFileId($previous, $folder) { | |||||
if ($folder) { | |||||
$stmt = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `fileid` > ? AND `mimetype` = ? ORDER BY `fileid` ASC', 1); | |||||
} else { | |||||
$stmt = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE `fileid` > ? AND `mimetype` != ? ORDER BY `fileid` ASC', 1); | |||||
} | |||||
$result = \OC_DB::executeAudited($stmt, array($previous,self::getFolderMimetype())); | |||||
if ($row = $result->fetchRow()) { | |||||
return $row['fileid']; | |||||
} else { | |||||
return 0; | |||||
} | |||||
} | |||||
static public function checkNext() { | |||||
// check both 1 file and 1 folder, this way new files are detected quicker because there are less folders than files usually | |||||
$previousFile = \OC_Appconfig::getValue('files', 'backgroundwatcher_previous_file', 0); | |||||
$previousFolder = \OC_Appconfig::getValue('files', 'backgroundwatcher_previous_folder', 0); | |||||
$nextFile = self::getNextFileId($previousFile, false); | |||||
$nextFolder = self::getNextFileId($previousFolder, true); | |||||
\OC_Appconfig::setValue('files', 'backgroundwatcher_previous_file', $nextFile); | |||||
\OC_Appconfig::setValue('files', 'backgroundwatcher_previous_folder', $nextFolder); | |||||
if ($nextFile > 0) { | |||||
self::checkUpdate($nextFile); | |||||
} | |||||
if ($nextFolder > 0) { | |||||
self::checkUpdate($nextFolder); | |||||
} | |||||
} | |||||
static public function checkAll() { | |||||
$previous = 0; | |||||
$next = 1; | |||||
while ($next != 0) { | |||||
$next = self::getNextFileId($previous, true); | |||||
self::checkUpdate($next); | |||||
} | |||||
$previous = 0; | |||||
$next = 1; | |||||
while ($next != 0) { | |||||
$next = self::getNextFileId($previous, false); | |||||
self::checkUpdate($next); | |||||
} | |||||
} | |||||
} |
$params = array($file); | $params = array($file); | ||||
} | } | ||||
$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, | $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, | ||||
`storage_mtime`, `encrypted`, `unencrypted_size`, `etag` | |||||
`storage_mtime`, `encrypted`, `unencrypted_size`, `etag`, `permissions` | |||||
FROM `*PREFIX*filecache` ' . $where; | FROM `*PREFIX*filecache` ' . $where; | ||||
$result = \OC_DB::executeAudited($sql, $params); | $result = \OC_DB::executeAudited($sql, $params); | ||||
$data = $result->fetchRow(); | $data = $result->fetchRow(); | ||||
if ($data['storage_mtime'] == 0) { | if ($data['storage_mtime'] == 0) { | ||||
$data['storage_mtime'] = $data['mtime']; | $data['storage_mtime'] = $data['mtime']; | ||||
} | } | ||||
$data['permissions'] = (int)$data['permissions']; | |||||
} | } | ||||
return $data; | return $data; | ||||
public function getFolderContentsById($fileId) { | public function getFolderContentsById($fileId) { | ||||
if ($fileId > -1) { | if ($fileId > -1) { | ||||
$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, | $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, | ||||
`storage_mtime`, `encrypted`, `unencrypted_size`, `etag` | |||||
`storage_mtime`, `encrypted`, `unencrypted_size`, `etag`, `permissions` | |||||
FROM `*PREFIX*filecache` WHERE `parent` = ? ORDER BY `name` ASC'; | FROM `*PREFIX*filecache` WHERE `parent` = ? ORDER BY `name` ASC'; | ||||
$result = \OC_DB::executeAudited($sql,array($fileId)); | $result = \OC_DB::executeAudited($sql,array($fileId)); | ||||
$files = $result->fetchAll(); | $files = $result->fetchAll(); | ||||
$file['encrypted_size'] = $file['size']; | $file['encrypted_size'] = $file['size']; | ||||
$file['size'] = $file['unencrypted_size']; | $file['size'] = $file['unencrypted_size']; | ||||
} | } | ||||
$file['permissions'] = (int)$file['permissions']; | |||||
} | } | ||||
return $files; | return $files; | ||||
} else { | } else { | ||||
* @return array | * @return array | ||||
*/ | */ | ||||
function buildParts(array $data) { | function buildParts(array $data) { | ||||
$fields = array('path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted', 'unencrypted_size', 'etag'); | |||||
$fields = array( | |||||
'path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted', 'unencrypted_size', | |||||
'etag', 'permissions'); | |||||
$params = array(); | $params = array(); | ||||
$queryParts = array(); | $queryParts = array(); | ||||
foreach ($data as $name => $value) { | foreach ($data as $name => $value) { | ||||
$sql = 'DELETE FROM `*PREFIX*filecache` WHERE `fileid` = ?'; | $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `fileid` = ?'; | ||||
\OC_DB::executeAudited($sql, array($entry['fileid'])); | \OC_DB::executeAudited($sql, array($entry['fileid'])); | ||||
$permissionsCache = new Permissions($this->storageId); | |||||
$permissionsCache->remove($entry['fileid']); | |||||
} | } | ||||
/** | /** | ||||
// normalize pattern | // normalize pattern | ||||
$pattern = $this->normalize($pattern); | $pattern = $this->normalize($pattern); | ||||
$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` | |||||
$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag`, `permissions` | |||||
FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `storage` = ?'; | FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `storage` = ?'; | ||||
$result = \OC_DB::executeAudited($sql, array($pattern, $this->getNumericStorageId())); | $result = \OC_DB::executeAudited($sql, array($pattern, $this->getNumericStorageId())); | ||||
$files = array(); | $files = array(); | ||||
} else { | } else { | ||||
$where = '`mimepart` = ?'; | $where = '`mimepart` = ?'; | ||||
} | } | ||||
$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag` | |||||
$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `unencrypted_size`, `etag`, `permissions` | |||||
FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?'; | FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?'; | ||||
$mimetype = $this->getMimetypeId($mimetype); | $mimetype = $this->getMimetypeId($mimetype); | ||||
$result = \OC_DB::executeAudited($sql, array($mimetype, $this->getNumericStorageId())); | $result = \OC_DB::executeAudited($sql, array($mimetype, $this->getNumericStorageId())); |
<?php | |||||
/** | |||||
* Copyright (c) 2012 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 OC\Files\Cache; | |||||
class Permissions { | |||||
/** | |||||
* @var string $storageId | |||||
*/ | |||||
private $storageId; | |||||
/** | |||||
* @var \OC\Files\Storage\Storage $storage | |||||
*/ | |||||
protected $storage; | |||||
/** | |||||
* @param \OC\Files\Storage\Storage|string $storage | |||||
*/ | |||||
public function __construct($storage) { | |||||
if ($storage instanceof \OC\Files\Storage\Storage) { | |||||
$this->storageId = $storage->getId(); | |||||
$this->storage = $storage; | |||||
} else { | |||||
$this->storageId = $storage; | |||||
$mountManager = \OC\Files\Filesystem::getMountManager(); | |||||
$mount = $mountManager->findByStorageId($this->storageId); | |||||
$firstMountPoint = reset($mount); | |||||
if ($firstMountPoint instanceof \OC\Files\Storage\Storage) { | |||||
$storage = $firstMountPoint->getStorage(); | |||||
$this->storage = $storage; | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* get the permissions for a single file | |||||
* | |||||
* @param int $fileId | |||||
* @param string $user | |||||
* @return int (-1 if file no permissions set) | |||||
*/ | |||||
public function get($fileId, $user) { | |||||
$sql = 'SELECT `permissions` FROM `*PREFIX*permissions` WHERE `user` = ? AND `fileid` = ?'; | |||||
$result = \OC_DB::executeAudited($sql, array($user, $fileId)); | |||||
if ($row = $result->fetchRow()) { | |||||
return $this->updatePermissions($row['permissions']); | |||||
} else { | |||||
return -1; | |||||
} | |||||
} | |||||
/** | |||||
* set the permissions of a file | |||||
* | |||||
* @param int $fileId | |||||
* @param string $user | |||||
* @param int $permissions | |||||
*/ | |||||
public function set($fileId, $user, $permissions) { | |||||
if (self::get($fileId, $user) !== -1) { | |||||
$sql = 'UPDATE `*PREFIX*permissions` SET `permissions` = ? WHERE `user` = ? AND `fileid` = ?'; | |||||
} else { | |||||
$sql = 'INSERT INTO `*PREFIX*permissions`(`permissions`, `user`, `fileid`) VALUES(?, ?,? )'; | |||||
} | |||||
\OC_DB::executeAudited($sql, array($permissions, $user, $fileId)); | |||||
} | |||||
/** | |||||
* get the permissions of multiply files | |||||
* | |||||
* @param int[] $fileIds | |||||
* @param string $user | |||||
* @return int[] | |||||
*/ | |||||
public function getMultiple($fileIds, $user) { | |||||
if (count($fileIds) === 0) { | |||||
return array(); | |||||
} | |||||
$params = $fileIds; | |||||
$params[] = $user; | |||||
$inPart = implode(', ', array_fill(0, count($fileIds), '?')); | |||||
$sql = 'SELECT `fileid`, `permissions` FROM `*PREFIX*permissions`' | |||||
. ' WHERE `fileid` IN (' . $inPart . ') AND `user` = ?'; | |||||
$result = \OC_DB::executeAudited($sql, $params); | |||||
$filePermissions = array(); | |||||
while ($row = $result->fetchRow()) { | |||||
$filePermissions[$row['fileid']] = $this->updatePermissions($row['permissions']); | |||||
} | |||||
return $filePermissions; | |||||
} | |||||
/** | |||||
* get the permissions for all files in a folder | |||||
* | |||||
* @param int $parentId | |||||
* @param string $user | |||||
* @return int[] | |||||
*/ | |||||
public function getDirectoryPermissions($parentId, $user) { | |||||
$sql = 'SELECT `*PREFIX*permissions`.`fileid`, `permissions` | |||||
FROM `*PREFIX*permissions` | |||||
INNER JOIN `*PREFIX*filecache` ON `*PREFIX*permissions`.`fileid` = `*PREFIX*filecache`.`fileid` | |||||
WHERE `*PREFIX*filecache`.`parent` = ? AND `*PREFIX*permissions`.`user` = ?'; | |||||
$result = \OC_DB::executeAudited($sql, array($parentId, $user)); | |||||
$filePermissions = array(); | |||||
while ($row = $result->fetchRow()) { | |||||
$filePermissions[$row['fileid']] = $this->updatePermissions($row['permissions']); | |||||
} | |||||
return $filePermissions; | |||||
} | |||||
/** | |||||
* remove the permissions for a file | |||||
* | |||||
* @param int $fileId | |||||
* @param string $user | |||||
*/ | |||||
public function remove($fileId, $user = null) { | |||||
if (is_null($user)) { | |||||
\OC_DB::executeAudited('DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ?', array($fileId)); | |||||
} else { | |||||
$sql = 'DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ? AND `user` = ?'; | |||||
\OC_DB::executeAudited($sql, array($fileId, $user)); | |||||
} | |||||
} | |||||
public function removeMultiple($fileIds, $user) { | |||||
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*permissions` WHERE `fileid` = ? AND `user` = ?'); | |||||
foreach ($fileIds as $fileId) { | |||||
\OC_DB::executeAudited($query, array($fileId, $user)); | |||||
} | |||||
} | |||||
/** | |||||
* get the list of users which have permissions stored for a file | |||||
* | |||||
* @param int $fileId | |||||
*/ | |||||
public function getUsers($fileId) { | |||||
$sql = 'SELECT `user` FROM `*PREFIX*permissions` WHERE `fileid` = ?'; | |||||
$result = \OC_DB::executeAudited($sql, array($fileId)); | |||||
$users = array(); | |||||
while ($row = $result->fetchRow()) { | |||||
$users[] = $row['user']; | |||||
} | |||||
return $users; | |||||
} | |||||
/** | |||||
* check if admin removed the share permission for the user and update the permissions | |||||
* | |||||
* @param int $permissions | |||||
* @return int | |||||
*/ | |||||
protected function updatePermissions($permissions) { | |||||
if (\OCP\Util::isSharingDisabledForUser()) { | |||||
$permissions &= ~\OCP\PERMISSION_SHARE; | |||||
} | |||||
return $permissions; | |||||
} | |||||
} |
*/ | */ | ||||
protected $cache; | protected $cache; | ||||
/** | |||||
* @var \OC\Files\Cache\Permissions $permissionsCache | |||||
*/ | |||||
protected $permissionsCache; | |||||
/** | /** | ||||
* @var boolean $cacheActive If true, perform cache operations, if false, do not affect cache | * @var boolean $cacheActive If true, perform cache operations, if false, do not affect cache | ||||
*/ | */ | ||||
$this->storage = $storage; | $this->storage = $storage; | ||||
$this->storageId = $this->storage->getId(); | $this->storageId = $this->storage->getId(); | ||||
$this->cache = $storage->getCache(); | $this->cache = $storage->getCache(); | ||||
$this->permissionsCache = $storage->getPermissionsCache(); | |||||
$this->cacheActive = !Config::getSystemValue('filesystem_cache_readonly', false); | $this->cacheActive = !Config::getSystemValue('filesystem_cache_readonly', false); | ||||
} | } | ||||
} | } | ||||
$data['etag'] = $this->storage->getETag($path); | $data['etag'] = $this->storage->getETag($path); | ||||
$data['storage_mtime'] = $data['mtime']; | $data['storage_mtime'] = $data['mtime']; | ||||
$data['permissions'] = $this->storage->getPermissions($path); | |||||
return $data; | return $data; | ||||
} | } | ||||
$newData = $data; | $newData = $data; | ||||
$cacheData = $this->cache->get($file); | $cacheData = $this->cache->get($file); | ||||
if ($cacheData) { | if ($cacheData) { | ||||
if (isset($cacheData['fileid'])) { | |||||
$this->permissionsCache->remove($cacheData['fileid']); | |||||
} | |||||
if ($reuseExisting) { | if ($reuseExisting) { | ||||
// prevent empty etag | // prevent empty etag | ||||
if (empty($cacheData['etag'])) { | if (empty($cacheData['etag'])) { |
list($storage, $internalPath) = $this->view->resolvePath($this->path); | list($storage, $internalPath) = $this->view->resolvePath($this->path); | ||||
if ($storage) { | if ($storage) { | ||||
$cache = $storage->getCache($internalPath); | $cache = $storage->getCache($internalPath); | ||||
$permissionsCache = $storage->getPermissionsCache($internalPath); | |||||
//trigger cache update check | //trigger cache update check | ||||
$this->view->getFileInfo($this->path); | $this->view->getFileInfo($this->path); | ||||
$files = $cache->getFolderContents($internalPath); | $files = $cache->getFolderContents($internalPath); | ||||
$permissions = $permissionsCache->getDirectoryPermissions($this->getId(), $this->root->getUser()->getUID()); | |||||
} else { | } else { | ||||
$files = array(); | $files = array(); | ||||
} | } | ||||
foreach ($files as $file) { | foreach ($files as $file) { | ||||
if ($file) { | if ($file) { | ||||
if (isset($permissions[$file['fileid']])) { | |||||
$file['permissions'] = $permissions[$file['fileid']]; | |||||
} | |||||
$node = $this->createNode($this->path . '/' . $file['name'], $file); | $node = $this->createNode($this->path . '/' . $file['name'], $file); | ||||
$result[] = $node; | $result[] = $node; | ||||
} | } |
return $this->scanner; | return $this->scanner; | ||||
} | } | ||||
public function getPermissionsCache($path = '') { | |||||
if (!isset($this->permissioncache)) { | |||||
$this->permissioncache = new \OC\Files\Cache\Permissions($this); | |||||
} | |||||
return $this->permissioncache; | |||||
} | |||||
public function getWatcher($path = '') { | public function getWatcher($path = '') { | ||||
if (!isset($this->watcher)) { | if (!isset($this->watcher)) { | ||||
$this->watcher = new \OC\Files\Cache\Watcher($this); | $this->watcher = new \OC\Files\Cache\Watcher($this); |
*/ | */ | ||||
public function getOwner($path); | public function getOwner($path); | ||||
/** | |||||
* get a permissions cache instance for the cache | |||||
* | |||||
* @param string $path | |||||
* @return \OC\Files\Cache\Permissions | |||||
*/ | |||||
public function getPermissionsCache($path = ''); | |||||
/** | /** | ||||
* get a watcher instance for the cache | * get a watcher instance for the cache | ||||
* | * |
return $this->storage->getOwner($path); | return $this->storage->getOwner($path); | ||||
} | } | ||||
/** | |||||
* get a permissions cache instance for the cache | |||||
* | |||||
* @param string $path | |||||
* @return \OC\Files\Cache\Permissions | |||||
*/ | |||||
public function getPermissionsCache($path = '') { | |||||
return $this->storage->getPermissionsCache($path); | |||||
} | |||||
/** | /** | ||||
* get a watcher instance for the cache | * get a watcher instance for the cache | ||||
* | * |
$data = null; | $data = null; | ||||
if ($storage) { | if ($storage) { | ||||
$cache = $storage->getCache($internalPath); | $cache = $storage->getCache($internalPath); | ||||
$permissionsCache = $storage->getPermissionsCache($internalPath); | |||||
$user = \OC_User::getUser(); | |||||
if (!$cache->inCache($internalPath)) { | if (!$cache->inCache($internalPath)) { | ||||
if (!$storage->file_exists($internalPath)) { | if (!$storage->file_exists($internalPath)) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
$permissions = $permissionsCache->get($data['fileid'], $user); | |||||
if ($permissions === -1) { | |||||
$permissions = $storage->getPermissions($internalPath); | |||||
$permissionsCache->set($data['fileid'], $user, $permissions); | |||||
} | |||||
$data['permissions'] = $permissions; | |||||
} | } | ||||
} | } | ||||
if (!$data) { | if (!$data) { | ||||
list($storage, $internalPath) = Filesystem::resolvePath($path); | list($storage, $internalPath) = Filesystem::resolvePath($path); | ||||
if ($storage) { | if ($storage) { | ||||
$cache = $storage->getCache($internalPath); | $cache = $storage->getCache($internalPath); | ||||
$permissionsCache = $storage->getPermissionsCache($internalPath); | |||||
$user = \OC_User::getUser(); | $user = \OC_User::getUser(); | ||||
if ($cache->getStatus($internalPath) < Cache\Cache::COMPLETE) { | if ($cache->getStatus($internalPath) < Cache\Cache::COMPLETE) { | ||||
foreach ($contents as $content) { | foreach ($contents as $content) { | ||||
$files[] = new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content); | $files[] = new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content); | ||||
} | } | ||||
$permissions = $permissionsCache->getDirectoryPermissions($folderId, $user); | |||||
$ids = array(); | $ids = array(); | ||||
foreach ($files as $i => $file) { | foreach ($files as $i => $file) { | ||||
if (!isset($permissions[$file['fileid']])) { | if (!isset($permissions[$file['fileid']])) { | ||||
$permissions[$file['fileid']] = $storage->getPermissions($file['path']); | $permissions[$file['fileid']] = $storage->getPermissions($file['path']); | ||||
$permissionsCache->set($file['fileid'], $user, $permissions[$file['fileid']]); | |||||
} | } | ||||
$files[$i]['permissions'] = $permissions[$file['fileid']]; | $files[$i]['permissions'] = $permissions[$file['fileid']]; | ||||
} | } | ||||
} else { //mountpoint in this folder, add an entry for it | } else { //mountpoint in this folder, add an entry for it | ||||
$rootEntry['name'] = $relativePath; | $rootEntry['name'] = $relativePath; | ||||
$rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file'; | $rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file'; | ||||
$subPermissionsCache = $subStorage->getPermissionsCache(''); | |||||
$permissions = $subPermissionsCache->get($rootEntry['fileid'], $user); | |||||
if ($permissions === -1) { | |||||
$permissions = $subStorage->getPermissions($rootEntry['path']); | |||||
$subPermissionsCache->set($rootEntry['fileid'], $user, $permissions); | |||||
} | |||||
$permissions = $rootEntry['permissions']; | |||||
// do not allow renaming/deleting the mount point if they are not shared files/folders | // do not allow renaming/deleting the mount point if they are not shared files/folders | ||||
// for shared files/folders we use the permissions given by the owner | // for shared files/folders we use the permissions given by the owner | ||||
if ($subStorage instanceof \OC\Files\Storage\Shared) { | if ($subStorage instanceof \OC\Files\Storage\Shared) { |
if (isset($uidOwner)) { | if (isset($uidOwner)) { | ||||
if ($fileDependent) { | if ($fileDependent) { | ||||
$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,' | $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,' | ||||
. ' `share_type`, `share_with`, `file_source`, `path`, `permissions`, `stime`,' | |||||
. ' `share_type`, `share_with`, `file_source`, `path`, `*PREFIX*share`.`permissions`, `stime`,' | |||||
. ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`'; | . ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`'; | ||||
} else { | } else { | ||||
$select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `permissions`,' | |||||
$select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,' | |||||
. ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`'; | . ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`'; | ||||
} | } | ||||
} else { | } else { | ||||
if ($format == \OC_Share_Backend_File::FORMAT_GET_FOLDER_CONTENTS || $format == \OC_Share_Backend_File::FORMAT_FILE_APP_ROOT) { | if ($format == \OC_Share_Backend_File::FORMAT_GET_FOLDER_CONTENTS || $format == \OC_Share_Backend_File::FORMAT_FILE_APP_ROOT) { | ||||
$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, ' | $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, ' | ||||
. '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, ' | . '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, ' | ||||
. '`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, ' | |||||
. '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, ' | |||||
. '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `unencrypted_size`, `encrypted`, `etag`, `mail_send`'; | . '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `unencrypted_size`, `encrypted`, `etag`, `mail_send`'; | ||||
} else { | } else { | ||||
$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`, | $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`, | ||||
`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`, | `*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`, | ||||
`file_source`, `path`, `file_target`, `permissions`, `stime`, `expiration`, `token`, `storage`, `mail_send`'; | |||||
`file_source`, `path`, `file_target`, `*PREFIX*share`.`permissions`, `stime`, `expiration`, `token`, `storage`, `mail_send`'; | |||||
} | } | ||||
} | } | ||||
} | } |
<?php | |||||
/** | |||||
* Copyright (c) 2012 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 Test\Files\Cache; | |||||
use OC\Files\Storage\Temporary; | |||||
class Permissions extends \PHPUnit_Framework_TestCase { | |||||
/*** | |||||
* @var \OC\Files\Cache\Permissions $permissionsCache | |||||
*/ | |||||
private $permissionsCache; | |||||
function setUp() { | |||||
$this->permissionsCache = new \OC\Files\Cache\Permissions('dummy'); | |||||
} | |||||
function testSimple() { | |||||
$ids = range(1, 10); | |||||
$user = uniqid(); | |||||
$this->assertEquals(-1, $this->permissionsCache->get(1, $user)); | |||||
$this->assertNotContains($user, $this->permissionsCache->getUsers(1)); | |||||
$this->permissionsCache->set(1, $user, 1); | |||||
$this->assertEquals(1, $this->permissionsCache->get(1, $user)); | |||||
$this->assertContains($user, $this->permissionsCache->getUsers(1)); | |||||
$this->assertEquals(-1, $this->permissionsCache->get(2, $user)); | |||||
$this->assertEquals(-1, $this->permissionsCache->get(1, $user . '2')); | |||||
$this->permissionsCache->set(1, $user, 2); | |||||
$this->assertEquals(2, $this->permissionsCache->get(1, $user)); | |||||
$this->permissionsCache->set(2, $user, 1); | |||||
$this->assertEquals(1, $this->permissionsCache->get(2, $user)); | |||||
$this->permissionsCache->remove(1, $user); | |||||
$this->assertEquals(-1, $this->permissionsCache->get(1, $user)); | |||||
$this->permissionsCache->remove(1, $user . '2'); | |||||
$this->assertEquals(1, $this->permissionsCache->get(2, $user)); | |||||
$expected = array(); | |||||
foreach ($ids as $id) { | |||||
$this->permissionsCache->set($id, $user, 10 + $id); | |||||
$expected[$id] = 10 + $id; | |||||
} | |||||
$this->assertEquals($expected, $this->permissionsCache->getMultiple($ids, $user)); | |||||
$this->permissionsCache->removeMultiple(array(10, 9), $user); | |||||
unset($expected[9]); | |||||
unset($expected[10]); | |||||
$this->assertEquals($expected, $this->permissionsCache->getMultiple($ids, $user)); | |||||
$this->permissionsCache->removeMultiple($ids, $user); | |||||
} | |||||
public function testUpdatePermissionsOnRescan() { | |||||
$storage = new Temporary(array()); | |||||
$scanner = $storage->getScanner(); | |||||
$cache = $storage->getCache(); | |||||
$permissionsCache = $storage->getPermissionsCache(); | |||||
$storage->file_put_contents('foo.txt', 'bar'); | |||||
$scanner->scan(''); | |||||
$id = $cache->getId('foo.txt'); | |||||
$permissionsCache->set($id, 'test', 1); | |||||
$scanner->scan(''); | |||||
$this->assertEquals(-1, $permissionsCache->get($id, 'test')); | |||||
} | |||||
} |
function tearDown() { | function tearDown() { | ||||
if ($this->cache) { | if ($this->cache) { | ||||
$ids = $this->cache->getAll(); | $ids = $this->cache->getAll(); | ||||
$permissionsCache = $this->storage->getPermissionsCache(); | |||||
$permissionsCache->removeMultiple($ids, \OC_User::getUser()); | |||||
$this->cache->clear(); | $this->cache->clear(); | ||||
} | } | ||||
} | } |
$this->assertEquals($time, $cachedData['mtime']); | $this->assertEquals($time, $cachedData['mtime']); | ||||
} | } | ||||
public function testUpdatePermissionsOnRescanOnlyForUpdatedFile() { | |||||
$permissionsCache = $this->storage->getPermissionsCache(); | |||||
$scanner = $this->storage->getScanner(); | |||||
$scanner->scan(''); | |||||
$cache = $this->storage->getCache(); | |||||
$loggedInUser = \OC_User::getUser(); | |||||
\OC_User::setUserId(self::$user); | |||||
FileSystem::getDirectoryContent('/'); | |||||
$past = time() - 600; | |||||
$cache->put('', array('storage_mtime' => $past)); | |||||
$this->assertNotEquals(-1, $permissionsCache->get($cache->getId('foo.txt'), self::$user)); | |||||
$this->assertNotEquals(-1, $permissionsCache->get($cache->getId('foo.png'), self::$user)); | |||||
$permissionsCache->set($cache->getId('foo.png'), self::$user, 15); | |||||
FileSystem::file_put_contents('/foo.txt', 'asd'); | |||||
$this->assertEquals(-1, $permissionsCache->get($cache->getId('foo.txt'), self::$user)); | |||||
$this->assertEquals(15, $permissionsCache->get($cache->getId('foo.png'), self::$user)); | |||||
FileSystem::getDirectoryContent('/'); | |||||
$this->assertEquals(15, $permissionsCache->get($cache->getId('foo.png'), self::$user)); | |||||
FileSystem::file_put_contents('/qwerty.txt', 'asd'); | |||||
FileSystem::getDirectoryContent('/'); | |||||
$this->assertEquals(15, $permissionsCache->get($cache->getId('foo.png'), self::$user)); | |||||
\OC_User::setUserId($loggedInUser); | |||||
} | |||||
} | } |
foreach ($this->storages as $storage) { | foreach ($this->storages as $storage) { | ||||
$cache = $storage->getCache(); | $cache = $storage->getCache(); | ||||
$ids = $cache->getAll(); | $ids = $cache->getAll(); | ||||
$permissionsCache = $storage->getPermissionsCache(); | |||||
$permissionsCache->removeMultiple($ids, \OC_User::getUser()); | |||||
$cache->clear(); | $cache->clear(); | ||||
} | } | ||||
} | } |
array('fileid' => 3, 'path' => '/bar/foo/qwerty', 'name' => 'qwerty', 'size' => 200, 'mtime' => 55, 'mimetype' => 'httpd/unix-directory') | array('fileid' => 3, 'path' => '/bar/foo/qwerty', 'name' => 'qwerty', 'size' => 200, 'mtime' => 55, 'mimetype' => 'httpd/unix-directory') | ||||
))); | ))); | ||||
$permissionsCache = $this->getMock('\OC\Files\Cache\Permissions', array(), array('/')); | |||||
$permissionsCache->expects($this->once()) | |||||
->method('getDirectoryPermissions') | |||||
->will($this->returnValue(array(2 => \OCP\PERMISSION_ALL))); | |||||
$root->expects($this->once()) | $root->expects($this->once()) | ||||
->method('getMountsIn') | ->method('getMountsIn') | ||||
->with('/bar/foo') | ->with('/bar/foo') | ||||
->will($this->returnValue(array())); | ->will($this->returnValue(array())); | ||||
$storage->expects($this->any()) | |||||
->method('getPermissionsCache') | |||||
->will($this->returnValue($permissionsCache)); | |||||
$storage->expects($this->any()) | $storage->expects($this->any()) | ||||
->method('getCache') | ->method('getCache') | ||||
->will($this->returnValue($cache)); | ->will($this->returnValue($cache)); |
foreach ($this->storages as $storage) { | foreach ($this->storages as $storage) { | ||||
$cache = $storage->getCache(); | $cache = $storage->getCache(); | ||||
$ids = $cache->getAll(); | $ids = $cache->getAll(); | ||||
$permissionsCache = $storage->getPermissionsCache(); | |||||
$permissionsCache->removeMultiple($ids, \OC_User::getUser()); | |||||
$cache->clear(); | $cache->clear(); | ||||
} | } | ||||
} | } |
// We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades | // We only can count up. The 4. digit is only for the internal patchlevel to trigger DB upgrades | ||||
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel | // between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel | ||||
// when updating major/minor version number. | // when updating major/minor version number. | ||||
$OC_Version=array(6, 90, 0, 3); | |||||
$OC_Version=array(6, 90, 0, 4); | |||||
// The human readable string | // The human readable string | ||||
$OC_VersionString='7.0 pre alpha'; | $OC_VersionString='7.0 pre alpha'; |