3
* Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
4
* This file is licensed under the Affero General Public License version 3 or
6
* See the COPYING-README file.
10
* Class to provide access to ownCloud filesystem via a "view", and methods for
11
* working with files within that view (e.g. read, write, delete, etc.). Each
12
* view is restricted to a set of directories via a virtual root. The default view
13
* uses the currently logged in user's data directory as root (parts of
14
* OC_Filesystem are merely a wrapper for OC_FilesystemView).
16
* Apps that need to access files outside of the user data folders (to modify files
17
* belonging to a user other than the one currently logged in, for example) should
18
* use this class directly rather than using OC_Filesystem, or making use of PHP's
19
* built-in file manipulation functions. This will ensure all hooks and proxies
20
* are triggered correctly.
22
* Filesystem functions are not called directly; they are passed to the correct
23
* \OC\Files\Storage\Storage object
29
private $fakeRoot = '';
30
private $internal_path_cache = array();
31
private $storage_cache = array();
33
public function __construct($root = '') {
34
$this->fakeRoot = $root;
37
public function getAbsolutePath($path = '/') {
41
if ($path[0] !== '/') {
44
return $this->fakeRoot . $path;
48
* change the root to a fake root
50
* @param string $fakeRoot
53
public function chroot($fakeRoot) {
54
if (!$fakeRoot == '') {
55
if ($fakeRoot[0] !== '/') {
56
$fakeRoot = '/' . $fakeRoot;
59
$this->fakeRoot = $fakeRoot;
67
public function getRoot() {
68
return $this->fakeRoot;
72
* get path relative to the root of the view
77
public function getRelativePath($path) {
78
if ($this->fakeRoot == '') {
81
if (strpos($path, $this->fakeRoot) !== 0) {
84
$path = substr($path, strlen($this->fakeRoot));
85
if (strlen($path) === 0) {
94
* get the mountpoint of the storage object for a path
95
* ( note: because a storage is not always mounted inside the fakeroot, the
96
* returned mountpoint is relative to the absolute root of the filesystem
97
* and doesn't take the chroot into account )
102
public function getMountPoint($path) {
103
return Filesystem::getMountPoint($this->getAbsolutePath($path));
107
* resolve a path to a storage and internal path
109
* @param string $path
110
* @return array consisting of the storage and the internal path
112
public function resolvePath($path) {
113
$a = $this->getAbsolutePath($path);
114
$p = Filesystem::normalizePath($a);
115
return Filesystem::resolvePath($p);
119
* return the path to a local version of the file
120
* we need this because we can't know if a file is stored local or not from
121
* outside the filestorage and for some purposes a local file is needed
123
* @param string $path
126
public function getLocalFile($path) {
127
$parent = substr($path, 0, strrpos($path, '/'));
128
$path = $this->getAbsolutePath($path);
129
list($storage, $internalPath) = Filesystem::resolvePath($path);
130
if (Filesystem::isValidPath($parent) and $storage) {
131
return $storage->getLocalFile($internalPath);
138
* @param string $path
141
public function getLocalFolder($path) {
142
$parent = substr($path, 0, strrpos($path, '/'));
143
$path = $this->getAbsolutePath($path);
144
list($storage, $internalPath) = Filesystem::resolvePath($path);
145
if (Filesystem::isValidPath($parent) and $storage) {
146
return $storage->getLocalFolder($internalPath);
153
* the following functions operate with arguments and return values identical
154
* to those of their PHP built-in equivalents. Mostly they are merely wrappers
155
* for \OC\Files\Storage\Storage via basicOperation().
157
public function mkdir($path) {
158
return $this->basicOperation('mkdir', $path, array('create', 'write'));
161
public function rmdir($path) {
162
if ($this->is_dir($path)) {
163
return $this->basicOperation('rmdir', $path, array('delete'));
169
public function opendir($path) {
170
return $this->basicOperation('opendir', $path, array('read'));
173
public function readdir($handle) {
174
$fsLocal = new Storage\Local(array('datadir' => '/'));
175
return $fsLocal->readdir($handle);
178
public function is_dir($path) {
182
return $this->basicOperation('is_dir', $path);
185
public function is_file($path) {
189
return $this->basicOperation('is_file', $path);
192
public function stat($path) {
193
return $this->basicOperation('stat', $path);
196
public function filetype($path) {
197
return $this->basicOperation('filetype', $path);
200
public function filesize($path) {
201
return $this->basicOperation('filesize', $path);
204
public function readfile($path) {
206
$handle = $this->fopen($path, 'rb');
208
$chunkSize = 8192; // 8 kB chunks
209
while (!feof($handle)) {
210
echo fread($handle, $chunkSize);
213
$size = $this->filesize($path);
219
public function isCreatable($path) {
220
return $this->basicOperation('isCreatable', $path);
223
public function isReadable($path) {
224
return $this->basicOperation('isReadable', $path);
227
public function isUpdatable($path) {
228
return $this->basicOperation('isUpdatable', $path);
231
public function isDeletable($path) {
232
return $this->basicOperation('isDeletable', $path);
235
public function isSharable($path) {
236
return $this->basicOperation('isSharable', $path);
239
public function file_exists($path) {
243
return $this->basicOperation('file_exists', $path);
246
public function filemtime($path) {
247
return $this->basicOperation('filemtime', $path);
250
public function touch($path, $mtime = null) {
251
if (!is_null($mtime) and !is_numeric($mtime)) {
252
$mtime = strtotime($mtime);
255
$hooks = array('touch');
257
if (!$this->file_exists($path)) {
261
$result = $this->basicOperation('touch', $path, $hooks, $mtime);
262
if (!$result) { //if native touch fails, we emulate it by changing the mtime in the cache
263
$this->putFileInfo($path, array('mtime' => $mtime));
268
public function file_get_contents($path) {
269
return $this->basicOperation('file_get_contents', $path, array('read'));
272
public function file_put_contents($path, $data) {
273
if (is_resource($data)) { //not having to deal with streams in file_put_contents makes life easier
274
$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
275
if (\OC_FileProxy::runPreProxies('file_put_contents', $absolutePath, $data)
276
and Filesystem::isValidPath($path)
277
and !Filesystem::isFileBlacklisted($path)
279
$path = $this->getRelativePath($absolutePath);
280
$exists = $this->file_exists($path);
282
if ($this->shouldEmitHooks($path)) {
285
Filesystem::CLASSNAME,
286
Filesystem::signal_create,
288
Filesystem::signal_param_path => $this->getHookPath($path),
289
Filesystem::signal_param_run => &$run
294
Filesystem::CLASSNAME,
295
Filesystem::signal_write,
297
Filesystem::signal_param_path => $this->getHookPath($path),
298
Filesystem::signal_param_run => &$run
305
$target = $this->fopen($path, 'w');
307
list ($count, $result) = \OC_Helper::streamCopy($data, $target);
310
if ($this->shouldEmitHooks($path) && $result !== false) {
313
Filesystem::CLASSNAME,
314
Filesystem::signal_post_create,
315
array(Filesystem::signal_param_path => $this->getHookPath($path))
319
Filesystem::CLASSNAME,
320
Filesystem::signal_post_write,
321
array(Filesystem::signal_param_path => $this->getHookPath($path))
324
\OC_FileProxy::runPostProxies('file_put_contents', $absolutePath, $count);
333
$hooks = ($this->file_exists($path)) ? array('write') : array('create', 'write');
334
return $this->basicOperation('file_put_contents', $path, $hooks, $data);
338
public function unlink($path) {
339
if ($path === '' || $path === '/') {
340
// do not allow deleting the root
343
$postFix = (substr($path, -1, 1) === '/') ? '/' : '';
344
$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
345
list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
346
if (!$internalPath || $internalPath === '' || $internalPath === '/') {
347
// do not allow deleting the storage's root / the mount point
348
// because for some storages it might delete the whole contents
349
// but isn't supposed to work that way
352
return $this->basicOperation('unlink', $path, array('delete'));
355
public function deleteAll($directory, $empty = false) {
356
return $this->rmdir($directory);
359
public function rename($path1, $path2) {
360
$postFix1 = (substr($path1, -1, 1) === '/') ? '/' : '';
361
$postFix2 = (substr($path2, -1, 1) === '/') ? '/' : '';
362
$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
363
$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
365
\OC_FileProxy::runPreProxies('rename', $absolutePath1, $absolutePath2)
366
and Filesystem::isValidPath($path2)
367
and Filesystem::isValidPath($path1)
368
and !Filesystem::isFileBlacklisted($path2)
370
$path1 = $this->getRelativePath($absolutePath1);
371
$path2 = $this->getRelativePath($absolutePath2);
373
if ($path1 == null or $path2 == null) {
377
if ($this->shouldEmitHooks() && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2))) {
378
// if it was a rename from a part file to a regular file it was a write and not a rename operation
380
Filesystem::CLASSNAME, Filesystem::signal_write,
382
Filesystem::signal_param_path => $this->getHookPath($path2),
383
Filesystem::signal_param_run => &$run
386
} elseif ($this->shouldEmitHooks()) {
388
Filesystem::CLASSNAME, Filesystem::signal_rename,
390
Filesystem::signal_param_oldpath => $this->getHookPath($path1),
391
Filesystem::signal_param_newpath => $this->getHookPath($path2),
392
Filesystem::signal_param_run => &$run
397
$mp1 = $this->getMountPoint($path1 . $postFix1);
398
$mp2 = $this->getMountPoint($path2 . $postFix2);
400
list($storage, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1);
401
list(, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2);
403
$result = $storage->rename($internalPath1, $internalPath2);
404
\OC_FileProxy::runPostProxies('rename', $absolutePath1, $absolutePath2);
409
if ($this->is_dir($path1)) {
410
$result = $this->copy($path1, $path2);
411
if ($result === true) {
412
list($storage1, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1);
413
$result = $storage1->deleteAll($internalPath1);
416
$source = $this->fopen($path1 . $postFix1, 'r');
417
$target = $this->fopen($path2 . $postFix2, 'w');
418
list($count, $result) = \OC_Helper::streamCopy($source, $target);
420
// close open handle - especially $source is necessary because unlink below will
421
// throw an exception on windows because the file is locked
425
if ($result !== false) {
426
list($storage1, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1);
427
$storage1->unlink($internalPath1);
431
if ($this->shouldEmitHooks() && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
432
// if it was a rename from a part file to a regular file it was a write and not a rename operation
434
Filesystem::CLASSNAME,
435
Filesystem::signal_post_write,
437
Filesystem::signal_param_path => $this->getHookPath($path2),
440
} elseif ($this->shouldEmitHooks() && $result !== false) {
442
Filesystem::CLASSNAME,
443
Filesystem::signal_post_rename,
445
Filesystem::signal_param_oldpath => $this->getHookPath($path1),
446
Filesystem::signal_param_newpath => $this->getHookPath($path2)
459
public function copy($path1, $path2) {
460
$postFix1 = (substr($path1, -1, 1) === '/') ? '/' : '';
461
$postFix2 = (substr($path2, -1, 1) === '/') ? '/' : '';
462
$absolutePath1 = Filesystem::normalizePath($this->getAbsolutePath($path1));
463
$absolutePath2 = Filesystem::normalizePath($this->getAbsolutePath($path2));
465
\OC_FileProxy::runPreProxies('copy', $absolutePath1, $absolutePath2)
466
and Filesystem::isValidPath($path2)
467
and Filesystem::isValidPath($path1)
468
and !Filesystem::isFileBlacklisted($path2)
470
$path1 = $this->getRelativePath($absolutePath1);
471
$path2 = $this->getRelativePath($absolutePath2);
473
if ($path1 == null or $path2 == null) {
477
$exists = $this->file_exists($path2);
478
if ($this->shouldEmitHooks()) {
480
Filesystem::CLASSNAME,
481
Filesystem::signal_copy,
483
Filesystem::signal_param_oldpath => $this->getHookPath($path1),
484
Filesystem::signal_param_newpath => $this->getHookPath($path2),
485
Filesystem::signal_param_run => &$run
488
if ($run and !$exists) {
490
Filesystem::CLASSNAME,
491
Filesystem::signal_create,
493
Filesystem::signal_param_path => $this->getHookPath($path2),
494
Filesystem::signal_param_run => &$run
500
Filesystem::CLASSNAME,
501
Filesystem::signal_write,
503
Filesystem::signal_param_path => $this->getHookPath($path2),
504
Filesystem::signal_param_run => &$run
510
$mp1 = $this->getMountPoint($path1 . $postFix1);
511
$mp2 = $this->getMountPoint($path2 . $postFix2);
513
list($storage, $internalPath1) = Filesystem::resolvePath($absolutePath1 . $postFix1);
514
list(, $internalPath2) = Filesystem::resolvePath($absolutePath2 . $postFix2);
516
$result = $storage->copy($internalPath1, $internalPath2);
521
if ($this->is_dir($path1) && ($dh = $this->opendir($path1))) {
522
$result = $this->mkdir($path2);
523
if (is_resource($dh)) {
524
while (($file = readdir($dh)) !== false) {
525
if (!Filesystem::isIgnoredDir($file)) {
526
$result = $this->copy($path1 . '/' . $file, $path2 . '/' . $file);
531
$source = $this->fopen($path1 . $postFix1, 'r');
532
$target = $this->fopen($path2 . $postFix2, 'w');
533
list($count, $result) = \OC_Helper::streamCopy($source, $target);
536
if ($this->shouldEmitHooks() && $result !== false) {
538
Filesystem::CLASSNAME,
539
Filesystem::signal_post_copy,
541
Filesystem::signal_param_oldpath => $this->getHookPath($path1),
542
Filesystem::signal_param_newpath => $this->getHookPath($path2)
547
Filesystem::CLASSNAME,
548
Filesystem::signal_post_create,
549
array(Filesystem::signal_param_path => $this->getHookPath($path2))
553
Filesystem::CLASSNAME,
554
Filesystem::signal_post_write,
555
array(Filesystem::signal_param_path => $this->getHookPath($path2))
567
public function fopen($path, $mode) {
594
\OC_Log::write('core', 'invalid mode (' . $mode . ') for ' . $path, \OC_Log::ERROR);
597
return $this->basicOperation('fopen', $path, $hooks, $mode);
600
public function toTmpFile($path) {
601
if (Filesystem::isValidPath($path)) {
602
$source = $this->fopen($path, 'r');
604
$extension = pathinfo($path, PATHINFO_EXTENSION);
605
$tmpFile = \OC_Helper::tmpFile($extension);
606
file_put_contents($tmpFile, $source);
616
public function fromTmpFile($tmpFile, $path) {
617
if (Filesystem::isValidPath($path)) {
619
debug_print_backtrace();
621
$source = fopen($tmpFile, 'r');
623
$this->file_put_contents($path, $source);
634
public function getMimeType($path) {
635
return $this->basicOperation('getMimeType', $path);
638
public function hash($type, $path, $raw = false) {
639
$postFix = (substr($path, -1, 1) === '/') ? '/' : '';
640
$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
641
if (\OC_FileProxy::runPreProxies('hash', $absolutePath) && Filesystem::isValidPath($path)) {
642
$path = $this->getRelativePath($absolutePath);
646
if ($this->shouldEmitHooks($path)) {
648
Filesystem::CLASSNAME,
649
Filesystem::signal_read,
650
array(Filesystem::signal_param_path => $this->getHookPath($path))
653
list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
655
$result = $storage->hash($type, $internalPath, $raw);
656
$result = \OC_FileProxy::runPostProxies('hash', $absolutePath, $result);
663
public function free_space($path = '/') {
664
return $this->basicOperation('free_space', $path);
668
* @brief abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage
669
* @param string $operation
670
* @param string $path
671
* @param array $hooks (optional)
672
* @param mixed $extraParam (optional)
675
* This method takes requests for basic filesystem functions (e.g. reading & writing
676
* files), processes hooks and proxies, sanitises paths, and finally passes them on to
677
* \OC\Files\Storage\Storage for delegation to a storage backend for execution
679
private function basicOperation($operation, $path, $hooks = array(), $extraParam = null) {
680
$postFix = (substr($path, -1, 1) === '/') ? '/' : '';
681
$absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path));
682
if (\OC_FileProxy::runPreProxies($operation, $absolutePath, $extraParam)
683
and Filesystem::isValidPath($path)
684
and !Filesystem::isFileBlacklisted($path)
686
$path = $this->getRelativePath($absolutePath);
691
$run = $this->runHooks($hooks, $path);
692
list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix);
693
if ($run and $storage) {
694
if (!is_null($extraParam)) {
695
$result = $storage->$operation($internalPath, $extraParam);
697
$result = $storage->$operation($internalPath);
699
$result = \OC_FileProxy::runPostProxies($operation, $this->getAbsolutePath($path), $result);
700
if ($this->shouldEmitHooks($path) && $result !== false) {
701
if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open
702
$this->runHooks($hooks, $path, true);
712
* get the path relative to the default root for hook usage
714
* @param string $path
717
private function getHookPath($path) {
718
if (!Filesystem::getView()) {
721
return Filesystem::getView()->getRelativePath($this->getAbsolutePath($path));
724
private function shouldEmitHooks($path = '') {
725
if ($path && Cache\Scanner::isPartialFile($path)) {
728
if (!Filesystem::$loaded) {
731
$defaultRoot = Filesystem::getRoot();
732
if ($this->fakeRoot === $defaultRoot) {
735
return (strlen($this->fakeRoot) > strlen($defaultRoot)) && (substr($this->fakeRoot, 0, strlen($defaultRoot) + 1) === $defaultRoot . '/');
738
private function runHooks($hooks, $path, $post = false) {
739
$path = $this->getHookPath($path);
740
$prefix = ($post) ? 'post_' : '';
742
if ($this->shouldEmitHooks($path)) {
743
foreach ($hooks as $hook) {
744
if ($hook != 'read') {
746
Filesystem::CLASSNAME,
749
Filesystem::signal_param_run => &$run,
750
Filesystem::signal_param_path => $path
755
Filesystem::CLASSNAME,
758
Filesystem::signal_param_path => $path
768
* check if a file or folder has been updated since $time
770
* @param string $path
774
public function hasUpdated($path, $time) {
775
return $this->basicOperation('hasUpdated', $path, array(), $time);
779
* get the filesystem info
781
* @param string $path
782
* @param boolean $includeMountPoints whether to add mountpoint sizes,
786
* returns an associative array with the following keys:
793
public function getFileInfo($path, $includeMountPoints = true) {
795
if (!Filesystem::isValidPath($path)) {
798
$path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
800
* @var \OC\Files\Storage\Storage $storage
801
* @var string $internalPath
803
list($storage, $internalPath) = Filesystem::resolvePath($path);
805
$cache = $storage->getCache($internalPath);
806
$permissionsCache = $storage->getPermissionsCache($internalPath);
807
$user = \OC_User::getUser();
809
if (!$cache->inCache($internalPath)) {
810
$scanner = $storage->getScanner($internalPath);
811
$scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
813
$watcher = $storage->getWatcher($internalPath);
814
$watcher->checkUpdate($internalPath);
817
$data = $cache->get($internalPath);
819
if ($data and $data['fileid']) {
820
if ($includeMountPoints and $data['mimetype'] === 'httpd/unix-directory') {
821
//add the sizes of other mountpoints to the folder
822
$mountPoints = Filesystem::getMountPoints($path);
823
foreach ($mountPoints as $mountPoint) {
824
$subStorage = Filesystem::getStorage($mountPoint);
826
$subCache = $subStorage->getCache('');
827
$rootEntry = $subCache->get('');
828
$data['size'] += isset($rootEntry['size']) ? $rootEntry['size'] : 0;
833
$permissions = $permissionsCache->get($data['fileid'], $user);
834
if ($permissions === -1) {
835
$permissions = $storage->getPermissions($internalPath);
836
$permissionsCache->set($data['fileid'], $user, $permissions);
838
$data['permissions'] = $permissions;
842
$data = \OC_FileProxy::runPostProxies('getFileInfo', $path, $data);
848
* get the content of a directory
850
* @param string $directory path under datadirectory
851
* @param string $mimetype_filter limit returned content to this mimetype or mimepart
854
public function getDirectoryContent($directory, $mimetype_filter = '') {
856
if (!Filesystem::isValidPath($directory)) {
859
$path = Filesystem::normalizePath($this->fakeRoot . '/' . $directory);
861
* @var \OC\Files\Storage\Storage $storage
862
* @var string $internalPath
864
list($storage, $internalPath) = Filesystem::resolvePath($path);
866
$cache = $storage->getCache($internalPath);
867
$permissionsCache = $storage->getPermissionsCache($internalPath);
868
$user = \OC_User::getUser();
870
if ($cache->getStatus($internalPath) < Cache\Cache::COMPLETE) {
871
$scanner = $storage->getScanner($internalPath);
872
$scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
874
$watcher = $storage->getWatcher($internalPath);
875
$watcher->checkUpdate($internalPath);
878
$files = $cache->getFolderContents($internalPath); //TODO: mimetype_filter
879
$permissions = $permissionsCache->getDirectoryPermissions($cache->getId($internalPath), $user);
882
foreach ($files as $i => $file) {
883
$files[$i]['type'] = $file['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file';
884
$ids[] = $file['fileid'];
886
if (!isset($permissions[$file['fileid']])) {
887
$permissions[$file['fileid']] = $storage->getPermissions($file['path']);
888
$permissionsCache->set($file['fileid'], $user, $permissions[$file['fileid']]);
890
$files[$i]['permissions'] = $permissions[$file['fileid']];
893
//add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
894
$mountPoints = Filesystem::getMountPoints($path);
895
$dirLength = strlen($path);
896
foreach ($mountPoints as $mountPoint) {
897
$subStorage = Filesystem::getStorage($mountPoint);
899
$subCache = $subStorage->getCache('');
901
if ($subCache->getStatus('') === Cache\Cache::NOT_FOUND) {
902
$subScanner = $subStorage->getScanner('');
903
$subScanner->scanFile('');
906
$rootEntry = $subCache->get('');
908
$relativePath = trim(substr($mountPoint, $dirLength), '/');
909
if ($pos = strpos($relativePath, '/')) {
910
//mountpoint inside subfolder add size to the correct folder
911
$entryName = substr($relativePath, 0, $pos);
912
foreach ($files as &$entry) {
913
if ($entry['name'] === $entryName) {
914
$entry['size'] += $rootEntry['size'];
917
} else { //mountpoint in this folder, add an entry for it
918
$rootEntry['name'] = $relativePath;
919
$rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file';
920
$subPermissionsCache = $subStorage->getPermissionsCache('');
921
$permissions = $subPermissionsCache->get($rootEntry['fileid'], $user);
922
if ($permissions === -1) {
923
$permissions = $subStorage->getPermissions($rootEntry['path']);
924
$subPermissionsCache->set($rootEntry['fileid'], $user, $permissions);
926
// do not allow renaming/deleting the mount point
927
$rootEntry['permissions'] = $permissions & (\OCP\PERMISSION_ALL - (\OCP\PERMISSION_UPDATE | \OCP\PERMISSION_DELETE));
929
//remove any existing entry with the same name
930
foreach ($files as $i => $file) {
931
if ($file['name'] === $rootEntry['name']) {
936
$files[] = $rootEntry;
942
if ($mimetype_filter) {
943
foreach ($files as $file) {
944
if (strpos($mimetype_filter, '/')) {
945
if ($file['mimetype'] === $mimetype_filter) {
949
if ($file['mimepart'] === $mimetype_filter) {
962
* change file metadata
964
* @param string $path
968
* returns the fileid of the updated file
970
public function putFileInfo($path, $data) {
971
$path = Filesystem::normalizePath($this->fakeRoot . '/' . $path);
973
* @var \OC\Files\Storage\Storage $storage
974
* @var string $internalPath
976
list($storage, $internalPath) = Filesystem::resolvePath($path);
978
$cache = $storage->getCache($path);
980
if (!$cache->inCache($internalPath)) {
981
$scanner = $storage->getScanner($internalPath);
982
$scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW);
985
return $cache->put($internalPath, $data);
992
* search for files with the name matching $query
994
* @param string $query
997
public function search($query) {
998
return $this->searchCommon('%' . $query . '%', 'search');
1002
* search for files by mimetype
1004
* @param string $mimetype
1007
public function searchByMime($mimetype) {
1008
return $this->searchCommon($mimetype, 'searchByMime');
1012
* @param string $query
1013
* @param string $method
1016
private function searchCommon($query, $method) {
1018
$rootLength = strlen($this->fakeRoot);
1020
$mountPoint = Filesystem::getMountPoint($this->fakeRoot);
1021
$storage = Filesystem::getStorage($mountPoint);
1023
$cache = $storage->getCache('');
1025
$results = $cache->$method($query);
1026
foreach ($results as $result) {
1027
if (substr($mountPoint . $result['path'], 0, $rootLength + 1) === $this->fakeRoot . '/') {
1028
$result['path'] = substr($mountPoint . $result['path'], $rootLength);
1033
$mountPoints = Filesystem::getMountPoints($this->fakeRoot);
1034
foreach ($mountPoints as $mountPoint) {
1035
$storage = Filesystem::getStorage($mountPoint);
1037
$cache = $storage->getCache('');
1039
$relativeMountPoint = substr($mountPoint, $rootLength);
1040
$results = $cache->$method($query);
1042
foreach ($results as $result) {
1043
$result['path'] = $relativeMountPoint . $result['path'];
1054
* Get the owner for a file or folder
1056
* @param string $path
1059
public function getOwner($path) {
1060
return $this->basicOperation('getOwner', $path);
1064
* get the ETag for a file or folder
1066
* @param string $path
1069
public function getETag($path) {
1071
* @var Storage\Storage $storage
1072
* @var string $internalPath
1074
list($storage, $internalPath) = $this->resolvePath($path);
1076
return $storage->getETag($internalPath);
1083
* Get the path of a file by id, relative to the view
1085
* Note that the resulting path is not guarantied to be unique for the id, multiple paths can point to the same file
1090
public function getPath($id) {
1091
list($storage, $internalPath) = Cache\Cache::getById($id);
1092
$mounts = Filesystem::getMountByStorageId($storage);
1093
foreach ($mounts as $mount) {
1095
* @var \OC\Files\Mount $mount
1097
$fullPath = $mount->getMountPoint() . $internalPath;
1098
if (!is_null($path = $this->getRelativePath($fullPath))) {