diff options
Diffstat (limited to 'lib/private/files')
21 files changed, 411 insertions, 263 deletions
diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php index 1c9de56f8c5..59963f41e3d 100644 --- a/lib/private/files/cache/cache.php +++ b/lib/private/files/cache/cache.php @@ -109,7 +109,7 @@ class Cache { * get the stored metadata of a file or folder * * @param string/int $file - * @return array | false + * @return array|false */ public function get($file) { if (is_string($file) or $file == '') { @@ -142,11 +142,11 @@ class Cache { } else { //fix types $data['fileid'] = (int)$data['fileid']; - $data['size'] = (int)$data['size']; + $data['size'] = 0 + $data['size']; $data['mtime'] = (int)$data['mtime']; $data['storage_mtime'] = (int)$data['storage_mtime']; $data['encrypted'] = (bool)$data['encrypted']; - $data['unencrypted_size'] = (int)$data['unencrypted_size']; + $data['unencrypted_size'] = 0 + $data['unencrypted_size']; $data['storage'] = $this->storageId; $data['mimetype'] = $this->getMimetype($data['mimetype']); $data['mimepart'] = $this->getMimetype($data['mimepart']); @@ -450,7 +450,7 @@ class Cache { * search for files matching $pattern * * @param string $pattern - * @return array of file data + * @return array an array of file data */ public function search($pattern) { @@ -532,9 +532,9 @@ class Cache { $result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId())); if ($row = $result->fetchRow()) { list($sum, $min, $unencryptedSum) = array_values($row); - $sum = (int)$sum; - $min = (int)$min; - $unencryptedSum = (int)$unencryptedSum; + $sum = 0 + $sum; + $min = 0 + $min; + $unencryptedSum = 0 + $unencryptedSum; if ($min === -1) { $totalSize = $min; } else { @@ -597,12 +597,16 @@ class Cache { * get the path of a file on this storage by it's id * * @param int $id - * @return string | null + * @return string|null */ public function getPathById($id) { $sql = 'SELECT `path` FROM `*PREFIX*filecache` WHERE `fileid` = ? AND `storage` = ?'; $result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId())); if ($row = $result->fetchRow()) { + // Oracle stores empty strings as null... + if ($row['path'] === null) { + return ''; + } return $row['path']; } else { return null; @@ -636,7 +640,7 @@ class Cache { /** * normalize the given path - * @param $path + * @param string $path * @return string */ public function normalize($path) { diff --git a/lib/private/files/cache/homecache.php b/lib/private/files/cache/homecache.php index 2326c46e8d0..f61769f0b9b 100644 --- a/lib/private/files/cache/homecache.php +++ b/lib/private/files/cache/homecache.php @@ -36,8 +36,10 @@ class HomeCache extends Cache { $result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId())); if ($row = $result->fetchRow()) { list($sum, $unencryptedSum) = array_values($row); - $totalSize = (int)$sum; - $unencryptedSize = (int)$unencryptedSum; + $totalSize = 0 + $sum; + $unencryptedSize = 0 + $unencryptedSum; + $entry['size'] += 0; + $entry['unencrypted_size'] += 0; if ($entry['size'] !== $totalSize) { $this->update($id, array('size' => $totalSize)); } diff --git a/lib/private/files/cache/permissions.php b/lib/private/files/cache/permissions.php index 2e2bdb20b78..eba18af3863 100644 --- a/lib/private/files/cache/permissions.php +++ b/lib/private/files/cache/permissions.php @@ -36,7 +36,7 @@ class Permissions { $sql = 'SELECT `permissions` FROM `*PREFIX*permissions` WHERE `user` = ? AND `fileid` = ?'; $result = \OC_DB::executeAudited($sql, array($user, $fileId)); if ($row = $result->fetchRow()) { - return $row['permissions']; + return $this->updatePermissions($row['permissions']); } else { return -1; } @@ -78,7 +78,7 @@ class Permissions { $result = \OC_DB::executeAudited($sql, $params); $filePermissions = array(); while ($row = $result->fetchRow()) { - $filePermissions[$row['fileid']] = $row['permissions']; + $filePermissions[$row['fileid']] = $this->updatePermissions($row['permissions']); } return $filePermissions; } @@ -99,7 +99,7 @@ class Permissions { $result = \OC_DB::executeAudited($sql, array($parentId, $user)); $filePermissions = array(); while ($row = $result->fetchRow()) { - $filePermissions[$row['fileid']] = $row['permissions']; + $filePermissions[$row['fileid']] = $this->updatePermissions($row['permissions']); } return $filePermissions; } @@ -140,4 +140,17 @@ class Permissions { } return $users; } + + /** + * check if admin removed the share permission for the user and update the permissions + * + * @param int $permissions + * @return int + */ + protected function updatePermissions($permissions) { + if (\OCP\Util::isSharingDisabledForUser()) { + $permissions &= ~\OCP\PERMISSION_SHARE; + } + return $permissions; + } } diff --git a/lib/private/files/cache/scanner.php b/lib/private/files/cache/scanner.php index c0bdde06a75..b97070fcdf0 100644 --- a/lib/private/files/cache/scanner.php +++ b/lib/private/files/cache/scanner.php @@ -10,6 +10,7 @@ namespace OC\Files\Cache; use OC\Files\Filesystem; use OC\Hooks\BasicEmitter; +use OCP\Config; /** * Class Scanner @@ -26,22 +27,27 @@ class Scanner extends BasicEmitter { /** * @var \OC\Files\Storage\Storage $storage */ - private $storage; + protected $storage; /** * @var string $storageId */ - private $storageId; + protected $storageId; /** * @var \OC\Files\Cache\Cache $cache */ - private $cache; + protected $cache; /** * @var \OC\Files\Cache\Permissions $permissionsCache */ - private $permissionsCache; + protected $permissionsCache; + + /** + * @var boolean $cacheActive If true, perform cache operations, if false, do not affect cache + */ + protected $cacheActive; const SCAN_RECURSIVE = true; const SCAN_SHALLOW = false; @@ -54,6 +60,7 @@ class Scanner extends BasicEmitter { $this->storageId = $this->storage->getId(); $this->cache = $storage->getCache(); $this->permissionsCache = $storage->getPermissionsCache(); + $this->cacheActive = !Config::getSystemValue('filesystem_cache_readonly', false); } /** @@ -61,7 +68,7 @@ class Scanner extends BasicEmitter { * * * * @param string $path - * @return array with metadata of the file + * @return array an array of metadata of the file */ public function getData($path) { if (!$this->storage->isReadable($path)) { @@ -88,7 +95,7 @@ class Scanner extends BasicEmitter { * @param string $file * @param int $reuseExisting * @param bool $parentExistsInCache - * @return array with metadata of the scanned file + * @return array an array of metadata of the scanned file */ public function scanFile($file, $reuseExisting = 0, $parentExistsInCache = false) { if (!self::isPartialFile($file) @@ -137,9 +144,12 @@ class Scanner extends BasicEmitter { $parent = ''; } $parentCacheData = $this->cache->get($parent); - $this->cache->update($parentCacheData['fileid'], array( - 'etag' => $this->storage->getETag($parent), - )); + \OC_Hook::emit('Scanner', 'updateCache', array('file' => $file, 'data' => $data)); + if($this->cacheActive) { + $this->cache->update($parentCacheData['fileid'], array( + 'etag' => $this->storage->getETag($parent), + )); + } } } } @@ -156,12 +166,18 @@ class Scanner extends BasicEmitter { } } if (!empty($newData)) { - $data['fileid'] = $this->cache->put($file, $newData); + \OC_Hook::emit('Scanner', 'addToCache', array('file' => $file, 'data' => $newData)); + if($this->cacheActive) { + $data['fileid'] = $this->cache->put($file, $newData); + } $this->emit('\OC\Files\Cache\Scanner', 'postScanFile', array($file, $this->storageId)); \OC_Hook::emit('\OC\Files\Cache\Scanner', 'post_scan_file', array('path' => $file, 'storage' => $this->storageId)); } } else { - $this->cache->remove($file); + \OC_Hook::emit('Scanner', 'removeFromCache', array('file' => $file)); + if($this->cacheActive) { + $this->cache->remove($file); + } } return $data; } @@ -174,7 +190,7 @@ class Scanner extends BasicEmitter { * @param string $path * @param bool $recursive * @param int $reuse - * @return array with the meta data of the scanned file or folder + * @return array an array of the meta data of the scanned file or folder */ public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1) { if ($reuse === -1) { @@ -244,7 +260,10 @@ class Scanner extends BasicEmitter { $removedChildren = \array_diff($existingChildren, $newChildren); foreach ($removedChildren as $childName) { $child = ($path) ? $path . '/' . $childName : $childName; - $this->cache->remove($child); + \OC_Hook::emit('Scanner', 'removeFromCache', array('file' => $child)); + if($this->cacheActive) { + $this->cache->remove($child); + } } \OC_DB::commit(); if ($exceptionOccurred){ @@ -263,17 +282,21 @@ class Scanner extends BasicEmitter { $size += $childSize; } } - $this->cache->put($path, array('size' => $size)); + $newData = array('size' => $size); + \OC_Hook::emit('Scanner', 'addToCache', array('file' => $child, 'data' => $newData)); + if($this->cacheActive) { + $this->cache->put($path, $newData); + } } $this->emit('\OC\Files\Cache\Scanner', 'postScanFolder', array($path, $this->storageId)); return $size; } /** - * @brief check if the file should be ignored when scanning + * check if the file should be ignored when scanning * NOTE: files with a '.part' extension are ignored as well! * prevents unfinished put requests to be scanned - * @param String $file + * @param string $file * @return boolean */ public static function isPartialFile($file) { @@ -290,8 +313,19 @@ class Scanner extends BasicEmitter { $lastPath = null; while (($path = $this->cache->getIncomplete()) !== false && $path !== $lastPath) { $this->scan($path, self::SCAN_RECURSIVE, self::REUSE_ETAG); - $this->cache->correctFolderSize($path); + \OC_Hook::emit('Scanner', 'correctFolderSize', array('path' => $path)); + if($this->cacheActive) { + $this->cache->correctFolderSize($path); + } $lastPath = $path; } } + + /** + * Set whether the cache is affected by scan operations + * @param boolean $active The active state of the cache + */ + public function setCacheActive($active) { + $this->cacheActive = $active; + } } diff --git a/lib/private/files/cache/updater.php b/lib/private/files/cache/updater.php index 199ce5dee78..f6feb6624b2 100644 --- a/lib/private/files/cache/updater.php +++ b/lib/private/files/cache/updater.php @@ -17,7 +17,7 @@ class Updater { * resolve a path to a storage and internal path * * @param string $path the relative path - * @return array consisting of the storage and the internal path + * @return array an array consisting of the storage and the internal path */ static public function resolvePath($path) { $view = \OC\Files\Filesystem::getView(); @@ -108,7 +108,7 @@ class Updater { } /** - * @brief get file owner and path + * get file owner and path * @param string $filename * @return string[] with the oweners uid and the owners path */ diff --git a/lib/private/files/cache/watcher.php b/lib/private/files/cache/watcher.php index 48aa6f853ce..5a4f53fb73d 100644 --- a/lib/private/files/cache/watcher.php +++ b/lib/private/files/cache/watcher.php @@ -45,7 +45,7 @@ class Watcher { } /** - * @param int $policy either \OC\Files\Cache\Watcher::UPDATE_NEVER, \OC\Files\Cache\Watcher::UPDATE_ONCE, \OC\Files\Cache\Watcher::UPDATE_ALWAYS + * @param int $policy either \OC\Files\Cache\Watcher::CHECK_NEVER, \OC\Files\Cache\Watcher::CHECK_ONCE, \OC\Files\Cache\Watcher::CHECK_ALWAYS */ public function setPolicy($policy) { $this->watchPolicy = $policy; @@ -55,7 +55,7 @@ class Watcher { * check $path for updates * * @param string $path - * @return boolean | array true if path was updated, otherwise the cached data is returned + * @return boolean|array true if path was updated, otherwise the cached data is returned */ public function checkUpdate($path) { if ($this->watchPolicy === self::CHECK_ALWAYS or ($this->watchPolicy === self::CHECK_ONCE and array_search($path, $this->checkedPaths) === false)) { diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php index d6940f50bf1..e7afeb4ccce 100644 --- a/lib/private/files/fileinfo.php +++ b/lib/private/files/fileinfo.php @@ -147,7 +147,7 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { } /** - * @return \OCP\Files\FileInfo::TYPE_FILE | \OCP\Files\FileInfo::TYPE_FOLDER + * @return \OCP\Files\FileInfo::TYPE_FILE|\OCP\Files\FileInfo::TYPE_FOLDER */ public function getType() { if (isset($this->data['type'])) { @@ -196,4 +196,28 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { public function isShareable() { return $this->checkPermissions(\OCP\PERMISSION_SHARE); } + + /** + * Check if a file or folder is shared + * @return bool + */ + public function isShared() { + $sid = $this->getStorage()->getId(); + if (!is_null($sid)) { + $sid = explode(':', $sid); + return ($sid[0] === 'shared'); + } + + return false; + } + + public function isMounted() { + $sid = $this->getStorage()->getId(); + if (!is_null($sid)) { + $sid = explode(':', $sid); + return ($sid[0] !== 'local' and $sid[0] !== 'home'); + } + + return false; + } } diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php index 52df1bec611..ad7213d2368 100644 --- a/lib/private/files/filesystem.php +++ b/lib/private/files/filesystem.php @@ -245,7 +245,7 @@ class Filesystem { } /** - * @param $id + * @param string $id * @return Mount\Mount[] */ public static function getMountByStorageId($id) { @@ -256,7 +256,7 @@ class Filesystem { } /** - * @param $id + * @param int $id * @return Mount\Mount[] */ public static function getMountByNumericId($id) { @@ -270,7 +270,7 @@ class Filesystem { * resolve a path to a storage and internal path * * @param string $path - * @return array consisting of the storage and the internal path + * @return array an array consisting of the storage and the internal path */ static public function resolvePath($path) { if (!self::$mounts) { @@ -384,7 +384,7 @@ class Filesystem { } /** - * @brief get the relative path of the root data directory for the current user + * get the relative path of the root data directory for the current user * @return string * * Returns path like /admin/files @@ -502,7 +502,7 @@ class Filesystem { } /** - * @brief check if the directory should be ignored when scanning + * check if the directory should be ignored when scanning * NOTE: the special directories . and .. would cause never ending recursion * @param String $dir * @return boolean @@ -662,7 +662,7 @@ class Filesystem { } /** - * @brief Fix common problems with a file path + * Fix common problems with a file path * @param string $path * @param bool $stripTrailingSlash * @return string diff --git a/lib/private/files/mapper.php b/lib/private/files/mapper.php index 833d4bd8d1c..666719da12d 100644 --- a/lib/private/files/mapper.php +++ b/lib/private/files/mapper.php @@ -97,8 +97,8 @@ class Mapper } /** - * @param $path - * @param $root + * @param string $path + * @param string $root * @return false|string */ public function stripRootFolder($path, $root) { diff --git a/lib/private/files/mount/manager.php b/lib/private/files/mount/manager.php index 91460b72730..db1f4600c74 100644 --- a/lib/private/files/mount/manager.php +++ b/lib/private/files/mount/manager.php @@ -33,7 +33,7 @@ class Manager { /** * Find the mount for $path * - * @param $path + * @param string $path * @return Mount */ public function find($path) { @@ -61,7 +61,7 @@ class Manager { /** * Find all mounts in $path * - * @param $path + * @param string $path * @return Mount[] */ public function findIn($path) { @@ -112,7 +112,7 @@ class Manager { /** * Find mounts by numeric storage id * - * @param string $id + * @param int $id * @return Mount[] */ public function findByNumericId($id) { diff --git a/lib/private/files/mount/mount.php b/lib/private/files/mount/mount.php index 08d5ddf348b..7c40853ac95 100644 --- a/lib/private/files/mount/mount.php +++ b/lib/private/files/mount/mount.php @@ -28,7 +28,7 @@ class Mount { private $loader; /** - * @param string | \OC\Files\Storage\Storage $storage + * @param string|\OC\Files\Storage\Storage $storage * @param string $mountpoint * @param array $arguments (optional)\ * @param \OC\Files\Storage\Loader $loader @@ -59,6 +59,8 @@ class Mount { } /** + * get complete path to the mount point, relative to data/ + * * @return string */ public function getMountPoint() { @@ -66,6 +68,15 @@ class Mount { } /** + * get name of the mount point + * + * @return string + */ + public function getMountPointName() { + return basename(rtrim($this->mountPoint, '/')); + } + + /** * @param string $mountPoint new mount point */ public function setMountPoint($mountPoint) { @@ -150,6 +161,6 @@ class Mount { * @param callable $wrapper */ public function wrapStorage($wrapper) { - $this->storage = $wrapper($this->mountPoint, $this->storage); + $this->storage = $wrapper($this->mountPoint, $this->getStorage()); } } diff --git a/lib/private/files/node/folder.php b/lib/private/files/node/folder.php index d9e0ddc2d61..1af34fc2be6 100644 --- a/lib/private/files/node/folder.php +++ b/lib/private/files/node/folder.php @@ -296,7 +296,7 @@ class Folder extends Node implements \OCP\Files\Folder { } /** - * @param $id + * @param int $id * @return \OC\Files\Node\Node[] */ public function getById($id) { diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php index 8a263d4ce1e..6b11603323a 100644 --- a/lib/private/files/storage/common.php +++ b/lib/private/files/storage/common.php @@ -8,6 +8,9 @@ namespace OC\Files\Storage; +use OC\Files\Filesystem; +use OC\Files\Cache\Watcher; + /** * Storage backend class for providing common filesystem operation methods * which are not storage-backend specific. @@ -19,7 +22,6 @@ namespace OC\Files\Storage; * Some \OC\Files\Storage\Common methods call functions which are first defined * in classes which extend it, e.g. $this->stat() . */ - abstract class Common implements \OC\Files\Storage\Storage { protected $cache; protected $scanner; @@ -35,6 +37,22 @@ abstract class Common implements \OC\Files\Storage\Storage { public function __construct($parameters) { } + /** + * Remove a file of folder + * + * @param string $path + * @return bool + */ + protected function remove($path) { + if ($this->is_dir($path)) { + return $this->rmdir($path); + } else if ($this->is_file($path)) { + return $this->unlink($path); + } else { + return false; + } + } + public function is_dir($path) { return $this->filetype($path) == 'dir'; } @@ -81,6 +99,10 @@ abstract class Common implements \OC\Files\Storage\Storage { } public function isSharable($path) { + if (\OC_Util::isSharingDisabledForUser()) { + return false; + } + return $this->isReadable($path); } @@ -132,20 +154,33 @@ abstract class Common implements \OC\Files\Storage\Storage { } public function rename($path1, $path2) { - if ($this->copy($path1, $path2)) { - $this->removeCachedFile($path1); - return $this->unlink($path1); - } else { - return false; - } + $this->remove($path2); + + $this->removeCachedFile($path1); + return $this->copy($path1, $path2) and $this->remove($path1); } public function copy($path1, $path2) { - $source = $this->fopen($path1, 'r'); - $target = $this->fopen($path2, 'w'); - list($count, $result) = \OC_Helper::streamCopy($source, $target); - $this->removeCachedFile($path2); - return $result; + if ($this->is_dir($path1)) { + $this->remove($path2); + $dir = $this->opendir($path1); + $this->mkdir($path2); + while ($file = readdir($dir)) { + if (!Filesystem::isIgnoredDir($file)) { + if (!$this->copy($path1 . '/' . $file, $path2 . '/' . $file)) { + return false; + } + } + } + closedir($dir); + return true; + } else { + $source = $this->fopen($path1, 'r'); + $target = $this->fopen($path2, 'w'); + list(, $result) = \OC_Helper::streamCopy($source, $target); + $this->removeCachedFile($path2); + return $result; + } } public function getMimeType($path) { @@ -276,6 +311,7 @@ abstract class Common implements \OC\Files\Storage\Storage { public function getWatcher($path = '') { if (!isset($this->watcher)) { $this->watcher = new \OC\Files\Cache\Watcher($this); + $this->watcher->setPolicy(\OC::$server->getConfig()->getSystemValue('filesystem_check_changes', Watcher::CHECK_ONCE)); } return $this->watcher; } @@ -317,7 +353,7 @@ abstract class Common implements \OC\Files\Storage\Storage { * clean a path, i.e. remove all redundant '.' and '..' * making sure that it can't point to higher than '/' * - * @param $path The path to clean + * @param string $path The path to clean * @return string cleaned path */ public function cleanPath($path) { @@ -347,7 +383,7 @@ abstract class Common implements \OC\Files\Storage\Storage { /** * get the free space in the storage * - * @param $path + * @param string $path * @return int */ public function free_space($path) { @@ -376,4 +412,14 @@ abstract class Common implements \OC\Files\Storage\Storage { protected function removeCachedFile($path) { unset($this->cachedFiles[$path]); } + + /** + * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class + * + * @param string $class + * @return bool + */ + public function instanceOfStorage($class) { + return is_a($this, $class); + } } diff --git a/lib/private/files/storage/home.php b/lib/private/files/storage/home.php index 1c2a682f197..f66096f6d9c 100644 --- a/lib/private/files/storage/home.php +++ b/lib/private/files/storage/home.php @@ -23,7 +23,7 @@ class Home extends Local { protected $user; /** - * @brief Construct a Home storage instance + * Construct a Home storage instance * @param array $arguments array with "user" containing the * storage owner and "legacy" containing "true" if the storage is * a legacy storage with "local::" URL instead of the new "home::" one. @@ -57,7 +57,7 @@ class Home extends Local { } /** - * @brief Returns the owner of this home storage + * Returns the owner of this home storage * @return \OC\User\User owner of this home storage */ public function getUser() { diff --git a/lib/private/files/storage/local.php b/lib/private/files/storage/local.php index de940fc7cdb..e33747bbd52 100644 --- a/lib/private/files/storage/local.php +++ b/lib/private/files/storage/local.php @@ -89,11 +89,10 @@ if (\OC_Util::runningOnWindows()) { public function stat($path) { $fullPath = $this->datadir . $path; $statResult = stat($fullPath); - - if ($statResult['size'] < 0) { - $size = self::getFileSizeFromOS($fullPath); - $statResult['size'] = $size; - $statResult[7] = $size; + if (PHP_INT_SIZE === 4 && !$this->is_dir($path)) { + $filesize = $this->filesize($path); + $statResult['size'] = $filesize; + $statResult[7] = $filesize; } return $statResult; } @@ -109,15 +108,13 @@ if (\OC_Util::runningOnWindows()) { public function filesize($path) { if ($this->is_dir($path)) { return 0; - } else { - $fullPath = $this->datadir . $path; - $fileSize = filesize($fullPath); - if ($fileSize < 0) { - return self::getFileSizeFromOS($fullPath); - } - - return $fileSize; } + $fullPath = $this->datadir . $path; + if (PHP_INT_SIZE === 4) { + $helper = new \OC\LargeFileHelper; + return $helper->getFilesize($fullPath); + } + return filesize($fullPath); } public function isReadable($path) { @@ -164,7 +161,14 @@ if (\OC_Util::runningOnWindows()) { } public function unlink($path) { - return $this->delTree($path); + if ($this->is_dir($path)) { + return $this->rmdir($path); + } else if ($this->is_file($path)) { + return unlink($this->datadir . $path); + } else { + return false; + } + } public function rename($path1, $path2) { @@ -177,20 +181,21 @@ if (\OC_Util::runningOnWindows()) { return false; } - if ($return = rename($this->datadir . $path1, $this->datadir . $path2)) { + if ($this->is_dir($path2)) { + $this->rmdir($path2); + } else if ($this->is_file($path2)) { + $this->unlink($path2); } - return $return; + + return rename($this->datadir . $path1, $this->datadir . $path2); } public function copy($path1, $path2) { - if ($this->is_dir($path2)) { - if (!$this->file_exists($path2)) { - $this->mkdir($path2); - } - $source = substr($path1, strrpos($path1, '/') + 1); - $path2 .= $source; + if ($this->is_dir($path1)) { + return parent::copy($path1, $path2); + } else { + return copy($this->datadir . $path1, $this->datadir . $path2); } - return copy($this->datadir . $path1, $this->datadir . $path2); } public function fopen($path, $mode) { @@ -212,59 +217,6 @@ if (\OC_Util::runningOnWindows()) { return $return; } - /** - * @param string $dir - */ - private function delTree($dir) { - $dirRelative = $dir; - $dir = $this->datadir . $dir; - if (!file_exists($dir)) return true; - if (!is_dir($dir) || is_link($dir)) return unlink($dir); - foreach (scandir($dir) as $item) { - if ($item == '.' || $item == '..') continue; - if (is_file($dir . '/' . $item)) { - if (unlink($dir . '/' . $item)) { - } - } elseif (is_dir($dir . '/' . $item)) { - if (!$this->delTree($dirRelative . "/" . $item)) { - return false; - }; - } - } - if ($return = rmdir($dir)) { - } - return $return; - } - - /** - * @param string $fullPath - */ - private static function getFileSizeFromOS($fullPath) { - $name = strtolower(php_uname('s')); - // Windows OS: we use COM to access the filesystem - if (strpos($name, 'win') !== false) { - if (class_exists('COM')) { - $fsobj = new \COM("Scripting.FileSystemObject"); - $f = $fsobj->GetFile($fullPath); - return $f->Size; - } - } else if (strpos($name, 'bsd') !== false) { - if (\OC_Helper::is_function_enabled('exec')) { - return (float)exec('stat -f %z ' . escapeshellarg($fullPath)); - } - } else if (strpos($name, 'linux') !== false) { - if (\OC_Helper::is_function_enabled('exec')) { - return (float)exec('stat -c %s ' . escapeshellarg($fullPath)); - } - } else { - \OC_Log::write('core', - 'Unable to determine file size of "' . $fullPath . '". Unknown OS: ' . $name, - \OC_Log::ERROR); - } - - return 0; - } - public function hash($type, $path, $raw = false) { return hash_file($type, $this->datadir . $path, $raw); } diff --git a/lib/private/files/storage/mappedlocal.php b/lib/private/files/storage/mappedlocal.php index 07691661644..ea4deaa66e8 100644 --- a/lib/private/files/storage/mappedlocal.php +++ b/lib/private/files/storage/mappedlocal.php @@ -10,29 +10,33 @@ namespace OC\Files\Storage; /** * for local filestore, we only have to map the paths */ -class MappedLocal extends \OC\Files\Storage\Common{ +class MappedLocal extends \OC\Files\Storage\Common { protected $datadir; private $mapper; public function __construct($arguments) { - $this->datadir=$arguments['datadir']; - if(substr($this->datadir, -1)!=='/') { - $this->datadir.='/'; + $this->datadir = $arguments['datadir']; + if (substr($this->datadir, -1) !== '/') { + $this->datadir .= '/'; } - $this->mapper= new \OC\Files\Mapper($this->datadir); + $this->mapper = new \OC\Files\Mapper($this->datadir); } + public function __destruct() { if (defined('PHPUNIT_RUN')) { $this->mapper->removePath($this->datadir, true, true); } } - public function getId(){ - return 'local::'.$this->datadir; + + public function getId() { + return 'local::' . $this->datadir; } + public function mkdir($path) { return @mkdir($this->buildPath($path), 0777, true); } + public function rmdir($path) { try { $it = new \RecursiveIteratorIterator( @@ -68,9 +72,10 @@ class MappedLocal extends \OC\Files\Storage\Common{ return false; } } + public function opendir($path) { $files = array('.', '..'); - $physicalPath= $this->buildPath($path); + $physicalPath = $this->buildPath($path); $logicalPath = $this->mapper->physicalToLogic($physicalPath); $dh = opendir($physicalPath); @@ -80,7 +85,7 @@ class MappedLocal extends \OC\Files\Storage\Common{ continue; } - $logicalFilePath = $this->mapper->physicalToLogic($physicalPath.'/'.$file); + $logicalFilePath = $this->mapper->physicalToLogic($physicalPath . '/' . $file); $file= $this->mapper->stripRootFolder($logicalFilePath, $logicalPath); $file = $this->stripLeading($file); @@ -88,121 +93,151 @@ class MappedLocal extends \OC\Files\Storage\Common{ } } - \OC\Files\Stream\Dir::register('local-win32'.$path, $files); - return opendir('fakedir://local-win32'.$path); + \OC\Files\Stream\Dir::register('local-win32' . $path, $files); + return opendir('fakedir://local-win32' . $path); } + public function is_dir($path) { - if(substr($path, -1)=='/') { - $path=substr($path, 0, -1); + if (substr($path, -1) == '/') { + $path = substr($path, 0, -1); } return is_dir($this->buildPath($path)); } + public function is_file($path) { return is_file($this->buildPath($path)); } + public function stat($path) { $fullPath = $this->buildPath($path); $statResult = stat($fullPath); - - if ($statResult['size'] < 0) { - $size = self::getFileSizeFromOS($fullPath); - $statResult['size'] = $size; - $statResult[7] = $size; + if (PHP_INT_SIZE === 4 && !$this->is_dir($path)) { + $filesize = $this->filesize($path); + $statResult['size'] = $filesize; + $statResult[7] = $filesize; } return $statResult; } + public function filetype($path) { - $filetype=filetype($this->buildPath($path)); - if($filetype=='link') { - $filetype=filetype(realpath($this->buildPath($path))); + $filetype = filetype($this->buildPath($path)); + if ($filetype == 'link') { + $filetype = filetype(realpath($this->buildPath($path))); } return $filetype; } + public function filesize($path) { - if($this->is_dir($path)) { + if ($this->is_dir($path)) { return 0; - }else{ - $fullPath = $this->buildPath($path); - $fileSize = filesize($fullPath); - if ($fileSize < 0) { - return self::getFileSizeFromOS($fullPath); - } - - return $fileSize; } + $fullPath = $this->buildPath($path); + if (PHP_INT_SIZE === 4) { + $helper = new \OC\LargeFileHelper; + return $helper->getFilesize($fullPath); + } + return filesize($fullPath); } + public function isReadable($path) { return is_readable($this->buildPath($path)); } + public function isUpdatable($path) { return is_writable($this->buildPath($path)); } + public function file_exists($path) { return file_exists($this->buildPath($path)); } + public function filemtime($path) { return filemtime($this->buildPath($path)); } - public function touch($path, $mtime=null) { + + public function touch($path, $mtime = null) { // sets the modification time of the file to the given value. // If mtime is nil the current time is set. // note that the access time of the file always changes to the current time. - if(!is_null($mtime)) { - $result=touch( $this->buildPath($path), $mtime ); - }else{ - $result=touch( $this->buildPath($path)); + if (!is_null($mtime)) { + $result = touch($this->buildPath($path), $mtime); + } else { + $result = touch($this->buildPath($path)); } - if( $result ) { - clearstatcache( true, $this->buildPath($path) ); + if ($result) { + clearstatcache(true, $this->buildPath($path)); } return $result; } + public function file_get_contents($path) { return file_get_contents($this->buildPath($path)); } + public function file_put_contents($path, $data) { return file_put_contents($this->buildPath($path), $data); } + public function unlink($path) { return $this->delTree($path); } + public function rename($path1, $path2) { if (!$this->isUpdatable($path1)) { - \OC_Log::write('core', 'unable to rename, file is not writable : '.$path1, \OC_Log::ERROR); + \OC_Log::write('core', 'unable to rename, file is not writable : ' . $path1, \OC_Log::ERROR); return false; } - if(! $this->file_exists($path1)) { - \OC_Log::write('core', 'unable to rename, file does not exists : '.$path1, \OC_Log::ERROR); + if (!$this->file_exists($path1)) { + \OC_Log::write('core', 'unable to rename, file does not exists : ' . $path1, \OC_Log::ERROR); return false; } + if ($this->is_dir($path2)) { + $this->rmdir($path2); + } else if ($this->is_file($path2)) { + $this->unlink($path2); + } + $physicPath1 = $this->buildPath($path1); $physicPath2 = $this->buildPath($path2); - if($return=rename($physicPath1, $physicPath2)) { + if ($return = rename($physicPath1, $physicPath2)) { // mapper needs to create copies or all children $this->copyMapping($path1, $path2); $this->cleanMapper($physicPath1, false, true); } return $return; } + public function copy($path1, $path2) { - if($this->is_dir($path2)) { - if(!$this->file_exists($path2)) { - $this->mkdir($path2); + if ($this->is_dir($path1)) { + if ($this->is_dir($path2)) { + $this->rmdir($path2); + } else if ($this->is_file($path2)) { + $this->unlink($path2); } - $source=substr($path1, strrpos($path1, '/')+1); - $path2.=$source; - } - if($return=copy($this->buildPath($path1), $this->buildPath($path2))) { - // mapper needs to create copies or all children - $this->copyMapping($path1, $path2); + $dir = $this->opendir($path1); + $this->mkdir($path2); + while ($file = readdir($dir)) { + if (!\OC\Files\Filesystem::isIgnoredDir($file)) { + if (!$this->copy($path1 . '/' . $file, $path2 . '/' . $file)) { + return false; + } + } + } + closedir($dir); + return true; + } else { + if ($return = copy($this->buildPath($path1), $this->buildPath($path2))) { + $this->copyMapping($path1, $path2); + } + return $return; } - return $return; } + public function fopen($path, $mode) { - if($return=fopen($this->buildPath($path), $mode)) { - switch($mode) { + if ($return = fopen($this->buildPath($path), $mode)) { + switch ($mode) { case 'r': break; case 'r+': @@ -223,15 +258,15 @@ class MappedLocal extends \OC\Files\Storage\Common{ * @param string $dir */ private function delTree($dir, $isLogicPath=true) { - $dirRelative=$dir; + $dirRelative = $dir; if ($isLogicPath) { - $dir=$this->buildPath($dir); + $dir = $this->buildPath($dir); } if (!file_exists($dir)) { return true; } if (!is_dir($dir) || is_link($dir)) { - if($return=unlink($dir)) { + if ($return = unlink($dir)) { $this->cleanMapper($dir, false); return $return; } @@ -240,52 +275,23 @@ class MappedLocal extends \OC\Files\Storage\Common{ if ($item == '.' || $item == '..') { continue; } - if(is_file($dir.'/'.$item)) { - if(unlink($dir.'/'.$item)) { - $this->cleanMapper($dir.'/'.$item, false); + if (is_file($dir . '/' . $item)) { + if (unlink($dir . '/' . $item)) { + $this->cleanMapper($dir . '/' . $item, false); } - }elseif(is_dir($dir.'/'.$item)) { - if (!$this->delTree($dir. "/" . $item, false)) { + } elseif (is_dir($dir . '/' . $item)) { + if (!$this->delTree($dir . "/" . $item, false)) { return false; }; } } - if($return=rmdir($dir)) { + if ($return = rmdir($dir)) { $this->cleanMapper($dir, false); } return $return; } - /** - * @param string $fullPath - */ - private static function getFileSizeFromOS($fullPath) { - $name = strtolower(php_uname('s')); - // Windows OS: we use COM to access the filesystem - if (strpos($name, 'win') !== false) { - if (class_exists('COM')) { - $fsobj = new \COM("Scripting.FileSystemObject"); - $f = $fsobj->GetFile($fullPath); - return $f->Size; - } - } else if (strpos($name, 'bsd') !== false) { - if (\OC_Helper::is_function_enabled('exec')) { - return (float)exec('stat -f %z ' . escapeshellarg($fullPath)); - } - } else if (strpos($name, 'linux') !== false) { - if (\OC_Helper::is_function_enabled('exec')) { - return (float)exec('stat -c %s ' . escapeshellarg($fullPath)); - } - } else { - \OC_Log::write('core', - 'Unable to determine file size of "'.$fullPath.'". Unknown OS: '.$name, - \OC_Log::ERROR); - } - - return 0; - } - - public function hash($type, $path, $raw=false) { + public function hash($type, $path, $raw = false) { return hash_file($type, $this->buildPath($path), $raw); } @@ -296,9 +302,11 @@ class MappedLocal extends \OC\Files\Storage\Common{ public function search($query) { return $this->searchInDir($query); } + public function getLocalFile($path) { return $this->buildPath($path); } + public function getLocalFolder($path) { return $this->buildPath($path); } @@ -306,20 +314,20 @@ class MappedLocal extends \OC\Files\Storage\Common{ /** * @param string $query */ - protected function searchInDir($query, $dir='') { - $files=array(); + protected function searchInDir($query, $dir = '') { + $files = array(); $physicalDir = $this->buildPath($dir); foreach (scandir($physicalDir) as $item) { if ($item == '.' || $item == '..') continue; - $physicalItem = $this->mapper->physicalToLogic($physicalDir.'/'.$item); - $item = substr($physicalItem, strlen($physicalDir)+1); + $physicalItem = $this->mapper->physicalToLogic($physicalDir . '/' . $item); + $item = substr($physicalItem, strlen($physicalDir) + 1); - if(strstr(strtolower($item), strtolower($query)) !== false) { - $files[]=$dir.'/'.$item; + if (strstr(strtolower($item), strtolower($query)) !== false) { + $files[] = $dir . '/' . $item; } - if(is_dir($physicalItem)) { - $files=array_merge($files, $this->searchInDir($query, $dir.'/'.$item)); + if (is_dir($physicalItem)) { + $files = array_merge($files, $this->searchInDir($query, $dir . '/' . $item)); } } return $files; @@ -327,30 +335,31 @@ class MappedLocal extends \OC\Files\Storage\Common{ /** * check if a file or folder has been updated since $time + * * @param string $path * @param int $time * @return bool */ public function hasUpdated($path, $time) { - return $this->filemtime($path)>$time; + return $this->filemtime($path) > $time; } /** * @param string $path */ - private function buildPath($path, $create=true) { + private function buildPath($path, $create = true) { $path = $this->stripLeading($path); - $fullPath = $this->datadir.$path; + $fullPath = $this->datadir . $path; return $this->mapper->logicToPhysical($fullPath, $create); } /** * @param string $path */ - private function cleanMapper($path, $isLogicPath=true, $recursive=true) { + private function cleanMapper($path, $isLogicPath = true, $recursive=true) { $fullPath = $path; if ($isLogicPath) { - $fullPath = $this->datadir.$path; + $fullPath = $this->datadir . $path; } $this->mapper->removePath($fullPath, $isLogicPath, $recursive); } @@ -363,8 +372,8 @@ class MappedLocal extends \OC\Files\Storage\Common{ $path1 = $this->stripLeading($path1); $path2 = $this->stripLeading($path2); - $fullPath1 = $this->datadir.$path1; - $fullPath2 = $this->datadir.$path2; + $fullPath1 = $this->datadir . $path1; + $fullPath2 = $this->datadir . $path2; $this->mapper->copy($fullPath1, $fullPath2); } @@ -373,10 +382,10 @@ class MappedLocal extends \OC\Files\Storage\Common{ * @param string $path */ private function stripLeading($path) { - if(strpos($path, '/') === 0) { + if (strpos($path, '/') === 0) { $path = substr($path, 1); } - if(strpos($path, '\\') === 0) { + if (strpos($path, '\\') === 0) { $path = substr($path, 1); } if ($path === false) { diff --git a/lib/private/files/storage/wrapper/quota.php b/lib/private/files/storage/wrapper/quota.php index a878b2c5cf6..c57c797f87a 100644 --- a/lib/private/files/storage/wrapper/quota.php +++ b/lib/private/files/storage/wrapper/quota.php @@ -30,7 +30,7 @@ class Quota extends Wrapper { } /** - * @return quota value + * @return int quota value */ public function getQuota() { return $this->quota; diff --git a/lib/private/files/storage/wrapper/wrapper.php b/lib/private/files/storage/wrapper/wrapper.php index 11ea9f71da7..364475a68e0 100644 --- a/lib/private/files/storage/wrapper/wrapper.php +++ b/lib/private/files/storage/wrapper/wrapper.php @@ -440,4 +440,25 @@ class Wrapper implements \OC\Files\Storage\Storage { public function isLocal() { return $this->storage->isLocal(); } + + /** + * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class + * + * @param string $class + * @return bool + */ + public function instanceOfStorage($class) { + return is_a($this, $class) or $this->storage->instanceOfStorage($class); + } + + /** + * Pass any methods custom to specific storage implementations to the wrapped storage + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) { + return call_user_func_array(array($this->storage, $method), $args); + } } diff --git a/lib/private/files/stream/oc.php b/lib/private/files/stream/oc.php index 88e7e062df9..c206b41f55e 100644 --- a/lib/private/files/stream/oc.php +++ b/lib/private/files/stream/oc.php @@ -18,7 +18,15 @@ class OC { static private $rootView; private $path; + + /** + * @var resource + */ private $dirSource; + + /** + * @var resource + */ private $fileSource; private $meta; diff --git a/lib/private/files/type/templatemanager.php b/lib/private/files/type/templatemanager.php index cd1536d2732..e693e7079a5 100644 --- a/lib/private/files/type/templatemanager.php +++ b/lib/private/files/type/templatemanager.php @@ -19,7 +19,7 @@ class TemplateManager { * get the path of the template for a mimetype * * @param string $mimetype - * @return string | null + * @return string|null */ public function getTemplatePath($mimetype) { if (isset($this->templates[$mimetype])) { diff --git a/lib/private/files/view.php b/lib/private/files/view.php index 47fc04c937d..0b8d336f260 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -11,7 +11,7 @@ * working with files within that view (e.g. read, write, delete, etc.). Each * view is restricted to a set of directories via a virtual root. The default view * uses the currently logged in user's data directory as root (parts of - * OC_Filesystem are merely a wrapper for OC_FilesystemView). + * OC_Filesystem are merely a wrapper for OC\Files\View). * * Apps that need to access files outside of the user data folders (to modify files * belonging to a user other than the one currently logged in, for example) should @@ -29,15 +29,14 @@ use OC\Files\Cache\Updater; class View { private $fakeRoot = ''; - private $internal_path_cache = array(); - private $storage_cache = array(); public function __construct($root = '') { $this->fakeRoot = $root; } public function getAbsolutePath($path = '/') { - if (!$path) { + $this->assertPathLength($path); + if ($path === '') { $path = '/'; } if ($path[0] !== '/') { @@ -77,6 +76,7 @@ class View { * @return string */ public function getRelativePath($path) { + $this->assertPathLength($path); if ($this->fakeRoot == '') { return $path; } @@ -109,7 +109,7 @@ class View { * resolve a path to a storage and internal path * * @param string $path - * @return array consisting of the storage and the internal path + * @return array an array consisting of the storage and the internal path */ public function resolvePath($path) { $a = $this->getAbsolutePath($path); @@ -168,6 +168,10 @@ class View { } } + /** + * @param string $path + * @return resource + */ public function opendir($path) { return $this->basicOperation('opendir', $path, array('read')); } @@ -204,6 +208,7 @@ class View { } public function readfile($path) { + $this->assertPathLength($path); @ob_end_clean(); $handle = $this->fopen($path, 'rb'); if ($handle) { @@ -428,7 +433,7 @@ class View { if ($this->is_dir($path1)) { $result = $this->copy($path1, $path2); if ($result === true) { - $result = $storage1->unlink($internalPath1); + $result = $storage1->rmdir($internalPath1); } } else { $source = $this->fopen($path1 . $postFix1, 'r'); @@ -552,6 +557,11 @@ class View { } } + /** + * @param string $path + * @param string $mode + * @return resource + */ public function fopen($path, $mode) { $hooks = array(); switch ($mode) { @@ -586,6 +596,7 @@ class View { } public function toTmpFile($path) { + $this->assertPathLength($path); if (Filesystem::isValidPath($path)) { $source = $this->fopen($path, 'r'); if ($source) { @@ -602,7 +613,7 @@ class View { } public function fromTmpFile($tmpFile, $path) { - + $this->assertPathLength($path); if (Filesystem::isValidPath($path)) { // Get directory that the file is going into @@ -631,6 +642,7 @@ class View { } public function getMimeType($path) { + $this->assertPathLength($path); return $this->basicOperation('getMimeType', $path); } @@ -660,11 +672,12 @@ class View { } public function free_space($path = '/') { + $this->assertPathLength($path); return $this->basicOperation('free_space', $path); } /** - * @brief abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage + * abstraction layer for basic filesystem functions: wrapper for \OC\Files\Storage\Storage * @param string $operation * @param string $path * @param array $hooks (optional) @@ -796,9 +809,10 @@ class View { * @param string $path * @param boolean $includeMountPoints whether to add mountpoint sizes, * defaults to true - * @return \OC\Files\FileInfo | false + * @return \OC\Files\FileInfo|false */ public function getFileInfo($path, $includeMountPoints = true) { + $this->assertPathLength($path); $data = array(); if (!Filesystem::isValidPath($path)) { return $data; @@ -869,6 +883,7 @@ class View { * @return FileInfo[] */ public function getDirectoryContent($directory, $mimetype_filter = '') { + $this->assertPathLength($directory); $result = array(); if (!Filesystem::isValidPath($directory)) { return $result; @@ -991,12 +1006,13 @@ class View { * change file metadata * * @param string $path - * @param array | \OCP\Files\FileInfo $data + * @param array|\OCP\Files\FileInfo $data * @return int * * returns the fileid of the updated file */ public function putFileInfo($path, $data) { + $this->assertPathLength($path); if ($data instanceof FileInfo) { $data = $data->getData(); } @@ -1144,4 +1160,12 @@ class View { } return null; } + + private function assertPathLength($path) { + $maxLen = min(PHP_MAXPATHLEN, 4000); + $pathLen = strlen($path); + if ($pathLen > $maxLen) { + throw new \OCP\Files\InvalidPathException("Path length($pathLen) exceeds max path length($maxLen): $path"); + } + } } |