Passed
Push — master ( 1f4c02...af3a59 )
by Roeland
14:40
created
lib/private/Files/Node/Folder.php 1 patch
Indentation   +526 added lines, -526 removed lines patch added patch discarded remove patch
@@ -42,537 +42,537 @@
 block discarded – undo
42 42
 use OCP\Files\Search\ISearchQuery;
43 43
 
44 44
 class Folder extends Node implements \OCP\Files\Folder {
45
-	/**
46
-	 * Creates a Folder that represents a non-existing path
47
-	 *
48
-	 * @param string $path path
49
-	 * @return string non-existing node class
50
-	 */
51
-	protected function createNonExistingNode($path) {
52
-		return new NonExistingFolder($this->root, $this->view, $path);
53
-	}
54
-
55
-	/**
56
-	 * @param string $path path relative to the folder
57
-	 * @return string
58
-	 * @throws \OCP\Files\NotPermittedException
59
-	 */
60
-	public function getFullPath($path) {
61
-		if (!$this->isValidPath($path)) {
62
-			throw new NotPermittedException('Invalid path');
63
-		}
64
-		return $this->path . $this->normalizePath($path);
65
-	}
66
-
67
-	/**
68
-	 * @param string $path
69
-	 * @return string
70
-	 */
71
-	public function getRelativePath($path) {
72
-		if ($this->path === '' or $this->path === '/') {
73
-			return $this->normalizePath($path);
74
-		}
75
-		if ($path === $this->path) {
76
-			return '/';
77
-		} elseif (strpos($path, $this->path . '/') !== 0) {
78
-			return null;
79
-		} else {
80
-			$path = substr($path, strlen($this->path));
81
-			return $this->normalizePath($path);
82
-		}
83
-	}
84
-
85
-	/**
86
-	 * check if a node is a (grand-)child of the folder
87
-	 *
88
-	 * @param \OC\Files\Node\Node $node
89
-	 * @return bool
90
-	 */
91
-	public function isSubNode($node) {
92
-		return strpos($node->getPath(), $this->path . '/') === 0;
93
-	}
94
-
95
-	/**
96
-	 * get the content of this directory
97
-	 *
98
-	 * @throws \OCP\Files\NotFoundException
99
-	 * @return Node[]
100
-	 */
101
-	public function getDirectoryListing() {
102
-		$folderContent = $this->view->getDirectoryContent($this->path);
103
-
104
-		return array_map(function (FileInfo $info) {
105
-			if ($info->getMimetype() === 'httpd/unix-directory') {
106
-				return new Folder($this->root, $this->view, $info->getPath(), $info);
107
-			} else {
108
-				return new File($this->root, $this->view, $info->getPath(), $info);
109
-			}
110
-		}, $folderContent);
111
-	}
112
-
113
-	/**
114
-	 * @param string $path
115
-	 * @param FileInfo $info
116
-	 * @return File|Folder
117
-	 */
118
-	protected function createNode($path, FileInfo $info = null) {
119
-		if (is_null($info)) {
120
-			$isDir = $this->view->is_dir($path);
121
-		} else {
122
-			$isDir = $info->getType() === FileInfo::TYPE_FOLDER;
123
-		}
124
-		if ($isDir) {
125
-			return new Folder($this->root, $this->view, $path, $info);
126
-		} else {
127
-			return new File($this->root, $this->view, $path, $info);
128
-		}
129
-	}
130
-
131
-	/**
132
-	 * Get the node at $path
133
-	 *
134
-	 * @param string $path
135
-	 * @return \OC\Files\Node\Node
136
-	 * @throws \OCP\Files\NotFoundException
137
-	 */
138
-	public function get($path) {
139
-		return $this->root->get($this->getFullPath($path));
140
-	}
141
-
142
-	/**
143
-	 * @param string $path
144
-	 * @return bool
145
-	 */
146
-	public function nodeExists($path) {
147
-		try {
148
-			$this->get($path);
149
-			return true;
150
-		} catch (NotFoundException $e) {
151
-			return false;
152
-		}
153
-	}
154
-
155
-	/**
156
-	 * @param string $path
157
-	 * @return \OC\Files\Node\Folder
158
-	 * @throws \OCP\Files\NotPermittedException
159
-	 */
160
-	public function newFolder($path) {
161
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
162
-			$fullPath = $this->getFullPath($path);
163
-			$nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
164
-			$this->sendHooks(['preWrite', 'preCreate'], [$nonExisting]);
165
-			if (!$this->view->mkdir($fullPath)) {
166
-				throw new NotPermittedException('Could not create folder');
167
-			}
168
-			$node = new Folder($this->root, $this->view, $fullPath);
169
-			$this->sendHooks(['postWrite', 'postCreate'], [$node]);
170
-			return $node;
171
-		} else {
172
-			throw new NotPermittedException('No create permission for folder');
173
-		}
174
-	}
175
-
176
-	/**
177
-	 * @param string $path
178
-	 * @param string | resource | null $content
179
-	 * @return \OC\Files\Node\File
180
-	 * @throws \OCP\Files\NotPermittedException
181
-	 */
182
-	public function newFile($path, $content = null) {
183
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
184
-			$fullPath = $this->getFullPath($path);
185
-			$nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
186
-			$this->sendHooks(['preWrite', 'preCreate'], [$nonExisting]);
187
-			if ($content !== null) {
188
-				$result = $this->view->file_put_contents($fullPath, $content);
189
-			} else {
190
-				$result = $this->view->touch($fullPath);
191
-			}
192
-			if ($result === false) {
193
-				throw new NotPermittedException('Could not create path');
194
-			}
195
-			$node = new File($this->root, $this->view, $fullPath);
196
-			$this->sendHooks(['postWrite', 'postCreate'], [$node]);
197
-			return $node;
198
-		}
199
-		throw new NotPermittedException('No create permission for path');
200
-	}
201
-
202
-	/**
203
-	 * search for files with the name matching $query
204
-	 *
205
-	 * @param string|ISearchQuery $query
206
-	 * @return \OC\Files\Node\Node[]
207
-	 */
208
-	public function search($query) {
209
-		if (is_string($query)) {
210
-			return $this->searchCommon('search', ['%' . $query . '%']);
211
-		} else {
212
-			return $this->searchCommon('searchQuery', [$query]);
213
-		}
214
-	}
215
-
216
-	/**
217
-	 * search for files by mimetype
218
-	 *
219
-	 * @param string $mimetype
220
-	 * @return Node[]
221
-	 */
222
-	public function searchByMime($mimetype) {
223
-		return $this->searchCommon('searchByMime', [$mimetype]);
224
-	}
225
-
226
-	/**
227
-	 * search for files by tag
228
-	 *
229
-	 * @param string|int $tag name or tag id
230
-	 * @param string $userId owner of the tags
231
-	 * @return Node[]
232
-	 */
233
-	public function searchByTag($tag, $userId) {
234
-		return $this->searchCommon('searchByTag', [$tag, $userId]);
235
-	}
236
-
237
-	/**
238
-	 * @param string $method cache method
239
-	 * @param array $args call args
240
-	 * @return \OC\Files\Node\Node[]
241
-	 */
242
-	private function searchCommon($method, $args) {
243
-		$limitToHome = ($method === 'searchQuery')? $args[0]->limitToHome(): false;
244
-		if ($limitToHome && count(explode('/', $this->path)) !== 3) {
245
-			throw new \InvalidArgumentException('searching by owner is only allows on the users home folder');
246
-		}
247
-
248
-		$files = [];
249
-		$rootLength = strlen($this->path);
250
-		$mount = $this->root->getMount($this->path);
251
-		$storage = $mount->getStorage();
252
-		$internalPath = $mount->getInternalPath($this->path);
253
-		$internalPath = rtrim($internalPath, '/');
254
-		if ($internalPath !== '') {
255
-			$internalPath = $internalPath . '/';
256
-		}
257
-		$internalRootLength = strlen($internalPath);
258
-
259
-		$cache = $storage->getCache('');
260
-
261
-		$results = call_user_func_array([$cache, $method], $args);
262
-		foreach ($results as $result) {
263
-			if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) {
264
-				$result['internalPath'] = $result['path'];
265
-				$result['path'] = substr($result['path'], $internalRootLength);
266
-				$result['storage'] = $storage;
267
-				$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
268
-			}
269
-		}
270
-
271
-		if (!$limitToHome) {
272
-			$mounts = $this->root->getMountsIn($this->path);
273
-			foreach ($mounts as $mount) {
274
-				$storage = $mount->getStorage();
275
-				if ($storage) {
276
-					$cache = $storage->getCache('');
277
-
278
-					$relativeMountPoint = ltrim(substr($mount->getMountPoint(), $rootLength), '/');
279
-					$results = call_user_func_array([$cache, $method], $args);
280
-					foreach ($results as $result) {
281
-						$result['internalPath'] = $result['path'];
282
-						$result['path'] = $relativeMountPoint . $result['path'];
283
-						$result['storage'] = $storage;
284
-						$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage,
285
-							$result['internalPath'], $result, $mount);
286
-					}
287
-				}
288
-			}
289
-		}
290
-
291
-		return array_map(function (FileInfo $file) {
292
-			return $this->createNode($file->getPath(), $file);
293
-		}, $files);
294
-	}
295
-
296
-	/**
297
-	 * @param int $id
298
-	 * @return \OC\Files\Node\Node[]
299
-	 */
300
-	public function getById($id) {
301
-		$mountCache = $this->root->getUserMountCache();
302
-		if (strpos($this->getPath(), '/', 1) > 0) {
303
-			list(, $user) = explode('/', $this->getPath());
304
-		} else {
305
-			$user = null;
306
-		}
307
-		$mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
308
-		$mounts = $this->root->getMountsIn($this->path);
309
-		$mounts[] = $this->root->getMount($this->path);
310
-		/** @var IMountPoint[] $folderMounts */
311
-		$folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
312
-			return $mountPoint->getMountPoint();
313
-		}, $mounts), $mounts);
314
-
315
-		/** @var ICachedMountInfo[] $mountsContainingFile */
316
-		$mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
317
-			return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
318
-		}));
319
-
320
-		if (count($mountsContainingFile) === 0) {
321
-			if ($user === $this->getAppDataDirectoryName()) {
322
-				return $this->getByIdInRootMount((int) $id);
323
-			}
324
-			return [];
325
-		}
326
-
327
-		$nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($folderMounts, $id) {
328
-			$mount = $folderMounts[$cachedMountInfo->getMountPoint()];
329
-			$cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
330
-			if (!$cacheEntry) {
331
-				return null;
332
-			}
333
-
334
-			// cache jails will hide the "true" internal path
335
-			$internalPath = ltrim($cachedMountInfo->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
336
-			$pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
337
-			$pathRelativeToMount = ltrim($pathRelativeToMount, '/');
338
-			$absolutePath = rtrim($cachedMountInfo->getMountPoint() . $pathRelativeToMount, '/');
339
-			return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
340
-				$absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
341
-				\OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
342
-			));
343
-		}, $mountsContainingFile);
344
-
345
-		$nodes = array_filter($nodes);
346
-
347
-		return array_filter($nodes, function (Node $node) {
348
-			return $this->getRelativePath($node->getPath());
349
-		});
350
-	}
351
-
352
-	protected function getAppDataDirectoryName(): string {
353
-		$instanceId = \OC::$server->getConfig()->getSystemValueString('instanceid');
354
-		return 'appdata_' . $instanceId;
355
-	}
356
-
357
-	/**
358
-	 * In case the path we are currently in is inside the appdata_* folder,
359
-	 * the original getById method does not work, because it can only look inside
360
-	 * the user's mount points. But the user has no mount point for the root storage.
361
-	 *
362
-	 * So in that case we directly check the mount of the root if it contains
363
-	 * the id. If it does we check if the path is inside the path we are working
364
-	 * in.
365
-	 *
366
-	 * @param int $id
367
-	 * @return array
368
-	 */
369
-	protected function getByIdInRootMount(int $id): array {
370
-		$mount = $this->root->getMount('');
371
-		$cacheEntry = $mount->getStorage()->getCache($this->path)->get($id);
372
-		if (!$cacheEntry) {
373
-			return [];
374
-		}
375
-
376
-		$absolutePath = '/' . ltrim($cacheEntry->getPath(), '/');
377
-		$currentPath = rtrim($this->path, '/') . '/';
378
-
379
-		if (strpos($absolutePath, $currentPath) !== 0) {
380
-			return [];
381
-		}
382
-
383
-		return [$this->root->createNode(
384
-			$absolutePath, new \OC\Files\FileInfo(
385
-				$absolutePath,
386
-				$mount->getStorage(),
387
-				$cacheEntry->getPath(),
388
-				$cacheEntry,
389
-				$mount
390
-		))];
391
-	}
392
-
393
-	public function getFreeSpace() {
394
-		return $this->view->free_space($this->path);
395
-	}
396
-
397
-	public function delete() {
398
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
399
-			$this->sendHooks(['preDelete']);
400
-			$fileInfo = $this->getFileInfo();
401
-			$this->view->rmdir($this->path);
402
-			$nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
403
-			$this->sendHooks(['postDelete'], [$nonExisting]);
404
-			$this->exists = false;
405
-		} else {
406
-			throw new NotPermittedException('No delete permission for path');
407
-		}
408
-	}
409
-
410
-	/**
411
-	 * Add a suffix to the name in case the file exists
412
-	 *
413
-	 * @param string $name
414
-	 * @return string
415
-	 * @throws NotPermittedException
416
-	 */
417
-	public function getNonExistingName($name) {
418
-		$uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
419
-		return trim($this->getRelativePath($uniqueName), '/');
420
-	}
421
-
422
-	/**
423
-	 * @param int $limit
424
-	 * @param int $offset
425
-	 * @return \OCP\Files\Node[]
426
-	 */
427
-	public function getRecent($limit, $offset = 0) {
428
-		$mimetypeLoader = \OC::$server->getMimeTypeLoader();
429
-		$mounts = $this->root->getMountsIn($this->path);
430
-		$mounts[] = $this->getMountPoint();
431
-
432
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
433
-			return $mount->getStorage();
434
-		});
435
-		$storageIds = array_map(function (IMountPoint $mount) {
436
-			return $mount->getStorage()->getCache()->getNumericStorageId();
437
-		}, $mounts);
438
-		/** @var IMountPoint[] $mountMap */
439
-		$mountMap = array_combine($storageIds, $mounts);
440
-		$folderMimetype = $mimetypeLoader->getId(FileInfo::MIMETYPE_FOLDER);
441
-
442
-		/*
45
+    /**
46
+     * Creates a Folder that represents a non-existing path
47
+     *
48
+     * @param string $path path
49
+     * @return string non-existing node class
50
+     */
51
+    protected function createNonExistingNode($path) {
52
+        return new NonExistingFolder($this->root, $this->view, $path);
53
+    }
54
+
55
+    /**
56
+     * @param string $path path relative to the folder
57
+     * @return string
58
+     * @throws \OCP\Files\NotPermittedException
59
+     */
60
+    public function getFullPath($path) {
61
+        if (!$this->isValidPath($path)) {
62
+            throw new NotPermittedException('Invalid path');
63
+        }
64
+        return $this->path . $this->normalizePath($path);
65
+    }
66
+
67
+    /**
68
+     * @param string $path
69
+     * @return string
70
+     */
71
+    public function getRelativePath($path) {
72
+        if ($this->path === '' or $this->path === '/') {
73
+            return $this->normalizePath($path);
74
+        }
75
+        if ($path === $this->path) {
76
+            return '/';
77
+        } elseif (strpos($path, $this->path . '/') !== 0) {
78
+            return null;
79
+        } else {
80
+            $path = substr($path, strlen($this->path));
81
+            return $this->normalizePath($path);
82
+        }
83
+    }
84
+
85
+    /**
86
+     * check if a node is a (grand-)child of the folder
87
+     *
88
+     * @param \OC\Files\Node\Node $node
89
+     * @return bool
90
+     */
91
+    public function isSubNode($node) {
92
+        return strpos($node->getPath(), $this->path . '/') === 0;
93
+    }
94
+
95
+    /**
96
+     * get the content of this directory
97
+     *
98
+     * @throws \OCP\Files\NotFoundException
99
+     * @return Node[]
100
+     */
101
+    public function getDirectoryListing() {
102
+        $folderContent = $this->view->getDirectoryContent($this->path);
103
+
104
+        return array_map(function (FileInfo $info) {
105
+            if ($info->getMimetype() === 'httpd/unix-directory') {
106
+                return new Folder($this->root, $this->view, $info->getPath(), $info);
107
+            } else {
108
+                return new File($this->root, $this->view, $info->getPath(), $info);
109
+            }
110
+        }, $folderContent);
111
+    }
112
+
113
+    /**
114
+     * @param string $path
115
+     * @param FileInfo $info
116
+     * @return File|Folder
117
+     */
118
+    protected function createNode($path, FileInfo $info = null) {
119
+        if (is_null($info)) {
120
+            $isDir = $this->view->is_dir($path);
121
+        } else {
122
+            $isDir = $info->getType() === FileInfo::TYPE_FOLDER;
123
+        }
124
+        if ($isDir) {
125
+            return new Folder($this->root, $this->view, $path, $info);
126
+        } else {
127
+            return new File($this->root, $this->view, $path, $info);
128
+        }
129
+    }
130
+
131
+    /**
132
+     * Get the node at $path
133
+     *
134
+     * @param string $path
135
+     * @return \OC\Files\Node\Node
136
+     * @throws \OCP\Files\NotFoundException
137
+     */
138
+    public function get($path) {
139
+        return $this->root->get($this->getFullPath($path));
140
+    }
141
+
142
+    /**
143
+     * @param string $path
144
+     * @return bool
145
+     */
146
+    public function nodeExists($path) {
147
+        try {
148
+            $this->get($path);
149
+            return true;
150
+        } catch (NotFoundException $e) {
151
+            return false;
152
+        }
153
+    }
154
+
155
+    /**
156
+     * @param string $path
157
+     * @return \OC\Files\Node\Folder
158
+     * @throws \OCP\Files\NotPermittedException
159
+     */
160
+    public function newFolder($path) {
161
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
162
+            $fullPath = $this->getFullPath($path);
163
+            $nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
164
+            $this->sendHooks(['preWrite', 'preCreate'], [$nonExisting]);
165
+            if (!$this->view->mkdir($fullPath)) {
166
+                throw new NotPermittedException('Could not create folder');
167
+            }
168
+            $node = new Folder($this->root, $this->view, $fullPath);
169
+            $this->sendHooks(['postWrite', 'postCreate'], [$node]);
170
+            return $node;
171
+        } else {
172
+            throw new NotPermittedException('No create permission for folder');
173
+        }
174
+    }
175
+
176
+    /**
177
+     * @param string $path
178
+     * @param string | resource | null $content
179
+     * @return \OC\Files\Node\File
180
+     * @throws \OCP\Files\NotPermittedException
181
+     */
182
+    public function newFile($path, $content = null) {
183
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
184
+            $fullPath = $this->getFullPath($path);
185
+            $nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
186
+            $this->sendHooks(['preWrite', 'preCreate'], [$nonExisting]);
187
+            if ($content !== null) {
188
+                $result = $this->view->file_put_contents($fullPath, $content);
189
+            } else {
190
+                $result = $this->view->touch($fullPath);
191
+            }
192
+            if ($result === false) {
193
+                throw new NotPermittedException('Could not create path');
194
+            }
195
+            $node = new File($this->root, $this->view, $fullPath);
196
+            $this->sendHooks(['postWrite', 'postCreate'], [$node]);
197
+            return $node;
198
+        }
199
+        throw new NotPermittedException('No create permission for path');
200
+    }
201
+
202
+    /**
203
+     * search for files with the name matching $query
204
+     *
205
+     * @param string|ISearchQuery $query
206
+     * @return \OC\Files\Node\Node[]
207
+     */
208
+    public function search($query) {
209
+        if (is_string($query)) {
210
+            return $this->searchCommon('search', ['%' . $query . '%']);
211
+        } else {
212
+            return $this->searchCommon('searchQuery', [$query]);
213
+        }
214
+    }
215
+
216
+    /**
217
+     * search for files by mimetype
218
+     *
219
+     * @param string $mimetype
220
+     * @return Node[]
221
+     */
222
+    public function searchByMime($mimetype) {
223
+        return $this->searchCommon('searchByMime', [$mimetype]);
224
+    }
225
+
226
+    /**
227
+     * search for files by tag
228
+     *
229
+     * @param string|int $tag name or tag id
230
+     * @param string $userId owner of the tags
231
+     * @return Node[]
232
+     */
233
+    public function searchByTag($tag, $userId) {
234
+        return $this->searchCommon('searchByTag', [$tag, $userId]);
235
+    }
236
+
237
+    /**
238
+     * @param string $method cache method
239
+     * @param array $args call args
240
+     * @return \OC\Files\Node\Node[]
241
+     */
242
+    private function searchCommon($method, $args) {
243
+        $limitToHome = ($method === 'searchQuery')? $args[0]->limitToHome(): false;
244
+        if ($limitToHome && count(explode('/', $this->path)) !== 3) {
245
+            throw new \InvalidArgumentException('searching by owner is only allows on the users home folder');
246
+        }
247
+
248
+        $files = [];
249
+        $rootLength = strlen($this->path);
250
+        $mount = $this->root->getMount($this->path);
251
+        $storage = $mount->getStorage();
252
+        $internalPath = $mount->getInternalPath($this->path);
253
+        $internalPath = rtrim($internalPath, '/');
254
+        if ($internalPath !== '') {
255
+            $internalPath = $internalPath . '/';
256
+        }
257
+        $internalRootLength = strlen($internalPath);
258
+
259
+        $cache = $storage->getCache('');
260
+
261
+        $results = call_user_func_array([$cache, $method], $args);
262
+        foreach ($results as $result) {
263
+            if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) {
264
+                $result['internalPath'] = $result['path'];
265
+                $result['path'] = substr($result['path'], $internalRootLength);
266
+                $result['storage'] = $storage;
267
+                $files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
268
+            }
269
+        }
270
+
271
+        if (!$limitToHome) {
272
+            $mounts = $this->root->getMountsIn($this->path);
273
+            foreach ($mounts as $mount) {
274
+                $storage = $mount->getStorage();
275
+                if ($storage) {
276
+                    $cache = $storage->getCache('');
277
+
278
+                    $relativeMountPoint = ltrim(substr($mount->getMountPoint(), $rootLength), '/');
279
+                    $results = call_user_func_array([$cache, $method], $args);
280
+                    foreach ($results as $result) {
281
+                        $result['internalPath'] = $result['path'];
282
+                        $result['path'] = $relativeMountPoint . $result['path'];
283
+                        $result['storage'] = $storage;
284
+                        $files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage,
285
+                            $result['internalPath'], $result, $mount);
286
+                    }
287
+                }
288
+            }
289
+        }
290
+
291
+        return array_map(function (FileInfo $file) {
292
+            return $this->createNode($file->getPath(), $file);
293
+        }, $files);
294
+    }
295
+
296
+    /**
297
+     * @param int $id
298
+     * @return \OC\Files\Node\Node[]
299
+     */
300
+    public function getById($id) {
301
+        $mountCache = $this->root->getUserMountCache();
302
+        if (strpos($this->getPath(), '/', 1) > 0) {
303
+            list(, $user) = explode('/', $this->getPath());
304
+        } else {
305
+            $user = null;
306
+        }
307
+        $mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
308
+        $mounts = $this->root->getMountsIn($this->path);
309
+        $mounts[] = $this->root->getMount($this->path);
310
+        /** @var IMountPoint[] $folderMounts */
311
+        $folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
312
+            return $mountPoint->getMountPoint();
313
+        }, $mounts), $mounts);
314
+
315
+        /** @var ICachedMountInfo[] $mountsContainingFile */
316
+        $mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
317
+            return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
318
+        }));
319
+
320
+        if (count($mountsContainingFile) === 0) {
321
+            if ($user === $this->getAppDataDirectoryName()) {
322
+                return $this->getByIdInRootMount((int) $id);
323
+            }
324
+            return [];
325
+        }
326
+
327
+        $nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($folderMounts, $id) {
328
+            $mount = $folderMounts[$cachedMountInfo->getMountPoint()];
329
+            $cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
330
+            if (!$cacheEntry) {
331
+                return null;
332
+            }
333
+
334
+            // cache jails will hide the "true" internal path
335
+            $internalPath = ltrim($cachedMountInfo->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
336
+            $pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
337
+            $pathRelativeToMount = ltrim($pathRelativeToMount, '/');
338
+            $absolutePath = rtrim($cachedMountInfo->getMountPoint() . $pathRelativeToMount, '/');
339
+            return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
340
+                $absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
341
+                \OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
342
+            ));
343
+        }, $mountsContainingFile);
344
+
345
+        $nodes = array_filter($nodes);
346
+
347
+        return array_filter($nodes, function (Node $node) {
348
+            return $this->getRelativePath($node->getPath());
349
+        });
350
+    }
351
+
352
+    protected function getAppDataDirectoryName(): string {
353
+        $instanceId = \OC::$server->getConfig()->getSystemValueString('instanceid');
354
+        return 'appdata_' . $instanceId;
355
+    }
356
+
357
+    /**
358
+     * In case the path we are currently in is inside the appdata_* folder,
359
+     * the original getById method does not work, because it can only look inside
360
+     * the user's mount points. But the user has no mount point for the root storage.
361
+     *
362
+     * So in that case we directly check the mount of the root if it contains
363
+     * the id. If it does we check if the path is inside the path we are working
364
+     * in.
365
+     *
366
+     * @param int $id
367
+     * @return array
368
+     */
369
+    protected function getByIdInRootMount(int $id): array {
370
+        $mount = $this->root->getMount('');
371
+        $cacheEntry = $mount->getStorage()->getCache($this->path)->get($id);
372
+        if (!$cacheEntry) {
373
+            return [];
374
+        }
375
+
376
+        $absolutePath = '/' . ltrim($cacheEntry->getPath(), '/');
377
+        $currentPath = rtrim($this->path, '/') . '/';
378
+
379
+        if (strpos($absolutePath, $currentPath) !== 0) {
380
+            return [];
381
+        }
382
+
383
+        return [$this->root->createNode(
384
+            $absolutePath, new \OC\Files\FileInfo(
385
+                $absolutePath,
386
+                $mount->getStorage(),
387
+                $cacheEntry->getPath(),
388
+                $cacheEntry,
389
+                $mount
390
+        ))];
391
+    }
392
+
393
+    public function getFreeSpace() {
394
+        return $this->view->free_space($this->path);
395
+    }
396
+
397
+    public function delete() {
398
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
399
+            $this->sendHooks(['preDelete']);
400
+            $fileInfo = $this->getFileInfo();
401
+            $this->view->rmdir($this->path);
402
+            $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
403
+            $this->sendHooks(['postDelete'], [$nonExisting]);
404
+            $this->exists = false;
405
+        } else {
406
+            throw new NotPermittedException('No delete permission for path');
407
+        }
408
+    }
409
+
410
+    /**
411
+     * Add a suffix to the name in case the file exists
412
+     *
413
+     * @param string $name
414
+     * @return string
415
+     * @throws NotPermittedException
416
+     */
417
+    public function getNonExistingName($name) {
418
+        $uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
419
+        return trim($this->getRelativePath($uniqueName), '/');
420
+    }
421
+
422
+    /**
423
+     * @param int $limit
424
+     * @param int $offset
425
+     * @return \OCP\Files\Node[]
426
+     */
427
+    public function getRecent($limit, $offset = 0) {
428
+        $mimetypeLoader = \OC::$server->getMimeTypeLoader();
429
+        $mounts = $this->root->getMountsIn($this->path);
430
+        $mounts[] = $this->getMountPoint();
431
+
432
+        $mounts = array_filter($mounts, function (IMountPoint $mount) {
433
+            return $mount->getStorage();
434
+        });
435
+        $storageIds = array_map(function (IMountPoint $mount) {
436
+            return $mount->getStorage()->getCache()->getNumericStorageId();
437
+        }, $mounts);
438
+        /** @var IMountPoint[] $mountMap */
439
+        $mountMap = array_combine($storageIds, $mounts);
440
+        $folderMimetype = $mimetypeLoader->getId(FileInfo::MIMETYPE_FOLDER);
441
+
442
+        /*
443 443
 		 * Construct an array of the storage id with their prefix path
444 444
 		 * This helps us to filter in the final query
445 445
 		 */
446
-		$filters = array_map(function (IMountPoint $mount) {
447
-			$storage = $mount->getStorage();
448
-
449
-			$storageId = $storage->getCache()->getNumericStorageId();
450
-			$prefix = '';
451
-
452
-			if ($storage->instanceOfStorage(Jail::class)) {
453
-				$prefix = $storage->getUnJailedPath('');
454
-			}
455
-
456
-			return [
457
-				'storageId' => $storageId,
458
-				'pathPrefix' => $prefix,
459
-			];
460
-		}, $mounts);
461
-
462
-		// Search in batches of 500 entries
463
-		$searchLimit = 500;
464
-		$results = [];
465
-		$searchResultCount = 0;
466
-		$count = 0;
467
-		do {
468
-			$searchResult = $this->recentSearch($searchLimit, $offset, $folderMimetype, $filters);
469
-
470
-			// Exit condition if there are no more results
471
-			if (count($searchResult) === 0) {
472
-				break;
473
-			}
474
-
475
-			$searchResultCount += count($searchResult);
476
-
477
-			$parseResult = $this->recentParse($searchResult, $mountMap, $mimetypeLoader);
478
-
479
-			foreach ($parseResult as $result) {
480
-				$results[] = $result;
481
-			}
482
-
483
-			$offset += $searchLimit;
484
-			$count++;
485
-		} while (count($results) < $limit && ($searchResultCount < (3 * $limit) || $count < 5));
486
-
487
-		return array_slice($results, 0, $limit);
488
-	}
489
-
490
-	private function recentSearch($limit, $offset, $folderMimetype, $filters) {
491
-		$dbconn = \OC::$server->getDatabaseConnection();
492
-		$builder = $dbconn->getQueryBuilder();
493
-		$query = $builder
494
-			->select('f.*')
495
-			->from('filecache', 'f');
496
-
497
-		/*
446
+        $filters = array_map(function (IMountPoint $mount) {
447
+            $storage = $mount->getStorage();
448
+
449
+            $storageId = $storage->getCache()->getNumericStorageId();
450
+            $prefix = '';
451
+
452
+            if ($storage->instanceOfStorage(Jail::class)) {
453
+                $prefix = $storage->getUnJailedPath('');
454
+            }
455
+
456
+            return [
457
+                'storageId' => $storageId,
458
+                'pathPrefix' => $prefix,
459
+            ];
460
+        }, $mounts);
461
+
462
+        // Search in batches of 500 entries
463
+        $searchLimit = 500;
464
+        $results = [];
465
+        $searchResultCount = 0;
466
+        $count = 0;
467
+        do {
468
+            $searchResult = $this->recentSearch($searchLimit, $offset, $folderMimetype, $filters);
469
+
470
+            // Exit condition if there are no more results
471
+            if (count($searchResult) === 0) {
472
+                break;
473
+            }
474
+
475
+            $searchResultCount += count($searchResult);
476
+
477
+            $parseResult = $this->recentParse($searchResult, $mountMap, $mimetypeLoader);
478
+
479
+            foreach ($parseResult as $result) {
480
+                $results[] = $result;
481
+            }
482
+
483
+            $offset += $searchLimit;
484
+            $count++;
485
+        } while (count($results) < $limit && ($searchResultCount < (3 * $limit) || $count < 5));
486
+
487
+        return array_slice($results, 0, $limit);
488
+    }
489
+
490
+    private function recentSearch($limit, $offset, $folderMimetype, $filters) {
491
+        $dbconn = \OC::$server->getDatabaseConnection();
492
+        $builder = $dbconn->getQueryBuilder();
493
+        $query = $builder
494
+            ->select('f.*')
495
+            ->from('filecache', 'f');
496
+
497
+        /*
498 498
 		 * Here is where we construct the filtering.
499 499
 		 * Note that this is expensive filtering as it is a lot of like queries.
500 500
 		 * However the alternative is we do this filtering and parsing later in php with the risk of looping endlessly
501 501
 		 */
502
-		$storageFilters = $builder->expr()->orX();
503
-		foreach ($filters as $filter) {
504
-			$storageFilter = $builder->expr()->andX(
505
-				$builder->expr()->eq('f.storage', $builder->createNamedParameter($filter['storageId']))
506
-			);
507
-
508
-			if ($filter['pathPrefix'] !== '') {
509
-				$storageFilter->add(
510
-					$builder->expr()->like('f.path', $builder->createNamedParameter($dbconn->escapeLikeParameter($filter['pathPrefix']) . '/%'))
511
-				);
512
-			}
513
-
514
-			$storageFilters->add($storageFilter);
515
-		}
516
-
517
-		$query->andWhere($storageFilters);
518
-
519
-		$query->andWhere($builder->expr()->orX(
520
-			// handle non empty folders separate
521
-				$builder->expr()->neq('f.mimetype', $builder->createNamedParameter($folderMimetype, IQueryBuilder::PARAM_INT)),
522
-				$builder->expr()->eq('f.size', new Literal(0))
523
-			))
524
-			->andWhere($builder->expr()->notLike('f.path', $builder->createNamedParameter('files_versions/%')))
525
-			->andWhere($builder->expr()->notLike('f.path', $builder->createNamedParameter('files_trashbin/%')))
526
-			->orderBy('f.mtime', 'DESC')
527
-			->setMaxResults($limit)
528
-			->setFirstResult($offset);
529
-
530
-		return $query->execute()->fetchAll();
531
-	}
532
-
533
-	private function recentParse($result, $mountMap, $mimetypeLoader) {
534
-		$files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
535
-			$mount = $mountMap[$entry['storage']];
536
-			$entry['internalPath'] = $entry['path'];
537
-			$entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
538
-			$entry['mimepart'] = $mimetypeLoader->getMimetypeById($entry['mimepart']);
539
-			$path = $this->getAbsolutePath($mount, $entry['path']);
540
-			if (is_null($path)) {
541
-				return null;
542
-			}
543
-			$fileInfo = new \OC\Files\FileInfo($path, $mount->getStorage(), $entry['internalPath'], $entry, $mount);
544
-			return $this->root->createNode($fileInfo->getPath(), $fileInfo);
545
-		}, $result));
546
-
547
-		return array_values(array_filter($files, function (Node $node) {
548
-			$cacheEntry = $node->getMountPoint()->getStorage()->getCache()->get($node->getId());
549
-			if (!$cacheEntry) {
550
-				return false;
551
-			}
552
-			$relative = $this->getRelativePath($node->getPath());
553
-			return $relative !== null && $relative !== '/'
554
-				&& ($cacheEntry->getPermissions() & \OCP\Constants::PERMISSION_READ) === \OCP\Constants::PERMISSION_READ;
555
-		}));
556
-	}
557
-
558
-	private function getAbsolutePath(IMountPoint $mount, $path) {
559
-		$storage = $mount->getStorage();
560
-		if ($storage->instanceOfStorage('\OC\Files\Storage\Wrapper\Jail')) {
561
-			if ($storage->instanceOfStorage(SharedStorage::class)) {
562
-				$storage->getSourceStorage();
563
-			}
564
-			/** @var \OC\Files\Storage\Wrapper\Jail $storage */
565
-			$jailRoot = $storage->getUnjailedPath('');
566
-			$rootLength = strlen($jailRoot) + 1;
567
-			if ($path === $jailRoot) {
568
-				return $mount->getMountPoint();
569
-			} elseif (substr($path, 0, $rootLength) === $jailRoot . '/') {
570
-				return $mount->getMountPoint() . substr($path, $rootLength);
571
-			} else {
572
-				return null;
573
-			}
574
-		} else {
575
-			return $mount->getMountPoint() . $path;
576
-		}
577
-	}
502
+        $storageFilters = $builder->expr()->orX();
503
+        foreach ($filters as $filter) {
504
+            $storageFilter = $builder->expr()->andX(
505
+                $builder->expr()->eq('f.storage', $builder->createNamedParameter($filter['storageId']))
506
+            );
507
+
508
+            if ($filter['pathPrefix'] !== '') {
509
+                $storageFilter->add(
510
+                    $builder->expr()->like('f.path', $builder->createNamedParameter($dbconn->escapeLikeParameter($filter['pathPrefix']) . '/%'))
511
+                );
512
+            }
513
+
514
+            $storageFilters->add($storageFilter);
515
+        }
516
+
517
+        $query->andWhere($storageFilters);
518
+
519
+        $query->andWhere($builder->expr()->orX(
520
+            // handle non empty folders separate
521
+                $builder->expr()->neq('f.mimetype', $builder->createNamedParameter($folderMimetype, IQueryBuilder::PARAM_INT)),
522
+                $builder->expr()->eq('f.size', new Literal(0))
523
+            ))
524
+            ->andWhere($builder->expr()->notLike('f.path', $builder->createNamedParameter('files_versions/%')))
525
+            ->andWhere($builder->expr()->notLike('f.path', $builder->createNamedParameter('files_trashbin/%')))
526
+            ->orderBy('f.mtime', 'DESC')
527
+            ->setMaxResults($limit)
528
+            ->setFirstResult($offset);
529
+
530
+        return $query->execute()->fetchAll();
531
+    }
532
+
533
+    private function recentParse($result, $mountMap, $mimetypeLoader) {
534
+        $files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
535
+            $mount = $mountMap[$entry['storage']];
536
+            $entry['internalPath'] = $entry['path'];
537
+            $entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
538
+            $entry['mimepart'] = $mimetypeLoader->getMimetypeById($entry['mimepart']);
539
+            $path = $this->getAbsolutePath($mount, $entry['path']);
540
+            if (is_null($path)) {
541
+                return null;
542
+            }
543
+            $fileInfo = new \OC\Files\FileInfo($path, $mount->getStorage(), $entry['internalPath'], $entry, $mount);
544
+            return $this->root->createNode($fileInfo->getPath(), $fileInfo);
545
+        }, $result));
546
+
547
+        return array_values(array_filter($files, function (Node $node) {
548
+            $cacheEntry = $node->getMountPoint()->getStorage()->getCache()->get($node->getId());
549
+            if (!$cacheEntry) {
550
+                return false;
551
+            }
552
+            $relative = $this->getRelativePath($node->getPath());
553
+            return $relative !== null && $relative !== '/'
554
+                && ($cacheEntry->getPermissions() & \OCP\Constants::PERMISSION_READ) === \OCP\Constants::PERMISSION_READ;
555
+        }));
556
+    }
557
+
558
+    private function getAbsolutePath(IMountPoint $mount, $path) {
559
+        $storage = $mount->getStorage();
560
+        if ($storage->instanceOfStorage('\OC\Files\Storage\Wrapper\Jail')) {
561
+            if ($storage->instanceOfStorage(SharedStorage::class)) {
562
+                $storage->getSourceStorage();
563
+            }
564
+            /** @var \OC\Files\Storage\Wrapper\Jail $storage */
565
+            $jailRoot = $storage->getUnjailedPath('');
566
+            $rootLength = strlen($jailRoot) + 1;
567
+            if ($path === $jailRoot) {
568
+                return $mount->getMountPoint();
569
+            } elseif (substr($path, 0, $rootLength) === $jailRoot . '/') {
570
+                return $mount->getMountPoint() . substr($path, $rootLength);
571
+            } else {
572
+                return null;
573
+            }
574
+        } else {
575
+            return $mount->getMountPoint() . $path;
576
+        }
577
+    }
578 578
 }
Please login to merge, or discard this patch.