Skip to content

Commit 7ee34a3

Browse files
authored
Merge pull request #38150 from nextcloud/lazy-folder-parent
2 parents 70e5d42 + 5ac0e9b commit 7ee34a3

File tree

7 files changed

+107
-38
lines changed

7 files changed

+107
-38
lines changed

apps/files_trashbin/lib/Trash/TrashItem.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,4 +186,8 @@ public function getCreationTime(): int {
186186
public function getUploadTime(): int {
187187
return $this->fileInfo->getUploadTime();
188188
}
189+
190+
public function getParentId(): int {
191+
return $this->fileInfo->getParentId();
192+
}
189193
}

lib/private/Files/FileInfo.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,4 +412,8 @@ public function getCreationTime(): int {
412412
public function getUploadTime(): int {
413413
return (int) $this->data['upload_time'];
414414
}
415+
416+
public function getParentId(): int {
417+
return $this->data['parent'] ?? -1;
418+
}
415419
}

lib/private/Files/Node/LazyFolder.php

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,13 @@
2626

2727
namespace OC\Files\Node;
2828

29+
use OC\Files\Filesystem;
2930
use OC\Files\Utils\PathHelper;
3031
use OCP\Files\Folder;
3132
use OCP\Constants;
33+
use OCP\Files\IRootFolder;
3234
use OCP\Files\Mount\IMountPoint;
35+
use OCP\Files\NotPermittedException;
3336

