aboutsummaryrefslogtreecommitdiffstats
path: root/lib/files/cache
diff options
context:
space:
mode:
authorRobin Appelman <icewind@owncloud.com>2012-09-16 16:52:32 +0200
committerRobin Appelman <icewind@owncloud.com>2012-09-16 16:52:32 +0200
commit954596c251cb3132878d8d5eafcc37c47b3f520e (patch)
tree526cf72cd6855b6d96be3b13f485734c0ba2d2e7 /lib/files/cache
parentc94fe38d3900acff474c909aaa730d7ab51f914d (diff)
downloadnextcloud-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.php189
-rw-r--r--lib/files/cache/scanner.php78
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;
+ }
+}