diff options
author | Robin Appelman <icewind@owncloud.com> | 2012-09-16 16:52:32 +0200 |
---|---|---|
committer | Robin Appelman <icewind@owncloud.com> | 2012-09-16 16:52:32 +0200 |
commit | 954596c251cb3132878d8d5eafcc37c47b3f520e (patch) | |
tree | 526cf72cd6855b6d96be3b13f485734c0ba2d2e7 /lib/files/cache | |
parent | c94fe38d3900acff474c909aaa730d7ab51f914d (diff) | |
download | nextcloud-server-954596c251cb3132878d8d5eafcc37c47b3f520e.tar.gz nextcloud-server-954596c251cb3132878d8d5eafcc37c47b3f520e.zip |
rework filecache to work directly on storage backends wip
Diffstat (limited to 'lib/files/cache')
-rw-r--r-- | lib/files/cache/cache.php | 189 | ||||
-rw-r--r-- | lib/files/cache/scanner.php | 78 |
2 files changed, 267 insertions, 0 deletions
diff --git a/lib/files/cache/cache.php b/lib/files/cache/cache.php new file mode 100644 index 00000000000..8fc575948dc --- /dev/null +++ b/lib/files/cache/cache.php @@ -0,0 +1,189 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +class Cache { + /** + * @var array partial data for the cache + */ + private static $partial = array(); + + /** + * get the stored metadata of a file or folder + * + * @param \OC\Files\File or int $file + * @return array + */ + static public function get($file) { + if ($file instanceof \OC\Files\File) { + $where = 'WHERE `storage` = ? AND `path_hash` = ?'; + $params = array($file->getStorageId(), $file->getInternalPath()); + } else { //file id + $where = 'WHERE `fileid` = ?'; + $params = array($file); + } + $query = \OC_DB::prepare( + 'SELECT `id`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime` + FROM `*PREFIX*filecache` ' . $where); + $result=$query->execute($params); + return $result->fetchRow(); + } + + /** + * store meta data for a file or folder + * + * @param \OC\Files\File $file + * @param array $data + * + * @return int file id + */ + static public function put(\OC\Files\File $file, array $data) { + if ($id = self::getId($file) > -1) { + self::update($id, $data); + return $id; + } else { + $key = $file->getStorageId() . '::' . $file->getInternalPath(); + if (isset(self::$partial[$key])) { //add any saved partial data + $data = array_merge($data, self::$partial[$key]); + unset(self::$partial[$key]); + } + + $requiredFields = array('size', 'mtime', 'mimetype'); + foreach ($requiredFields as $field) { + if (!isset($data[$field])) { //data not complete save as partial and return + self::$partial[$key] = $data; + return -1; + } + } + + $data['path'] = $file->getInternalPath(); + $data['parent'] = self::getParentId($file); + $data['name'] = basename($file->getInternalPath()); + + list($queryParts, $params) = self::buildParts($data); + $queryParts[] = '`storage`'; + $params[] = $file->getStorageId(); + $valuesPlaceholder = array_fill(0, count($queryParts), '?'); + + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache`(' . implode(', ', $queryParts) . ' VALUES(' . implode(', ', $valuesPlaceholder) . ')'); + $query->execute($params); + + return \OC_DB::insertid('*PREFIX*filecache'); + } + } + + /** + * update the metadata in the cache + * + * @param int $id + * @param array $data + */ + static public function update($id, array $data) { + list($queryParts, $params) = self::buildParts($data); + $params[] = $id; + + $query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=? WHERE fileid = ?'); + $query->execute($params); + } + + /** + * extract query parts and params array from data array + * + * @param array $data + * @return array + */ + private static function buildParts(array $data) { + $fields = array('path', 'parent', 'name', 'mimetype', 'size', 'mtime'); + + $params = array(); + $queryParts = array(); + foreach ($data as $name => $value) { + if (array_search($name, $fields) !== false) { + $params[] = $value; + $queryParts[] = '`' . $name . '`'; + if ($name === 'path') { + $params[] = md5($value); + $queryParts[] = '`path_hash`'; + } elseif ($name === 'mimetype') { + $params[] = substr($value, 0, strpos($value, '/')); + $queryParts[] = '`mimepart`'; + } + } + } + return array($queryParts, $params); + } + + /** + * get the file id for a file + * + * @param \OC\Files\File $file + * @return int + */ + static public function getId(\OC\Files\File $file) { + $storageId = $file->getStorageId(); + $pathHash = md5($file->getInternalPath()); + + $query = \OC_DB::prepare('SELECT id FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?'); + $result = $query->execute(array($storageId, $pathHash)); + + if ($row = $result->fetchRow()) { + return $row['id']; + } else { + return -1; + } + } + + /** + * get the id of the parent folder of a file + * + * @param \OC\Files\File $file + * return int + */ + static public function getParentId(\OC\Files\File $file) { + $path = $file->getInternalPath(); + if ($path === '/' or $path === '') { + return -1; + } else { + return self::getId(new \OC\Files\File($file->getStorage(), dirname($path))); + } + } + + /** + * check if a file is available in the cache + * + * @param \OC\Files\File $file + * @return bool + */ + static public function inCache(\OC\Files\File $file) { + return self::getId($file) != -1; + } + + /** + * remove a file or folder from the cache + * + * @param \OC\Files\File $file + */ + public function remove(\OC\Files\File $file) { + $storageId = $file->getStorageId(); + $pathHash = md5($file->getInternalPath()); + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?'); + $query->execute(array($storageId, $pathHash)); + } + + /** + * remove all entries for files that are stored on $storage form the cache + * + * @param \OC\Files\Storage\Storage $storage + */ + public function removeStorage(\OC\Files\Storage\Storage $storage) { + $storageId = $storage->getId(); + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*filecache` WHERE storage=?'); + $query->execute(array($storageId)); + } +} diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php new file mode 100644 index 00000000000..8f2c5bda5ca --- /dev/null +++ b/lib/files/cache/scanner.php @@ -0,0 +1,78 @@ +<?php +/** + * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +class Scanner { + const SCAN_RECURSIVE = true; + const SCAN_SHALLOW = false; + + /** + * get all the metadata of a file or folder + * * + * @param \OC\Files\File $file + * @return array with metadata of the file + */ + public static function getData(\OC\Files\File $file) { + $data = array(); + $storage = $file->getStorage(); + $path = $file->getInternalPath(); + if (!$storage->isReadable($path)) return null; //cant read, nothing we can do + clearstatcache(); + $data['mimetype'] = $storage->getMimeType($path); + $data['mtime'] = $storage->filemtime($path); + if ($data['mimetype'] == 'httpd/unix-directory') { + $data['size'] = -1; //unknown + $data['permissions'] = $storage->getPermissions($path . '/'); + } else { + $data['size'] = $storage->filesize($path); + $data['permissions'] = $storage->getPermissions($path); + } + return $data; + } + + /** + * scan a single file and store it in the cache + * + * @param \OC\Files\File $file + * @return array with metadata of the scanned file + */ + public static function scanFile(\OC\Files\File $file) { + $data = self::getData($file); + Cache::put($file, $data); + return $data; + } + + /** + * scan all the files in a folder and store them in the cache + * + * @param \OC\Files\File $folder + * @param SCAN_RECURSIVE/SCAN_SHALLOW $recursive + * @return int the size of the scanned folder or -1 if the size is unknown at this stage + */ + public static function scan(\OC\Files\File $folder, $recursive) { + $size = 0; + $storage = $folder->getStorage(); + $path = $folder->getInternalPath(); + if ($dh = $storage->opendir($path)) { + while ($file = readdir($dh)) { + if ($file !== '.' and $file !== '..') { + $child = new \OC\Files\File($storage, $path . '/' . $file); + $data = self::scanFile($child); + if ($recursive === self::SCAN_RECURSIVE and $data['mimetype'] === 'httpd/unix-directory') { + $data['size'] = self::scan($child, self::SCAN_RECURSIVE); + } + if ($data['size'] >= 0 and $size >= 0) { + $size += $data['size']; + } + } + } + } + return $size; + } +} |