/** * Correct the parent folders' ETags for all users shared the file at $target * * @param string $target */ public static function correctFolders($target) { $uid = \OCP\User::getUser(); $uidOwner = \OC\Files\Filesystem::getOwner($target); $info = \OC\Files\Filesystem::getFileInfo($target); // Correct Shared folders of other users shared with $users = \OCP\Share::getUsersItemShared('file', $info['fileid'], $uidOwner, true); if (!empty($users)) { while (!empty($users)) { $reshareUsers = array(); foreach ($users as $user) { if ($user !== $uidOwner) { $etag = \OC\Files\Filesystem::getETag(''); \OCP\Config::setUserValue($user, 'files_sharing', 'etag', $etag); // Look for reshares $reshareUsers = array_merge($reshareUsers, \OCP\Share::getUsersItemShared('file', $info['fileid'], $user, true)); } } $users = $reshareUsers; } // Correct folders of shared file owner $target = substr($target, 8); if ($uidOwner !== $uid && ($source = \OC_Share_Backend_File::getSource($target))) { \OC\Files\Filesystem::initMountPoints($uidOwner); $source = '/' . $uidOwner . '/' . $source['path']; \OC\Files\Cache\Updater::correctFolder($source, $info['mtime']); } } }
public function testMoveCrossStorage() { $storage2 = new Temporary(array()); $cache2 = $storage2->getCache(); Filesystem::mount($storage2, array(), '/bar'); $this->storage->file_put_contents('foo.txt', 'qwerty'); $this->updater->update('foo.txt'); $this->assertTrue($this->cache->inCache('foo.txt')); $this->assertFalse($cache2->inCache('bar.txt')); $cached = $this->cache->get('foo.txt'); // "rename" $storage2->file_put_contents('bar.txt', 'qwerty'); $this->storage->unlink('foo.txt'); $this->assertTrue($this->cache->inCache('foo.txt')); $this->assertFalse($cache2->inCache('bar.txt')); $this->updater->rename('foo.txt', 'bar/bar.txt'); $this->assertFalse($this->cache->inCache('foo.txt')); $this->assertTrue($cache2->inCache('bar.txt')); $cachedTarget = $cache2->get('bar.txt'); $this->assertEquals($cached['mtime'], $cachedTarget['mtime']); $this->assertEquals($cached['size'], $cachedTarget['size']); $this->assertEquals($cached['etag'], $cachedTarget['etag']); $this->assertEquals($cached['fileid'], $cachedTarget['fileid']); }
public function testMoveDisabled() { $this->storage->file_put_contents('foo.txt', 'qwerty'); $this->updater->update('foo.txt'); $this->assertTrue($this->cache->inCache('foo.txt')); $this->assertFalse($this->cache->inCache('bar.txt')); $cached = $this->cache->get('foo.txt'); $this->storage->rename('foo.txt', 'bar.txt'); $this->assertTrue($this->cache->inCache('foo.txt')); $this->assertFalse($this->cache->inCache('bar.txt')); $this->updater->disable(); $this->updater->rename('foo.txt', 'bar.txt'); $this->assertTrue($this->cache->inCache('foo.txt')); $this->assertFalse($this->cache->inCache('bar.txt')); }
public function testMove() { $this->storage->file_put_contents('foo.txt', 'qwerty'); $this->updater->update('foo.txt'); $this->assertTrue($this->cache->inCache('foo.txt')); $this->assertFalse($this->cache->inCache('bar.txt')); $cached = $this->cache->get('foo.txt'); $this->storage->rename('foo.txt', 'bar.txt'); $this->assertTrue($this->cache->inCache('foo.txt')); $this->assertFalse($this->cache->inCache('bar.txt')); $this->updater->rename('foo.txt', 'bar.txt'); $this->assertFalse($this->cache->inCache('foo.txt')); $this->assertTrue($this->cache->inCache('bar.txt')); $cachedTarget = $this->cache->get('bar.txt'); $this->assertEquals($cached['etag'], $cachedTarget['etag']); $this->assertEquals($cached['mtime'], $cachedTarget['mtime']); $this->assertEquals($cached['size'], $cachedTarget['size']); $this->assertEquals($cached['fileid'], $cachedTarget['fileid']); }
/** * abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage * * @param string $operation * @param string $path * @param array $hooks (optional) * @param mixed $extraParam (optional) * @return mixed * * This method takes requests for basic filesystem functions (e.g. reading & writing * files), processes hooks and proxies, sanitises paths, and finally passes them on to * \OC\Files\Storage\Storage for delegation to a storage backend for execution */ private function basicOperation($operation, $path, $hooks = array(), $extraParam = null) { $postFix = substr($path, -1, 1) === '/' ? '/' : ''; $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); if (\OC_FileProxy::runPreProxies($operation, $absolutePath, $extraParam) and Filesystem::isValidPath($path) and !Filesystem::isFileBlacklisted($path)) { $path = $this->getRelativePath($absolutePath); if ($path == null) { return false; } $run = $this->runHooks($hooks, $path); list($storage, $internalPath) = Filesystem::resolvePath($absolutePath . $postFix); if ($run and $storage) { if (!is_null($extraParam)) { $result = $storage->{$operation}($internalPath, $extraParam); } else { $result = $storage->{$operation}($internalPath); } $result = \OC_FileProxy::runPostProxies($operation, $this->getAbsolutePath($path), $result); if (in_array('delete', $hooks)) { $this->updater->remove($path); } if (in_array('write', $hooks)) { $this->updater->update($path); } if (in_array('touch', $hooks)) { $this->updater->update($path, $extraParam); } if ($this->shouldEmitHooks($path) && $result !== false) { if ($operation != 'fopen') { //no post hooks for fopen, the file stream is still open $this->runHooks($hooks, $path, true); } } return $result; } } return null; }
/** * get the content of a directory * * @param string $directory path under datadirectory * @param string $mimetype_filter limit returned content to this mimetype or mimepart * @return FileInfo[] */ public function getDirectoryContent($directory, $mimetype_filter = '') { $this->assertPathLength($directory); $result = array(); if (!Filesystem::isValidPath($directory)) { return $result; } $path = $this->getAbsolutePath($directory); $path = Filesystem::normalizePath($path); $mount = $this->getMount($directory); $storage = $mount->getStorage(); $internalPath = $mount->getInternalPath($path); if ($storage) { $cache = $storage->getCache($internalPath); $user = \OC_User::getUser(); $data = $cache->get($internalPath); $watcher = $storage->getWatcher($internalPath); if (!$data or $data['size'] === -1) { if (!$storage->file_exists($internalPath)) { return array(); } $scanner = $storage->getScanner($internalPath); $scanner->scan($internalPath, Cache\Scanner::SCAN_SHALLOW); $data = $cache->get($internalPath); } else { if ($watcher->checkUpdate($internalPath, $data)) { $this->updater->propagate($path); $data = $cache->get($internalPath); } } $folderId = $data['fileid']; /** * @var \OC\Files\FileInfo[] $files */ $files = array(); $contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter foreach ($contents as $content) { if ($content['permissions'] === 0) { $content['permissions'] = $storage->getPermissions($content['path']); $cache->update($content['fileid'], array('permissions' => $content['permissions'])); } // if sharing was disabled for the user we remove the share permissions if (\OCP\Util::isSharingDisabledForUser()) { $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; } $files[] = new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount); } //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders $mounts = Filesystem::getMountManager()->findIn($path); $dirLength = strlen($path); foreach ($mounts as $mount) { $mountPoint = $mount->getMountPoint(); $subStorage = $mount->getStorage(); if ($subStorage) { $subCache = $subStorage->getCache(''); if ($subCache->getStatus('') === Cache\Cache::NOT_FOUND) { $subScanner = $subStorage->getScanner(''); try { $subScanner->scanFile(''); } catch (\OCP\Files\StorageNotAvailableException $e) { continue; } catch (\OCP\Files\StorageInvalidException $e) { continue; } catch (\Exception $e) { // sometimes when the storage is not available it can be any exception \OCP\Util::writeLog('core', 'Exception while scanning storage "' . $subStorage->getId() . '": ' . get_class($e) . ': ' . $e->getMessage(), \OCP\Util::ERROR); continue; } } $rootEntry = $subCache->get(''); if ($rootEntry) { $relativePath = trim(substr($mountPoint, $dirLength), '/'); if ($pos = strpos($relativePath, '/')) { //mountpoint inside subfolder add size to the correct folder $entryName = substr($relativePath, 0, $pos); foreach ($files as &$entry) { if ($entry['name'] === $entryName) { $entry['size'] += $rootEntry['size']; } } } else { //mountpoint in this folder, add an entry for it $rootEntry['name'] = $relativePath; $rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file'; $permissions = $rootEntry['permissions']; // do not allow renaming/deleting the mount point if they are not shared files/folders // for shared files/folders we use the permissions given by the owner if ($mount instanceof MoveableMount) { $rootEntry['permissions'] = $permissions | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE; } else { $rootEntry['permissions'] = $permissions & \OCP\Constants::PERMISSION_ALL - (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE); } //remove any existing entry with the same name foreach ($files as $i => $file) { if ($file['name'] === $rootEntry['name']) { unset($files[$i]); break; } } $rootEntry['path'] = substr(Filesystem::normalizePath($path . '/' . $rootEntry['name']), strlen($user) + 2); // full path without /$user/ // if sharing was disabled for the user we remove the share permissions if (\OCP\Util::isSharingDisabledForUser()) { $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; } $files[] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount); } } } } if ($mimetype_filter) { foreach ($files as $file) { if (strpos($mimetype_filter, '/')) { if ($file['mimetype'] === $mimetype_filter) { $result[] = $file; } } else { if ($file['mimepart'] === $mimetype_filter) { $result[] = $file; } } } } else { $result = $files; } } return $result; }
/** * @param string[] $hooks * @param string $path * @param bool $post * @return bool */ private function runHooks($hooks, $path, $post = false) { $path = $this->getHookPath($path); $prefix = $post ? 'post_' : ''; $run = true; if ($this->shouldEmitHooks($path)) { foreach ($hooks as $hook) { // manually triger updater hooks to ensure they are called first if ($post) { if ($hook == 'write') { Updater::writeHook(array('path' => $path)); } elseif ($hook == 'touch') { Updater::touchHook(array('path' => $path)); } else { if ($hook == 'delete') { Updater::deleteHook(array('path' => $path)); } } } if ($hook != 'read') { \OC_Hook::emit(Filesystem::CLASSNAME, $prefix . $hook, array(Filesystem::signal_param_run => &$run, Filesystem::signal_param_path => $path)); } elseif (!$post) { \OC_Hook::emit(Filesystem::CLASSNAME, $prefix . $hook, array(Filesystem::signal_param_path => $path)); } } } return $run; }