2013-09-01 21:47:48 +04:00
|
|
|
<?php
|
|
|
|
/**
|
2016-07-21 18:07:57 +03:00
|
|
|
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
|
|
|
*
|
2019-12-03 21:57:53 +03:00
|
|
|
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
|
2020-03-31 11:49:10 +03:00
|
|
|
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
2020-08-24 15:54:25 +03:00
|
|
|
* @author Georg Ehrke <oc.list@georgehrke.com>
|
2016-07-21 18:07:57 +03:00
|
|
|
* @author Joas Schilling <coding@schilljs.com>
|
2019-12-03 21:57:53 +03:00
|
|
|
* @author Julius Härtl <jus@bitgrid.net>
|
2015-03-26 13:44:34 +03:00
|
|
|
* @author Morris Jobke <hey@morrisjobke.de>
|
2016-07-21 19:13:36 +03:00
|
|
|
* @author Robin Appelman <robin@icewind.nl>
|
2016-01-12 17:02:16 +03:00
|
|
|
* @author Robin McCorkell <robin@mccorkell.me.uk>
|
2019-12-03 21:57:53 +03:00
|
|
|
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
2020-12-16 16:54:15 +03:00
|
|
|
* @author Vincent Petry <vincent@nextcloud.com>
|
2015-03-26 13:44:34 +03:00
|
|
|
*
|
|
|
|
* @license AGPL-3.0
|
|
|
|
*
|
|
|
|
* This code is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License, version 3,
|
|
|
|
* as published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program 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, version 3,
|
2019-12-03 21:57:53 +03:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
2015-03-26 13:44:34 +03:00
|
|
|
*
|
2013-09-01 21:47:48 +04:00
|
|
|
*/
|
2015-02-26 13:37:37 +03:00
|
|
|
|
2013-09-01 21:47:48 +04:00
|
|
|
namespace OC\Files\Node;
|
|
|
|
|
2021-03-19 15:41:00 +03:00
|
|
|
use OC\Files\Search\SearchBinaryOperator;
|
2021-03-18 18:35:41 +03:00
|
|
|
use OC\Files\Search\SearchComparison;
|
2021-03-26 19:10:25 +03:00
|
|
|
use OC\Files\Search\SearchOrder;
|
2021-03-18 18:35:41 +03:00
|
|
|
use OC\Files\Search\SearchQuery;
|
2021-03-19 15:35:37 +03:00
|
|
|
use OCP\Files\Cache\ICacheEntry;
|
2016-09-18 19:36:53 +03:00
|
|
|
use OCP\Files\Config\ICachedMountInfo;
|
2015-09-08 23:38:50 +03:00
|
|
|
use OCP\Files\FileInfo;
|
2016-07-22 15:37:37 +03:00
|
|
|
use OCP\Files\Mount\IMountPoint;
|
2013-09-10 21:44:23 +04:00
|
|
|
use OCP\Files\NotFoundException;
|
|
|
|
use OCP\Files\NotPermittedException;
|
2021-03-19 15:41:00 +03:00
|
|
|
use OCP\Files\Search\ISearchBinaryOperator;
|
2021-03-18 18:35:41 +03:00
|
|
|
use OCP\Files\Search\ISearchComparison;
|
|
|
|
use OCP\Files\Search\ISearchOperator;
|
2021-03-26 19:10:25 +03:00
|
|
|
use OCP\Files\Search\ISearchOrder;
|
2019-11-08 17:05:21 +03:00
|
|
|
use OCP\Files\Search\ISearchQuery;
|
2021-03-18 18:35:41 +03:00
|
|
|
use OCP\IUserManager;
|
2013-09-01 21:47:48 +04:00
|
|
|
|
2013-09-10 21:44:23 +04:00
|
|
|
class Folder extends Node implements \OCP\Files\Folder {
|
2016-11-14 20:29:11 +03:00
|
|
|
/**
|
|
|
|
* Creates a Folder that represents a non-existing path
|
|
|
|
*
|
|
|
|
* @param string $path path
|
|
|
|
* @return string non-existing node class
|
|
|
|
*/
|
|
|
|
protected function createNonExistingNode($path) {
|
|
|
|
return new NonExistingFolder($this->root, $this->view, $path);
|
|
|
|
}
|
|
|
|
|
2013-09-01 21:47:48 +04:00
|
|
|
/**
|
|
|
|
* @param string $path path relative to the folder
|
|
|
|
* @return string
|
2013-09-10 21:44:23 +04:00
|
|
|
* @throws \OCP\Files\NotPermittedException
|
2013-09-01 21:47:48 +04:00
|
|
|
*/
|
|
|
|
public function getFullPath($path) {
|
|
|
|
if (!$this->isValidPath($path)) {
|
2016-10-24 12:32:17 +03:00
|
|
|
throw new NotPermittedException('Invalid path');
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|
|
|
|
return $this->path . $this->normalizePath($path);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $path
|
2021-03-19 20:13:59 +03:00
|
|
|
* @return string|null
|
2013-09-01 21:47:48 +04:00
|
|
|
*/
|
|
|
|
public function getRelativePath($path) {
|
|
|
|
if ($this->path === '' or $this->path === '/') {
|
|
|
|
return $this->normalizePath($path);
|
|
|
|
}
|
2014-08-05 18:58:10 +04:00
|
|
|
if ($path === $this->path) {
|
|
|
|
return '/';
|
2020-04-10 11:35:09 +03:00
|
|
|
} elseif (strpos($path, $this->path . '/') !== 0) {
|
2014-08-06 14:06:41 +04:00
|
|
|
return null;
|
2013-09-01 21:47:48 +04:00
|
|
|
} else {
|
|
|
|
$path = substr($path, strlen($this->path));
|
2014-08-05 18:58:10 +04:00
|
|
|
return $this->normalizePath($path);
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* check if a node is a (grand-)child of the folder
|
|
|
|
*
|
|
|
|
* @param \OC\Files\Node\Node $node
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function isSubNode($node) {
|
|
|
|
return strpos($node->getPath(), $this->path . '/') === 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get the content of this directory
|
|
|
|
*
|
|
|
|
* @return Node[]
|
2021-03-18 18:35:41 +03:00
|
|
|
* @throws \OCP\Files\NotFoundException
|
2013-09-01 21:47:48 +04:00
|
|
|
*/
|
|
|
|
public function getDirectoryListing() {
|
2015-09-08 23:38:50 +03:00
|
|
|
$folderContent = $this->view->getDirectoryContent($this->path);
|
2013-09-01 21:47:48 +04:00
|
|
|
|
2016-09-18 19:36:53 +03:00
|
|
|
return array_map(function (FileInfo $info) {
|
2015-09-08 23:38:50 +03:00
|
|
|
if ($info->getMimetype() === 'httpd/unix-directory') {
|
|
|
|
return new Folder($this->root, $this->view, $info->getPath(), $info);
|
|
|
|
} else {
|
|
|
|
return new File($this->root, $this->view, $info->getPath(), $info);
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|
2015-09-08 23:38:50 +03:00
|
|
|
}, $folderContent);
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $path
|
2016-03-21 16:20:33 +03:00
|
|
|
* @param FileInfo $info
|
2013-09-01 21:47:48 +04:00
|
|
|
* @return File|Folder
|
|
|
|
*/
|
2016-03-21 16:20:33 +03:00
|
|
|
protected function createNode($path, FileInfo $info = null) {
|
|
|
|
if (is_null($info)) {
|
2013-09-01 21:47:48 +04:00
|
|
|
$isDir = $this->view->is_dir($path);
|
|
|
|
} else {
|
2016-03-21 16:20:33 +03:00
|
|
|
$isDir = $info->getType() === FileInfo::TYPE_FOLDER;
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|
|
|
|
if ($isDir) {
|
2016-02-18 17:41:10 +03:00
|
|
|
return new Folder($this->root, $this->view, $path, $info);
|
2013-09-01 21:47:48 +04:00
|
|
|
} else {
|
2016-02-18 17:41:10 +03:00
|
|
|
return new File($this->root, $this->view, $path, $info);
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the node at $path
|
|
|
|
*
|
|
|
|
* @param string $path
|
|
|
|
* @return \OC\Files\Node\Node
|
2013-09-10 21:44:23 +04:00
|
|
|
* @throws \OCP\Files\NotFoundException
|
2013-09-01 21:47:48 +04:00
|
|
|
*/
|
|
|
|
public function get($path) {
|
|
|
|
return $this->root->get($this->getFullPath($path));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $path
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function nodeExists($path) {
|
|
|
|
try {
|
|
|
|
$this->get($path);
|
|
|
|
return true;
|
|
|
|
} catch (NotFoundException $e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $path
|
2013-09-10 21:44:23 +04:00
|
|
|
* @return \OC\Files\Node\Folder
|
|
|
|
* @throws \OCP\Files\NotPermittedException
|
2013-09-01 21:47:48 +04:00
|
|
|
*/
|
|
|
|
public function newFolder($path) {
|
2014-11-25 18:28:41 +03:00
|
|
|
if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
|
2013-09-01 21:47:48 +04:00
|
|
|
$fullPath = $this->getFullPath($path);
|
|
|
|
$nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
|
2019-09-03 13:30:10 +03:00
|
|
|
$this->sendHooks(['preWrite', 'preCreate'], [$nonExisting]);
|
2020-04-10 15:19:56 +03:00
|
|
|
if (!$this->view->mkdir($fullPath)) {
|
2019-04-29 17:12:01 +03:00
|
|
|
throw new NotPermittedException('Could not create folder');
|
|
|
|
}
|
2013-09-01 21:47:48 +04:00
|
|
|
$node = new Folder($this->root, $this->view, $fullPath);
|
2019-09-03 13:30:10 +03:00
|
|
|
$this->sendHooks(['postWrite', 'postCreate'], [$node]);
|
2013-09-01 21:47:48 +04:00
|
|
|
return $node;
|
|
|
|
} else {
|
2016-10-24 12:32:17 +03:00
|
|
|
throw new NotPermittedException('No create permission for folder');
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $path
|
2020-02-16 03:14:52 +03:00
|
|
|
* @param string | resource | null $content
|
2013-09-10 21:44:23 +04:00
|
|
|
* @return \OC\Files\Node\File
|
|
|
|
* @throws \OCP\Files\NotPermittedException
|
2013-09-01 21:47:48 +04:00
|
|
|
*/
|
2020-02-16 03:14:52 +03:00
|
|
|
public function newFile($path, $content = null) {
|
2021-04-20 12:20:20 +03:00
|
|
|
if (empty($path)) {
|
|
|
|
throw new NotPermittedException('Could not create as provided path is empty');
|
|
|
|
}
|
2014-11-25 18:28:41 +03:00
|
|
|
if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
|
2013-09-01 21:47:48 +04:00
|
|
|
$fullPath = $this->getFullPath($path);
|
|
|
|
$nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
|
2019-09-03 13:30:10 +03:00
|
|
|
$this->sendHooks(['preWrite', 'preCreate'], [$nonExisting]);
|
2020-02-16 03:14:52 +03:00
|
|
|
if ($content !== null) {
|
|
|
|
$result = $this->view->file_put_contents($fullPath, $content);
|
|
|
|
} else {
|
|
|
|
$result = $this->view->touch($fullPath);
|
|
|
|
}
|
2020-08-13 16:41:26 +03:00
|
|
|
if ($result === false) {
|
2019-05-28 14:05:20 +03:00
|
|
|
throw new NotPermittedException('Could not create path');
|
|
|
|
}
|
2013-09-01 21:47:48 +04:00
|
|
|
$node = new File($this->root, $this->view, $fullPath);
|
2019-09-03 13:30:10 +03:00
|
|
|
$this->sendHooks(['postWrite', 'postCreate'], [$node]);
|
2013-09-01 21:47:48 +04:00
|
|
|
return $node;
|
|
|
|
}
|
2019-05-28 14:05:20 +03:00
|
|
|
throw new NotPermittedException('No create permission for path');
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|
|
|
|
|
2021-03-18 18:35:41 +03:00
|
|
|
private function queryFromOperator(ISearchOperator $operator, string $uid = null): ISearchQuery {
|
2021-03-18 19:38:31 +03:00
|
|
|
if ($uid === null) {
|
|
|
|
$user = null;
|
2021-03-18 18:35:41 +03:00
|
|
|
} else {
|
|
|
|
/** @var IUserManager $userManager */
|
|
|
|
$userManager = \OC::$server->query(IUserManager::class);
|
|
|
|
$user = $userManager->get($uid);
|
|
|
|
}
|
|
|
|
return new SearchQuery($operator, 0, 0, [], $user);
|
|
|
|
}
|
|
|
|
|
2013-09-01 21:47:48 +04:00
|
|
|
/**
|
|
|
|
* search for files with the name matching $query
|
|
|
|
*
|
2019-11-08 17:05:21 +03:00
|
|
|
* @param string|ISearchQuery $query
|
2013-09-10 21:44:23 +04:00
|
|
|
* @return \OC\Files\Node\Node[]
|
2013-09-01 21:47:48 +04:00
|
|
|
*/
|
|
|
|
public function search($query) {
|
2017-02-02 20:20:08 +03:00
|
|
|
if (is_string($query)) {
|
2021-03-18 18:35:41 +03:00
|
|
|
$query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%' . $query . '%'));
|
2017-02-02 20:20:08 +03:00
|
|
|
}
|
2013-09-01 21:47:48 +04:00
|
|
|
|
2021-03-19 16:26:44 +03:00
|
|
|
// Limit+offset for queries with ordering
|
2021-03-19 15:35:37 +03:00
|
|
|
//
|
2021-03-19 16:26:44 +03:00
|
|
|
// Because we currently can't do ordering between the results from different storages in sql
|
|
|
|
// The only way to do ordering is requesting the $limit number of entries from all storages
|
|
|
|
// sorting them and returning the first $limit entries.
|
2021-03-18 19:38:31 +03:00
|
|
|
//
|
2021-03-19 16:26:44 +03:00
|
|
|
// For offset we have the same problem, we don't know how many entries from each storage should be skipped
|
|
|
|
// by a given $offset, so instead we query $offset + $limit from each storage and return entries $offset..($offset+$limit)
|
|
|
|
// after merging and sorting them.
|
2021-03-19 15:35:37 +03:00
|
|
|
//
|
2021-03-19 16:26:44 +03:00
|
|
|
// This is suboptimal but because limit and offset tend to be fairly small in real world use cases it should
|
|
|
|
// still be significantly better than disabling paging altogether
|
2021-03-18 19:38:31 +03:00
|
|
|
|
2021-03-18 18:35:41 +03:00
|
|
|
$limitToHome = $query->limitToHome();
|
2019-11-08 17:05:21 +03:00
|
|
|
if ($limitToHome && count(explode('/', $this->path)) !== 3) {
|
|
|
|
throw new \InvalidArgumentException('searching by owner is only allows on the users home folder');
|
|
|
|
}
|
|
|
|
|
2021-03-19 15:41:00 +03:00
|
|
|
$rootLength = strlen($this->path);
|
|
|
|
$mount = $this->root->getMount($this->path);
|
|
|
|
$storage = $mount->getStorage();
|
|
|
|
$internalPath = $mount->getInternalPath($this->path);
|
|
|
|
$internalPath = rtrim($internalPath, '/');
|
|
|
|
if ($internalPath !== '') {
|
|
|
|
$internalPath = $internalPath . '/';
|
|
|
|
}
|
|
|
|
|
2021-03-19 16:26:44 +03:00
|
|
|
$subQueryLimit = $query->getLimit() > 0 ? $query->getLimit() + $query->getOffset() : 0;
|
2021-03-19 15:41:00 +03:00
|
|
|
$rootQuery = new SearchQuery(
|
|
|
|
new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_AND, [
|
2021-03-19 16:26:44 +03:00
|
|
|
new SearchComparison(ISearchComparison::COMPARE_LIKE, 'path', $internalPath . '%'),
|
|
|
|
$query->getSearchOperation(),
|
2021-03-26 19:10:25 +03:00
|
|
|
]),
|
2021-03-18 19:38:31 +03:00
|
|
|
$subQueryLimit,
|
|
|
|
0,
|
|
|
|
$query->getOrder(),
|
|
|
|
$query->getUser()
|
|
|
|
);
|
|
|
|
|
2020-03-26 11:30:18 +03:00
|
|
|
$files = [];
|
2013-09-01 21:47:48 +04:00
|
|
|
|
|
|
|
$cache = $storage->getCache('');
|
|
|
|
|
2021-03-19 15:41:00 +03:00
|
|
|
$results = $cache->searchQuery($rootQuery);
|
2013-09-01 21:47:48 +04:00
|
|
|
foreach ($results as $result) {
|
2021-03-19 15:41:00 +03:00
|
|
|
$files[] = $this->cacheEntryToFileInfo($mount, '', $internalPath, $result);
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|
|
|
|
|
2019-11-08 17:05:21 +03:00
|
|
|
if (!$limitToHome) {
|
|
|
|
$mounts = $this->root->getMountsIn($this->path);
|
|
|
|
foreach ($mounts as $mount) {
|
2021-03-18 19:38:31 +03:00
|
|
|
$subQuery = new SearchQuery(
|
|
|
|
$query->getSearchOperation(),
|
|
|
|
$subQueryLimit,
|
|
|
|
0,
|
|
|
|
$query->getOrder(),
|
|
|
|
$query->getUser()
|
|
|
|
);
|
|
|
|
|
2019-11-08 17:05:21 +03:00
|
|
|
$storage = $mount->getStorage();
|
|
|
|
if ($storage) {
|
|
|
|
$cache = $storage->getCache('');
|
2013-09-01 21:47:48 +04:00
|
|
|
|
2019-11-08 17:05:21 +03:00
|
|
|
$relativeMountPoint = ltrim(substr($mount->getMountPoint(), $rootLength), '/');
|
2021-03-18 19:38:31 +03:00
|
|
|
$results = $cache->searchQuery($subQuery);
|
2019-11-08 17:05:21 +03:00
|
|
|
foreach ($results as $result) {
|
2021-03-19 15:35:37 +03:00
|
|
|
$files[] = $this->cacheEntryToFileInfo($mount, $relativeMountPoint, '', $result);
|
2019-11-08 17:05:21 +03:00
|
|
|
}
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-19 16:26:44 +03:00
|
|
|
$order = $query->getOrder();
|
|
|
|
if ($order) {
|
2021-03-26 19:10:25 +03:00
|
|
|
usort($files, function (FileInfo $a, FileInfo $b) use ($order) {
|
2021-03-19 16:26:44 +03:00
|
|
|
foreach ($order as $orderField) {
|
|
|
|
$cmp = $orderField->sortFileInfo($a, $b);
|
|
|
|
if ($cmp !== 0) {
|
|
|
|
return $cmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
$files = array_values(array_slice($files, $query->getOffset(), $query->getLimit() > 0 ? $query->getLimit() : null));
|
|
|
|
|
2016-09-18 19:36:53 +03:00
|
|
|
return array_map(function (FileInfo $file) {
|
2016-03-21 16:20:33 +03:00
|
|
|
return $this->createNode($file->getPath(), $file);
|
|
|
|
}, $files);
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|
|
|
|
|
2021-03-19 15:35:37 +03:00
|
|
|
private function cacheEntryToFileInfo(IMountPoint $mount, string $appendRoot, string $trimRoot, ICacheEntry $cacheEntry): FileInfo {
|
|
|
|
$trimLength = strlen($trimRoot);
|
|
|
|
$cacheEntry['internalPath'] = $cacheEntry['path'];
|
2021-03-19 15:41:00 +03:00
|
|
|
$cacheEntry['path'] = $appendRoot . substr($cacheEntry['path'], $trimLength);
|
2021-03-19 15:35:37 +03:00
|
|
|
return new \OC\Files\FileInfo($this->path . '/' . $cacheEntry['path'], $mount->getStorage(), $cacheEntry['internalPath'], $cacheEntry, $mount);
|
|
|
|
}
|
|
|
|
|
2021-03-18 18:35:41 +03:00
|
|
|
/**
|
|
|
|
* search for files by mimetype
|
|
|
|
*
|
|
|
|
* @param string $mimetype
|
|
|
|
* @return Node[]
|
|
|
|
*/
|
|
|
|
public function searchByMime($mimetype) {
|
|
|
|
if (strpos($mimetype, '/') === false) {
|
|
|
|
$query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', $mimetype . '/%'));
|
|
|
|
} else {
|
|
|
|
$query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', $mimetype));
|
|
|
|
}
|
|
|
|
return $this->search($query);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* search for files by tag
|
|
|
|
*
|
|
|
|
* @param string|int $tag name or tag id
|
|
|
|
* @param string $userId owner of the tags
|
|
|
|
* @return Node[]
|
|
|
|
*/
|
|
|
|
public function searchByTag($tag, $userId) {
|
|
|
|
$query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'tagname', $tag), $userId);
|
|
|
|
return $this->search($query);
|
|
|
|
}
|
|
|
|
|
2013-09-01 21:47:48 +04:00
|
|
|
/**
|
2014-05-12 00:51:30 +04:00
|
|
|
* @param int $id
|
2013-09-10 21:44:23 +04:00
|
|
|
* @return \OC\Files\Node\Node[]
|
2013-09-01 21:47:48 +04:00
|
|
|
*/
|
|
|
|
public function getById($id) {
|
2016-09-18 19:36:53 +03:00
|
|
|
$mountCache = $this->root->getUserMountCache();
|
2017-04-21 18:11:26 +03:00
|
|
|
if (strpos($this->getPath(), '/', 1) > 0) {
|
2021-01-12 12:15:48 +03:00
|
|
|
[, $user] = explode('/', $this->getPath());
|
2017-04-21 18:11:26 +03:00
|
|
|
} else {
|
|
|
|
$user = null;
|
|
|
|
}
|
|
|
|
$mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
|
2014-08-05 18:58:10 +04:00
|
|
|
$mounts = $this->root->getMountsIn($this->path);
|
|
|
|
$mounts[] = $this->root->getMount($this->path);
|
2016-09-18 19:36:53 +03:00
|
|
|
/** @var IMountPoint[] $folderMounts */
|
|
|
|
$folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
|
|
|
|
return $mountPoint->getMountPoint();
|
|
|
|
}, $mounts), $mounts);
|
2014-08-05 18:58:10 +04:00
|
|
|
|
2016-09-18 19:36:53 +03:00
|
|
|
/** @var ICachedMountInfo[] $mountsContainingFile */
|
|
|
|
$mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
|
|
|
|
return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
|
|
|
|
}));
|
|
|
|
|
|
|
|
if (count($mountsContainingFile) === 0) {
|
2019-09-17 12:15:59 +03:00
|
|
|
if ($user === $this->getAppDataDirectoryName()) {
|
2021-03-18 18:35:41 +03:00
|
|
|
return $this->getByIdInRootMount((int)$id);
|
2019-09-17 12:15:59 +03:00
|
|
|
}
|
2016-09-18 19:36:53 +03:00
|
|
|
return [];
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|
2016-09-18 19:36:53 +03:00
|
|
|
|
2018-03-20 00:05:04 +03:00
|
|
|
$nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($folderMounts, $id) {
|
2016-09-18 19:36:53 +03:00
|
|
|
$mount = $folderMounts[$cachedMountInfo->getMountPoint()];
|
2018-03-20 00:05:04 +03:00
|
|
|
$cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
|
|
|
|
if (!$cacheEntry) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// cache jails will hide the "true" internal path
|
|
|
|
$internalPath = ltrim($cachedMountInfo->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
|
2016-09-18 19:36:53 +03:00
|
|
|
$pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
|
|
|
|
$pathRelativeToMount = ltrim($pathRelativeToMount, '/');
|
2018-11-28 17:18:29 +03:00
|
|
|
$absolutePath = rtrim($cachedMountInfo->getMountPoint() . $pathRelativeToMount, '/');
|
2016-09-18 19:36:53 +03:00
|
|
|
return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
|
|
|
|
$absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
|
|
|
|
\OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
|
|
|
|
));
|
|
|
|
}, $mountsContainingFile);
|
|
|
|
|
2018-03-20 00:05:04 +03:00
|
|
|
$nodes = array_filter($nodes);
|
|
|
|
|
2016-09-18 19:36:53 +03:00
|
|
|
return array_filter($nodes, function (Node $node) {
|
|
|
|
return $this->getRelativePath($node->getPath());
|
|
|
|
});
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|
|
|
|
|
2019-09-17 12:15:59 +03:00
|
|
|
protected function getAppDataDirectoryName(): string {
|
|
|
|
$instanceId = \OC::$server->getConfig()->getSystemValueString('instanceid');
|
|
|
|
return 'appdata_' . $instanceId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* In case the path we are currently in is inside the appdata_* folder,
|
|
|
|
* the original getById method does not work, because it can only look inside
|
|
|
|
* the user's mount points. But the user has no mount point for the root storage.
|
|
|
|
*
|
|
|
|
* So in that case we directly check the mount of the root if it contains
|
|
|
|
* the id. If it does we check if the path is inside the path we are working
|
|
|
|
* in.
|
|
|
|
*
|
|
|
|
* @param int $id
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
protected function getByIdInRootMount(int $id): array {
|
|
|
|
$mount = $this->root->getMount('');
|
|
|
|
$cacheEntry = $mount->getStorage()->getCache($this->path)->get($id);
|
|
|
|
if (!$cacheEntry) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
$absolutePath = '/' . ltrim($cacheEntry->getPath(), '/');
|
|
|
|
$currentPath = rtrim($this->path, '/') . '/';
|
|
|
|
|
|
|
|
if (strpos($absolutePath, $currentPath) !== 0) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
return [$this->root->createNode(
|
|
|
|
$absolutePath, new \OC\Files\FileInfo(
|
2021-03-18 18:35:41 +03:00
|
|
|
$absolutePath,
|
|
|
|
$mount->getStorage(),
|
|
|
|
$cacheEntry->getPath(),
|
|
|
|
$cacheEntry,
|
|
|
|
$mount
|
2019-09-17 12:15:59 +03:00
|
|
|
))];
|
|
|
|
}
|
|
|
|
|
2013-09-01 21:47:48 +04:00
|
|
|
public function getFreeSpace() {
|
|
|
|
return $this->view->free_space($this->path);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function delete() {
|
2014-11-25 18:28:41 +03:00
|
|
|
if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
|
2020-03-26 11:30:18 +03:00
|
|
|
$this->sendHooks(['preDelete']);
|
2015-12-01 15:22:58 +03:00
|
|
|
$fileInfo = $this->getFileInfo();
|
2013-09-01 21:47:48 +04:00
|
|
|
$this->view->rmdir($this->path);
|
2015-12-01 15:22:58 +03:00
|
|
|
$nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
|
2019-09-03 13:30:10 +03:00
|
|
|
$this->sendHooks(['postDelete'], [$nonExisting]);
|
2013-09-01 21:47:48 +04:00
|
|
|
$this->exists = false;
|
|
|
|
} else {
|
2016-10-24 12:32:17 +03:00
|
|
|
throw new NotPermittedException('No delete permission for path');
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-24 17:00:36 +03:00
|
|
|
/**
|
|
|
|
* Add a suffix to the name in case the file exists
|
|
|
|
*
|
|
|
|
* @param string $name
|
|
|
|
* @return string
|
|
|
|
* @throws NotPermittedException
|
|
|
|
*/
|
|
|
|
public function getNonExistingName($name) {
|
|
|
|
$uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
|
|
|
|
return trim($this->getRelativePath($uniqueName), '/');
|
|
|
|
}
|
2016-07-22 15:37:37 +03:00
|
|
|
|
|
|
|
/**
|
2016-07-22 14:58:53 +03:00
|
|
|
* @param int $limit
|
|
|
|
* @param int $offset
|
2016-07-22 15:37:37 +03:00
|
|
|
* @return \OCP\Files\Node[]
|
|
|
|
*/
|
2016-07-22 14:58:53 +03:00
|
|
|
public function getRecent($limit, $offset = 0) {
|
2021-03-26 19:10:25 +03:00
|
|
|
$query = new SearchQuery(
|
|
|
|
new SearchBinaryOperator(
|
|
|
|
// filter out non empty folders
|
|
|
|
ISearchBinaryOperator::OPERATOR_OR,
|
|
|
|
[
|
|
|
|
new SearchBinaryOperator(
|
|
|
|
ISearchBinaryOperator::OPERATOR_NOT,
|
|
|
|
[
|
|
|
|
new SearchComparison(
|
|
|
|
ISearchComparison::COMPARE_EQUAL,
|
|
|
|
'mimetype',
|
|
|
|
FileInfo::MIMETYPE_FOLDER
|
|
|
|
),
|
|
|
|
]
|
|
|
|
),
|
|
|
|
new SearchComparison(
|
|
|
|
ISearchComparison::COMPARE_EQUAL,
|
|
|
|
'size',
|
|
|
|
0
|
|
|
|
),
|
|
|
|
]
|
|
|
|
),
|
|
|
|
$limit,
|
|
|
|
$offset,
|
|
|
|
[
|
|
|
|
new SearchOrder(
|
|
|
|
ISearchOrder::DIRECTION_DESCENDING,
|
|
|
|
'mtime'
|
|
|
|
),
|
|
|
|
]
|
|
|
|
);
|
|
|
|
return $this->search($query);
|
2016-07-22 15:37:37 +03:00
|
|
|
}
|
2013-09-01 21:47:48 +04:00
|
|
|
}
|