Passed
Push — master ( 63276c...4a52d9 )
by Roeland
08:29
created
lib/private/Files/Node/Folder.php 1 patch
Indentation   +430 added lines, -430 removed lines patch added patch discarded remove patch
@@ -37,434 +37,434 @@
 block discarded – undo
37 37
 use OCP\Files\Search\ISearchOperator;
38 38
 
39 39
 class Folder extends Node implements \OCP\Files\Folder {
40
-	/**
41
-	 * Creates a Folder that represents a non-existing path
42
-	 *
43
-	 * @param string $path path
44
-	 * @return string non-existing node class
45
-	 */
46
-	protected function createNonExistingNode($path) {
47
-		return new NonExistingFolder($this->root, $this->view, $path);
48
-	}
49
-
50
-	/**
51
-	 * @param string $path path relative to the folder
52
-	 * @return string
53
-	 * @throws \OCP\Files\NotPermittedException
54
-	 */
55
-	public function getFullPath($path) {
56
-		if (!$this->isValidPath($path)) {
57
-			throw new NotPermittedException('Invalid path');
58
-		}
59
-		return $this->path . $this->normalizePath($path);
60
-	}
61
-
62
-	/**
63
-	 * @param string $path
64
-	 * @return string
65
-	 */
66
-	public function getRelativePath($path) {
67
-		if ($this->path === '' or $this->path === '/') {
68
-			return $this->normalizePath($path);
69
-		}
70
-		if ($path === $this->path) {
71
-			return '/';
72
-		} else if (strpos($path, $this->path . '/') !== 0) {
73
-			return null;
74
-		} else {
75
-			$path = substr($path, strlen($this->path));
76
-			return $this->normalizePath($path);
77
-		}
78
-	}
79
-
80
-	/**
81
-	 * check if a node is a (grand-)child of the folder
82
-	 *
83
-	 * @param \OC\Files\Node\Node $node
84
-	 * @return bool
85
-	 */
86
-	public function isSubNode($node) {
87
-		return strpos($node->getPath(), $this->path . '/') === 0;
88
-	}
89
-
90
-	/**
91
-	 * get the content of this directory
92
-	 *
93
-	 * @throws \OCP\Files\NotFoundException
94
-	 * @return Node[]
95
-	 */
96
-	public function getDirectoryListing() {
97
-		$folderContent = $this->view->getDirectoryContent($this->path);
98
-
99
-		return array_map(function (FileInfo $info) {
100
-			if ($info->getMimetype() === 'httpd/unix-directory') {
101
-				return new Folder($this->root, $this->view, $info->getPath(), $info);
102
-			} else {
103
-				return new File($this->root, $this->view, $info->getPath(), $info);
104
-			}
105
-		}, $folderContent);
106
-	}
107
-
108
-	/**
109
-	 * @param string $path
110
-	 * @param FileInfo $info
111
-	 * @return File|Folder
112
-	 */
113
-	protected function createNode($path, FileInfo $info = null) {
114
-		if (is_null($info)) {
115
-			$isDir = $this->view->is_dir($path);
116
-		} else {
117
-			$isDir = $info->getType() === FileInfo::TYPE_FOLDER;
118
-		}
119
-		if ($isDir) {
120
-			return new Folder($this->root, $this->view, $path, $info);
121
-		} else {
122
-			return new File($this->root, $this->view, $path, $info);
123
-		}
124
-	}
125
-
126
-	/**
127
-	 * Get the node at $path
128
-	 *
129
-	 * @param string $path
130
-	 * @return \OC\Files\Node\Node
131
-	 * @throws \OCP\Files\NotFoundException
132
-	 */
133
-	public function get($path) {
134
-		return $this->root->get($this->getFullPath($path));
135
-	}
136
-
137
-	/**
138
-	 * @param string $path
139
-	 * @return bool
140
-	 */
141
-	public function nodeExists($path) {
142
-		try {
143
-			$this->get($path);
144
-			return true;
145
-		} catch (NotFoundException $e) {
146
-			return false;
147
-		}
148
-	}
149
-
150
-	/**
151
-	 * @param string $path
152
-	 * @return \OC\Files\Node\Folder
153
-	 * @throws \OCP\Files\NotPermittedException
154
-	 */
155
-	public function newFolder($path) {
156
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
157
-			$fullPath = $this->getFullPath($path);
158
-			$nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
159
-			$this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
160
-			$this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
161
-			if(!$this->view->mkdir($fullPath)) {
162
-				throw new NotPermittedException('Could not create folder');
163
-			}
164
-			$node = new Folder($this->root, $this->view, $fullPath);
165
-			$this->root->emit('\OC\Files', 'postWrite', array($node));
166
-			$this->root->emit('\OC\Files', 'postCreate', array($node));
167
-			return $node;
168
-		} else {
169
-			throw new NotPermittedException('No create permission for folder');
170
-		}
171
-	}
172
-
173
-	/**
174
-	 * @param string $path
175
-	 * @return \OC\Files\Node\File
176
-	 * @throws \OCP\Files\NotPermittedException
177
-	 */
178
-	public function newFile($path) {
179
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
180
-			$fullPath = $this->getFullPath($path);
181
-			$nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
182
-			$this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
183
-			$this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
184
-			if (!$this->view->touch($fullPath)) {
185
-				throw new NotPermittedException('Could not create path');
186
-			}
187
-			$node = new File($this->root, $this->view, $fullPath);
188
-			$this->root->emit('\OC\Files', 'postWrite', array($node));
189
-			$this->root->emit('\OC\Files', 'postCreate', array($node));
190
-			return $node;
191
-		}
192
-		throw new NotPermittedException('No create permission for path');
193
-	}
194
-
195
-	/**
196
-	 * search for files with the name matching $query
197
-	 *
198
-	 * @param string|ISearchOperator $query
199
-	 * @return \OC\Files\Node\Node[]
200
-	 */
201
-	public function search($query) {
202
-		if (is_string($query)) {
203
-			return $this->searchCommon('search', array('%' . $query . '%'));
204
-		} else {
205
-			return $this->searchCommon('searchQuery', array($query));
206
-		}
207
-	}
208
-
209
-	/**
210
-	 * search for files by mimetype
211
-	 *
212
-	 * @param string $mimetype
213
-	 * @return Node[]
214
-	 */
215
-	public function searchByMime($mimetype) {
216
-		return $this->searchCommon('searchByMime', array($mimetype));
217
-	}
218
-
219
-	/**
220
-	 * search for files by tag
221
-	 *
222
-	 * @param string|int $tag name or tag id
223
-	 * @param string $userId owner of the tags
224
-	 * @return Node[]
225
-	 */
226
-	public function searchByTag($tag, $userId) {
227
-		return $this->searchCommon('searchByTag', array($tag, $userId));
228
-	}
229
-
230
-	/**
231
-	 * @param string $method cache method
232
-	 * @param array $args call args
233
-	 * @return \OC\Files\Node\Node[]
234
-	 */
235
-	private function searchCommon($method, $args) {
236
-		$files = array();
237
-		$rootLength = strlen($this->path);
238
-		$mount = $this->root->getMount($this->path);
239
-		$storage = $mount->getStorage();
240
-		$internalPath = $mount->getInternalPath($this->path);
241
-		$internalPath = rtrim($internalPath, '/');
242
-		if ($internalPath !== '') {
243
-			$internalPath = $internalPath . '/';
244
-		}
245
-		$internalRootLength = strlen($internalPath);
246
-
247
-		$cache = $storage->getCache('');
248
-
249
-		$results = call_user_func_array(array($cache, $method), $args);
250
-		foreach ($results as $result) {
251
-			if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) {
252
-				$result['internalPath'] = $result['path'];
253
-				$result['path'] = substr($result['path'], $internalRootLength);
254
-				$result['storage'] = $storage;
255
-				$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
256
-			}
257
-		}
258
-
259
-		$mounts = $this->root->getMountsIn($this->path);
260
-		foreach ($mounts as $mount) {
261
-			$storage = $mount->getStorage();
262
-			if ($storage) {
263
-				$cache = $storage->getCache('');
264
-
265
-				$relativeMountPoint = ltrim(substr($mount->getMountPoint(), $rootLength), '/');
266
-				$results = call_user_func_array(array($cache, $method), $args);
267
-				foreach ($results as $result) {
268
-					$result['internalPath'] = $result['path'];
269
-					$result['path'] = $relativeMountPoint . $result['path'];
270
-					$result['storage'] = $storage;
271
-					$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
272
-				}
273
-			}
274
-		}
275
-
276
-		return array_map(function (FileInfo $file) {
277
-			return $this->createNode($file->getPath(), $file);
278
-		}, $files);
279
-	}
280
-
281
-	/**
282
-	 * @param int $id
283
-	 * @return \OC\Files\Node\Node[]
284
-	 */
285
-	public function getById($id) {
286
-		$mountCache = $this->root->getUserMountCache();
287
-		if (strpos($this->getPath(), '/', 1) > 0) {
288
-			list(, $user) = explode('/', $this->getPath());
289
-		} else {
290
-			$user = null;
291
-		}
292
-		$mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
293
-		$mounts = $this->root->getMountsIn($this->path);
294
-		$mounts[] = $this->root->getMount($this->path);
295
-		/** @var IMountPoint[] $folderMounts */
296
-		$folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
297
-			return $mountPoint->getMountPoint();
298
-		}, $mounts), $mounts);
299
-
300
-		/** @var ICachedMountInfo[] $mountsContainingFile */
301
-		$mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
302
-			return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
303
-		}));
304
-
305
-		if (count($mountsContainingFile) === 0) {
306
-			return [];
307
-		}
308
-
309
-		$nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($folderMounts, $id) {
310
-			$mount = $folderMounts[$cachedMountInfo->getMountPoint()];
311
-			$cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
312
-			if (!$cacheEntry) {
313
-				return null;
314
-			}
315
-
316
-			// cache jails will hide the "true" internal path
317
-			$internalPath = ltrim($cachedMountInfo->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
318
-			$pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
319
-			$pathRelativeToMount = ltrim($pathRelativeToMount, '/');
320
-			$absolutePath = rtrim($cachedMountInfo->getMountPoint() . $pathRelativeToMount, '/');
321
-			return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
322
-				$absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
323
-				\OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
324
-			));
325
-		}, $mountsContainingFile);
326
-
327
-		$nodes = array_filter($nodes);
328
-
329
-		return array_filter($nodes, function (Node $node) {
330
-			return $this->getRelativePath($node->getPath());
331
-		});
332
-	}
333
-
334
-	public function getFreeSpace() {
335
-		return $this->view->free_space($this->path);
336
-	}
337
-
338
-	public function delete() {
339
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
340
-			$this->sendHooks(array('preDelete'));
341
-			$fileInfo = $this->getFileInfo();
342
-			$this->view->rmdir($this->path);
343
-			$nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
344
-			$this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
345
-			$this->exists = false;
346
-		} else {
347
-			throw new NotPermittedException('No delete permission for path');
348
-		}
349
-	}
350
-
351
-	/**
352
-	 * Add a suffix to the name in case the file exists
353
-	 *
354
-	 * @param string $name
355
-	 * @return string
356
-	 * @throws NotPermittedException
357
-	 */
358
-	public function getNonExistingName($name) {
359
-		$uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
360
-		return trim($this->getRelativePath($uniqueName), '/');
361
-	}
362
-
363
-	/**
364
-	 * @param int $limit
365
-	 * @param int $offset
366
-	 * @return \OCP\Files\Node[]
367
-	 */
368
-	public function getRecent($limit, $offset = 0) {
369
-		$mimetypeLoader = \OC::$server->getMimeTypeLoader();
370
-		$mounts = $this->root->getMountsIn($this->path);
371
-		$mounts[] = $this->getMountPoint();
372
-
373
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
374
-			return $mount->getStorage();
375
-		});
376
-		$storageIds = array_map(function (IMountPoint $mount) {
377
-			return $mount->getStorage()->getCache()->getNumericStorageId();
378
-		}, $mounts);
379
-		/** @var IMountPoint[] $mountMap */
380
-		$mountMap = array_combine($storageIds, $mounts);
381
-		$folderMimetype = $mimetypeLoader->getId(FileInfo::MIMETYPE_FOLDER);
382
-
383
-		// Search in batches of 500 entries
384
-		$searchLimit = 500;
385
-		$results = [];
386
-		$searchResultCount = 0;
387
-		$count = 0;
388
-		do {
389
-			$searchResult = $this->recentSearch($searchLimit, $offset, $storageIds, $folderMimetype);
390
-
391
-			// Exit condition if there are no more results
392
-			if (count($searchResult) === 0) {
393
-				break;
394
-			}
395
-
396
-			$searchResultCount += count($searchResult);
397
-
398
-			$parseResult = $this->recentParse($searchResult, $mountMap, $mimetypeLoader);
399
-
400
-			foreach ($parseResult as $result) {
401
-				$results[] = $result;
402
-			}
403
-
404
-			$offset += $searchLimit;
405
-			$count++;
406
-		} while (count($results) < $limit && ($searchResultCount < (3 * $limit) || $count < 5));
407
-
408
-		return array_slice($results, 0, $limit);
409
-	}
410
-
411
-	private function recentSearch($limit, $offset, $storageIds, $folderMimetype) {
412
-		$builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
413
-		$query = $builder
414
-			->select('f.*')
415
-			->from('filecache', 'f')
416
-			->andWhere($builder->expr()->in('f.storage', $builder->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)))
417
-			->andWhere($builder->expr()->orX(
418
-			// handle non empty folders separate
419
-				$builder->expr()->neq('f.mimetype', $builder->createNamedParameter($folderMimetype, IQueryBuilder::PARAM_INT)),
420
-				$builder->expr()->eq('f.size', new Literal(0))
421
-			))
422
-			->andWhere($builder->expr()->notLike('f.path', $builder->createNamedParameter('files_versions/%')))
423
-			->andWhere($builder->expr()->notLike('f.path', $builder->createNamedParameter('files_trashbin/%')))
424
-			->orderBy('f.mtime', 'DESC')
425
-			->setMaxResults($limit)
426
-			->setFirstResult($offset);
427
-		return $query->execute()->fetchAll();
428
-	}
429
-
430
-	private function recentParse($result, $mountMap, $mimetypeLoader) {
431
-		$files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
432
-			$mount = $mountMap[$entry['storage']];
433
-			$entry['internalPath'] = $entry['path'];
434
-			$entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
435
-			$entry['mimepart'] = $mimetypeLoader->getMimetypeById($entry['mimepart']);
436
-			$path = $this->getAbsolutePath($mount, $entry['path']);
437
-			if (is_null($path)) {
438
-				return null;
439
-			}
440
-			$fileInfo = new \OC\Files\FileInfo($path, $mount->getStorage(), $entry['internalPath'], $entry, $mount);
441
-			return $this->root->createNode($fileInfo->getPath(), $fileInfo);
442
-		}, $result));
443
-
444
-		return array_values(array_filter($files, function (Node $node) {
445
-			$relative = $this->getRelativePath($node->getPath());
446
-			return $relative !== null && $relative !== '/';
447
-		}));
448
-	}
449
-
450
-	private function getAbsolutePath(IMountPoint $mount, $path) {
451
-		$storage = $mount->getStorage();
452
-		if ($storage->instanceOfStorage('\OC\Files\Storage\Wrapper\Jail')) {
453
-			if ($storage->instanceOfStorage(SharedStorage::class)) {
454
-				$storage->getSourceStorage();
455
-			}
456
-			/** @var \OC\Files\Storage\Wrapper\Jail $storage */
457
-			$jailRoot = $storage->getUnjailedPath('');
458
-			$rootLength = strlen($jailRoot) + 1;
459
-			if ($path === $jailRoot) {
460
-				return $mount->getMountPoint();
461
-			} else if (substr($path, 0, $rootLength) === $jailRoot . '/') {
462
-				return $mount->getMountPoint() . substr($path, $rootLength);
463
-			} else {
464
-				return null;
465
-			}
466
-		} else {
467
-			return $mount->getMountPoint() . $path;
468
-		}
469
-	}
40
+    /**
41
+     * Creates a Folder that represents a non-existing path
42
+     *
43
+     * @param string $path path
44
+     * @return string non-existing node class
45
+     */
46
+    protected function createNonExistingNode($path) {
47
+        return new NonExistingFolder($this->root, $this->view, $path);
48
+    }
49
+
50
+    /**
51
+     * @param string $path path relative to the folder
52
+     * @return string
53
+     * @throws \OCP\Files\NotPermittedException
54
+     */
55
+    public function getFullPath($path) {
56
+        if (!$this->isValidPath($path)) {
57
+            throw new NotPermittedException('Invalid path');
58
+        }
59
+        return $this->path . $this->normalizePath($path);
60
+    }
61
+
62
+    /**
63
+     * @param string $path
64
+     * @return string
65
+     */
66
+    public function getRelativePath($path) {
67
+        if ($this->path === '' or $this->path === '/') {
68
+            return $this->normalizePath($path);
69
+        }
70
+        if ($path === $this->path) {
71
+            return '/';
72
+        } else if (strpos($path, $this->path . '/') !== 0) {
73
+            return null;
74
+        } else {
75
+            $path = substr($path, strlen($this->path));
76
+            return $this->normalizePath($path);
77
+        }
78
+    }
79
+
80
+    /**
81
+     * check if a node is a (grand-)child of the folder
82
+     *
83
+     * @param \OC\Files\Node\Node $node
84
+     * @return bool
85
+     */
86
+    public function isSubNode($node) {
87
+        return strpos($node->getPath(), $this->path . '/') === 0;
88
+    }
89
+
90
+    /**
91
+     * get the content of this directory
92
+     *
93
+     * @throws \OCP\Files\NotFoundException
94
+     * @return Node[]
95
+     */
96
+    public function getDirectoryListing() {
97
+        $folderContent = $this->view->getDirectoryContent($this->path);
98
+
99
+        return array_map(function (FileInfo $info) {
100
+            if ($info->getMimetype() === 'httpd/unix-directory') {
101
+                return new Folder($this->root, $this->view, $info->getPath(), $info);
102
+            } else {
103
+                return new File($this->root, $this->view, $info->getPath(), $info);
104
+            }
105
+        }, $folderContent);
106
+    }
107
+
108
+    /**
109
+     * @param string $path
110
+     * @param FileInfo $info
111
+     * @return File|Folder
112
+     */
113
+    protected function createNode($path, FileInfo $info = null) {
114
+        if (is_null($info)) {
115
+            $isDir = $this->view->is_dir($path);
116
+        } else {
117
+            $isDir = $info->getType() === FileInfo::TYPE_FOLDER;
118
+        }
119
+        if ($isDir) {
120
+            return new Folder($this->root, $this->view, $path, $info);
121
+        } else {
122
+            return new File($this->root, $this->view, $path, $info);
123
+        }
124
+    }
125
+
126
+    /**
127
+     * Get the node at $path
128
+     *
129
+     * @param string $path
130
+     * @return \OC\Files\Node\Node
131
+     * @throws \OCP\Files\NotFoundException
132
+     */
133
+    public function get($path) {
134
+        return $this->root->get($this->getFullPath($path));
135
+    }
136
+
137
+    /**
138
+     * @param string $path
139
+     * @return bool
140
+     */
141
+    public function nodeExists($path) {
142
+        try {
143
+            $this->get($path);
144
+            return true;
145
+        } catch (NotFoundException $e) {
146
+            return false;
147
+        }
148
+    }
149
+
150
+    /**
151
+     * @param string $path
152
+     * @return \OC\Files\Node\Folder
153
+     * @throws \OCP\Files\NotPermittedException
154
+     */
155
+    public function newFolder($path) {
156
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
157
+            $fullPath = $this->getFullPath($path);
158
+            $nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
159
+            $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
160
+            $this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
161
+            if(!$this->view->mkdir($fullPath)) {
162
+                throw new NotPermittedException('Could not create folder');
163
+            }
164
+            $node = new Folder($this->root, $this->view, $fullPath);
165
+            $this->root->emit('\OC\Files', 'postWrite', array($node));
166
+            $this->root->emit('\OC\Files', 'postCreate', array($node));
167
+            return $node;
168
+        } else {
169
+            throw new NotPermittedException('No create permission for folder');
170
+        }
171
+    }
172
+
173
+    /**
174
+     * @param string $path
175
+     * @return \OC\Files\Node\File
176
+     * @throws \OCP\Files\NotPermittedException
177
+     */
178
+    public function newFile($path) {
179
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
180
+            $fullPath = $this->getFullPath($path);
181
+            $nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
182
+            $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
183
+            $this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
184
+            if (!$this->view->touch($fullPath)) {
185
+                throw new NotPermittedException('Could not create path');
186
+            }
187
+            $node = new File($this->root, $this->view, $fullPath);
188
+            $this->root->emit('\OC\Files', 'postWrite', array($node));
189
+            $this->root->emit('\OC\Files', 'postCreate', array($node));
190
+            return $node;
191
+        }
192
+        throw new NotPermittedException('No create permission for path');
193
+    }
194
+
195
+    /**
196
+     * search for files with the name matching $query
197
+     *
198
+     * @param string|ISearchOperator $query
199
+     * @return \OC\Files\Node\Node[]
200
+     */
201
+    public function search($query) {
202
+        if (is_string($query)) {
203
+            return $this->searchCommon('search', array('%' . $query . '%'));
204
+        } else {
205
+            return $this->searchCommon('searchQuery', array($query));
206
+        }
207
+    }
208
+
209
+    /**
210
+     * search for files by mimetype
211
+     *
212
+     * @param string $mimetype
213
+     * @return Node[]
214
+     */
215
+    public function searchByMime($mimetype) {
216
+        return $this->searchCommon('searchByMime', array($mimetype));
217
+    }
218
+
219
+    /**
220
+     * search for files by tag
221
+     *
222
+     * @param string|int $tag name or tag id
223
+     * @param string $userId owner of the tags
224
+     * @return Node[]
225
+     */
226
+    public function searchByTag($tag, $userId) {
227
+        return $this->searchCommon('searchByTag', array($tag, $userId));
228
+    }
229
+
230
+    /**
231
+     * @param string $method cache method
232
+     * @param array $args call args
233
+     * @return \OC\Files\Node\Node[]
234
+     */
235
+    private function searchCommon($method, $args) {
236
+        $files = array();
237
+        $rootLength = strlen($this->path);
238
+        $mount = $this->root->getMount($this->path);
239
+        $storage = $mount->getStorage();
240
+        $internalPath = $mount->getInternalPath($this->path);
241
+        $internalPath = rtrim($internalPath, '/');
242
+        if ($internalPath !== '') {
243
+            $internalPath = $internalPath . '/';
244
+        }
245
+        $internalRootLength = strlen($internalPath);
246
+
247
+        $cache = $storage->getCache('');
248
+
249
+        $results = call_user_func_array(array($cache, $method), $args);
250
+        foreach ($results as $result) {
251
+            if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) {
252
+                $result['internalPath'] = $result['path'];
253
+                $result['path'] = substr($result['path'], $internalRootLength);
254
+                $result['storage'] = $storage;
255
+                $files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
256
+            }
257
+        }
258
+
259
+        $mounts = $this->root->getMountsIn($this->path);
260
+        foreach ($mounts as $mount) {
261
+            $storage = $mount->getStorage();
262
+            if ($storage) {
263
+                $cache = $storage->getCache('');
264
+
265
+                $relativeMountPoint = ltrim(substr($mount->getMountPoint(), $rootLength), '/');
266
+                $results = call_user_func_array(array($cache, $method), $args);
267
+                foreach ($results as $result) {
268
+                    $result['internalPath'] = $result['path'];
269
+                    $result['path'] = $relativeMountPoint . $result['path'];
270
+                    $result['storage'] = $storage;
271
+                    $files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
272
+                }
273
+            }
274
+        }
275
+
276
+        return array_map(function (FileInfo $file) {
277
+            return $this->createNode($file->getPath(), $file);
278
+        }, $files);
279
+    }
280
+
281
+    /**
282
+     * @param int $id
283
+     * @return \OC\Files\Node\Node[]
284
+     */
285
+    public function getById($id) {
286
+        $mountCache = $this->root->getUserMountCache();
287
+        if (strpos($this->getPath(), '/', 1) > 0) {
288
+            list(, $user) = explode('/', $this->getPath());
289
+        } else {
290
+            $user = null;
291
+        }
292
+        $mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
293
+        $mounts = $this->root->getMountsIn($this->path);
294
+        $mounts[] = $this->root->getMount($this->path);
295
+        /** @var IMountPoint[] $folderMounts */
296
+        $folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
297
+            return $mountPoint->getMountPoint();
298
+        }, $mounts), $mounts);
299
+
300
+        /** @var ICachedMountInfo[] $mountsContainingFile */
301
+        $mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
302
+            return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
303
+        }));
304
+
305
+        if (count($mountsContainingFile) === 0) {
306
+            return [];
307
+        }
308
+
309
+        $nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($folderMounts, $id) {
310
+            $mount = $folderMounts[$cachedMountInfo->getMountPoint()];
311
+            $cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
312
+            if (!$cacheEntry) {
313
+                return null;
314
+            }
315
+
316
+            // cache jails will hide the "true" internal path
317
+            $internalPath = ltrim($cachedMountInfo->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
318
+            $pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
319
+            $pathRelativeToMount = ltrim($pathRelativeToMount, '/');
320
+            $absolutePath = rtrim($cachedMountInfo->getMountPoint() . $pathRelativeToMount, '/');
321
+            return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
322
+                $absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
323
+                \OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
324
+            ));
325
+        }, $mountsContainingFile);
326
+
327
+        $nodes = array_filter($nodes);
328
+
329
+        return array_filter($nodes, function (Node $node) {
330
+            return $this->getRelativePath($node->getPath());
331
+        });
332
+    }
333
+
334
+    public function getFreeSpace() {
335
+        return $this->view->free_space($this->path);
336
+    }
337
+
338
+    public function delete() {
339
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
340
+            $this->sendHooks(array('preDelete'));
341
+            $fileInfo = $this->getFileInfo();
342
+            $this->view->rmdir($this->path);
343
+            $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
344
+            $this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
345
+            $this->exists = false;
346
+        } else {
347
+            throw new NotPermittedException('No delete permission for path');
348
+        }
349
+    }
350
+
351
+    /**
352
+     * Add a suffix to the name in case the file exists
353
+     *
354
+     * @param string $name
355
+     * @return string
356
+     * @throws NotPermittedException
357
+     */
358
+    public function getNonExistingName($name) {
359
+        $uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
360
+        return trim($this->getRelativePath($uniqueName), '/');
361
+    }
362
+
363
+    /**
364
+     * @param int $limit
365
+     * @param int $offset
366
+     * @return \OCP\Files\Node[]
367
+     */
368
+    public function getRecent($limit, $offset = 0) {
369
+        $mimetypeLoader = \OC::$server->getMimeTypeLoader();
370
+        $mounts = $this->root->getMountsIn($this->path);
371
+        $mounts[] = $this->getMountPoint();
372
+
373
+        $mounts = array_filter($mounts, function (IMountPoint $mount) {
374
+            return $mount->getStorage();
375
+        });
376
+        $storageIds = array_map(function (IMountPoint $mount) {
377
+            return $mount->getStorage()->getCache()->getNumericStorageId();
378
+        }, $mounts);
379
+        /** @var IMountPoint[] $mountMap */
380
+        $mountMap = array_combine($storageIds, $mounts);
381
+        $folderMimetype = $mimetypeLoader->getId(FileInfo::MIMETYPE_FOLDER);
382
+
383
+        // Search in batches of 500 entries
384
+        $searchLimit = 500;
385
+        $results = [];
386
+        $searchResultCount = 0;
387
+        $count = 0;
388
+        do {
389
+            $searchResult = $this->recentSearch($searchLimit, $offset, $storageIds, $folderMimetype);
390
+
391
+            // Exit condition if there are no more results
392
+            if (count($searchResult) === 0) {
393
+                break;
394
+            }
395
+
396
+            $searchResultCount += count($searchResult);
397
+
398
+            $parseResult = $this->recentParse($searchResult, $mountMap, $mimetypeLoader);
399
+
400
+            foreach ($parseResult as $result) {
401
+                $results[] = $result;
402
+            }
403
+
404
+            $offset += $searchLimit;
405
+            $count++;
406
+        } while (count($results) < $limit && ($searchResultCount < (3 * $limit) || $count < 5));
407
+
408
+        return array_slice($results, 0, $limit);
409
+    }
410
+
411
+    private function recentSearch($limit, $offset, $storageIds, $folderMimetype) {
412
+        $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
413
+        $query = $builder
414
+            ->select('f.*')
415
+            ->from('filecache', 'f')
416
+            ->andWhere($builder->expr()->in('f.storage', $builder->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)))
417
+            ->andWhere($builder->expr()->orX(
418
+            // handle non empty folders separate
419
+                $builder->expr()->neq('f.mimetype', $builder->createNamedParameter($folderMimetype, IQueryBuilder::PARAM_INT)),
420
+                $builder->expr()->eq('f.size', new Literal(0))
421
+            ))
422
+            ->andWhere($builder->expr()->notLike('f.path', $builder->createNamedParameter('files_versions/%')))
423
+            ->andWhere($builder->expr()->notLike('f.path', $builder->createNamedParameter('files_trashbin/%')))
424
+            ->orderBy('f.mtime', 'DESC')
425
+            ->setMaxResults($limit)
426
+            ->setFirstResult($offset);
427
+        return $query->execute()->fetchAll();
428
+    }
429
+
430
+    private function recentParse($result, $mountMap, $mimetypeLoader) {
431
+        $files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
432
+            $mount = $mountMap[$entry['storage']];
433
+            $entry['internalPath'] = $entry['path'];
434
+            $entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
435
+            $entry['mimepart'] = $mimetypeLoader->getMimetypeById($entry['mimepart']);
436
+            $path = $this->getAbsolutePath($mount, $entry['path']);
437
+            if (is_null($path)) {
438
+                return null;
439
+            }
440
+            $fileInfo = new \OC\Files\FileInfo($path, $mount->getStorage(), $entry['internalPath'], $entry, $mount);
441
+            return $this->root->createNode($fileInfo->getPath(), $fileInfo);
442
+        }, $result));
443
+
444
+        return array_values(array_filter($files, function (Node $node) {
445
+            $relative = $this->getRelativePath($node->getPath());
446
+            return $relative !== null && $relative !== '/';
447
+        }));
448
+    }
449
+
450
+    private function getAbsolutePath(IMountPoint $mount, $path) {
451
+        $storage = $mount->getStorage();
452
+        if ($storage->instanceOfStorage('\OC\Files\Storage\Wrapper\Jail')) {
453
+            if ($storage->instanceOfStorage(SharedStorage::class)) {
454
+                $storage->getSourceStorage();
455
+            }
456
+            /** @var \OC\Files\Storage\Wrapper\Jail $storage */
457
+            $jailRoot = $storage->getUnjailedPath('');
458
+            $rootLength = strlen($jailRoot) + 1;
459
+            if ($path === $jailRoot) {
460
+                return $mount->getMountPoint();
461
+            } else if (substr($path, 0, $rootLength) === $jailRoot . '/') {
462
+                return $mount->getMountPoint() . substr($path, $rootLength);
463
+            } else {
464
+                return null;
465
+            }
466
+        } else {
467
+            return $mount->getMountPoint() . $path;
468
+        }
469
+    }
470 470
 }
Please login to merge, or discard this patch.