3437
/**
3538
* Class LazyFolder
@@ -41,23 +44,33 @@
4144
*/
4245
class LazyFolder implements Folder {
4346
/** @var \Closure(): Folder */
44-
private $folderClosure;
45-
46-
/** @var LazyFolder | null */
47-
protected $folder = null;
48-
47+
private \Closure $folderClosure;
48+
protected ?Folder $folder = null;
49+
protected IRootFolder $rootFolder;
4950
protected array $data;
5051

5152
/**
52-
* LazyFolder constructor.
53-
*
53+
* @param IRootFolder $rootFolder
5454
* @param \Closure(): Folder $folderClosure
55+
* @param array $data
5556
*/
56-
public function __construct(\Closure $folderClosure, array $data = []) {
57+
public function __construct(IRootFolder $rootFolder, \Closure $folderClosure, array $data = []) {
58+
$this->rootFolder = $rootFolder;
5759
$this->folderClosure = $folderClosure;
5860
$this->data = $data;
5961
}
6062

63+
protected function getRootFolder(): IRootFolder {
64+
return $this->rootFolder;
65+
}
66+
67+
protected function getRealFolder(): Folder {
68+
if ($this->folder === null) {
69+
$this->folder = call_user_func($this->folderClosure);
70+
}
71+
return $this->folder;
72+
}
73+
6174
/**
6275
* Magic method to first get the real rootFolder and then
6376
* call $method with $args on it
@@ -67,11 +80,7 @@ public function __construct(\Closure $folderClosure, array $data = []) {
6780
* @return mixed
6881
*/
6982
public function __call($method, $args) {
70-
if ($this->folder === null) {
71-
$this->folder = call_user_func($this->folderClosure);
72-
}
73-
74-
return call_user_func_array([$this->folder, $method], $args);
83+
return call_user_func_array([$this->getRealFolder(), $method], $args);
7584
}
7685

7786
/**
@@ -148,7 +157,7 @@ public function unMount($mount) {
148157
* @inheritDoc
149158
*/
150159
public function get($path) {
151-
return $this->__call(__FUNCTION__, func_get_args());
160+
return $this->getRootFolder()->get($this->getFullPath($path));
152161
}
153162

154163
/**
@@ -207,6 +216,9 @@ public function getInternalPath() {
207216
* @inheritDoc
208217
*/
209218
public function getId() {
219+
if (isset($this->data['fileid'])) {
220+
return $this->data['fileid'];
221+
}
210222
return $this->__call(__FUNCTION__, func_get_args());
211223
}
212224

@@ -221,20 +233,29 @@ public function stat() {
221233
* @inheritDoc
222234
*/
223235
public function getMTime() {
236+
if (isset($this->data['mtime'])) {
237+
return $this->data['mtime'];
238+
}
224239
return $this->__call(__FUNCTION__, func_get_args());
225240
}
226241

227242
/**
228243
* @inheritDoc
229244
*/
230245
public function getSize($includeMounts = true): int|float {
246+
if (isset($this->data['size'])) {
247+
return $this->data['size'];
248+
}
231249
return $this->__call(__FUNCTION__, func_get_args());
232250
}
233251

234252
/**
235253
* @inheritDoc
236254
*/
237255
public function getEtag() {
256+
if (isset($this->data['etag'])) {
257+
return $this->data['etag'];
258+
}
238259
return $this->__call(__FUNCTION__, func_get_args());
239260
}
240261

@@ -299,6 +320,12 @@ public function getParent() {
299320
* @inheritDoc
300321
*/
301322
public function getName() {
323+
if (isset($this->data['path'])) {
324+
return basename($this->data['path']);
325+
}
326+
if (isset($this->data['name'])) {
327+
return $this->data['name'];
328+
}
302329
return $this->__call(__FUNCTION__, func_get_args());
303330
}
304331

@@ -390,6 +417,13 @@ public function getExtension(): string {
390417
* @inheritDoc
391418
*/
392419
public function getFullPath($path) {
420+
if (isset($this->data['path'])) {
421+
$path = PathHelper::normalizePath($path);
422+
if (!Filesystem::isValidPath($path)) {
423+
throw new NotPermittedException('Invalid path "' . $path . '"');
424+
}
425+
return $this->data['path'] . $path;
426+
}
393427
return $this->__call(__FUNCTION__, func_get_args());
394428
}
395429

@@ -533,4 +567,11 @@ public function getUploadTime(): int {
533567
public function getRelativePath($path) {
534568
return PathHelper::getRelativePath($this->getPath(), $path);
535569
}
570+
571+
public function getParentId(): int {
572+
if (isset($this->data['parent'])) {
573+
return $this->data['parent'];
574+
}
575+
return $this->__call(__FUNCTION__, func_get_args());
576+
}
536577
}

lib/private/Files/Node/LazyRoot.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,18 @@
3333
* @package OC\Files\Node
3434
*/
3535
class LazyRoot extends LazyFolder implements IRootFolder {
36-
/**
37-
* @inheritDoc
38-
*/
36+
public function __construct(\Closure $folderClosure, array $data = []) {
37+
parent::__construct($this, $folderClosure, $data);
38+
}
39+
40+
protected function getRootFolder(): IRootFolder {
41+
$folder = $this->getRealFolder();
42+
if (!$folder instanceof IRootFolder) {
43+
throw new \Exception('Lazy root folder closure didn\'t return a root folder');
44+
}
45+
return $folder;
46+
}
47+
3948
public function getUserFolder($userId) {
4049
return $this->__call(__FUNCTION__, func_get_args());
4150
}

lib/private/Files/Node/LazyUserFolder.php

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,17 @@
3434
use Psr\Log\LoggerInterface;
3535

3636
class LazyUserFolder extends LazyFolder {
37-
private IRootFolder $root;
3837
private IUser $user;
3938
private string $path;
4039
private IMountManager $mountManager;
4140

4241
public function __construct(IRootFolder $rootFolder, IUser $user, IMountManager $mountManager) {
43-
$this->root = $rootFolder;
4442
$this->user = $user;
4543
$this->mountManager = $mountManager;
4644
$this->path = '/' . $user->getUID() . '/files';
47-
parent::__construct(function () use ($user): Folder {
45+
parent::__construct($rootFolder, function () use ($user): Folder {
4846
try {
49-
$node = $this->root->get($this->path);
47+
$node = $this->getRootFolder()->get($this->path);
5048
if ($node instanceof File) {
5149
$e = new \RuntimeException();
5250
\OCP\Server::get(LoggerInterface::class)->error('User root storage is not a folder: ' . $this->path, [
@@ -56,10 +54,10 @@ public function __construct(IRootFolder $rootFolder, IUser $user, IMountManager
5654
}
5755
return $node;
5856
} catch (NotFoundException $e) {
59-
if (!$this->root->nodeExists('/' . $user->getUID())) {
60-
$this->root->newFolder('/' . $user->getUID());
57+
if (!$this->getRootFolder()->nodeExists('/' . $user->getUID())) {
58+
$this->getRootFolder()->newFolder('/' . $user->getUID());
6159
}
62-
return $this->root->newFolder($this->path);
60+
return $this->getRootFolder()->newFolder($this->path);
6361
}
6462
}, [
6563
'path' => $this->path,
@@ -71,15 +69,15 @@ public function __construct(IRootFolder $rootFolder, IUser $user, IMountManager
7169
}
7270

7371
public function get($path) {
74-
return $this->root->get('/' . $this->user->getUID() . '/files/' . ltrim($path, '/'));
72+
return $this->getRootFolder()->get('/' . $this->user->getUID() . '/files/' . ltrim($path, '/'));
7573
}
7674

7775
/**
7876
* @param int $id
7977
* @return \OCP\Files\Node[]
8078
*/
8179
public function getById($id) {
82-
return $this->root->getByIdInPath((int)$id, $this->getPath());
80+
return $this->getRootFolder()->getByIdInPath((int)$id, $this->getPath());
8381
}
8482

8583
public function getMountPoint() {

lib/private/Files/Node/Node.php

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,7 @@ class Node implements INode {
5959

6060
protected ?FileInfo $fileInfo;
6161

62-
/**
63-
* @var Node|null
64-
*/
65-
protected $parent;
62+
protected ?INode $parent;
6663

6764
private bool $infoHasSubMountsIncluded;
6865

@@ -300,7 +297,16 @@ public function getParent(): INode|IRootFolder {
300297
return $this->root;
301298
}
302299

303-
$this->parent = $this->root->get($newPath);
300+
// gather the metadata we already know about our parent
301+
$parentData = [
302+
'path' => $newPath,
303+
'fileid' => $this->getFileInfo()->getParentId(),
304+
];
305+
306+
// and create lazy folder with it instead of always querying
307+
$this->parent = new LazyFolder($this->root, function () use ($newPath) {
308+
return $this->root->get($newPath);
309+
}, $parentData);
304310
}
305311

306312
return $this->parent;
@@ -328,13 +334,7 @@ protected function normalizePath($path) {
328334
* @return bool
329335
*/
330336
public function isValidPath($path) {
331-
if (!$path || $path[0] !== '/') {
332-
$path = '/' . $path;
333-
}
334-
if (strstr($path, '/../') || strrchr($path, '/') === '/..') {
335-
return false;
336-
}
337-
return true;
337+
return Filesystem::isValidPath($path);
338338
}
339339

340340
public function isMounted() {
@@ -477,4 +477,8 @@ public function getCreationTime(): int {
477477
public function getUploadTime(): int {
478478
return $this->getFileInfo()->getUploadTime();
479479
}
480+
481+
public function getParentId(): int {
482+
return $this->fileInfo->getParentId();
483+
}
480484
}

lib/public/Files/FileInfo.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,4 +299,13 @@ public function getCreationTime(): int;
299299
* @since 18.0.0
300300
*/
301301
public function getUploadTime(): int;
302+
303+
/**
304+
* Get the fileid or the parent folder
305+
* or -1 if this item has no parent folder (because it is the root)
306+
*
307+
* @return int
308+
* @since 28.0.0
309+
*/
310+
public function getParentId(): int;
302311
}

0 commit comments

Comments
 (0)