From 2522c25af726a8487ac13855e8a035b990cd69a4 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 21 Oct 2012 02:12:58 +0200 Subject: [PATCH] use OC_Files::getFileInfo and OC_Files::getDirectoryContent as high level api for the filecache most apps would want to use this api instead of using the cache directly --- lib/files.php | 108 +++++++++++++++++----------------- lib/files/filesystem.php | 73 ++++++++++++++++++----- lib/files/storage/storage.php | 7 +++ tests/lib/files.php | 87 +++++++++++++++++++++++++++ 4 files changed, 204 insertions(+), 71 deletions(-) create mode 100644 tests/lib/files.php diff --git a/lib/files.php b/lib/files.php index ba111bee96..8d402c0001 100644 --- a/lib/files.php +++ b/lib/files.php @@ -41,69 +41,67 @@ class OC_Files { * - versioned */ public static function getFileInfo($path) { - if (($path == '/Shared' || substr($path, 0, 8) == '/Shared/') && OC_App::isEnabled('files_sharing')) { - if ($path == '/Shared') { - list($info) = OCP\Share::getItemsSharedWith('file', OC_Share_Backend_File::FORMAT_FILE_APP_ROOT); - }else{ - $info['size'] = \OC\Files\Filesystem::filesize($path); - $info['mtime'] = \OC\Files\Filesystem::filemtime($path); - $info['ctime'] = \OC\Files\Filesystem::filectime($path); - $info['mimetype'] = \OC\Files\Filesystem::getMimeType($path); - $info['encrypted'] = false; - $info['versioned'] = false; + $path=\OC\Files\Filesystem::normalizePath($path); + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $path + */ + list($storage, $internalPath)=\OC\Files\Filesystem::resolvePath($path); + $cache=$storage->getCache(); + $data = $cache->get($internalPath); + + if($data['mimetype'] === 'httpd/unix-directory'){ + //add the sizes of other mountpoints to the folder + $mountPoints = \OC\Files\Filesystem::getMountPoints($path); + foreach($mountPoints as $mountPoint){ + $subStorage = \OC\Files\Filesystem::getStorage($mountPoint); + $subCache = $subStorage->getCache(); + $rootEntry = $subCache->get(''); + + $data['size'] += $rootEntry['size']; } - } else { - $info = OC_FileCache::get($path); } - return $info; + + return $data; } /** * get the content of a directory - * @param dir $directory path under datadirectory + * @param string $directory path under datadirectory + * @return array */ public static function getDirectoryContent($directory, $mimetype_filter = '') { - $directory=\OC\Files\Filesystem::normalizePath($directory); - if($directory=='/') { - $directory=''; - } - $files = array(); - if (($directory == '/Shared' || substr($directory, 0, 8) == '/Shared/') && OC_App::isEnabled('files_sharing')) { - if ($directory == '/Shared') { - $files = OCP\Share::getItemsSharedWith('file', OC_Share_Backend_File::FORMAT_FILE_APP, array('folder' => $directory, 'mimetype_filter' => $mimetype_filter)); - } else { - $pos = strpos($directory, '/', 8); - // Get shared folder name - if ($pos !== false) { - $itemTarget = substr($directory, 7, $pos - 7); - } else { - $itemTarget = substr($directory, 7); + $path=\OC\Files\Filesystem::normalizePath($directory); + /** + * @var \OC\Files\Storage\Storage $storage + * @var string $path + */ + list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($path); + $cache=$storage->getCache(); + $files=$cache->getFolderContents($internalPath); //TODO: mimetype_filter + + //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders + $mountPoints = \OC\Files\Filesystem::getMountPoints($directory); + $dirLength = strlen($path); + foreach($mountPoints as $mountPoint){ + $subStorage = \OC\Files\Filesystem::getStorage($mountPoint); + $subCache = $subStorage->getCache(); + $rootEntry = $subCache->get(''); + + $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']; + } } - $files = OCP\Share::getItemSharedWith('folder', $itemTarget, OC_Share_Backend_File::FORMAT_FILE_APP, array('folder' => $directory, 'mimetype_filter' => $mimetype_filter)); - } - } else { - $files = OC_FileCache::getFolderContent($directory, false, $mimetype_filter); - foreach ($files as &$file) { - $file['directory'] = $directory; - $file['type'] = ($file['mimetype'] == 'httpd/unix-directory') ? 'dir' : 'file'; - $permissions = OCP\Share::PERMISSION_READ; - // NOTE: Remove check when new encryption is merged - if (!$file['encrypted']) { - $permissions |= OCP\Share::PERMISSION_SHARE; - } - if ($file['type'] == 'dir' && $file['writable']) { - $permissions |= OCP\Share::PERMISSION_CREATE; - } - if ($file['writable']) { - $permissions |= OCP\Share::PERMISSION_UPDATE | OCP\Share::PERMISSION_DELETE; - } - $file['permissions'] = $permissions; - } - if ($directory == '' && OC_App::isEnabled('files_sharing')) { - // Add 'Shared' folder - $files = array_merge($files, OCP\Share::getItemsSharedWith('file', OC_Share_Backend_File::FORMAT_FILE_APP_ROOT)); + }else{ //mountpoint in this folder, add an entry for it + $rootEntry['name'] = $relativePath; + $files[] = $rootEntry; } } + usort($files, "fileCmp");//TODO: remove this once ajax is merged return $files; } @@ -145,7 +143,7 @@ class OC_Files { set_time_limit(0); $zip = new ZipArchive(); $filename = OC_Helper::tmpFile('.zip'); - if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==TRUE) { + if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) { exit("cannot open <$filename>\n"); } foreach($files as $file) { @@ -166,7 +164,7 @@ class OC_Files { set_time_limit(0); $zip = new ZipArchive(); $filename = OC_Helper::tmpFile('.zip'); - if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==TRUE) { + if ($zip->open($filename, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)!==true) { exit("cannot open <$filename>\n"); } $file=$dir.'/'.$files; @@ -446,7 +444,7 @@ class OC_Files { $setting = 'php_value '.$key.' '.$size; $hasReplaced = 0; $content = preg_replace($pattern, $setting, $htaccess, 1, $hasReplaced); - if($content !== NULL) { + if($content !== null) { $htaccess = $content; } if($hasReplaced == 0) { diff --git a/lib/files/filesystem.php b/lib/files/filesystem.php index 05dd698ab4..b7f8483fbf 100644 --- a/lib/files/filesystem.php +++ b/lib/files/filesystem.php @@ -164,6 +164,43 @@ class Filesystem { return $foundMountPoint; } + /** + * get a list of all mount points in a directory + * + * @param string $path + * @return string[] + */ + static public function getMountPoints($path) { + $path = self::normalizePath($path); + if (strlen($path) > 1) { + $path .= '/'; + } + $pathLength = strlen($path); + + $mountPoints = array_keys(self::$mounts); + $result = array(); + foreach ($mountPoints as $mountPoint) { + if (substr($mountPoint, 0, $pathLength) === $path and strlen($mountPoint) > $pathLength) { + $result[] = $mountPoint; + } + } + return $result; + } + + /** + * get the storage mounted at $mountPoint + * + * @param string $mountPoint + * @return \OC\Files\Storage\Storage + */ + public static function getStorage($mountPoint) { + if (!isset(self::$storages[$mountPoint])) { + $mount = self::$mounts[$mountPoint]; + self::$storages[$mountPoint] = self::createStorage($mount['class'], $mount['arguments']); + } + return self::$storages[$mountPoint]; + } + /** * resolve a path to a storage and internal path * @@ -173,14 +210,14 @@ class Filesystem { static public function resolvePath($path) { $mountpoint = self::getMountPoint($path); if ($mountpoint) { - if (!isset(self::$storages[$mountpoint])) { - $mount = self::$mounts[$mountpoint]; - self::$storages[$mountpoint] = self::createStorage($mount['class'], $mount['arguments']); + $storage = self::getStorage($mountpoint); + if ($mountpoint === $path) { + $internalPath = ''; + } else { + $internalPath = substr($path, strlen($mountpoint)); } - $storage = self::$storages[$mountpoint]; - $internalPath = substr($path, strlen($mountpoint)); return array($storage, $internalPath); - }else{ + } else { return array(null, null); } } @@ -302,18 +339,22 @@ class Filesystem { /** * mount an \OC\Files\Storage\Storage in our virtual filesystem * - * @param \OC\Files\Storage\Storage $storage + * @param \OC\Files\Storage\Storage|string $class * @param array $arguments * @param string $mountpoint */ static public function mount($class, $arguments, $mountpoint) { - if ($mountpoint[0] != '/') { - $mountpoint = '/' . $mountpoint; + $mountpoint = self::normalizePath($mountpoint); + if (strlen($mountpoint) > 1) { + $mountpoint .= '/'; } - if (substr($mountpoint, -1) !== '/') { - $mountpoint = $mountpoint . '/'; + + if ($class instanceof \OC\Files\Storage\Storage) { + self::$mounts[$mountpoint] = array('class' => get_class($class), 'arguments' => $arguments); + self::$storages[$mountpoint] = $class; + } else { + self::$mounts[$mountpoint] = array('class' => $class, 'arguments' => $arguments); } - self::$mounts[$mountpoint] = array('class' => $class, 'arguments' => $arguments); } /** @@ -522,15 +563,15 @@ class Filesystem { static public function removeETagHook($params, $root = false) { if (isset($params['path'])) { - $path=$params['path']; + $path = $params['path']; } else { - $path=$params['oldpath']; + $path = $params['oldpath']; } if ($root) { // reduce path to the required part of it (no 'username/files') - $fakeRootView = new OC_FilesystemView($root); + $fakeRootView = new View($root); $count = 1; - $path=str_replace(OC_App::getStorage("files")->getAbsolutePath(), "", $fakeRootView->getAbsolutePath($path), $count); + $path = str_replace(\OC_App::getStorage("files")->getAbsolutePath(''), "", $fakeRootView->getAbsolutePath($path), $count); } $path = self::normalizePath($path); diff --git a/lib/files/storage/storage.php b/lib/files/storage/storage.php index b1ec0bdb50..853e8ba519 100644 --- a/lib/files/storage/storage.php +++ b/lib/files/storage/storage.php @@ -52,6 +52,13 @@ interface Storage{ * returning true for other changes in the folder is optional */ public function hasUpdated($path,$time); + + /** + * @return \OC\Files\Cache\Cache + */ public function getCache(); + /** + * @return \OC\Files\Cache\Scanner + */ public function getScanner(); } diff --git a/tests/lib/files.php b/tests/lib/files.php new file mode 100644 index 0000000000..9cb5276845 --- /dev/null +++ b/tests/lib/files.php @@ -0,0 +1,87 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. */ + +use \OC\Files\Filesystem as Filesystem; + +class Test_Files extends PHPUnit_Framework_TestCase { + /** + * @var \OC\Files\Storage\Storage[] $storages; + */ + private $storages = array(); + + public function setUp() { + Filesystem::clearMounts(); + } + + public function tearDown() { + foreach ($this->storages as $storage) { + $cache = $storage->getCache(); + $cache->clear(); + } + } + + public function testCacheAPI() { + $storage1 = $this->getTestStorage(); + $storage2 = $this->getTestStorage(); + $storage3 = $this->getTestStorage(); + Filesystem::mount($storage1, array(), '/'); + Filesystem::mount($storage2, array(), '/substorage'); + Filesystem::mount($storage3, array(), '/folder/anotherstorage'); + $textSize = strlen("dummy file data\n"); + $imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo.png'); + $storageSize = $textSize * 2 + $imageSize; + + $cachedData = OC_Files::getFileInfo('/foo.txt'); + $this->assertEquals($textSize, $cachedData['size']); + $this->assertEquals('text/plain', $cachedData['mimetype']); + + $cachedData = OC_Files::getFileInfo('/'); + $this->assertEquals($storageSize * 3, $cachedData['size']); + $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']); + + $cachedData = OC_Files::getFileInfo('/folder'); + $this->assertEquals($storageSize + $textSize, $cachedData['size']); + $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']); + + $folderData = OC_Files::getDirectoryContent('/'); + /** + * expected entries: + * folder + * foo.png + * foo.txt + * substorage + */ + $this->assertEquals(4, count($folderData)); + $this->assertEquals('folder', $folderData[0]['name']); + $this->assertEquals('foo.png', $folderData[1]['name']); + $this->assertEquals('foo.txt', $folderData[2]['name']); + $this->assertEquals('substorage', $folderData[3]['name']); + + $this->assertEquals($storageSize + $textSize, $folderData[0]['size']); + $this->assertEquals($imageSize, $folderData[1]['size']); + $this->assertEquals($textSize, $folderData[2]['size']); + $this->assertEquals($storageSize, $folderData[3]['size']); + } + + /** + * @return OC\Files\Storage\Storage + */ + private function getTestStorage() { + $storage = new \OC\Files\Storage\Temporary(array()); + $textData = "dummy file data\n"; + $imgData = file_get_contents(\OC::$SERVERROOT . '/core/img/logo.png'); + $storage->mkdir('folder'); + $storage->file_put_contents('foo.txt', $textData); + $storage->file_put_contents('foo.png', $imgData); + $storage->file_put_contents('folder/bar.txt', $textData); + + $scanner = $storage->getScanner(); + $scanner->scan(''); + $this->storages[] = $storage; + return $storage; + } +}