@@ -34,61 +34,61 @@ |
||
34 | 34 | require_once __DIR__ . '/lib/versioncheck.php'; |
35 | 35 | |
36 | 36 | try { |
37 | - require_once __DIR__ . '/lib/base.php'; |
|
38 | - if (\OCP\Util::needUpgrade()) { |
|
39 | - // since the behavior of apps or remotes are unpredictable during |
|
40 | - // an upgrade, return a 503 directly |
|
41 | - OC_Template::printErrorPage('Service unavailable', '', 503); |
|
42 | - exit; |
|
43 | - } |
|
37 | + require_once __DIR__ . '/lib/base.php'; |
|
38 | + if (\OCP\Util::needUpgrade()) { |
|
39 | + // since the behavior of apps or remotes are unpredictable during |
|
40 | + // an upgrade, return a 503 directly |
|
41 | + OC_Template::printErrorPage('Service unavailable', '', 503); |
|
42 | + exit; |
|
43 | + } |
|
44 | 44 | |
45 | - OC::checkMaintenanceMode(\OC::$server->get(\OC\SystemConfig::class)); |
|
46 | - $request = \OC::$server->getRequest(); |
|
47 | - $pathInfo = $request->getPathInfo(); |
|
45 | + OC::checkMaintenanceMode(\OC::$server->get(\OC\SystemConfig::class)); |
|
46 | + $request = \OC::$server->getRequest(); |
|
47 | + $pathInfo = $request->getPathInfo(); |
|
48 | 48 | |
49 | - if (!$pathInfo && $request->getParam('service', '') === '') { |
|
50 | - http_response_code(404); |
|
51 | - exit; |
|
52 | - } elseif ($request->getParam('service', '')) { |
|
53 | - $service = $request->getParam('service', ''); |
|
54 | - } else { |
|
55 | - $pathInfo = trim($pathInfo, '/'); |
|
56 | - [$service] = explode('/', $pathInfo); |
|
57 | - } |
|
58 | - $file = \OC::$server->getConfig()->getAppValue('core', 'public_' . strip_tags($service)); |
|
59 | - if ($file === '') { |
|
60 | - http_response_code(404); |
|
61 | - exit; |
|
62 | - } |
|
49 | + if (!$pathInfo && $request->getParam('service', '') === '') { |
|
50 | + http_response_code(404); |
|
51 | + exit; |
|
52 | + } elseif ($request->getParam('service', '')) { |
|
53 | + $service = $request->getParam('service', ''); |
|
54 | + } else { |
|
55 | + $pathInfo = trim($pathInfo, '/'); |
|
56 | + [$service] = explode('/', $pathInfo); |
|
57 | + } |
|
58 | + $file = \OC::$server->getConfig()->getAppValue('core', 'public_' . strip_tags($service)); |
|
59 | + if ($file === '') { |
|
60 | + http_response_code(404); |
|
61 | + exit; |
|
62 | + } |
|
63 | 63 | |
64 | - $parts = explode('/', $file, 2); |
|
65 | - $app = $parts[0]; |
|
64 | + $parts = explode('/', $file, 2); |
|
65 | + $app = $parts[0]; |
|
66 | 66 | |
67 | - // Load all required applications |
|
68 | - \OC::$REQUESTEDAPP = $app; |
|
69 | - OC_App::loadApps(['authentication']); |
|
70 | - OC_App::loadApps(['filesystem', 'logging']); |
|
67 | + // Load all required applications |
|
68 | + \OC::$REQUESTEDAPP = $app; |
|
69 | + OC_App::loadApps(['authentication']); |
|
70 | + OC_App::loadApps(['filesystem', 'logging']); |
|
71 | 71 | |
72 | - if (!\OC::$server->getAppManager()->isInstalled($app)) { |
|
73 | - http_response_code(404); |
|
74 | - exit; |
|
75 | - } |
|
76 | - OC_App::loadApp($app); |
|
77 | - OC_User::setIncognitoMode(true); |
|
72 | + if (!\OC::$server->getAppManager()->isInstalled($app)) { |
|
73 | + http_response_code(404); |
|
74 | + exit; |
|
75 | + } |
|
76 | + OC_App::loadApp($app); |
|
77 | + OC_User::setIncognitoMode(true); |
|
78 | 78 | |
79 | - $baseuri = OC::$WEBROOT . '/public.php/' . $service . '/'; |
|
79 | + $baseuri = OC::$WEBROOT . '/public.php/' . $service . '/'; |
|
80 | 80 | |
81 | - require_once OC_App::getAppPath($app) . '/' . $parts[1]; |
|
81 | + require_once OC_App::getAppPath($app) . '/' . $parts[1]; |
|
82 | 82 | } catch (Exception $ex) { |
83 | - $status = 500; |
|
84 | - if ($ex instanceof \OC\ServiceUnavailableException) { |
|
85 | - $status = 503; |
|
86 | - } |
|
87 | - //show the user a detailed error page |
|
88 | - \OC::$server->getLogger()->logException($ex, ['app' => 'public']); |
|
89 | - OC_Template::printExceptionErrorPage($ex, $status); |
|
83 | + $status = 500; |
|
84 | + if ($ex instanceof \OC\ServiceUnavailableException) { |
|
85 | + $status = 503; |
|
86 | + } |
|
87 | + //show the user a detailed error page |
|
88 | + \OC::$server->getLogger()->logException($ex, ['app' => 'public']); |
|
89 | + OC_Template::printExceptionErrorPage($ex, $status); |
|
90 | 90 | } catch (Error $ex) { |
91 | - //show the user a detailed error page |
|
92 | - \OC::$server->getLogger()->logException($ex, ['app' => 'public']); |
|
93 | - OC_Template::printExceptionErrorPage($ex, 500); |
|
91 | + //show the user a detailed error page |
|
92 | + \OC::$server->getLogger()->logException($ex, ['app' => 'public']); |
|
93 | + OC_Template::printExceptionErrorPage($ex, 500); |
|
94 | 94 | } |
@@ -31,10 +31,10 @@ discard block |
||
31 | 31 | * |
32 | 32 | */ |
33 | 33 | |
34 | -require_once __DIR__ . '/lib/versioncheck.php'; |
|
34 | +require_once __DIR__.'/lib/versioncheck.php'; |
|
35 | 35 | |
36 | 36 | try { |
37 | - require_once __DIR__ . '/lib/base.php'; |
|
37 | + require_once __DIR__.'/lib/base.php'; |
|
38 | 38 | if (\OCP\Util::needUpgrade()) { |
39 | 39 | // since the behavior of apps or remotes are unpredictable during |
40 | 40 | // an upgrade, return a 503 directly |
@@ -55,7 +55,7 @@ discard block |
||
55 | 55 | $pathInfo = trim($pathInfo, '/'); |
56 | 56 | [$service] = explode('/', $pathInfo); |
57 | 57 | } |
58 | - $file = \OC::$server->getConfig()->getAppValue('core', 'public_' . strip_tags($service)); |
|
58 | + $file = \OC::$server->getConfig()->getAppValue('core', 'public_'.strip_tags($service)); |
|
59 | 59 | if ($file === '') { |
60 | 60 | http_response_code(404); |
61 | 61 | exit; |
@@ -76,9 +76,9 @@ discard block |
||
76 | 76 | OC_App::loadApp($app); |
77 | 77 | OC_User::setIncognitoMode(true); |
78 | 78 | |
79 | - $baseuri = OC::$WEBROOT . '/public.php/' . $service . '/'; |
|
79 | + $baseuri = OC::$WEBROOT.'/public.php/'.$service.'/'; |
|
80 | 80 | |
81 | - require_once OC_App::getAppPath($app) . '/' . $parts[1]; |
|
81 | + require_once OC_App::getAppPath($app).'/'.$parts[1]; |
|
82 | 82 | } catch (Exception $ex) { |
83 | 83 | $status = 500; |
84 | 84 | if ($ex instanceof \OC\ServiceUnavailableException) { |
@@ -40,151 +40,151 @@ |
||
40 | 40 | use OCP\ILogger; |
41 | 41 | |
42 | 42 | class Autoloader { |
43 | - /** @var bool */ |
|
44 | - private $useGlobalClassPath = true; |
|
45 | - /** @var array */ |
|
46 | - private $validRoots = []; |
|
47 | - |
|
48 | - /** |
|
49 | - * Optional low-latency memory cache for class to path mapping. |
|
50 | - * |
|
51 | - * @var \OC\Memcache\Cache |
|
52 | - */ |
|
53 | - protected $memoryCache; |
|
54 | - |
|
55 | - /** |
|
56 | - * Autoloader constructor. |
|
57 | - * |
|
58 | - * @param string[] $validRoots |
|
59 | - */ |
|
60 | - public function __construct(array $validRoots) { |
|
61 | - foreach ($validRoots as $root) { |
|
62 | - $this->validRoots[$root] = true; |
|
63 | - } |
|
64 | - } |
|
65 | - |
|
66 | - /** |
|
67 | - * Add a path to the list of valid php roots for auto loading |
|
68 | - * |
|
69 | - * @param string $root |
|
70 | - */ |
|
71 | - public function addValidRoot(string $root) { |
|
72 | - $root = stream_resolve_include_path($root); |
|
73 | - $this->validRoots[$root] = true; |
|
74 | - } |
|
75 | - |
|
76 | - /** |
|
77 | - * disable the usage of the global classpath \OC::$CLASSPATH |
|
78 | - */ |
|
79 | - public function disableGlobalClassPath() { |
|
80 | - $this->useGlobalClassPath = false; |
|
81 | - } |
|
82 | - |
|
83 | - /** |
|
84 | - * enable the usage of the global classpath \OC::$CLASSPATH |
|
85 | - */ |
|
86 | - public function enableGlobalClassPath() { |
|
87 | - $this->useGlobalClassPath = true; |
|
88 | - } |
|
89 | - |
|
90 | - /** |
|
91 | - * get the possible paths for a class |
|
92 | - * |
|
93 | - * @param string $class |
|
94 | - * @return array an array of possible paths |
|
95 | - */ |
|
96 | - public function findClass(string $class): array { |
|
97 | - $class = trim($class, '\\'); |
|
98 | - |
|
99 | - $paths = []; |
|
100 | - if ($this->useGlobalClassPath && array_key_exists($class, \OC::$CLASSPATH)) { |
|
101 | - $paths[] = \OC::$CLASSPATH[$class]; |
|
102 | - /** |
|
103 | - * @TODO: Remove this when necessary |
|
104 | - * Remove "apps/" from inclusion path for smooth migration to multi app dir |
|
105 | - */ |
|
106 | - if (strpos(\OC::$CLASSPATH[$class], 'apps/') === 0) { |
|
107 | - \OCP\Util::writeLog('core', 'include path for class "' . $class . '" starts with "apps/"', ILogger::DEBUG); |
|
108 | - $paths[] = str_replace('apps/', '', \OC::$CLASSPATH[$class]); |
|
109 | - } |
|
110 | - } elseif (strpos($class, 'OC_') === 0) { |
|
111 | - $paths[] = \OC::$SERVERROOT . '/lib/private/legacy/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php'); |
|
112 | - } elseif (strpos($class, 'OCA\\') === 0) { |
|
113 | - [, $app, $rest] = explode('\\', $class, 3); |
|
114 | - $app = strtolower($app); |
|
115 | - $appPath = \OC_App::getAppPath($app); |
|
116 | - if ($appPath && stream_resolve_include_path($appPath)) { |
|
117 | - $paths[] = $appPath . '/' . strtolower(str_replace('\\', '/', $rest) . '.php'); |
|
118 | - // If not found in the root of the app directory, insert '/lib' after app id and try again. |
|
119 | - $paths[] = $appPath . '/lib/' . strtolower(str_replace('\\', '/', $rest) . '.php'); |
|
120 | - } |
|
121 | - } elseif ($class === 'Test\\TestCase') { |
|
122 | - // This File is considered public API, so we make sure that the class |
|
123 | - // can still be loaded, although the PSR-4 paths have not been loaded. |
|
124 | - $paths[] = \OC::$SERVERROOT . '/tests/lib/TestCase.php'; |
|
125 | - } |
|
126 | - return $paths; |
|
127 | - } |
|
128 | - |
|
129 | - /** |
|
130 | - * @param string $fullPath |
|
131 | - * @return bool |
|
132 | - * @throws AutoloadNotAllowedException |
|
133 | - */ |
|
134 | - protected function isValidPath(string $fullPath): bool { |
|
135 | - foreach ($this->validRoots as $root => $true) { |
|
136 | - if (substr($fullPath, 0, strlen($root) + 1) === $root . '/') { |
|
137 | - return true; |
|
138 | - } |
|
139 | - } |
|
140 | - throw new AutoloadNotAllowedException($fullPath); |
|
141 | - } |
|
142 | - |
|
143 | - /** |
|
144 | - * Load the specified class |
|
145 | - * |
|
146 | - * @param string $class |
|
147 | - * @return bool |
|
148 | - * @throws AutoloadNotAllowedException |
|
149 | - */ |
|
150 | - public function load(string $class): bool { |
|
151 | - $pathsToRequire = null; |
|
152 | - if ($this->memoryCache) { |
|
153 | - $pathsToRequire = $this->memoryCache->get($class); |
|
154 | - } |
|
155 | - |
|
156 | - if (class_exists($class, false)) { |
|
157 | - return false; |
|
158 | - } |
|
159 | - |
|
160 | - if (!is_array($pathsToRequire)) { |
|
161 | - // No cache or cache miss |
|
162 | - $pathsToRequire = []; |
|
163 | - foreach ($this->findClass($class) as $path) { |
|
164 | - $fullPath = stream_resolve_include_path($path); |
|
165 | - if ($fullPath && $this->isValidPath($fullPath)) { |
|
166 | - $pathsToRequire[] = $fullPath; |
|
167 | - } |
|
168 | - } |
|
169 | - |
|
170 | - if ($this->memoryCache) { |
|
171 | - $this->memoryCache->set($class, $pathsToRequire, 60); // cache 60 sec |
|
172 | - } |
|
173 | - } |
|
174 | - |
|
175 | - foreach ($pathsToRequire as $fullPath) { |
|
176 | - require_once $fullPath; |
|
177 | - } |
|
178 | - |
|
179 | - return false; |
|
180 | - } |
|
181 | - |
|
182 | - /** |
|
183 | - * Sets the optional low-latency cache for class to path mapping. |
|
184 | - * |
|
185 | - * @param \OC\Memcache\Cache $memoryCache Instance of memory cache. |
|
186 | - */ |
|
187 | - public function setMemoryCache(\OC\Memcache\Cache $memoryCache = null) { |
|
188 | - $this->memoryCache = $memoryCache; |
|
189 | - } |
|
43 | + /** @var bool */ |
|
44 | + private $useGlobalClassPath = true; |
|
45 | + /** @var array */ |
|
46 | + private $validRoots = []; |
|
47 | + |
|
48 | + /** |
|
49 | + * Optional low-latency memory cache for class to path mapping. |
|
50 | + * |
|
51 | + * @var \OC\Memcache\Cache |
|
52 | + */ |
|
53 | + protected $memoryCache; |
|
54 | + |
|
55 | + /** |
|
56 | + * Autoloader constructor. |
|
57 | + * |
|
58 | + * @param string[] $validRoots |
|
59 | + */ |
|
60 | + public function __construct(array $validRoots) { |
|
61 | + foreach ($validRoots as $root) { |
|
62 | + $this->validRoots[$root] = true; |
|
63 | + } |
|
64 | + } |
|
65 | + |
|
66 | + /** |
|
67 | + * Add a path to the list of valid php roots for auto loading |
|
68 | + * |
|
69 | + * @param string $root |
|
70 | + */ |
|
71 | + public function addValidRoot(string $root) { |
|
72 | + $root = stream_resolve_include_path($root); |
|
73 | + $this->validRoots[$root] = true; |
|
74 | + } |
|
75 | + |
|
76 | + /** |
|
77 | + * disable the usage of the global classpath \OC::$CLASSPATH |
|
78 | + */ |
|
79 | + public function disableGlobalClassPath() { |
|
80 | + $this->useGlobalClassPath = false; |
|
81 | + } |
|
82 | + |
|
83 | + /** |
|
84 | + * enable the usage of the global classpath \OC::$CLASSPATH |
|
85 | + */ |
|
86 | + public function enableGlobalClassPath() { |
|
87 | + $this->useGlobalClassPath = true; |
|
88 | + } |
|
89 | + |
|
90 | + /** |
|
91 | + * get the possible paths for a class |
|
92 | + * |
|
93 | + * @param string $class |
|
94 | + * @return array an array of possible paths |
|
95 | + */ |
|
96 | + public function findClass(string $class): array { |
|
97 | + $class = trim($class, '\\'); |
|
98 | + |
|
99 | + $paths = []; |
|
100 | + if ($this->useGlobalClassPath && array_key_exists($class, \OC::$CLASSPATH)) { |
|
101 | + $paths[] = \OC::$CLASSPATH[$class]; |
|
102 | + /** |
|
103 | + * @TODO: Remove this when necessary |
|
104 | + * Remove "apps/" from inclusion path for smooth migration to multi app dir |
|
105 | + */ |
|
106 | + if (strpos(\OC::$CLASSPATH[$class], 'apps/') === 0) { |
|
107 | + \OCP\Util::writeLog('core', 'include path for class "' . $class . '" starts with "apps/"', ILogger::DEBUG); |
|
108 | + $paths[] = str_replace('apps/', '', \OC::$CLASSPATH[$class]); |
|
109 | + } |
|
110 | + } elseif (strpos($class, 'OC_') === 0) { |
|
111 | + $paths[] = \OC::$SERVERROOT . '/lib/private/legacy/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php'); |
|
112 | + } elseif (strpos($class, 'OCA\\') === 0) { |
|
113 | + [, $app, $rest] = explode('\\', $class, 3); |
|
114 | + $app = strtolower($app); |
|
115 | + $appPath = \OC_App::getAppPath($app); |
|
116 | + if ($appPath && stream_resolve_include_path($appPath)) { |
|
117 | + $paths[] = $appPath . '/' . strtolower(str_replace('\\', '/', $rest) . '.php'); |
|
118 | + // If not found in the root of the app directory, insert '/lib' after app id and try again. |
|
119 | + $paths[] = $appPath . '/lib/' . strtolower(str_replace('\\', '/', $rest) . '.php'); |
|
120 | + } |
|
121 | + } elseif ($class === 'Test\\TestCase') { |
|
122 | + // This File is considered public API, so we make sure that the class |
|
123 | + // can still be loaded, although the PSR-4 paths have not been loaded. |
|
124 | + $paths[] = \OC::$SERVERROOT . '/tests/lib/TestCase.php'; |
|
125 | + } |
|
126 | + return $paths; |
|
127 | + } |
|
128 | + |
|
129 | + /** |
|
130 | + * @param string $fullPath |
|
131 | + * @return bool |
|
132 | + * @throws AutoloadNotAllowedException |
|
133 | + */ |
|
134 | + protected function isValidPath(string $fullPath): bool { |
|
135 | + foreach ($this->validRoots as $root => $true) { |
|
136 | + if (substr($fullPath, 0, strlen($root) + 1) === $root . '/') { |
|
137 | + return true; |
|
138 | + } |
|
139 | + } |
|
140 | + throw new AutoloadNotAllowedException($fullPath); |
|
141 | + } |
|
142 | + |
|
143 | + /** |
|
144 | + * Load the specified class |
|
145 | + * |
|
146 | + * @param string $class |
|
147 | + * @return bool |
|
148 | + * @throws AutoloadNotAllowedException |
|
149 | + */ |
|
150 | + public function load(string $class): bool { |
|
151 | + $pathsToRequire = null; |
|
152 | + if ($this->memoryCache) { |
|
153 | + $pathsToRequire = $this->memoryCache->get($class); |
|
154 | + } |
|
155 | + |
|
156 | + if (class_exists($class, false)) { |
|
157 | + return false; |
|
158 | + } |
|
159 | + |
|
160 | + if (!is_array($pathsToRequire)) { |
|
161 | + // No cache or cache miss |
|
162 | + $pathsToRequire = []; |
|
163 | + foreach ($this->findClass($class) as $path) { |
|
164 | + $fullPath = stream_resolve_include_path($path); |
|
165 | + if ($fullPath && $this->isValidPath($fullPath)) { |
|
166 | + $pathsToRequire[] = $fullPath; |
|
167 | + } |
|
168 | + } |
|
169 | + |
|
170 | + if ($this->memoryCache) { |
|
171 | + $this->memoryCache->set($class, $pathsToRequire, 60); // cache 60 sec |
|
172 | + } |
|
173 | + } |
|
174 | + |
|
175 | + foreach ($pathsToRequire as $fullPath) { |
|
176 | + require_once $fullPath; |
|
177 | + } |
|
178 | + |
|
179 | + return false; |
|
180 | + } |
|
181 | + |
|
182 | + /** |
|
183 | + * Sets the optional low-latency cache for class to path mapping. |
|
184 | + * |
|
185 | + * @param \OC\Memcache\Cache $memoryCache Instance of memory cache. |
|
186 | + */ |
|
187 | + public function setMemoryCache(\OC\Memcache\Cache $memoryCache = null) { |
|
188 | + $this->memoryCache = $memoryCache; |
|
189 | + } |
|
190 | 190 | } |
@@ -104,24 +104,24 @@ discard block |
||
104 | 104 | * Remove "apps/" from inclusion path for smooth migration to multi app dir |
105 | 105 | */ |
106 | 106 | if (strpos(\OC::$CLASSPATH[$class], 'apps/') === 0) { |
107 | - \OCP\Util::writeLog('core', 'include path for class "' . $class . '" starts with "apps/"', ILogger::DEBUG); |
|
107 | + \OCP\Util::writeLog('core', 'include path for class "'.$class.'" starts with "apps/"', ILogger::DEBUG); |
|
108 | 108 | $paths[] = str_replace('apps/', '', \OC::$CLASSPATH[$class]); |
109 | 109 | } |
110 | 110 | } elseif (strpos($class, 'OC_') === 0) { |
111 | - $paths[] = \OC::$SERVERROOT . '/lib/private/legacy/' . strtolower(str_replace('_', '/', substr($class, 3)) . '.php'); |
|
111 | + $paths[] = \OC::$SERVERROOT.'/lib/private/legacy/'.strtolower(str_replace('_', '/', substr($class, 3)).'.php'); |
|
112 | 112 | } elseif (strpos($class, 'OCA\\') === 0) { |
113 | 113 | [, $app, $rest] = explode('\\', $class, 3); |
114 | 114 | $app = strtolower($app); |
115 | 115 | $appPath = \OC_App::getAppPath($app); |
116 | 116 | if ($appPath && stream_resolve_include_path($appPath)) { |
117 | - $paths[] = $appPath . '/' . strtolower(str_replace('\\', '/', $rest) . '.php'); |
|
117 | + $paths[] = $appPath.'/'.strtolower(str_replace('\\', '/', $rest).'.php'); |
|
118 | 118 | // If not found in the root of the app directory, insert '/lib' after app id and try again. |
119 | - $paths[] = $appPath . '/lib/' . strtolower(str_replace('\\', '/', $rest) . '.php'); |
|
119 | + $paths[] = $appPath.'/lib/'.strtolower(str_replace('\\', '/', $rest).'.php'); |
|
120 | 120 | } |
121 | 121 | } elseif ($class === 'Test\\TestCase') { |
122 | 122 | // This File is considered public API, so we make sure that the class |
123 | 123 | // can still be loaded, although the PSR-4 paths have not been loaded. |
124 | - $paths[] = \OC::$SERVERROOT . '/tests/lib/TestCase.php'; |
|
124 | + $paths[] = \OC::$SERVERROOT.'/tests/lib/TestCase.php'; |
|
125 | 125 | } |
126 | 126 | return $paths; |
127 | 127 | } |
@@ -133,7 +133,7 @@ discard block |
||
133 | 133 | */ |
134 | 134 | protected function isValidPath(string $fullPath): bool { |
135 | 135 | foreach ($this->validRoots as $root => $true) { |
136 | - if (substr($fullPath, 0, strlen($root) + 1) === $root . '/') { |
|
136 | + if (substr($fullPath, 0, strlen($root) + 1) === $root.'/') { |
|
137 | 137 | return true; |
138 | 138 | } |
139 | 139 | } |
@@ -53,235 +53,235 @@ |
||
53 | 53 | use Psr\Http\Message\RequestInterface; |
54 | 54 | |
55 | 55 | class SwiftFactory { |
56 | - private $cache; |
|
57 | - private $params; |
|
58 | - /** @var Container|null */ |
|
59 | - private $container = null; |
|
60 | - private $logger; |
|
56 | + private $cache; |
|
57 | + private $params; |
|
58 | + /** @var Container|null */ |
|
59 | + private $container = null; |
|
60 | + private $logger; |
|
61 | 61 | |
62 | - public const DEFAULT_OPTIONS = [ |
|
63 | - 'autocreate' => false, |
|
64 | - 'urlType' => 'publicURL', |
|
65 | - 'catalogName' => 'swift', |
|
66 | - 'catalogType' => 'object-store' |
|
67 | - ]; |
|
62 | + public const DEFAULT_OPTIONS = [ |
|
63 | + 'autocreate' => false, |
|
64 | + 'urlType' => 'publicURL', |
|
65 | + 'catalogName' => 'swift', |
|
66 | + 'catalogType' => 'object-store' |
|
67 | + ]; |
|
68 | 68 | |
69 | - public function __construct(ICache $cache, array $params, ILogger $logger) { |
|
70 | - $this->cache = $cache; |
|
71 | - $this->params = $params; |
|
72 | - $this->logger = $logger; |
|
73 | - } |
|
69 | + public function __construct(ICache $cache, array $params, ILogger $logger) { |
|
70 | + $this->cache = $cache; |
|
71 | + $this->params = $params; |
|
72 | + $this->logger = $logger; |
|
73 | + } |
|
74 | 74 | |
75 | - /** |
|
76 | - * Gets currently cached token id |
|
77 | - * |
|
78 | - * @return string |
|
79 | - * @throws StorageAuthException |
|
80 | - */ |
|
81 | - public function getCachedTokenId() { |
|
82 | - if (!isset($this->params['cachedToken'])) { |
|
83 | - throw new StorageAuthException('Unauthenticated ObjectStore connection'); |
|
84 | - } |
|
75 | + /** |
|
76 | + * Gets currently cached token id |
|
77 | + * |
|
78 | + * @return string |
|
79 | + * @throws StorageAuthException |
|
80 | + */ |
|
81 | + public function getCachedTokenId() { |
|
82 | + if (!isset($this->params['cachedToken'])) { |
|
83 | + throw new StorageAuthException('Unauthenticated ObjectStore connection'); |
|
84 | + } |
|
85 | 85 | |
86 | - // Is it V2 token? |
|
87 | - if (isset($this->params['cachedToken']['token'])) { |
|
88 | - return $this->params['cachedToken']['token']['id']; |
|
89 | - } |
|
86 | + // Is it V2 token? |
|
87 | + if (isset($this->params['cachedToken']['token'])) { |
|
88 | + return $this->params['cachedToken']['token']['id']; |
|
89 | + } |
|
90 | 90 | |
91 | - return $this->params['cachedToken']['id']; |
|
92 | - } |
|
91 | + return $this->params['cachedToken']['id']; |
|
92 | + } |
|
93 | 93 | |
94 | - private function getCachedToken(string $cacheKey) { |
|
95 | - $cachedTokenString = $this->cache->get($cacheKey . '/token'); |
|
96 | - if ($cachedTokenString) { |
|
97 | - return json_decode($cachedTokenString, true); |
|
98 | - } else { |
|
99 | - return null; |
|
100 | - } |
|
101 | - } |
|
94 | + private function getCachedToken(string $cacheKey) { |
|
95 | + $cachedTokenString = $this->cache->get($cacheKey . '/token'); |
|
96 | + if ($cachedTokenString) { |
|
97 | + return json_decode($cachedTokenString, true); |
|
98 | + } else { |
|
99 | + return null; |
|
100 | + } |
|
101 | + } |
|
102 | 102 | |
103 | - private function cacheToken(Token $token, string $serviceUrl, string $cacheKey) { |
|
104 | - if ($token instanceof \OpenStack\Identity\v3\Models\Token) { |
|
105 | - // for v3 the catalog is cached as part of the token, so no need to cache $serviceUrl separately |
|
106 | - $value = $token->export(); |
|
107 | - } else { |
|
108 | - /** @var \OpenStack\Identity\v2\Models\Token $token */ |
|
109 | - $value = [ |
|
110 | - 'serviceUrl' => $serviceUrl, |
|
111 | - 'token' => [ |
|
112 | - 'issued_at' => $token->issuedAt->format('c'), |
|
113 | - 'expires' => $token->expires->format('c'), |
|
114 | - 'id' => $token->id, |
|
115 | - 'tenant' => $token->tenant |
|
116 | - ] |
|
117 | - ]; |
|
118 | - } |
|
103 | + private function cacheToken(Token $token, string $serviceUrl, string $cacheKey) { |
|
104 | + if ($token instanceof \OpenStack\Identity\v3\Models\Token) { |
|
105 | + // for v3 the catalog is cached as part of the token, so no need to cache $serviceUrl separately |
|
106 | + $value = $token->export(); |
|
107 | + } else { |
|
108 | + /** @var \OpenStack\Identity\v2\Models\Token $token */ |
|
109 | + $value = [ |
|
110 | + 'serviceUrl' => $serviceUrl, |
|
111 | + 'token' => [ |
|
112 | + 'issued_at' => $token->issuedAt->format('c'), |
|
113 | + 'expires' => $token->expires->format('c'), |
|
114 | + 'id' => $token->id, |
|
115 | + 'tenant' => $token->tenant |
|
116 | + ] |
|
117 | + ]; |
|
118 | + } |
|
119 | 119 | |
120 | - $this->params['cachedToken'] = $value; |
|
121 | - $this->cache->set($cacheKey . '/token', json_encode($value)); |
|
122 | - } |
|
120 | + $this->params['cachedToken'] = $value; |
|
121 | + $this->cache->set($cacheKey . '/token', json_encode($value)); |
|
122 | + } |
|
123 | 123 | |
124 | - /** |
|
125 | - * @return OpenStack |
|
126 | - * @throws StorageAuthException |
|
127 | - */ |
|
128 | - private function getClient() { |
|
129 | - if (isset($this->params['bucket'])) { |
|
130 | - $this->params['container'] = $this->params['bucket']; |
|
131 | - } |
|
132 | - if (!isset($this->params['container'])) { |
|
133 | - $this->params['container'] = 'nextcloud'; |
|
134 | - } |
|
135 | - if (isset($this->params['user']) && is_array($this->params['user'])) { |
|
136 | - $userName = $this->params['user']['name']; |
|
137 | - } else { |
|
138 | - if (!isset($this->params['username']) && isset($this->params['user'])) { |
|
139 | - $this->params['username'] = $this->params['user']; |
|
140 | - } |
|
141 | - $userName = $this->params['username']; |
|
142 | - } |
|
143 | - if (!isset($this->params['tenantName']) && isset($this->params['tenant'])) { |
|
144 | - $this->params['tenantName'] = $this->params['tenant']; |
|
145 | - } |
|
146 | - if (isset($this->params['domain'])) { |
|
147 | - $this->params['scope']['project']['name'] = $this->params['tenant']; |
|
148 | - $this->params['scope']['project']['domain']['name'] = $this->params['domain']; |
|
149 | - } |
|
150 | - $this->params = array_merge(self::DEFAULT_OPTIONS, $this->params); |
|
124 | + /** |
|
125 | + * @return OpenStack |
|
126 | + * @throws StorageAuthException |
|
127 | + */ |
|
128 | + private function getClient() { |
|
129 | + if (isset($this->params['bucket'])) { |
|
130 | + $this->params['container'] = $this->params['bucket']; |
|
131 | + } |
|
132 | + if (!isset($this->params['container'])) { |
|
133 | + $this->params['container'] = 'nextcloud'; |
|
134 | + } |
|
135 | + if (isset($this->params['user']) && is_array($this->params['user'])) { |
|
136 | + $userName = $this->params['user']['name']; |
|
137 | + } else { |
|
138 | + if (!isset($this->params['username']) && isset($this->params['user'])) { |
|
139 | + $this->params['username'] = $this->params['user']; |
|
140 | + } |
|
141 | + $userName = $this->params['username']; |
|
142 | + } |
|
143 | + if (!isset($this->params['tenantName']) && isset($this->params['tenant'])) { |
|
144 | + $this->params['tenantName'] = $this->params['tenant']; |
|
145 | + } |
|
146 | + if (isset($this->params['domain'])) { |
|
147 | + $this->params['scope']['project']['name'] = $this->params['tenant']; |
|
148 | + $this->params['scope']['project']['domain']['name'] = $this->params['domain']; |
|
149 | + } |
|
150 | + $this->params = array_merge(self::DEFAULT_OPTIONS, $this->params); |
|
151 | 151 | |
152 | - $cacheKey = $userName . '@' . $this->params['url'] . '/' . $this->params['container']; |
|
153 | - $token = $this->getCachedToken($cacheKey); |
|
154 | - $this->params['cachedToken'] = $token; |
|
152 | + $cacheKey = $userName . '@' . $this->params['url'] . '/' . $this->params['container']; |
|
153 | + $token = $this->getCachedToken($cacheKey); |
|
154 | + $this->params['cachedToken'] = $token; |
|
155 | 155 | |
156 | - $httpClient = new Client([ |
|
157 | - 'base_uri' => TransportUtils::normalizeUrl($this->params['url']), |
|
158 | - 'handler' => HandlerStack::create() |
|
159 | - ]); |
|
156 | + $httpClient = new Client([ |
|
157 | + 'base_uri' => TransportUtils::normalizeUrl($this->params['url']), |
|
158 | + 'handler' => HandlerStack::create() |
|
159 | + ]); |
|
160 | 160 | |
161 | - if (isset($this->params['user']) && is_array($this->params['user']) && isset($this->params['user']['name'])) { |
|
162 | - if (!isset($this->params['scope'])) { |
|
163 | - throw new StorageAuthException('Scope has to be defined for V3 requests'); |
|
164 | - } |
|
161 | + if (isset($this->params['user']) && is_array($this->params['user']) && isset($this->params['user']['name'])) { |
|
162 | + if (!isset($this->params['scope'])) { |
|
163 | + throw new StorageAuthException('Scope has to be defined for V3 requests'); |
|
164 | + } |
|
165 | 165 | |
166 | - return $this->auth(IdentityV3Service::factory($httpClient), $cacheKey); |
|
167 | - } else { |
|
168 | - return $this->auth(SwiftV2CachingAuthService::factory($httpClient), $cacheKey); |
|
169 | - } |
|
170 | - } |
|
166 | + return $this->auth(IdentityV3Service::factory($httpClient), $cacheKey); |
|
167 | + } else { |
|
168 | + return $this->auth(SwiftV2CachingAuthService::factory($httpClient), $cacheKey); |
|
169 | + } |
|
170 | + } |
|
171 | 171 | |
172 | - /** |
|
173 | - * @param IdentityV2Service|IdentityV3Service $authService |
|
174 | - * @param string $cacheKey |
|
175 | - * @return OpenStack |
|
176 | - * @throws StorageAuthException |
|
177 | - */ |
|
178 | - private function auth($authService, string $cacheKey) { |
|
179 | - $this->params['identityService'] = $authService; |
|
180 | - $this->params['authUrl'] = $this->params['url']; |
|
172 | + /** |
|
173 | + * @param IdentityV2Service|IdentityV3Service $authService |
|
174 | + * @param string $cacheKey |
|
175 | + * @return OpenStack |
|
176 | + * @throws StorageAuthException |
|
177 | + */ |
|
178 | + private function auth($authService, string $cacheKey) { |
|
179 | + $this->params['identityService'] = $authService; |
|
180 | + $this->params['authUrl'] = $this->params['url']; |
|
181 | 181 | |
182 | - $cachedToken = $this->params['cachedToken']; |
|
183 | - $hasValidCachedToken = false; |
|
184 | - if (\is_array($cachedToken)) { |
|
185 | - if ($authService instanceof IdentityV3Service) { |
|
186 | - $token = $authService->generateTokenFromCache($cachedToken); |
|
187 | - if (\is_null($token->catalog)) { |
|
188 | - $this->logger->warning('Invalid cached token for swift, no catalog set: ' . json_encode($cachedToken)); |
|
189 | - } elseif ($token->hasExpired()) { |
|
190 | - $this->logger->debug('Cached token for swift expired'); |
|
191 | - } else { |
|
192 | - $hasValidCachedToken = true; |
|
193 | - } |
|
194 | - } else { |
|
195 | - try { |
|
196 | - /** @var \OpenStack\Identity\v2\Models\Token $token */ |
|
197 | - $token = $authService->model(\OpenStack\Identity\v2\Models\Token::class, $cachedToken['token']); |
|
198 | - $now = new \DateTimeImmutable("now"); |
|
199 | - if ($token->expires > $now) { |
|
200 | - $hasValidCachedToken = true; |
|
201 | - $this->params['v2cachedToken'] = $token; |
|
202 | - $this->params['v2serviceUrl'] = $cachedToken['serviceUrl']; |
|
203 | - } else { |
|
204 | - $this->logger->debug('Cached token for swift expired'); |
|
205 | - } |
|
206 | - } catch (\Exception $e) { |
|
207 | - $this->logger->logException($e); |
|
208 | - } |
|
209 | - } |
|
210 | - } |
|
182 | + $cachedToken = $this->params['cachedToken']; |
|
183 | + $hasValidCachedToken = false; |
|
184 | + if (\is_array($cachedToken)) { |
|
185 | + if ($authService instanceof IdentityV3Service) { |
|
186 | + $token = $authService->generateTokenFromCache($cachedToken); |
|
187 | + if (\is_null($token->catalog)) { |
|
188 | + $this->logger->warning('Invalid cached token for swift, no catalog set: ' . json_encode($cachedToken)); |
|
189 | + } elseif ($token->hasExpired()) { |
|
190 | + $this->logger->debug('Cached token for swift expired'); |
|
191 | + } else { |
|
192 | + $hasValidCachedToken = true; |
|
193 | + } |
|
194 | + } else { |
|
195 | + try { |
|
196 | + /** @var \OpenStack\Identity\v2\Models\Token $token */ |
|
197 | + $token = $authService->model(\OpenStack\Identity\v2\Models\Token::class, $cachedToken['token']); |
|
198 | + $now = new \DateTimeImmutable("now"); |
|
199 | + if ($token->expires > $now) { |
|
200 | + $hasValidCachedToken = true; |
|
201 | + $this->params['v2cachedToken'] = $token; |
|
202 | + $this->params['v2serviceUrl'] = $cachedToken['serviceUrl']; |
|
203 | + } else { |
|
204 | + $this->logger->debug('Cached token for swift expired'); |
|
205 | + } |
|
206 | + } catch (\Exception $e) { |
|
207 | + $this->logger->logException($e); |
|
208 | + } |
|
209 | + } |
|
210 | + } |
|
211 | 211 | |
212 | - if (!$hasValidCachedToken) { |
|
213 | - unset($this->params['cachedToken']); |
|
214 | - try { |
|
215 | - [$token, $serviceUrl] = $authService->authenticate($this->params); |
|
216 | - $this->cacheToken($token, $serviceUrl, $cacheKey); |
|
217 | - } catch (ConnectException $e) { |
|
218 | - throw new StorageAuthException('Failed to connect to keystone, verify the keystone url', $e); |
|
219 | - } catch (ClientException $e) { |
|
220 | - $statusCode = $e->getResponse()->getStatusCode(); |
|
221 | - if ($statusCode === 404) { |
|
222 | - throw new StorageAuthException('Keystone not found, verify the keystone url', $e); |
|
223 | - } elseif ($statusCode === 412) { |
|
224 | - throw new StorageAuthException('Precondition failed, verify the keystone url', $e); |
|
225 | - } elseif ($statusCode === 401) { |
|
226 | - throw new StorageAuthException('Authentication failed, verify the username, password and possibly tenant', $e); |
|
227 | - } else { |
|
228 | - throw new StorageAuthException('Unknown error', $e); |
|
229 | - } |
|
230 | - } catch (RequestException $e) { |
|
231 | - throw new StorageAuthException('Connection reset while connecting to keystone, verify the keystone url', $e); |
|
232 | - } |
|
233 | - } |
|
212 | + if (!$hasValidCachedToken) { |
|
213 | + unset($this->params['cachedToken']); |
|
214 | + try { |
|
215 | + [$token, $serviceUrl] = $authService->authenticate($this->params); |
|
216 | + $this->cacheToken($token, $serviceUrl, $cacheKey); |
|
217 | + } catch (ConnectException $e) { |
|
218 | + throw new StorageAuthException('Failed to connect to keystone, verify the keystone url', $e); |
|
219 | + } catch (ClientException $e) { |
|
220 | + $statusCode = $e->getResponse()->getStatusCode(); |
|
221 | + if ($statusCode === 404) { |
|
222 | + throw new StorageAuthException('Keystone not found, verify the keystone url', $e); |
|
223 | + } elseif ($statusCode === 412) { |
|
224 | + throw new StorageAuthException('Precondition failed, verify the keystone url', $e); |
|
225 | + } elseif ($statusCode === 401) { |
|
226 | + throw new StorageAuthException('Authentication failed, verify the username, password and possibly tenant', $e); |
|
227 | + } else { |
|
228 | + throw new StorageAuthException('Unknown error', $e); |
|
229 | + } |
|
230 | + } catch (RequestException $e) { |
|
231 | + throw new StorageAuthException('Connection reset while connecting to keystone, verify the keystone url', $e); |
|
232 | + } |
|
233 | + } |
|
234 | 234 | |
235 | 235 | |
236 | - $client = new OpenStack($this->params); |
|
236 | + $client = new OpenStack($this->params); |
|
237 | 237 | |
238 | - return $client; |
|
239 | - } |
|
238 | + return $client; |
|
239 | + } |
|
240 | 240 | |
241 | - /** |
|
242 | - * @return \OpenStack\ObjectStore\v1\Models\Container |
|
243 | - * @throws StorageAuthException |
|
244 | - * @throws StorageNotAvailableException |
|
245 | - */ |
|
246 | - public function getContainer() { |
|
247 | - if (is_null($this->container)) { |
|
248 | - $this->container = $this->createContainer(); |
|
249 | - } |
|
241 | + /** |
|
242 | + * @return \OpenStack\ObjectStore\v1\Models\Container |
|
243 | + * @throws StorageAuthException |
|
244 | + * @throws StorageNotAvailableException |
|
245 | + */ |
|
246 | + public function getContainer() { |
|
247 | + if (is_null($this->container)) { |
|
248 | + $this->container = $this->createContainer(); |
|
249 | + } |
|
250 | 250 | |
251 | - return $this->container; |
|
252 | - } |
|
251 | + return $this->container; |
|
252 | + } |
|
253 | 253 | |
254 | - /** |
|
255 | - * @return \OpenStack\ObjectStore\v1\Models\Container |
|
256 | - * @throws StorageAuthException |
|
257 | - * @throws StorageNotAvailableException |
|
258 | - */ |
|
259 | - private function createContainer() { |
|
260 | - $client = $this->getClient(); |
|
261 | - $objectStoreService = $client->objectStoreV1(); |
|
254 | + /** |
|
255 | + * @return \OpenStack\ObjectStore\v1\Models\Container |
|
256 | + * @throws StorageAuthException |
|
257 | + * @throws StorageNotAvailableException |
|
258 | + */ |
|
259 | + private function createContainer() { |
|
260 | + $client = $this->getClient(); |
|
261 | + $objectStoreService = $client->objectStoreV1(); |
|
262 | 262 | |
263 | - $autoCreate = isset($this->params['autocreate']) && $this->params['autocreate'] === true; |
|
264 | - try { |
|
265 | - $container = $objectStoreService->getContainer($this->params['container']); |
|
266 | - if ($autoCreate) { |
|
267 | - $container->getMetadata(); |
|
268 | - } |
|
269 | - return $container; |
|
270 | - } catch (BadResponseError $ex) { |
|
271 | - // if the container does not exist and autocreate is true try to create the container on the fly |
|
272 | - if ($ex->getResponse()->getStatusCode() === 404 && $autoCreate) { |
|
273 | - return $objectStoreService->createContainer([ |
|
274 | - 'name' => $this->params['container'] |
|
275 | - ]); |
|
276 | - } else { |
|
277 | - throw new StorageNotAvailableException('Invalid response while trying to get container info', StorageNotAvailableException::STATUS_ERROR, $ex); |
|
278 | - } |
|
279 | - } catch (ConnectException $e) { |
|
280 | - /** @var RequestInterface $request */ |
|
281 | - $request = $e->getRequest(); |
|
282 | - $host = $request->getUri()->getHost() . ':' . $request->getUri()->getPort(); |
|
283 | - \OC::$server->getLogger()->error("Can't connect to object storage server at $host"); |
|
284 | - throw new StorageNotAvailableException("Can't connect to object storage server at $host", StorageNotAvailableException::STATUS_ERROR, $e); |
|
285 | - } |
|
286 | - } |
|
263 | + $autoCreate = isset($this->params['autocreate']) && $this->params['autocreate'] === true; |
|
264 | + try { |
|
265 | + $container = $objectStoreService->getContainer($this->params['container']); |
|
266 | + if ($autoCreate) { |
|
267 | + $container->getMetadata(); |
|
268 | + } |
|
269 | + return $container; |
|
270 | + } catch (BadResponseError $ex) { |
|
271 | + // if the container does not exist and autocreate is true try to create the container on the fly |
|
272 | + if ($ex->getResponse()->getStatusCode() === 404 && $autoCreate) { |
|
273 | + return $objectStoreService->createContainer([ |
|
274 | + 'name' => $this->params['container'] |
|
275 | + ]); |
|
276 | + } else { |
|
277 | + throw new StorageNotAvailableException('Invalid response while trying to get container info', StorageNotAvailableException::STATUS_ERROR, $ex); |
|
278 | + } |
|
279 | + } catch (ConnectException $e) { |
|
280 | + /** @var RequestInterface $request */ |
|
281 | + $request = $e->getRequest(); |
|
282 | + $host = $request->getUri()->getHost() . ':' . $request->getUri()->getPort(); |
|
283 | + \OC::$server->getLogger()->error("Can't connect to object storage server at $host"); |
|
284 | + throw new StorageNotAvailableException("Can't connect to object storage server at $host", StorageNotAvailableException::STATUS_ERROR, $e); |
|
285 | + } |
|
286 | + } |
|
287 | 287 | } |
@@ -47,380 +47,380 @@ |
||
47 | 47 | * Cache mounts points per user in the cache so we can easilly look them up |
48 | 48 | */ |
49 | 49 | class UserMountCache implements IUserMountCache { |
50 | - /** |
|
51 | - * @var IDBConnection |
|
52 | - */ |
|
53 | - private $connection; |
|
54 | - |
|
55 | - /** |
|
56 | - * @var IUserManager |
|
57 | - */ |
|
58 | - private $userManager; |
|
59 | - |
|
60 | - /** |
|
61 | - * Cached mount info. |
|
62 | - * Map of $userId to ICachedMountInfo. |
|
63 | - * |
|
64 | - * @var ICache |
|
65 | - **/ |
|
66 | - private $mountsForUsers; |
|
67 | - |
|
68 | - /** |
|
69 | - * @var ILogger |
|
70 | - */ |
|
71 | - private $logger; |
|
72 | - |
|
73 | - /** |
|
74 | - * @var ICache |
|
75 | - */ |
|
76 | - private $cacheInfoCache; |
|
77 | - |
|
78 | - /** |
|
79 | - * UserMountCache constructor. |
|
80 | - * |
|
81 | - * @param IDBConnection $connection |
|
82 | - * @param IUserManager $userManager |
|
83 | - * @param ILogger $logger |
|
84 | - */ |
|
85 | - public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) { |
|
86 | - $this->connection = $connection; |
|
87 | - $this->userManager = $userManager; |
|
88 | - $this->logger = $logger; |
|
89 | - $this->cacheInfoCache = new CappedMemoryCache(); |
|
90 | - $this->mountsForUsers = new CappedMemoryCache(); |
|
91 | - } |
|
92 | - |
|
93 | - public function registerMounts(IUser $user, array $mounts) { |
|
94 | - // filter out non-proper storages coming from unit tests |
|
95 | - $mounts = array_filter($mounts, function (IMountPoint $mount) { |
|
96 | - return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache(); |
|
97 | - }); |
|
98 | - /** @var ICachedMountInfo[] $newMounts */ |
|
99 | - $newMounts = array_map(function (IMountPoint $mount) use ($user) { |
|
100 | - // filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet) |
|
101 | - if ($mount->getStorageRootId() === -1) { |
|
102 | - return null; |
|
103 | - } else { |
|
104 | - return new LazyStorageMountInfo($user, $mount); |
|
105 | - } |
|
106 | - }, $mounts); |
|
107 | - $newMounts = array_values(array_filter($newMounts)); |
|
108 | - $newMountRootIds = array_map(function (ICachedMountInfo $mount) { |
|
109 | - return $mount->getRootId(); |
|
110 | - }, $newMounts); |
|
111 | - $newMounts = array_combine($newMountRootIds, $newMounts); |
|
112 | - |
|
113 | - $cachedMounts = $this->getMountsForUser($user); |
|
114 | - $cachedMountRootIds = array_map(function (ICachedMountInfo $mount) { |
|
115 | - return $mount->getRootId(); |
|
116 | - }, $cachedMounts); |
|
117 | - $cachedMounts = array_combine($cachedMountRootIds, $cachedMounts); |
|
118 | - |
|
119 | - $addedMounts = []; |
|
120 | - $removedMounts = []; |
|
121 | - |
|
122 | - foreach ($newMounts as $rootId => $newMount) { |
|
123 | - if (!isset($cachedMounts[$rootId])) { |
|
124 | - $addedMounts[] = $newMount; |
|
125 | - } |
|
126 | - } |
|
127 | - |
|
128 | - foreach ($cachedMounts as $rootId => $cachedMount) { |
|
129 | - if (!isset($newMounts[$rootId])) { |
|
130 | - $removedMounts[] = $cachedMount; |
|
131 | - } |
|
132 | - } |
|
133 | - |
|
134 | - $changedMounts = $this->findChangedMounts($newMounts, $cachedMounts); |
|
135 | - |
|
136 | - foreach ($addedMounts as $mount) { |
|
137 | - $this->addToCache($mount); |
|
138 | - $this->mountsForUsers[$user->getUID()][] = $mount; |
|
139 | - } |
|
140 | - foreach ($removedMounts as $mount) { |
|
141 | - $this->removeFromCache($mount); |
|
142 | - $index = array_search($mount, $this->mountsForUsers[$user->getUID()]); |
|
143 | - unset($this->mountsForUsers[$user->getUID()][$index]); |
|
144 | - } |
|
145 | - foreach ($changedMounts as $mount) { |
|
146 | - $this->updateCachedMount($mount); |
|
147 | - } |
|
148 | - } |
|
149 | - |
|
150 | - /** |
|
151 | - * @param ICachedMountInfo[] $newMounts |
|
152 | - * @param ICachedMountInfo[] $cachedMounts |
|
153 | - * @return ICachedMountInfo[] |
|
154 | - */ |
|
155 | - private function findChangedMounts(array $newMounts, array $cachedMounts) { |
|
156 | - $new = []; |
|
157 | - foreach ($newMounts as $mount) { |
|
158 | - $new[$mount->getRootId()] = $mount; |
|
159 | - } |
|
160 | - $changed = []; |
|
161 | - foreach ($cachedMounts as $cachedMount) { |
|
162 | - $rootId = $cachedMount->getRootId(); |
|
163 | - if (isset($new[$rootId])) { |
|
164 | - $newMount = $new[$rootId]; |
|
165 | - if ( |
|
166 | - $newMount->getMountPoint() !== $cachedMount->getMountPoint() || |
|
167 | - $newMount->getStorageId() !== $cachedMount->getStorageId() || |
|
168 | - $newMount->getMountId() !== $cachedMount->getMountId() |
|
169 | - ) { |
|
170 | - $changed[] = $newMount; |
|
171 | - } |
|
172 | - } |
|
173 | - } |
|
174 | - return $changed; |
|
175 | - } |
|
176 | - |
|
177 | - private function addToCache(ICachedMountInfo $mount) { |
|
178 | - if ($mount->getStorageId() !== -1) { |
|
179 | - $this->connection->insertIfNotExist('*PREFIX*mounts', [ |
|
180 | - 'storage_id' => $mount->getStorageId(), |
|
181 | - 'root_id' => $mount->getRootId(), |
|
182 | - 'user_id' => $mount->getUser()->getUID(), |
|
183 | - 'mount_point' => $mount->getMountPoint(), |
|
184 | - 'mount_id' => $mount->getMountId() |
|
185 | - ], ['root_id', 'user_id']); |
|
186 | - } else { |
|
187 | - // in some cases this is legitimate, like orphaned shares |
|
188 | - $this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint()); |
|
189 | - } |
|
190 | - } |
|
191 | - |
|
192 | - private function updateCachedMount(ICachedMountInfo $mount) { |
|
193 | - $builder = $this->connection->getQueryBuilder(); |
|
194 | - |
|
195 | - $query = $builder->update('mounts') |
|
196 | - ->set('storage_id', $builder->createNamedParameter($mount->getStorageId())) |
|
197 | - ->set('mount_point', $builder->createNamedParameter($mount->getMountPoint())) |
|
198 | - ->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT)) |
|
199 | - ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID()))) |
|
200 | - ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT))); |
|
201 | - |
|
202 | - $query->execute(); |
|
203 | - } |
|
204 | - |
|
205 | - private function removeFromCache(ICachedMountInfo $mount) { |
|
206 | - $builder = $this->connection->getQueryBuilder(); |
|
207 | - |
|
208 | - $query = $builder->delete('mounts') |
|
209 | - ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID()))) |
|
210 | - ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT))); |
|
211 | - $query->execute(); |
|
212 | - } |
|
213 | - |
|
214 | - private function dbRowToMountInfo(array $row) { |
|
215 | - $user = $this->userManager->get($row['user_id']); |
|
216 | - if (is_null($user)) { |
|
217 | - return null; |
|
218 | - } |
|
219 | - $mount_id = $row['mount_id']; |
|
220 | - if (!is_null($mount_id)) { |
|
221 | - $mount_id = (int)$mount_id; |
|
222 | - } |
|
223 | - return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $mount_id, isset($row['path']) ? $row['path'] : ''); |
|
224 | - } |
|
225 | - |
|
226 | - /** |
|
227 | - * @param IUser $user |
|
228 | - * @return ICachedMountInfo[] |
|
229 | - */ |
|
230 | - public function getMountsForUser(IUser $user) { |
|
231 | - if (!isset($this->mountsForUsers[$user->getUID()])) { |
|
232 | - $builder = $this->connection->getQueryBuilder(); |
|
233 | - $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path') |
|
234 | - ->from('mounts', 'm') |
|
235 | - ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid')) |
|
236 | - ->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID()))); |
|
237 | - |
|
238 | - $result = $query->execute(); |
|
239 | - $rows = $result->fetchAll(); |
|
240 | - $result->closeCursor(); |
|
241 | - |
|
242 | - $this->mountsForUsers[$user->getUID()] = array_filter(array_map([$this, 'dbRowToMountInfo'], $rows)); |
|
243 | - } |
|
244 | - return $this->mountsForUsers[$user->getUID()]; |
|
245 | - } |
|
246 | - |
|
247 | - /** |
|
248 | - * @param int $numericStorageId |
|
249 | - * @param string|null $user limit the results to a single user |
|
250 | - * @return CachedMountInfo[] |
|
251 | - */ |
|
252 | - public function getMountsForStorageId($numericStorageId, $user = null) { |
|
253 | - $builder = $this->connection->getQueryBuilder(); |
|
254 | - $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path') |
|
255 | - ->from('mounts', 'm') |
|
256 | - ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid')) |
|
257 | - ->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT))); |
|
258 | - |
|
259 | - if ($user) { |
|
260 | - $query->andWhere($builder->expr()->eq('user_id', $builder->createPositionalParameter($user))); |
|
261 | - } |
|
262 | - |
|
263 | - $result = $query->execute(); |
|
264 | - $rows = $result->fetchAll(); |
|
265 | - $result->closeCursor(); |
|
266 | - |
|
267 | - return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows)); |
|
268 | - } |
|
269 | - |
|
270 | - /** |
|
271 | - * @param int $rootFileId |
|
272 | - * @return CachedMountInfo[] |
|
273 | - */ |
|
274 | - public function getMountsForRootId($rootFileId) { |
|
275 | - $builder = $this->connection->getQueryBuilder(); |
|
276 | - $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path') |
|
277 | - ->from('mounts', 'm') |
|
278 | - ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid')) |
|
279 | - ->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT))); |
|
280 | - |
|
281 | - $result = $query->execute(); |
|
282 | - $rows = $result->fetchAll(); |
|
283 | - $result->closeCursor(); |
|
284 | - |
|
285 | - return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows)); |
|
286 | - } |
|
287 | - |
|
288 | - /** |
|
289 | - * @param $fileId |
|
290 | - * @return array |
|
291 | - * @throws \OCP\Files\NotFoundException |
|
292 | - */ |
|
293 | - private function getCacheInfoFromFileId($fileId) { |
|
294 | - if (!isset($this->cacheInfoCache[$fileId])) { |
|
295 | - $builder = $this->connection->getQueryBuilder(); |
|
296 | - $query = $builder->select('storage', 'path', 'mimetype') |
|
297 | - ->from('filecache') |
|
298 | - ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))); |
|
299 | - |
|
300 | - $result = $query->execute(); |
|
301 | - $row = $result->fetch(); |
|
302 | - $result->closeCursor(); |
|
303 | - |
|
304 | - if (is_array($row)) { |
|
305 | - $this->cacheInfoCache[$fileId] = [ |
|
306 | - (int)$row['storage'], |
|
307 | - $row['path'], |
|
308 | - (int)$row['mimetype'] |
|
309 | - ]; |
|
310 | - } else { |
|
311 | - throw new NotFoundException('File with id "' . $fileId . '" not found'); |
|
312 | - } |
|
313 | - } |
|
314 | - return $this->cacheInfoCache[$fileId]; |
|
315 | - } |
|
316 | - |
|
317 | - /** |
|
318 | - * @param int $fileId |
|
319 | - * @param string|null $user optionally restrict the results to a single user |
|
320 | - * @return ICachedMountFileInfo[] |
|
321 | - * @since 9.0.0 |
|
322 | - */ |
|
323 | - public function getMountsForFileId($fileId, $user = null) { |
|
324 | - try { |
|
325 | - [$storageId, $internalPath] = $this->getCacheInfoFromFileId($fileId); |
|
326 | - } catch (NotFoundException $e) { |
|
327 | - return []; |
|
328 | - } |
|
329 | - $mountsForStorage = $this->getMountsForStorageId($storageId, $user); |
|
330 | - |
|
331 | - // filter mounts that are from the same storage but a different directory |
|
332 | - $filteredMounts = array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) { |
|
333 | - if ($fileId === $mount->getRootId()) { |
|
334 | - return true; |
|
335 | - } |
|
336 | - $internalMountPath = $mount->getRootInternalPath(); |
|
337 | - |
|
338 | - return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/'; |
|
339 | - }); |
|
340 | - |
|
341 | - return array_map(function (ICachedMountInfo $mount) use ($internalPath) { |
|
342 | - return new CachedMountFileInfo( |
|
343 | - $mount->getUser(), |
|
344 | - $mount->getStorageId(), |
|
345 | - $mount->getRootId(), |
|
346 | - $mount->getMountPoint(), |
|
347 | - $mount->getMountId(), |
|
348 | - $mount->getRootInternalPath(), |
|
349 | - $internalPath |
|
350 | - ); |
|
351 | - }, $filteredMounts); |
|
352 | - } |
|
353 | - |
|
354 | - /** |
|
355 | - * Remove all cached mounts for a user |
|
356 | - * |
|
357 | - * @param IUser $user |
|
358 | - */ |
|
359 | - public function removeUserMounts(IUser $user) { |
|
360 | - $builder = $this->connection->getQueryBuilder(); |
|
361 | - |
|
362 | - $query = $builder->delete('mounts') |
|
363 | - ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID()))); |
|
364 | - $query->execute(); |
|
365 | - } |
|
366 | - |
|
367 | - public function removeUserStorageMount($storageId, $userId) { |
|
368 | - $builder = $this->connection->getQueryBuilder(); |
|
369 | - |
|
370 | - $query = $builder->delete('mounts') |
|
371 | - ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId))) |
|
372 | - ->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT))); |
|
373 | - $query->execute(); |
|
374 | - } |
|
375 | - |
|
376 | - public function remoteStorageMounts($storageId) { |
|
377 | - $builder = $this->connection->getQueryBuilder(); |
|
378 | - |
|
379 | - $query = $builder->delete('mounts') |
|
380 | - ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT))); |
|
381 | - $query->execute(); |
|
382 | - } |
|
383 | - |
|
384 | - /** |
|
385 | - * @param array $users |
|
386 | - * @return array |
|
387 | - */ |
|
388 | - public function getUsedSpaceForUsers(array $users) { |
|
389 | - $builder = $this->connection->getQueryBuilder(); |
|
390 | - |
|
391 | - $slash = $builder->createNamedParameter('/'); |
|
392 | - |
|
393 | - $mountPoint = $builder->func()->concat( |
|
394 | - $builder->func()->concat($slash, 'user_id'), |
|
395 | - $slash |
|
396 | - ); |
|
397 | - |
|
398 | - $userIds = array_map(function (IUser $user) { |
|
399 | - return $user->getUID(); |
|
400 | - }, $users); |
|
401 | - |
|
402 | - $query = $builder->select('m.user_id', 'f.size') |
|
403 | - ->from('mounts', 'm') |
|
404 | - ->innerJoin('m', 'filecache', 'f', |
|
405 | - $builder->expr()->andX( |
|
406 | - $builder->expr()->eq('m.storage_id', 'f.storage'), |
|
407 | - $builder->expr()->eq('f.path_hash', $builder->createNamedParameter(md5('files'))) |
|
408 | - )) |
|
409 | - ->where($builder->expr()->eq('m.mount_point', $mountPoint)) |
|
410 | - ->andWhere($builder->expr()->in('m.user_id', $builder->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY))); |
|
411 | - |
|
412 | - $result = $query->execute(); |
|
413 | - |
|
414 | - $results = []; |
|
415 | - while ($row = $result->fetch()) { |
|
416 | - $results[$row['user_id']] = $row['size']; |
|
417 | - } |
|
418 | - $result->closeCursor(); |
|
419 | - return $results; |
|
420 | - } |
|
421 | - |
|
422 | - public function clear(): void { |
|
423 | - $this->cacheInfoCache = new CappedMemoryCache(); |
|
424 | - $this->mountsForUsers = new CappedMemoryCache(); |
|
425 | - } |
|
50 | + /** |
|
51 | + * @var IDBConnection |
|
52 | + */ |
|
53 | + private $connection; |
|
54 | + |
|
55 | + /** |
|
56 | + * @var IUserManager |
|
57 | + */ |
|
58 | + private $userManager; |
|
59 | + |
|
60 | + /** |
|
61 | + * Cached mount info. |
|
62 | + * Map of $userId to ICachedMountInfo. |
|
63 | + * |
|
64 | + * @var ICache |
|
65 | + **/ |
|
66 | + private $mountsForUsers; |
|
67 | + |
|
68 | + /** |
|
69 | + * @var ILogger |
|
70 | + */ |
|
71 | + private $logger; |
|
72 | + |
|
73 | + /** |
|
74 | + * @var ICache |
|
75 | + */ |
|
76 | + private $cacheInfoCache; |
|
77 | + |
|
78 | + /** |
|
79 | + * UserMountCache constructor. |
|
80 | + * |
|
81 | + * @param IDBConnection $connection |
|
82 | + * @param IUserManager $userManager |
|
83 | + * @param ILogger $logger |
|
84 | + */ |
|
85 | + public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) { |
|
86 | + $this->connection = $connection; |
|
87 | + $this->userManager = $userManager; |
|
88 | + $this->logger = $logger; |
|
89 | + $this->cacheInfoCache = new CappedMemoryCache(); |
|
90 | + $this->mountsForUsers = new CappedMemoryCache(); |
|
91 | + } |
|
92 | + |
|
93 | + public function registerMounts(IUser $user, array $mounts) { |
|
94 | + // filter out non-proper storages coming from unit tests |
|
95 | + $mounts = array_filter($mounts, function (IMountPoint $mount) { |
|
96 | + return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache(); |
|
97 | + }); |
|
98 | + /** @var ICachedMountInfo[] $newMounts */ |
|
99 | + $newMounts = array_map(function (IMountPoint $mount) use ($user) { |
|
100 | + // filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet) |
|
101 | + if ($mount->getStorageRootId() === -1) { |
|
102 | + return null; |
|
103 | + } else { |
|
104 | + return new LazyStorageMountInfo($user, $mount); |
|
105 | + } |
|
106 | + }, $mounts); |
|
107 | + $newMounts = array_values(array_filter($newMounts)); |
|
108 | + $newMountRootIds = array_map(function (ICachedMountInfo $mount) { |
|
109 | + return $mount->getRootId(); |
|
110 | + }, $newMounts); |
|
111 | + $newMounts = array_combine($newMountRootIds, $newMounts); |
|
112 | + |
|
113 | + $cachedMounts = $this->getMountsForUser($user); |
|
114 | + $cachedMountRootIds = array_map(function (ICachedMountInfo $mount) { |
|
115 | + return $mount->getRootId(); |
|
116 | + }, $cachedMounts); |
|
117 | + $cachedMounts = array_combine($cachedMountRootIds, $cachedMounts); |
|
118 | + |
|
119 | + $addedMounts = []; |
|
120 | + $removedMounts = []; |
|
121 | + |
|
122 | + foreach ($newMounts as $rootId => $newMount) { |
|
123 | + if (!isset($cachedMounts[$rootId])) { |
|
124 | + $addedMounts[] = $newMount; |
|
125 | + } |
|
126 | + } |
|
127 | + |
|
128 | + foreach ($cachedMounts as $rootId => $cachedMount) { |
|
129 | + if (!isset($newMounts[$rootId])) { |
|
130 | + $removedMounts[] = $cachedMount; |
|
131 | + } |
|
132 | + } |
|
133 | + |
|
134 | + $changedMounts = $this->findChangedMounts($newMounts, $cachedMounts); |
|
135 | + |
|
136 | + foreach ($addedMounts as $mount) { |
|
137 | + $this->addToCache($mount); |
|
138 | + $this->mountsForUsers[$user->getUID()][] = $mount; |
|
139 | + } |
|
140 | + foreach ($removedMounts as $mount) { |
|
141 | + $this->removeFromCache($mount); |
|
142 | + $index = array_search($mount, $this->mountsForUsers[$user->getUID()]); |
|
143 | + unset($this->mountsForUsers[$user->getUID()][$index]); |
|
144 | + } |
|
145 | + foreach ($changedMounts as $mount) { |
|
146 | + $this->updateCachedMount($mount); |
|
147 | + } |
|
148 | + } |
|
149 | + |
|
150 | + /** |
|
151 | + * @param ICachedMountInfo[] $newMounts |
|
152 | + * @param ICachedMountInfo[] $cachedMounts |
|
153 | + * @return ICachedMountInfo[] |
|
154 | + */ |
|
155 | + private function findChangedMounts(array $newMounts, array $cachedMounts) { |
|
156 | + $new = []; |
|
157 | + foreach ($newMounts as $mount) { |
|
158 | + $new[$mount->getRootId()] = $mount; |
|
159 | + } |
|
160 | + $changed = []; |
|
161 | + foreach ($cachedMounts as $cachedMount) { |
|
162 | + $rootId = $cachedMount->getRootId(); |
|
163 | + if (isset($new[$rootId])) { |
|
164 | + $newMount = $new[$rootId]; |
|
165 | + if ( |
|
166 | + $newMount->getMountPoint() !== $cachedMount->getMountPoint() || |
|
167 | + $newMount->getStorageId() !== $cachedMount->getStorageId() || |
|
168 | + $newMount->getMountId() !== $cachedMount->getMountId() |
|
169 | + ) { |
|
170 | + $changed[] = $newMount; |
|
171 | + } |
|
172 | + } |
|
173 | + } |
|
174 | + return $changed; |
|
175 | + } |
|
176 | + |
|
177 | + private function addToCache(ICachedMountInfo $mount) { |
|
178 | + if ($mount->getStorageId() !== -1) { |
|
179 | + $this->connection->insertIfNotExist('*PREFIX*mounts', [ |
|
180 | + 'storage_id' => $mount->getStorageId(), |
|
181 | + 'root_id' => $mount->getRootId(), |
|
182 | + 'user_id' => $mount->getUser()->getUID(), |
|
183 | + 'mount_point' => $mount->getMountPoint(), |
|
184 | + 'mount_id' => $mount->getMountId() |
|
185 | + ], ['root_id', 'user_id']); |
|
186 | + } else { |
|
187 | + // in some cases this is legitimate, like orphaned shares |
|
188 | + $this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint()); |
|
189 | + } |
|
190 | + } |
|
191 | + |
|
192 | + private function updateCachedMount(ICachedMountInfo $mount) { |
|
193 | + $builder = $this->connection->getQueryBuilder(); |
|
194 | + |
|
195 | + $query = $builder->update('mounts') |
|
196 | + ->set('storage_id', $builder->createNamedParameter($mount->getStorageId())) |
|
197 | + ->set('mount_point', $builder->createNamedParameter($mount->getMountPoint())) |
|
198 | + ->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT)) |
|
199 | + ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID()))) |
|
200 | + ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT))); |
|
201 | + |
|
202 | + $query->execute(); |
|
203 | + } |
|
204 | + |
|
205 | + private function removeFromCache(ICachedMountInfo $mount) { |
|
206 | + $builder = $this->connection->getQueryBuilder(); |
|
207 | + |
|
208 | + $query = $builder->delete('mounts') |
|
209 | + ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID()))) |
|
210 | + ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT))); |
|
211 | + $query->execute(); |
|
212 | + } |
|
213 | + |
|
214 | + private function dbRowToMountInfo(array $row) { |
|
215 | + $user = $this->userManager->get($row['user_id']); |
|
216 | + if (is_null($user)) { |
|
217 | + return null; |
|
218 | + } |
|
219 | + $mount_id = $row['mount_id']; |
|
220 | + if (!is_null($mount_id)) { |
|
221 | + $mount_id = (int)$mount_id; |
|
222 | + } |
|
223 | + return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $mount_id, isset($row['path']) ? $row['path'] : ''); |
|
224 | + } |
|
225 | + |
|
226 | + /** |
|
227 | + * @param IUser $user |
|
228 | + * @return ICachedMountInfo[] |
|
229 | + */ |
|
230 | + public function getMountsForUser(IUser $user) { |
|
231 | + if (!isset($this->mountsForUsers[$user->getUID()])) { |
|
232 | + $builder = $this->connection->getQueryBuilder(); |
|
233 | + $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path') |
|
234 | + ->from('mounts', 'm') |
|
235 | + ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid')) |
|
236 | + ->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID()))); |
|
237 | + |
|
238 | + $result = $query->execute(); |
|
239 | + $rows = $result->fetchAll(); |
|
240 | + $result->closeCursor(); |
|
241 | + |
|
242 | + $this->mountsForUsers[$user->getUID()] = array_filter(array_map([$this, 'dbRowToMountInfo'], $rows)); |
|
243 | + } |
|
244 | + return $this->mountsForUsers[$user->getUID()]; |
|
245 | + } |
|
246 | + |
|
247 | + /** |
|
248 | + * @param int $numericStorageId |
|
249 | + * @param string|null $user limit the results to a single user |
|
250 | + * @return CachedMountInfo[] |
|
251 | + */ |
|
252 | + public function getMountsForStorageId($numericStorageId, $user = null) { |
|
253 | + $builder = $this->connection->getQueryBuilder(); |
|
254 | + $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path') |
|
255 | + ->from('mounts', 'm') |
|
256 | + ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid')) |
|
257 | + ->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT))); |
|
258 | + |
|
259 | + if ($user) { |
|
260 | + $query->andWhere($builder->expr()->eq('user_id', $builder->createPositionalParameter($user))); |
|
261 | + } |
|
262 | + |
|
263 | + $result = $query->execute(); |
|
264 | + $rows = $result->fetchAll(); |
|
265 | + $result->closeCursor(); |
|
266 | + |
|
267 | + return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows)); |
|
268 | + } |
|
269 | + |
|
270 | + /** |
|
271 | + * @param int $rootFileId |
|
272 | + * @return CachedMountInfo[] |
|
273 | + */ |
|
274 | + public function getMountsForRootId($rootFileId) { |
|
275 | + $builder = $this->connection->getQueryBuilder(); |
|
276 | + $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path') |
|
277 | + ->from('mounts', 'm') |
|
278 | + ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid')) |
|
279 | + ->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT))); |
|
280 | + |
|
281 | + $result = $query->execute(); |
|
282 | + $rows = $result->fetchAll(); |
|
283 | + $result->closeCursor(); |
|
284 | + |
|
285 | + return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows)); |
|
286 | + } |
|
287 | + |
|
288 | + /** |
|
289 | + * @param $fileId |
|
290 | + * @return array |
|
291 | + * @throws \OCP\Files\NotFoundException |
|
292 | + */ |
|
293 | + private function getCacheInfoFromFileId($fileId) { |
|
294 | + if (!isset($this->cacheInfoCache[$fileId])) { |
|
295 | + $builder = $this->connection->getQueryBuilder(); |
|
296 | + $query = $builder->select('storage', 'path', 'mimetype') |
|
297 | + ->from('filecache') |
|
298 | + ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))); |
|
299 | + |
|
300 | + $result = $query->execute(); |
|
301 | + $row = $result->fetch(); |
|
302 | + $result->closeCursor(); |
|
303 | + |
|
304 | + if (is_array($row)) { |
|
305 | + $this->cacheInfoCache[$fileId] = [ |
|
306 | + (int)$row['storage'], |
|
307 | + $row['path'], |
|
308 | + (int)$row['mimetype'] |
|
309 | + ]; |
|
310 | + } else { |
|
311 | + throw new NotFoundException('File with id "' . $fileId . '" not found'); |
|
312 | + } |
|
313 | + } |
|
314 | + return $this->cacheInfoCache[$fileId]; |
|
315 | + } |
|
316 | + |
|
317 | + /** |
|
318 | + * @param int $fileId |
|
319 | + * @param string|null $user optionally restrict the results to a single user |
|
320 | + * @return ICachedMountFileInfo[] |
|
321 | + * @since 9.0.0 |
|
322 | + */ |
|
323 | + public function getMountsForFileId($fileId, $user = null) { |
|
324 | + try { |
|
325 | + [$storageId, $internalPath] = $this->getCacheInfoFromFileId($fileId); |
|
326 | + } catch (NotFoundException $e) { |
|
327 | + return []; |
|
328 | + } |
|
329 | + $mountsForStorage = $this->getMountsForStorageId($storageId, $user); |
|
330 | + |
|
331 | + // filter mounts that are from the same storage but a different directory |
|
332 | + $filteredMounts = array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) { |
|
333 | + if ($fileId === $mount->getRootId()) { |
|
334 | + return true; |
|
335 | + } |
|
336 | + $internalMountPath = $mount->getRootInternalPath(); |
|
337 | + |
|
338 | + return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/'; |
|
339 | + }); |
|
340 | + |
|
341 | + return array_map(function (ICachedMountInfo $mount) use ($internalPath) { |
|
342 | + return new CachedMountFileInfo( |
|
343 | + $mount->getUser(), |
|
344 | + $mount->getStorageId(), |
|
345 | + $mount->getRootId(), |
|
346 | + $mount->getMountPoint(), |
|
347 | + $mount->getMountId(), |
|
348 | + $mount->getRootInternalPath(), |
|
349 | + $internalPath |
|
350 | + ); |
|
351 | + }, $filteredMounts); |
|
352 | + } |
|
353 | + |
|
354 | + /** |
|
355 | + * Remove all cached mounts for a user |
|
356 | + * |
|
357 | + * @param IUser $user |
|
358 | + */ |
|
359 | + public function removeUserMounts(IUser $user) { |
|
360 | + $builder = $this->connection->getQueryBuilder(); |
|
361 | + |
|
362 | + $query = $builder->delete('mounts') |
|
363 | + ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID()))); |
|
364 | + $query->execute(); |
|
365 | + } |
|
366 | + |
|
367 | + public function removeUserStorageMount($storageId, $userId) { |
|
368 | + $builder = $this->connection->getQueryBuilder(); |
|
369 | + |
|
370 | + $query = $builder->delete('mounts') |
|
371 | + ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId))) |
|
372 | + ->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT))); |
|
373 | + $query->execute(); |
|
374 | + } |
|
375 | + |
|
376 | + public function remoteStorageMounts($storageId) { |
|
377 | + $builder = $this->connection->getQueryBuilder(); |
|
378 | + |
|
379 | + $query = $builder->delete('mounts') |
|
380 | + ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT))); |
|
381 | + $query->execute(); |
|
382 | + } |
|
383 | + |
|
384 | + /** |
|
385 | + * @param array $users |
|
386 | + * @return array |
|
387 | + */ |
|
388 | + public function getUsedSpaceForUsers(array $users) { |
|
389 | + $builder = $this->connection->getQueryBuilder(); |
|
390 | + |
|
391 | + $slash = $builder->createNamedParameter('/'); |
|
392 | + |
|
393 | + $mountPoint = $builder->func()->concat( |
|
394 | + $builder->func()->concat($slash, 'user_id'), |
|
395 | + $slash |
|
396 | + ); |
|
397 | + |
|
398 | + $userIds = array_map(function (IUser $user) { |
|
399 | + return $user->getUID(); |
|
400 | + }, $users); |
|
401 | + |
|
402 | + $query = $builder->select('m.user_id', 'f.size') |
|
403 | + ->from('mounts', 'm') |
|
404 | + ->innerJoin('m', 'filecache', 'f', |
|
405 | + $builder->expr()->andX( |
|
406 | + $builder->expr()->eq('m.storage_id', 'f.storage'), |
|
407 | + $builder->expr()->eq('f.path_hash', $builder->createNamedParameter(md5('files'))) |
|
408 | + )) |
|
409 | + ->where($builder->expr()->eq('m.mount_point', $mountPoint)) |
|
410 | + ->andWhere($builder->expr()->in('m.user_id', $builder->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY))); |
|
411 | + |
|
412 | + $result = $query->execute(); |
|
413 | + |
|
414 | + $results = []; |
|
415 | + while ($row = $result->fetch()) { |
|
416 | + $results[$row['user_id']] = $row['size']; |
|
417 | + } |
|
418 | + $result->closeCursor(); |
|
419 | + return $results; |
|
420 | + } |
|
421 | + |
|
422 | + public function clear(): void { |
|
423 | + $this->cacheInfoCache = new CappedMemoryCache(); |
|
424 | + $this->mountsForUsers = new CappedMemoryCache(); |
|
425 | + } |
|
426 | 426 | } |
@@ -37,190 +37,190 @@ |
||
37 | 37 | * Tools for transforming search queries into database queries |
38 | 38 | */ |
39 | 39 | class QuerySearchHelper { |
40 | - protected static $searchOperatorMap = [ |
|
41 | - ISearchComparison::COMPARE_LIKE => 'iLike', |
|
42 | - ISearchComparison::COMPARE_EQUAL => 'eq', |
|
43 | - ISearchComparison::COMPARE_GREATER_THAN => 'gt', |
|
44 | - ISearchComparison::COMPARE_GREATER_THAN_EQUAL => 'gte', |
|
45 | - ISearchComparison::COMPARE_LESS_THAN => 'lt', |
|
46 | - ISearchComparison::COMPARE_LESS_THAN_EQUAL => 'lte' |
|
47 | - ]; |
|
48 | - |
|
49 | - protected static $searchOperatorNegativeMap = [ |
|
50 | - ISearchComparison::COMPARE_LIKE => 'notLike', |
|
51 | - ISearchComparison::COMPARE_EQUAL => 'neq', |
|
52 | - ISearchComparison::COMPARE_GREATER_THAN => 'lte', |
|
53 | - ISearchComparison::COMPARE_GREATER_THAN_EQUAL => 'lt', |
|
54 | - ISearchComparison::COMPARE_LESS_THAN => 'gte', |
|
55 | - ISearchComparison::COMPARE_LESS_THAN_EQUAL => 'lt' |
|
56 | - ]; |
|
57 | - |
|
58 | - public const TAG_FAVORITE = '_$!<Favorite>!$_'; |
|
59 | - |
|
60 | - /** @var IMimeTypeLoader */ |
|
61 | - private $mimetypeLoader; |
|
62 | - |
|
63 | - /** |
|
64 | - * QuerySearchUtil constructor. |
|
65 | - * |
|
66 | - * @param IMimeTypeLoader $mimetypeLoader |
|
67 | - */ |
|
68 | - public function __construct(IMimeTypeLoader $mimetypeLoader) { |
|
69 | - $this->mimetypeLoader = $mimetypeLoader; |
|
70 | - } |
|
71 | - |
|
72 | - /** |
|
73 | - * Whether or not the tag tables should be joined to complete the search |
|
74 | - * |
|
75 | - * @param ISearchOperator $operator |
|
76 | - * @return boolean |
|
77 | - */ |
|
78 | - public function shouldJoinTags(ISearchOperator $operator) { |
|
79 | - if ($operator instanceof ISearchBinaryOperator) { |
|
80 | - return array_reduce($operator->getArguments(), function ($shouldJoin, ISearchOperator $operator) { |
|
81 | - return $shouldJoin || $this->shouldJoinTags($operator); |
|
82 | - }, false); |
|
83 | - } elseif ($operator instanceof ISearchComparison) { |
|
84 | - return $operator->getField() === 'tagname' || $operator->getField() === 'favorite'; |
|
85 | - } |
|
86 | - return false; |
|
87 | - } |
|
88 | - |
|
89 | - /** |
|
90 | - * @param IQueryBuilder $builder |
|
91 | - * @param ISearchOperator $operator |
|
92 | - */ |
|
93 | - public function searchOperatorArrayToDBExprArray(IQueryBuilder $builder, array $operators) { |
|
94 | - return array_filter(array_map(function ($operator) use ($builder) { |
|
95 | - return $this->searchOperatorToDBExpr($builder, $operator); |
|
96 | - }, $operators)); |
|
97 | - } |
|
98 | - |
|
99 | - public function searchOperatorToDBExpr(IQueryBuilder $builder, ISearchOperator $operator) { |
|
100 | - $expr = $builder->expr(); |
|
101 | - if ($operator instanceof ISearchBinaryOperator) { |
|
102 | - if (count($operator->getArguments()) === 0) { |
|
103 | - return null; |
|
104 | - } |
|
105 | - |
|
106 | - switch ($operator->getType()) { |
|
107 | - case ISearchBinaryOperator::OPERATOR_NOT: |
|
108 | - $negativeOperator = $operator->getArguments()[0]; |
|
109 | - if ($negativeOperator instanceof ISearchComparison) { |
|
110 | - return $this->searchComparisonToDBExpr($builder, $negativeOperator, self::$searchOperatorNegativeMap); |
|
111 | - } else { |
|
112 | - throw new \InvalidArgumentException('Binary operators inside "not" is not supported'); |
|
113 | - } |
|
114 | - // no break |
|
115 | - case ISearchBinaryOperator::OPERATOR_AND: |
|
116 | - return call_user_func_array([$expr, 'andX'], $this->searchOperatorArrayToDBExprArray($builder, $operator->getArguments())); |
|
117 | - case ISearchBinaryOperator::OPERATOR_OR: |
|
118 | - return call_user_func_array([$expr, 'orX'], $this->searchOperatorArrayToDBExprArray($builder, $operator->getArguments())); |
|
119 | - default: |
|
120 | - throw new \InvalidArgumentException('Invalid operator type: ' . $operator->getType()); |
|
121 | - } |
|
122 | - } elseif ($operator instanceof ISearchComparison) { |
|
123 | - return $this->searchComparisonToDBExpr($builder, $operator, self::$searchOperatorMap); |
|
124 | - } else { |
|
125 | - throw new \InvalidArgumentException('Invalid operator type: ' . get_class($operator)); |
|
126 | - } |
|
127 | - } |
|
128 | - |
|
129 | - private function searchComparisonToDBExpr(IQueryBuilder $builder, ISearchComparison $comparison, array $operatorMap) { |
|
130 | - $this->validateComparison($comparison); |
|
131 | - |
|
132 | - [$field, $value, $type] = $this->getOperatorFieldAndValue($comparison); |
|
133 | - if (isset($operatorMap[$type])) { |
|
134 | - $queryOperator = $operatorMap[$type]; |
|
135 | - return $builder->expr()->$queryOperator($field, $this->getParameterForValue($builder, $value)); |
|
136 | - } else { |
|
137 | - throw new \InvalidArgumentException('Invalid operator type: ' . $comparison->getType()); |
|
138 | - } |
|
139 | - } |
|
140 | - |
|
141 | - private function getOperatorFieldAndValue(ISearchComparison $operator) { |
|
142 | - $field = $operator->getField(); |
|
143 | - $value = $operator->getValue(); |
|
144 | - $type = $operator->getType(); |
|
145 | - if ($field === 'mimetype') { |
|
146 | - if ($operator->getType() === ISearchComparison::COMPARE_EQUAL) { |
|
147 | - $value = (int)$this->mimetypeLoader->getId($value); |
|
148 | - } elseif ($operator->getType() === ISearchComparison::COMPARE_LIKE) { |
|
149 | - // transform "mimetype='foo/%'" to "mimepart='foo'" |
|
150 | - if (preg_match('|(.+)/%|', $value, $matches)) { |
|
151 | - $field = 'mimepart'; |
|
152 | - $value = (int)$this->mimetypeLoader->getId($matches[1]); |
|
153 | - $type = ISearchComparison::COMPARE_EQUAL; |
|
154 | - } elseif (strpos($value, '%') !== false) { |
|
155 | - throw new \InvalidArgumentException('Unsupported query value for mimetype: ' . $value . ', only values in the format "mime/type" or "mime/%" are supported'); |
|
156 | - } else { |
|
157 | - $field = 'mimetype'; |
|
158 | - $value = (int)$this->mimetypeLoader->getId($value); |
|
159 | - $type = ISearchComparison::COMPARE_EQUAL; |
|
160 | - } |
|
161 | - } |
|
162 | - } elseif ($field === 'favorite') { |
|
163 | - $field = 'tag.category'; |
|
164 | - $value = self::TAG_FAVORITE; |
|
165 | - } elseif ($field === 'tagname') { |
|
166 | - $field = 'tag.category'; |
|
167 | - } elseif ($field === 'fileid') { |
|
168 | - $field = 'file.fileid'; |
|
169 | - } |
|
170 | - return [$field, $value, $type]; |
|
171 | - } |
|
172 | - |
|
173 | - private function validateComparison(ISearchComparison $operator) { |
|
174 | - $types = [ |
|
175 | - 'mimetype' => 'string', |
|
176 | - 'mtime' => 'integer', |
|
177 | - 'name' => 'string', |
|
178 | - 'size' => 'integer', |
|
179 | - 'tagname' => 'string', |
|
180 | - 'favorite' => 'boolean', |
|
181 | - 'fileid' => 'integer' |
|
182 | - ]; |
|
183 | - $comparisons = [ |
|
184 | - 'mimetype' => ['eq', 'like'], |
|
185 | - 'mtime' => ['eq', 'gt', 'lt', 'gte', 'lte'], |
|
186 | - 'name' => ['eq', 'like'], |
|
187 | - 'size' => ['eq', 'gt', 'lt', 'gte', 'lte'], |
|
188 | - 'tagname' => ['eq', 'like'], |
|
189 | - 'favorite' => ['eq'], |
|
190 | - 'fileid' => ['eq'] |
|
191 | - ]; |
|
192 | - |
|
193 | - if (!isset($types[$operator->getField()])) { |
|
194 | - throw new \InvalidArgumentException('Unsupported comparison field ' . $operator->getField()); |
|
195 | - } |
|
196 | - $type = $types[$operator->getField()]; |
|
197 | - if (gettype($operator->getValue()) !== $type) { |
|
198 | - throw new \InvalidArgumentException('Invalid type for field ' . $operator->getField()); |
|
199 | - } |
|
200 | - if (!in_array($operator->getType(), $comparisons[$operator->getField()])) { |
|
201 | - throw new \InvalidArgumentException('Unsupported comparison for field ' . $operator->getField() . ': ' . $operator->getType()); |
|
202 | - } |
|
203 | - } |
|
204 | - |
|
205 | - private function getParameterForValue(IQueryBuilder $builder, $value) { |
|
206 | - if ($value instanceof \DateTime) { |
|
207 | - $value = $value->getTimestamp(); |
|
208 | - } |
|
209 | - if (is_numeric($value)) { |
|
210 | - $type = IQueryBuilder::PARAM_INT; |
|
211 | - } else { |
|
212 | - $type = IQueryBuilder::PARAM_STR; |
|
213 | - } |
|
214 | - return $builder->createNamedParameter($value, $type); |
|
215 | - } |
|
216 | - |
|
217 | - /** |
|
218 | - * @param IQueryBuilder $query |
|
219 | - * @param ISearchOrder[] $orders |
|
220 | - */ |
|
221 | - public function addSearchOrdersToQuery(IQueryBuilder $query, array $orders) { |
|
222 | - foreach ($orders as $order) { |
|
223 | - $query->addOrderBy($order->getField(), $order->getDirection()); |
|
224 | - } |
|
225 | - } |
|
40 | + protected static $searchOperatorMap = [ |
|
41 | + ISearchComparison::COMPARE_LIKE => 'iLike', |
|
42 | + ISearchComparison::COMPARE_EQUAL => 'eq', |
|
43 | + ISearchComparison::COMPARE_GREATER_THAN => 'gt', |
|
44 | + ISearchComparison::COMPARE_GREATER_THAN_EQUAL => 'gte', |
|
45 | + ISearchComparison::COMPARE_LESS_THAN => 'lt', |
|
46 | + ISearchComparison::COMPARE_LESS_THAN_EQUAL => 'lte' |
|
47 | + ]; |
|
48 | + |
|
49 | + protected static $searchOperatorNegativeMap = [ |
|
50 | + ISearchComparison::COMPARE_LIKE => 'notLike', |
|
51 | + ISearchComparison::COMPARE_EQUAL => 'neq', |
|
52 | + ISearchComparison::COMPARE_GREATER_THAN => 'lte', |
|
53 | + ISearchComparison::COMPARE_GREATER_THAN_EQUAL => 'lt', |
|
54 | + ISearchComparison::COMPARE_LESS_THAN => 'gte', |
|
55 | + ISearchComparison::COMPARE_LESS_THAN_EQUAL => 'lt' |
|
56 | + ]; |
|
57 | + |
|
58 | + public const TAG_FAVORITE = '_$!<Favorite>!$_'; |
|
59 | + |
|
60 | + /** @var IMimeTypeLoader */ |
|
61 | + private $mimetypeLoader; |
|
62 | + |
|
63 | + /** |
|
64 | + * QuerySearchUtil constructor. |
|
65 | + * |
|
66 | + * @param IMimeTypeLoader $mimetypeLoader |
|
67 | + */ |
|
68 | + public function __construct(IMimeTypeLoader $mimetypeLoader) { |
|
69 | + $this->mimetypeLoader = $mimetypeLoader; |
|
70 | + } |
|
71 | + |
|
72 | + /** |
|
73 | + * Whether or not the tag tables should be joined to complete the search |
|
74 | + * |
|
75 | + * @param ISearchOperator $operator |
|
76 | + * @return boolean |
|
77 | + */ |
|
78 | + public function shouldJoinTags(ISearchOperator $operator) { |
|
79 | + if ($operator instanceof ISearchBinaryOperator) { |
|
80 | + return array_reduce($operator->getArguments(), function ($shouldJoin, ISearchOperator $operator) { |
|
81 | + return $shouldJoin || $this->shouldJoinTags($operator); |
|
82 | + }, false); |
|
83 | + } elseif ($operator instanceof ISearchComparison) { |
|
84 | + return $operator->getField() === 'tagname' || $operator->getField() === 'favorite'; |
|
85 | + } |
|
86 | + return false; |
|
87 | + } |
|
88 | + |
|
89 | + /** |
|
90 | + * @param IQueryBuilder $builder |
|
91 | + * @param ISearchOperator $operator |
|
92 | + */ |
|
93 | + public function searchOperatorArrayToDBExprArray(IQueryBuilder $builder, array $operators) { |
|
94 | + return array_filter(array_map(function ($operator) use ($builder) { |
|
95 | + return $this->searchOperatorToDBExpr($builder, $operator); |
|
96 | + }, $operators)); |
|
97 | + } |
|
98 | + |
|
99 | + public function searchOperatorToDBExpr(IQueryBuilder $builder, ISearchOperator $operator) { |
|
100 | + $expr = $builder->expr(); |
|
101 | + if ($operator instanceof ISearchBinaryOperator) { |
|
102 | + if (count($operator->getArguments()) === 0) { |
|
103 | + return null; |
|
104 | + } |
|
105 | + |
|
106 | + switch ($operator->getType()) { |
|
107 | + case ISearchBinaryOperator::OPERATOR_NOT: |
|
108 | + $negativeOperator = $operator->getArguments()[0]; |
|
109 | + if ($negativeOperator instanceof ISearchComparison) { |
|
110 | + return $this->searchComparisonToDBExpr($builder, $negativeOperator, self::$searchOperatorNegativeMap); |
|
111 | + } else { |
|
112 | + throw new \InvalidArgumentException('Binary operators inside "not" is not supported'); |
|
113 | + } |
|
114 | + // no break |
|
115 | + case ISearchBinaryOperator::OPERATOR_AND: |
|
116 | + return call_user_func_array([$expr, 'andX'], $this->searchOperatorArrayToDBExprArray($builder, $operator->getArguments())); |
|
117 | + case ISearchBinaryOperator::OPERATOR_OR: |
|
118 | + return call_user_func_array([$expr, 'orX'], $this->searchOperatorArrayToDBExprArray($builder, $operator->getArguments())); |
|
119 | + default: |
|
120 | + throw new \InvalidArgumentException('Invalid operator type: ' . $operator->getType()); |
|
121 | + } |
|
122 | + } elseif ($operator instanceof ISearchComparison) { |
|
123 | + return $this->searchComparisonToDBExpr($builder, $operator, self::$searchOperatorMap); |
|
124 | + } else { |
|
125 | + throw new \InvalidArgumentException('Invalid operator type: ' . get_class($operator)); |
|
126 | + } |
|
127 | + } |
|
128 | + |
|
129 | + private function searchComparisonToDBExpr(IQueryBuilder $builder, ISearchComparison $comparison, array $operatorMap) { |
|
130 | + $this->validateComparison($comparison); |
|
131 | + |
|
132 | + [$field, $value, $type] = $this->getOperatorFieldAndValue($comparison); |
|
133 | + if (isset($operatorMap[$type])) { |
|
134 | + $queryOperator = $operatorMap[$type]; |
|
135 | + return $builder->expr()->$queryOperator($field, $this->getParameterForValue($builder, $value)); |
|
136 | + } else { |
|
137 | + throw new \InvalidArgumentException('Invalid operator type: ' . $comparison->getType()); |
|
138 | + } |
|
139 | + } |
|
140 | + |
|
141 | + private function getOperatorFieldAndValue(ISearchComparison $operator) { |
|
142 | + $field = $operator->getField(); |
|
143 | + $value = $operator->getValue(); |
|
144 | + $type = $operator->getType(); |
|
145 | + if ($field === 'mimetype') { |
|
146 | + if ($operator->getType() === ISearchComparison::COMPARE_EQUAL) { |
|
147 | + $value = (int)$this->mimetypeLoader->getId($value); |
|
148 | + } elseif ($operator->getType() === ISearchComparison::COMPARE_LIKE) { |
|
149 | + // transform "mimetype='foo/%'" to "mimepart='foo'" |
|
150 | + if (preg_match('|(.+)/%|', $value, $matches)) { |
|
151 | + $field = 'mimepart'; |
|
152 | + $value = (int)$this->mimetypeLoader->getId($matches[1]); |
|
153 | + $type = ISearchComparison::COMPARE_EQUAL; |
|
154 | + } elseif (strpos($value, '%') !== false) { |
|
155 | + throw new \InvalidArgumentException('Unsupported query value for mimetype: ' . $value . ', only values in the format "mime/type" or "mime/%" are supported'); |
|
156 | + } else { |
|
157 | + $field = 'mimetype'; |
|
158 | + $value = (int)$this->mimetypeLoader->getId($value); |
|
159 | + $type = ISearchComparison::COMPARE_EQUAL; |
|
160 | + } |
|
161 | + } |
|
162 | + } elseif ($field === 'favorite') { |
|
163 | + $field = 'tag.category'; |
|
164 | + $value = self::TAG_FAVORITE; |
|
165 | + } elseif ($field === 'tagname') { |
|
166 | + $field = 'tag.category'; |
|
167 | + } elseif ($field === 'fileid') { |
|
168 | + $field = 'file.fileid'; |
|
169 | + } |
|
170 | + return [$field, $value, $type]; |
|
171 | + } |
|
172 | + |
|
173 | + private function validateComparison(ISearchComparison $operator) { |
|
174 | + $types = [ |
|
175 | + 'mimetype' => 'string', |
|
176 | + 'mtime' => 'integer', |
|
177 | + 'name' => 'string', |
|
178 | + 'size' => 'integer', |
|
179 | + 'tagname' => 'string', |
|
180 | + 'favorite' => 'boolean', |
|
181 | + 'fileid' => 'integer' |
|
182 | + ]; |
|
183 | + $comparisons = [ |
|
184 | + 'mimetype' => ['eq', 'like'], |
|
185 | + 'mtime' => ['eq', 'gt', 'lt', 'gte', 'lte'], |
|
186 | + 'name' => ['eq', 'like'], |
|
187 | + 'size' => ['eq', 'gt', 'lt', 'gte', 'lte'], |
|
188 | + 'tagname' => ['eq', 'like'], |
|
189 | + 'favorite' => ['eq'], |
|
190 | + 'fileid' => ['eq'] |
|
191 | + ]; |
|
192 | + |
|
193 | + if (!isset($types[$operator->getField()])) { |
|
194 | + throw new \InvalidArgumentException('Unsupported comparison field ' . $operator->getField()); |
|
195 | + } |
|
196 | + $type = $types[$operator->getField()]; |
|
197 | + if (gettype($operator->getValue()) !== $type) { |
|
198 | + throw new \InvalidArgumentException('Invalid type for field ' . $operator->getField()); |
|
199 | + } |
|
200 | + if (!in_array($operator->getType(), $comparisons[$operator->getField()])) { |
|
201 | + throw new \InvalidArgumentException('Unsupported comparison for field ' . $operator->getField() . ': ' . $operator->getType()); |
|
202 | + } |
|
203 | + } |
|
204 | + |
|
205 | + private function getParameterForValue(IQueryBuilder $builder, $value) { |
|
206 | + if ($value instanceof \DateTime) { |
|
207 | + $value = $value->getTimestamp(); |
|
208 | + } |
|
209 | + if (is_numeric($value)) { |
|
210 | + $type = IQueryBuilder::PARAM_INT; |
|
211 | + } else { |
|
212 | + $type = IQueryBuilder::PARAM_STR; |
|
213 | + } |
|
214 | + return $builder->createNamedParameter($value, $type); |
|
215 | + } |
|
216 | + |
|
217 | + /** |
|
218 | + * @param IQueryBuilder $query |
|
219 | + * @param ISearchOrder[] $orders |
|
220 | + */ |
|
221 | + public function addSearchOrdersToQuery(IQueryBuilder $query, array $orders) { |
|
222 | + foreach ($orders as $order) { |
|
223 | + $query->addOrderBy($order->getField(), $order->getDirection()); |
|
224 | + } |
|
225 | + } |
|
226 | 226 | } |
@@ -32,66 +32,66 @@ |
||
32 | 32 | use OCP\Files\Cache\ICacheEntry; |
33 | 33 | |
34 | 34 | class HomeCache extends Cache { |
35 | - /** |
|
36 | - * get the size of a folder and set it in the cache |
|
37 | - * |
|
38 | - * @param string $path |
|
39 | - * @param array $entry (optional) meta data of the folder |
|
40 | - * @return int |
|
41 | - */ |
|
42 | - public function calculateFolderSize($path, $entry = null) { |
|
43 | - if ($path !== '/' and $path !== '' and $path !== 'files' and $path !== 'files_trashbin' and $path !== 'files_versions') { |
|
44 | - return parent::calculateFolderSize($path, $entry); |
|
45 | - } elseif ($path === '' or $path === '/') { |
|
46 | - // since the size of / isn't used (the size of /files is used instead) there is no use in calculating it |
|
47 | - return 0; |
|
48 | - } |
|
35 | + /** |
|
36 | + * get the size of a folder and set it in the cache |
|
37 | + * |
|
38 | + * @param string $path |
|
39 | + * @param array $entry (optional) meta data of the folder |
|
40 | + * @return int |
|
41 | + */ |
|
42 | + public function calculateFolderSize($path, $entry = null) { |
|
43 | + if ($path !== '/' and $path !== '' and $path !== 'files' and $path !== 'files_trashbin' and $path !== 'files_versions') { |
|
44 | + return parent::calculateFolderSize($path, $entry); |
|
45 | + } elseif ($path === '' or $path === '/') { |
|
46 | + // since the size of / isn't used (the size of /files is used instead) there is no use in calculating it |
|
47 | + return 0; |
|
48 | + } |
|
49 | 49 | |
50 | - $totalSize = 0; |
|
51 | - if (is_null($entry)) { |
|
52 | - $entry = $this->get($path); |
|
53 | - } |
|
54 | - if ($entry && $entry['mimetype'] === 'httpd/unix-directory') { |
|
55 | - $id = $entry['fileid']; |
|
50 | + $totalSize = 0; |
|
51 | + if (is_null($entry)) { |
|
52 | + $entry = $this->get($path); |
|
53 | + } |
|
54 | + if ($entry && $entry['mimetype'] === 'httpd/unix-directory') { |
|
55 | + $id = $entry['fileid']; |
|
56 | 56 | |
57 | - $query = $this->connection->getQueryBuilder(); |
|
58 | - $query->selectAlias($query->func()->sum('size'), 'f1') |
|
59 | - ->from('filecache') |
|
60 | - ->where($query->expr()->eq('parent', $query->createNamedParameter($id))) |
|
61 | - ->andWhere($query->expr()->eq('storage', $query->createNamedParameter($this->getNumericStorageId()))) |
|
62 | - ->andWhere($query->expr()->gte('size', $query->createNamedParameter(0))); |
|
57 | + $query = $this->connection->getQueryBuilder(); |
|
58 | + $query->selectAlias($query->func()->sum('size'), 'f1') |
|
59 | + ->from('filecache') |
|
60 | + ->where($query->expr()->eq('parent', $query->createNamedParameter($id))) |
|
61 | + ->andWhere($query->expr()->eq('storage', $query->createNamedParameter($this->getNumericStorageId()))) |
|
62 | + ->andWhere($query->expr()->gte('size', $query->createNamedParameter(0))); |
|
63 | 63 | |
64 | - $result = $query->execute(); |
|
65 | - $row = $result->fetch(); |
|
66 | - $result->closeCursor(); |
|
64 | + $result = $query->execute(); |
|
65 | + $row = $result->fetch(); |
|
66 | + $result->closeCursor(); |
|
67 | 67 | |
68 | - if ($row) { |
|
69 | - [$sum] = array_values($row); |
|
70 | - $totalSize = 0 + $sum; |
|
71 | - $entry['size'] += 0; |
|
72 | - if ($entry['size'] !== $totalSize) { |
|
73 | - $this->update($id, ['size' => $totalSize]); |
|
74 | - } |
|
75 | - } |
|
76 | - $result->closeCursor(); |
|
77 | - } |
|
78 | - return $totalSize; |
|
79 | - } |
|
68 | + if ($row) { |
|
69 | + [$sum] = array_values($row); |
|
70 | + $totalSize = 0 + $sum; |
|
71 | + $entry['size'] += 0; |
|
72 | + if ($entry['size'] !== $totalSize) { |
|
73 | + $this->update($id, ['size' => $totalSize]); |
|
74 | + } |
|
75 | + } |
|
76 | + $result->closeCursor(); |
|
77 | + } |
|
78 | + return $totalSize; |
|
79 | + } |
|
80 | 80 | |
81 | - /** |
|
82 | - * @param string $path |
|
83 | - * @return ICacheEntry |
|
84 | - */ |
|
85 | - public function get($path) { |
|
86 | - $data = parent::get($path); |
|
87 | - if ($path === '' or $path === '/') { |
|
88 | - // only the size of the "files" dir counts |
|
89 | - $filesData = parent::get('files'); |
|
81 | + /** |
|
82 | + * @param string $path |
|
83 | + * @return ICacheEntry |
|
84 | + */ |
|
85 | + public function get($path) { |
|
86 | + $data = parent::get($path); |
|
87 | + if ($path === '' or $path === '/') { |
|
88 | + // only the size of the "files" dir counts |
|
89 | + $filesData = parent::get('files'); |
|
90 | 90 | |
91 | - if (isset($filesData['size'])) { |
|
92 | - $data['size'] = $filesData['size']; |
|
93 | - } |
|
94 | - } |
|
95 | - return $data; |
|
96 | - } |
|
91 | + if (isset($filesData['size'])) { |
|
92 | + $data['size'] = $filesData['size']; |
|
93 | + } |
|
94 | + } |
|
95 | + return $data; |
|
96 | + } |
|
97 | 97 | } |
@@ -25,28 +25,28 @@ |
||
25 | 25 | use OCP\IDBConnection; |
26 | 26 | |
27 | 27 | class HomePropagator extends Propagator { |
28 | - private $ignoredBaseFolders; |
|
28 | + private $ignoredBaseFolders; |
|
29 | 29 | |
30 | - /** |
|
31 | - * @param \OC\Files\Storage\Storage $storage |
|
32 | - */ |
|
33 | - public function __construct(\OC\Files\Storage\Storage $storage, IDBConnection $connection) { |
|
34 | - parent::__construct($storage, $connection); |
|
35 | - $this->ignoredBaseFolders = ['files_encryption']; |
|
36 | - } |
|
30 | + /** |
|
31 | + * @param \OC\Files\Storage\Storage $storage |
|
32 | + */ |
|
33 | + public function __construct(\OC\Files\Storage\Storage $storage, IDBConnection $connection) { |
|
34 | + parent::__construct($storage, $connection); |
|
35 | + $this->ignoredBaseFolders = ['files_encryption']; |
|
36 | + } |
|
37 | 37 | |
38 | 38 | |
39 | - /** |
|
40 | - * @param string $internalPath |
|
41 | - * @param int $time |
|
42 | - * @param int $sizeDifference number of bytes the file has grown |
|
43 | - */ |
|
44 | - public function propagateChange($internalPath, $time, $sizeDifference = 0) { |
|
45 | - [$baseFolder] = explode('/', $internalPath, 2); |
|
46 | - if (in_array($baseFolder, $this->ignoredBaseFolders)) { |
|
47 | - return []; |
|
48 | - } else { |
|
49 | - parent::propagateChange($internalPath, $time, $sizeDifference); |
|
50 | - } |
|
51 | - } |
|
39 | + /** |
|
40 | + * @param string $internalPath |
|
41 | + * @param int $time |
|
42 | + * @param int $sizeDifference number of bytes the file has grown |
|
43 | + */ |
|
44 | + public function propagateChange($internalPath, $time, $sizeDifference = 0) { |
|
45 | + [$baseFolder] = explode('/', $internalPath, 2); |
|
46 | + if (in_array($baseFolder, $this->ignoredBaseFolders)) { |
|
47 | + return []; |
|
48 | + } else { |
|
49 | + parent::propagateChange($internalPath, $time, $sizeDifference); |
|
50 | + } |
|
51 | + } |
|
52 | 52 | } |
@@ -28,19 +28,19 @@ |
||
28 | 28 | use OC\Files\Storage\Wrapper\Jail; |
29 | 29 | |
30 | 30 | class JailPropagator extends Propagator { |
31 | - /** |
|
32 | - * @var Jail |
|
33 | - */ |
|
34 | - protected $storage; |
|
31 | + /** |
|
32 | + * @var Jail |
|
33 | + */ |
|
34 | + protected $storage; |
|
35 | 35 | |
36 | - /** |
|
37 | - * @param string $internalPath |
|
38 | - * @param int $time |
|
39 | - * @param int $sizeDifference |
|
40 | - */ |
|
41 | - public function propagateChange($internalPath, $time, $sizeDifference = 0) { |
|
42 | - /** @var \OC\Files\Storage\Storage $storage */ |
|
43 | - [$storage, $sourceInternalPath] = $this->storage->resolvePath($internalPath); |
|
44 | - $storage->getPropagator()->propagateChange($sourceInternalPath, $time, $sizeDifference); |
|
45 | - } |
|
36 | + /** |
|
37 | + * @param string $internalPath |
|
38 | + * @param int $time |
|
39 | + * @param int $sizeDifference |
|
40 | + */ |
|
41 | + public function propagateChange($internalPath, $time, $sizeDifference = 0) { |
|
42 | + /** @var \OC\Files\Storage\Storage $storage */ |
|
43 | + [$storage, $sourceInternalPath] = $this->storage->resolvePath($internalPath); |
|
44 | + $storage->getPropagator()->propagateChange($sourceInternalPath, $time, $sizeDifference); |
|
45 | + } |
|
46 | 46 | } |
@@ -39,608 +39,608 @@ |
||
39 | 39 | use OCP\Lock\ILockingProvider; |
40 | 40 | |
41 | 41 | class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStreamStorage { |
42 | - /** |
|
43 | - * @var \OC\Files\Storage\Storage $storage |
|
44 | - */ |
|
45 | - protected $storage; |
|
46 | - |
|
47 | - public $cache; |
|
48 | - public $scanner; |
|
49 | - public $watcher; |
|
50 | - public $propagator; |
|
51 | - public $updater; |
|
52 | - |
|
53 | - /** |
|
54 | - * @param array $parameters |
|
55 | - */ |
|
56 | - public function __construct($parameters) { |
|
57 | - $this->storage = $parameters['storage']; |
|
58 | - } |
|
59 | - |
|
60 | - /** |
|
61 | - * @return \OC\Files\Storage\Storage |
|
62 | - */ |
|
63 | - public function getWrapperStorage() { |
|
64 | - return $this->storage; |
|
65 | - } |
|
66 | - |
|
67 | - /** |
|
68 | - * Get the identifier for the storage, |
|
69 | - * the returned id should be the same for every storage object that is created with the same parameters |
|
70 | - * and two storage objects with the same id should refer to two storages that display the same files. |
|
71 | - * |
|
72 | - * @return string |
|
73 | - */ |
|
74 | - public function getId() { |
|
75 | - return $this->getWrapperStorage()->getId(); |
|
76 | - } |
|
77 | - |
|
78 | - /** |
|
79 | - * see https://www.php.net/manual/en/function.mkdir.php |
|
80 | - * |
|
81 | - * @param string $path |
|
82 | - * @return bool |
|
83 | - */ |
|
84 | - public function mkdir($path) { |
|
85 | - return $this->getWrapperStorage()->mkdir($path); |
|
86 | - } |
|
87 | - |
|
88 | - /** |
|
89 | - * see https://www.php.net/manual/en/function.rmdir.php |
|
90 | - * |
|
91 | - * @param string $path |
|
92 | - * @return bool |
|
93 | - */ |
|
94 | - public function rmdir($path) { |
|
95 | - return $this->getWrapperStorage()->rmdir($path); |
|
96 | - } |
|
97 | - |
|
98 | - /** |
|
99 | - * see https://www.php.net/manual/en/function.opendir.php |
|
100 | - * |
|
101 | - * @param string $path |
|
102 | - * @return resource|bool |
|
103 | - */ |
|
104 | - public function opendir($path) { |
|
105 | - return $this->getWrapperStorage()->opendir($path); |
|
106 | - } |
|
107 | - |
|
108 | - /** |
|
109 | - * see https://www.php.net/manual/en/function.is_dir.php |
|
110 | - * |
|
111 | - * @param string $path |
|
112 | - * @return bool |
|
113 | - */ |
|
114 | - public function is_dir($path) { |
|
115 | - return $this->getWrapperStorage()->is_dir($path); |
|
116 | - } |
|
117 | - |
|
118 | - /** |
|
119 | - * see https://www.php.net/manual/en/function.is_file.php |
|
120 | - * |
|
121 | - * @param string $path |
|
122 | - * @return bool |
|
123 | - */ |
|
124 | - public function is_file($path) { |
|
125 | - return $this->getWrapperStorage()->is_file($path); |
|
126 | - } |
|
127 | - |
|
128 | - /** |
|
129 | - * see https://www.php.net/manual/en/function.stat.php |
|
130 | - * only the following keys are required in the result: size and mtime |
|
131 | - * |
|
132 | - * @param string $path |
|
133 | - * @return array|bool |
|
134 | - */ |
|
135 | - public function stat($path) { |
|
136 | - return $this->getWrapperStorage()->stat($path); |
|
137 | - } |
|
138 | - |
|
139 | - /** |
|
140 | - * see https://www.php.net/manual/en/function.filetype.php |
|
141 | - * |
|
142 | - * @param string $path |
|
143 | - * @return string|bool |
|
144 | - */ |
|
145 | - public function filetype($path) { |
|
146 | - return $this->getWrapperStorage()->filetype($path); |
|
147 | - } |
|
148 | - |
|
149 | - /** |
|
150 | - * see https://www.php.net/manual/en/function.filesize.php |
|
151 | - * The result for filesize when called on a folder is required to be 0 |
|
152 | - * |
|
153 | - * @param string $path |
|
154 | - * @return int|bool |
|
155 | - */ |
|
156 | - public function filesize($path) { |
|
157 | - return $this->getWrapperStorage()->filesize($path); |
|
158 | - } |
|
159 | - |
|
160 | - /** |
|
161 | - * check if a file can be created in $path |
|
162 | - * |
|
163 | - * @param string $path |
|
164 | - * @return bool |
|
165 | - */ |
|
166 | - public function isCreatable($path) { |
|
167 | - return $this->getWrapperStorage()->isCreatable($path); |
|
168 | - } |
|
169 | - |
|
170 | - /** |
|
171 | - * check if a file can be read |
|
172 | - * |
|
173 | - * @param string $path |
|
174 | - * @return bool |
|
175 | - */ |
|
176 | - public function isReadable($path) { |
|
177 | - return $this->getWrapperStorage()->isReadable($path); |
|
178 | - } |
|
179 | - |
|
180 | - /** |
|
181 | - * check if a file can be written to |
|
182 | - * |
|
183 | - * @param string $path |
|
184 | - * @return bool |
|
185 | - */ |
|
186 | - public function isUpdatable($path) { |
|
187 | - return $this->getWrapperStorage()->isUpdatable($path); |
|
188 | - } |
|
189 | - |
|
190 | - /** |
|
191 | - * check if a file can be deleted |
|
192 | - * |
|
193 | - * @param string $path |
|
194 | - * @return bool |
|
195 | - */ |
|
196 | - public function isDeletable($path) { |
|
197 | - return $this->getWrapperStorage()->isDeletable($path); |
|
198 | - } |
|
199 | - |
|
200 | - /** |
|
201 | - * check if a file can be shared |
|
202 | - * |
|
203 | - * @param string $path |
|
204 | - * @return bool |
|
205 | - */ |
|
206 | - public function isSharable($path) { |
|
207 | - return $this->getWrapperStorage()->isSharable($path); |
|
208 | - } |
|
209 | - |
|
210 | - /** |
|
211 | - * get the full permissions of a path. |
|
212 | - * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php |
|
213 | - * |
|
214 | - * @param string $path |
|
215 | - * @return int |
|
216 | - */ |
|
217 | - public function getPermissions($path) { |
|
218 | - return $this->getWrapperStorage()->getPermissions($path); |
|
219 | - } |
|
220 | - |
|
221 | - /** |
|
222 | - * see https://www.php.net/manual/en/function.file_exists.php |
|
223 | - * |
|
224 | - * @param string $path |
|
225 | - * @return bool |
|
226 | - */ |
|
227 | - public function file_exists($path) { |
|
228 | - return $this->getWrapperStorage()->file_exists($path); |
|
229 | - } |
|
230 | - |
|
231 | - /** |
|
232 | - * see https://www.php.net/manual/en/function.filemtime.php |
|
233 | - * |
|
234 | - * @param string $path |
|
235 | - * @return int|bool |
|
236 | - */ |
|
237 | - public function filemtime($path) { |
|
238 | - return $this->getWrapperStorage()->filemtime($path); |
|
239 | - } |
|
240 | - |
|
241 | - /** |
|
242 | - * see https://www.php.net/manual/en/function.file_get_contents.php |
|
243 | - * |
|
244 | - * @param string $path |
|
245 | - * @return string|bool |
|
246 | - */ |
|
247 | - public function file_get_contents($path) { |
|
248 | - return $this->getWrapperStorage()->file_get_contents($path); |
|
249 | - } |
|
250 | - |
|
251 | - /** |
|
252 | - * see https://www.php.net/manual/en/function.file_put_contents.php |
|
253 | - * |
|
254 | - * @param string $path |
|
255 | - * @param mixed $data |
|
256 | - * @return int|false |
|
257 | - */ |
|
258 | - public function file_put_contents($path, $data) { |
|
259 | - return $this->getWrapperStorage()->file_put_contents($path, $data); |
|
260 | - } |
|
261 | - |
|
262 | - /** |
|
263 | - * see https://www.php.net/manual/en/function.unlink.php |
|
264 | - * |
|
265 | - * @param string $path |
|
266 | - * @return bool |
|
267 | - */ |
|
268 | - public function unlink($path) { |
|
269 | - return $this->getWrapperStorage()->unlink($path); |
|
270 | - } |
|
271 | - |
|
272 | - /** |
|
273 | - * see https://www.php.net/manual/en/function.rename.php |
|
274 | - * |
|
275 | - * @param string $path1 |
|
276 | - * @param string $path2 |
|
277 | - * @return bool |
|
278 | - */ |
|
279 | - public function rename($path1, $path2) { |
|
280 | - return $this->getWrapperStorage()->rename($path1, $path2); |
|
281 | - } |
|
282 | - |
|
283 | - /** |
|
284 | - * see https://www.php.net/manual/en/function.copy.php |
|
285 | - * |
|
286 | - * @param string $path1 |
|
287 | - * @param string $path2 |
|
288 | - * @return bool |
|
289 | - */ |
|
290 | - public function copy($path1, $path2) { |
|
291 | - return $this->getWrapperStorage()->copy($path1, $path2); |
|
292 | - } |
|
293 | - |
|
294 | - /** |
|
295 | - * see https://www.php.net/manual/en/function.fopen.php |
|
296 | - * |
|
297 | - * @param string $path |
|
298 | - * @param string $mode |
|
299 | - * @return resource|bool |
|
300 | - */ |
|
301 | - public function fopen($path, $mode) { |
|
302 | - return $this->getWrapperStorage()->fopen($path, $mode); |
|
303 | - } |
|
304 | - |
|
305 | - /** |
|
306 | - * get the mimetype for a file or folder |
|
307 | - * The mimetype for a folder is required to be "httpd/unix-directory" |
|
308 | - * |
|
309 | - * @param string $path |
|
310 | - * @return string|bool |
|
311 | - */ |
|
312 | - public function getMimeType($path) { |
|
313 | - return $this->getWrapperStorage()->getMimeType($path); |
|
314 | - } |
|
315 | - |
|
316 | - /** |
|
317 | - * see https://www.php.net/manual/en/function.hash.php |
|
318 | - * |
|
319 | - * @param string $type |
|
320 | - * @param string $path |
|
321 | - * @param bool $raw |
|
322 | - * @return string|bool |
|
323 | - */ |
|
324 | - public function hash($type, $path, $raw = false) { |
|
325 | - return $this->getWrapperStorage()->hash($type, $path, $raw); |
|
326 | - } |
|
327 | - |
|
328 | - /** |
|
329 | - * see https://www.php.net/manual/en/function.free_space.php |
|
330 | - * |
|
331 | - * @param string $path |
|
332 | - * @return int|bool |
|
333 | - */ |
|
334 | - public function free_space($path) { |
|
335 | - return $this->getWrapperStorage()->free_space($path); |
|
336 | - } |
|
337 | - |
|
338 | - /** |
|
339 | - * search for occurrences of $query in file names |
|
340 | - * |
|
341 | - * @param string $query |
|
342 | - * @return array|bool |
|
343 | - */ |
|
344 | - public function search($query) { |
|
345 | - return $this->getWrapperStorage()->search($query); |
|
346 | - } |
|
347 | - |
|
348 | - /** |
|
349 | - * see https://www.php.net/manual/en/function.touch.php |
|
350 | - * If the backend does not support the operation, false should be returned |
|
351 | - * |
|
352 | - * @param string $path |
|
353 | - * @param int $mtime |
|
354 | - * @return bool |
|
355 | - */ |
|
356 | - public function touch($path, $mtime = null) { |
|
357 | - return $this->getWrapperStorage()->touch($path, $mtime); |
|
358 | - } |
|
359 | - |
|
360 | - /** |
|
361 | - * get the path to a local version of the file. |
|
362 | - * The local version of the file can be temporary and doesn't have to be persistent across requests |
|
363 | - * |
|
364 | - * @param string $path |
|
365 | - * @return string|bool |
|
366 | - */ |
|
367 | - public function getLocalFile($path) { |
|
368 | - return $this->getWrapperStorage()->getLocalFile($path); |
|
369 | - } |
|
370 | - |
|
371 | - /** |
|
372 | - * check if a file or folder has been updated since $time |
|
373 | - * |
|
374 | - * @param string $path |
|
375 | - * @param int $time |
|
376 | - * @return bool |
|
377 | - * |
|
378 | - * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed. |
|
379 | - * returning true for other changes in the folder is optional |
|
380 | - */ |
|
381 | - public function hasUpdated($path, $time) { |
|
382 | - return $this->getWrapperStorage()->hasUpdated($path, $time); |
|
383 | - } |
|
384 | - |
|
385 | - /** |
|
386 | - * get a cache instance for the storage |
|
387 | - * |
|
388 | - * @param string $path |
|
389 | - * @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache |
|
390 | - * @return \OC\Files\Cache\Cache |
|
391 | - */ |
|
392 | - public function getCache($path = '', $storage = null) { |
|
393 | - if (!$storage) { |
|
394 | - $storage = $this; |
|
395 | - } |
|
396 | - return $this->getWrapperStorage()->getCache($path, $storage); |
|
397 | - } |
|
398 | - |
|
399 | - /** |
|
400 | - * get a scanner instance for the storage |
|
401 | - * |
|
402 | - * @param string $path |
|
403 | - * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner |
|
404 | - * @return \OC\Files\Cache\Scanner |
|
405 | - */ |
|
406 | - public function getScanner($path = '', $storage = null) { |
|
407 | - if (!$storage) { |
|
408 | - $storage = $this; |
|
409 | - } |
|
410 | - return $this->getWrapperStorage()->getScanner($path, $storage); |
|
411 | - } |
|
412 | - |
|
413 | - |
|
414 | - /** |
|
415 | - * get the user id of the owner of a file or folder |
|
416 | - * |
|
417 | - * @param string $path |
|
418 | - * @return string |
|
419 | - */ |
|
420 | - public function getOwner($path) { |
|
421 | - return $this->getWrapperStorage()->getOwner($path); |
|
422 | - } |
|
423 | - |
|
424 | - /** |
|
425 | - * get a watcher instance for the cache |
|
426 | - * |
|
427 | - * @param string $path |
|
428 | - * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher |
|
429 | - * @return \OC\Files\Cache\Watcher |
|
430 | - */ |
|
431 | - public function getWatcher($path = '', $storage = null) { |
|
432 | - if (!$storage) { |
|
433 | - $storage = $this; |
|
434 | - } |
|
435 | - return $this->getWrapperStorage()->getWatcher($path, $storage); |
|
436 | - } |
|
437 | - |
|
438 | - public function getPropagator($storage = null) { |
|
439 | - if (!$storage) { |
|
440 | - $storage = $this; |
|
441 | - } |
|
442 | - return $this->getWrapperStorage()->getPropagator($storage); |
|
443 | - } |
|
444 | - |
|
445 | - public function getUpdater($storage = null) { |
|
446 | - if (!$storage) { |
|
447 | - $storage = $this; |
|
448 | - } |
|
449 | - return $this->getWrapperStorage()->getUpdater($storage); |
|
450 | - } |
|
451 | - |
|
452 | - /** |
|
453 | - * @return \OC\Files\Cache\Storage |
|
454 | - */ |
|
455 | - public function getStorageCache() { |
|
456 | - return $this->getWrapperStorage()->getStorageCache(); |
|
457 | - } |
|
458 | - |
|
459 | - /** |
|
460 | - * get the ETag for a file or folder |
|
461 | - * |
|
462 | - * @param string $path |
|
463 | - * @return string|bool |
|
464 | - */ |
|
465 | - public function getETag($path) { |
|
466 | - return $this->getWrapperStorage()->getETag($path); |
|
467 | - } |
|
468 | - |
|
469 | - /** |
|
470 | - * Returns true |
|
471 | - * |
|
472 | - * @return true |
|
473 | - */ |
|
474 | - public function test() { |
|
475 | - return $this->getWrapperStorage()->test(); |
|
476 | - } |
|
477 | - |
|
478 | - /** |
|
479 | - * Returns the wrapped storage's value for isLocal() |
|
480 | - * |
|
481 | - * @return bool wrapped storage's isLocal() value |
|
482 | - */ |
|
483 | - public function isLocal() { |
|
484 | - return $this->getWrapperStorage()->isLocal(); |
|
485 | - } |
|
486 | - |
|
487 | - /** |
|
488 | - * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class |
|
489 | - * |
|
490 | - * @param string $class |
|
491 | - * @return bool |
|
492 | - */ |
|
493 | - public function instanceOfStorage($class) { |
|
494 | - if (ltrim($class, '\\') === 'OC\Files\Storage\Shared') { |
|
495 | - // FIXME Temporary fix to keep existing checks working |
|
496 | - $class = '\OCA\Files_Sharing\SharedStorage'; |
|
497 | - } |
|
498 | - return is_a($this, $class) or $this->getWrapperStorage()->instanceOfStorage($class); |
|
499 | - } |
|
500 | - |
|
501 | - /** |
|
502 | - * Pass any methods custom to specific storage implementations to the wrapped storage |
|
503 | - * |
|
504 | - * @param string $method |
|
505 | - * @param array $args |
|
506 | - * @return mixed |
|
507 | - */ |
|
508 | - public function __call($method, $args) { |
|
509 | - return call_user_func_array([$this->getWrapperStorage(), $method], $args); |
|
510 | - } |
|
511 | - |
|
512 | - /** |
|
513 | - * A custom storage implementation can return an url for direct download of a give file. |
|
514 | - * |
|
515 | - * For now the returned array can hold the parameter url - in future more attributes might follow. |
|
516 | - * |
|
517 | - * @param string $path |
|
518 | - * @return array|bool |
|
519 | - */ |
|
520 | - public function getDirectDownload($path) { |
|
521 | - return $this->getWrapperStorage()->getDirectDownload($path); |
|
522 | - } |
|
523 | - |
|
524 | - /** |
|
525 | - * Get availability of the storage |
|
526 | - * |
|
527 | - * @return array [ available, last_checked ] |
|
528 | - */ |
|
529 | - public function getAvailability() { |
|
530 | - return $this->getWrapperStorage()->getAvailability(); |
|
531 | - } |
|
532 | - |
|
533 | - /** |
|
534 | - * Set availability of the storage |
|
535 | - * |
|
536 | - * @param bool $isAvailable |
|
537 | - */ |
|
538 | - public function setAvailability($isAvailable) { |
|
539 | - $this->getWrapperStorage()->setAvailability($isAvailable); |
|
540 | - } |
|
541 | - |
|
542 | - /** |
|
543 | - * @param string $path the path of the target folder |
|
544 | - * @param string $fileName the name of the file itself |
|
545 | - * @return void |
|
546 | - * @throws InvalidPathException |
|
547 | - */ |
|
548 | - public function verifyPath($path, $fileName) { |
|
549 | - $this->getWrapperStorage()->verifyPath($path, $fileName); |
|
550 | - } |
|
551 | - |
|
552 | - /** |
|
553 | - * @param IStorage $sourceStorage |
|
554 | - * @param string $sourceInternalPath |
|
555 | - * @param string $targetInternalPath |
|
556 | - * @return bool |
|
557 | - */ |
|
558 | - public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { |
|
559 | - if ($sourceStorage === $this) { |
|
560 | - return $this->copy($sourceInternalPath, $targetInternalPath); |
|
561 | - } |
|
562 | - |
|
563 | - return $this->getWrapperStorage()->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); |
|
564 | - } |
|
565 | - |
|
566 | - /** |
|
567 | - * @param IStorage $sourceStorage |
|
568 | - * @param string $sourceInternalPath |
|
569 | - * @param string $targetInternalPath |
|
570 | - * @return bool |
|
571 | - */ |
|
572 | - public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { |
|
573 | - if ($sourceStorage === $this) { |
|
574 | - return $this->rename($sourceInternalPath, $targetInternalPath); |
|
575 | - } |
|
576 | - |
|
577 | - return $this->getWrapperStorage()->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); |
|
578 | - } |
|
579 | - |
|
580 | - /** |
|
581 | - * @param string $path |
|
582 | - * @return array |
|
583 | - */ |
|
584 | - public function getMetaData($path) { |
|
585 | - return $this->getWrapperStorage()->getMetaData($path); |
|
586 | - } |
|
587 | - |
|
588 | - /** |
|
589 | - * @param string $path |
|
590 | - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
|
591 | - * @param \OCP\Lock\ILockingProvider $provider |
|
592 | - * @throws \OCP\Lock\LockedException |
|
593 | - */ |
|
594 | - public function acquireLock($path, $type, ILockingProvider $provider) { |
|
595 | - if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { |
|
596 | - $this->getWrapperStorage()->acquireLock($path, $type, $provider); |
|
597 | - } |
|
598 | - } |
|
599 | - |
|
600 | - /** |
|
601 | - * @param string $path |
|
602 | - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
|
603 | - * @param \OCP\Lock\ILockingProvider $provider |
|
604 | - */ |
|
605 | - public function releaseLock($path, $type, ILockingProvider $provider) { |
|
606 | - if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { |
|
607 | - $this->getWrapperStorage()->releaseLock($path, $type, $provider); |
|
608 | - } |
|
609 | - } |
|
610 | - |
|
611 | - /** |
|
612 | - * @param string $path |
|
613 | - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
|
614 | - * @param \OCP\Lock\ILockingProvider $provider |
|
615 | - */ |
|
616 | - public function changeLock($path, $type, ILockingProvider $provider) { |
|
617 | - if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { |
|
618 | - $this->getWrapperStorage()->changeLock($path, $type, $provider); |
|
619 | - } |
|
620 | - } |
|
621 | - |
|
622 | - /** |
|
623 | - * @return bool |
|
624 | - */ |
|
625 | - public function needsPartFile() { |
|
626 | - return $this->getWrapperStorage()->needsPartFile(); |
|
627 | - } |
|
628 | - |
|
629 | - public function writeStream(string $path, $stream, int $size = null): int { |
|
630 | - $storage = $this->getWrapperStorage(); |
|
631 | - if ($storage->instanceOfStorage(IWriteStreamStorage::class)) { |
|
632 | - /** @var IWriteStreamStorage $storage */ |
|
633 | - return $storage->writeStream($path, $stream, $size); |
|
634 | - } else { |
|
635 | - $target = $this->fopen($path, 'w'); |
|
636 | - [$count, $result] = \OC_Helper::streamCopy($stream, $target); |
|
637 | - fclose($stream); |
|
638 | - fclose($target); |
|
639 | - return $count; |
|
640 | - } |
|
641 | - } |
|
642 | - |
|
643 | - public function getDirectoryContent($directory): \Traversable { |
|
644 | - return $this->getWrapperStorage()->getDirectoryContent($directory); |
|
645 | - } |
|
42 | + /** |
|
43 | + * @var \OC\Files\Storage\Storage $storage |
|
44 | + */ |
|
45 | + protected $storage; |
|
46 | + |
|
47 | + public $cache; |
|
48 | + public $scanner; |
|
49 | + public $watcher; |
|
50 | + public $propagator; |
|
51 | + public $updater; |
|
52 | + |
|
53 | + /** |
|
54 | + * @param array $parameters |
|
55 | + */ |
|
56 | + public function __construct($parameters) { |
|
57 | + $this->storage = $parameters['storage']; |
|
58 | + } |
|
59 | + |
|
60 | + /** |
|
61 | + * @return \OC\Files\Storage\Storage |
|
62 | + */ |
|
63 | + public function getWrapperStorage() { |
|
64 | + return $this->storage; |
|
65 | + } |
|
66 | + |
|
67 | + /** |
|
68 | + * Get the identifier for the storage, |
|
69 | + * the returned id should be the same for every storage object that is created with the same parameters |
|
70 | + * and two storage objects with the same id should refer to two storages that display the same files. |
|
71 | + * |
|
72 | + * @return string |
|
73 | + */ |
|
74 | + public function getId() { |
|
75 | + return $this->getWrapperStorage()->getId(); |
|
76 | + } |
|
77 | + |
|
78 | + /** |
|
79 | + * see https://www.php.net/manual/en/function.mkdir.php |
|
80 | + * |
|
81 | + * @param string $path |
|
82 | + * @return bool |
|
83 | + */ |
|
84 | + public function mkdir($path) { |
|
85 | + return $this->getWrapperStorage()->mkdir($path); |
|
86 | + } |
|
87 | + |
|
88 | + /** |
|
89 | + * see https://www.php.net/manual/en/function.rmdir.php |
|
90 | + * |
|
91 | + * @param string $path |
|
92 | + * @return bool |
|
93 | + */ |
|
94 | + public function rmdir($path) { |
|
95 | + return $this->getWrapperStorage()->rmdir($path); |
|
96 | + } |
|
97 | + |
|
98 | + /** |
|
99 | + * see https://www.php.net/manual/en/function.opendir.php |
|
100 | + * |
|
101 | + * @param string $path |
|
102 | + * @return resource|bool |
|
103 | + */ |
|
104 | + public function opendir($path) { |
|
105 | + return $this->getWrapperStorage()->opendir($path); |
|
106 | + } |
|
107 | + |
|
108 | + /** |
|
109 | + * see https://www.php.net/manual/en/function.is_dir.php |
|
110 | + * |
|
111 | + * @param string $path |
|
112 | + * @return bool |
|
113 | + */ |
|
114 | + public function is_dir($path) { |
|
115 | + return $this->getWrapperStorage()->is_dir($path); |
|
116 | + } |
|
117 | + |
|
118 | + /** |
|
119 | + * see https://www.php.net/manual/en/function.is_file.php |
|
120 | + * |
|
121 | + * @param string $path |
|
122 | + * @return bool |
|
123 | + */ |
|
124 | + public function is_file($path) { |
|
125 | + return $this->getWrapperStorage()->is_file($path); |
|
126 | + } |
|
127 | + |
|
128 | + /** |
|
129 | + * see https://www.php.net/manual/en/function.stat.php |
|
130 | + * only the following keys are required in the result: size and mtime |
|
131 | + * |
|
132 | + * @param string $path |
|
133 | + * @return array|bool |
|
134 | + */ |
|
135 | + public function stat($path) { |
|
136 | + return $this->getWrapperStorage()->stat($path); |
|
137 | + } |
|
138 | + |
|
139 | + /** |
|
140 | + * see https://www.php.net/manual/en/function.filetype.php |
|
141 | + * |
|
142 | + * @param string $path |
|
143 | + * @return string|bool |
|
144 | + */ |
|
145 | + public function filetype($path) { |
|
146 | + return $this->getWrapperStorage()->filetype($path); |
|
147 | + } |
|
148 | + |
|
149 | + /** |
|
150 | + * see https://www.php.net/manual/en/function.filesize.php |
|
151 | + * The result for filesize when called on a folder is required to be 0 |
|
152 | + * |
|
153 | + * @param string $path |
|
154 | + * @return int|bool |
|
155 | + */ |
|
156 | + public function filesize($path) { |
|
157 | + return $this->getWrapperStorage()->filesize($path); |
|
158 | + } |
|
159 | + |
|
160 | + /** |
|
161 | + * check if a file can be created in $path |
|
162 | + * |
|
163 | + * @param string $path |
|
164 | + * @return bool |
|
165 | + */ |
|
166 | + public function isCreatable($path) { |
|
167 | + return $this->getWrapperStorage()->isCreatable($path); |
|
168 | + } |
|
169 | + |
|
170 | + /** |
|
171 | + * check if a file can be read |
|
172 | + * |
|
173 | + * @param string $path |
|
174 | + * @return bool |
|
175 | + */ |
|
176 | + public function isReadable($path) { |
|
177 | + return $this->getWrapperStorage()->isReadable($path); |
|
178 | + } |
|
179 | + |
|
180 | + /** |
|
181 | + * check if a file can be written to |
|
182 | + * |
|
183 | + * @param string $path |
|
184 | + * @return bool |
|
185 | + */ |
|
186 | + public function isUpdatable($path) { |
|
187 | + return $this->getWrapperStorage()->isUpdatable($path); |
|
188 | + } |
|
189 | + |
|
190 | + /** |
|
191 | + * check if a file can be deleted |
|
192 | + * |
|
193 | + * @param string $path |
|
194 | + * @return bool |
|
195 | + */ |
|
196 | + public function isDeletable($path) { |
|
197 | + return $this->getWrapperStorage()->isDeletable($path); |
|
198 | + } |
|
199 | + |
|
200 | + /** |
|
201 | + * check if a file can be shared |
|
202 | + * |
|
203 | + * @param string $path |
|
204 | + * @return bool |
|
205 | + */ |
|
206 | + public function isSharable($path) { |
|
207 | + return $this->getWrapperStorage()->isSharable($path); |
|
208 | + } |
|
209 | + |
|
210 | + /** |
|
211 | + * get the full permissions of a path. |
|
212 | + * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php |
|
213 | + * |
|
214 | + * @param string $path |
|
215 | + * @return int |
|
216 | + */ |
|
217 | + public function getPermissions($path) { |
|
218 | + return $this->getWrapperStorage()->getPermissions($path); |
|
219 | + } |
|
220 | + |
|
221 | + /** |
|
222 | + * see https://www.php.net/manual/en/function.file_exists.php |
|
223 | + * |
|
224 | + * @param string $path |
|
225 | + * @return bool |
|
226 | + */ |
|
227 | + public function file_exists($path) { |
|
228 | + return $this->getWrapperStorage()->file_exists($path); |
|
229 | + } |
|
230 | + |
|
231 | + /** |
|
232 | + * see https://www.php.net/manual/en/function.filemtime.php |
|
233 | + * |
|
234 | + * @param string $path |
|
235 | + * @return int|bool |
|
236 | + */ |
|
237 | + public function filemtime($path) { |
|
238 | + return $this->getWrapperStorage()->filemtime($path); |
|
239 | + } |
|
240 | + |
|
241 | + /** |
|
242 | + * see https://www.php.net/manual/en/function.file_get_contents.php |
|
243 | + * |
|
244 | + * @param string $path |
|
245 | + * @return string|bool |
|
246 | + */ |
|
247 | + public function file_get_contents($path) { |
|
248 | + return $this->getWrapperStorage()->file_get_contents($path); |
|
249 | + } |
|
250 | + |
|
251 | + /** |
|
252 | + * see https://www.php.net/manual/en/function.file_put_contents.php |
|
253 | + * |
|
254 | + * @param string $path |
|
255 | + * @param mixed $data |
|
256 | + * @return int|false |
|
257 | + */ |
|
258 | + public function file_put_contents($path, $data) { |
|
259 | + return $this->getWrapperStorage()->file_put_contents($path, $data); |
|
260 | + } |
|
261 | + |
|
262 | + /** |
|
263 | + * see https://www.php.net/manual/en/function.unlink.php |
|
264 | + * |
|
265 | + * @param string $path |
|
266 | + * @return bool |
|
267 | + */ |
|
268 | + public function unlink($path) { |
|
269 | + return $this->getWrapperStorage()->unlink($path); |
|
270 | + } |
|
271 | + |
|
272 | + /** |
|
273 | + * see https://www.php.net/manual/en/function.rename.php |
|
274 | + * |
|
275 | + * @param string $path1 |
|
276 | + * @param string $path2 |
|
277 | + * @return bool |
|
278 | + */ |
|
279 | + public function rename($path1, $path2) { |
|
280 | + return $this->getWrapperStorage()->rename($path1, $path2); |
|
281 | + } |
|
282 | + |
|
283 | + /** |
|
284 | + * see https://www.php.net/manual/en/function.copy.php |
|
285 | + * |
|
286 | + * @param string $path1 |
|
287 | + * @param string $path2 |
|
288 | + * @return bool |
|
289 | + */ |
|
290 | + public function copy($path1, $path2) { |
|
291 | + return $this->getWrapperStorage()->copy($path1, $path2); |
|
292 | + } |
|
293 | + |
|
294 | + /** |
|
295 | + * see https://www.php.net/manual/en/function.fopen.php |
|
296 | + * |
|
297 | + * @param string $path |
|
298 | + * @param string $mode |
|
299 | + * @return resource|bool |
|
300 | + */ |
|
301 | + public function fopen($path, $mode) { |
|
302 | + return $this->getWrapperStorage()->fopen($path, $mode); |
|
303 | + } |
|
304 | + |
|
305 | + /** |
|
306 | + * get the mimetype for a file or folder |
|
307 | + * The mimetype for a folder is required to be "httpd/unix-directory" |
|
308 | + * |
|
309 | + * @param string $path |
|
310 | + * @return string|bool |
|
311 | + */ |
|
312 | + public function getMimeType($path) { |
|
313 | + return $this->getWrapperStorage()->getMimeType($path); |
|
314 | + } |
|
315 | + |
|
316 | + /** |
|
317 | + * see https://www.php.net/manual/en/function.hash.php |
|
318 | + * |
|
319 | + * @param string $type |
|
320 | + * @param string $path |
|
321 | + * @param bool $raw |
|
322 | + * @return string|bool |
|
323 | + */ |
|
324 | + public function hash($type, $path, $raw = false) { |
|
325 | + return $this->getWrapperStorage()->hash($type, $path, $raw); |
|
326 | + } |
|
327 | + |
|
328 | + /** |
|
329 | + * see https://www.php.net/manual/en/function.free_space.php |
|
330 | + * |
|
331 | + * @param string $path |
|
332 | + * @return int|bool |
|
333 | + */ |
|
334 | + public function free_space($path) { |
|
335 | + return $this->getWrapperStorage()->free_space($path); |
|
336 | + } |
|
337 | + |
|
338 | + /** |
|
339 | + * search for occurrences of $query in file names |
|
340 | + * |
|
341 | + * @param string $query |
|
342 | + * @return array|bool |
|
343 | + */ |
|
344 | + public function search($query) { |
|
345 | + return $this->getWrapperStorage()->search($query); |
|
346 | + } |
|
347 | + |
|
348 | + /** |
|
349 | + * see https://www.php.net/manual/en/function.touch.php |
|
350 | + * If the backend does not support the operation, false should be returned |
|
351 | + * |
|
352 | + * @param string $path |
|
353 | + * @param int $mtime |
|
354 | + * @return bool |
|
355 | + */ |
|
356 | + public function touch($path, $mtime = null) { |
|
357 | + return $this->getWrapperStorage()->touch($path, $mtime); |
|
358 | + } |
|
359 | + |
|
360 | + /** |
|
361 | + * get the path to a local version of the file. |
|
362 | + * The local version of the file can be temporary and doesn't have to be persistent across requests |
|
363 | + * |
|
364 | + * @param string $path |
|
365 | + * @return string|bool |
|
366 | + */ |
|
367 | + public function getLocalFile($path) { |
|
368 | + return $this->getWrapperStorage()->getLocalFile($path); |
|
369 | + } |
|
370 | + |
|
371 | + /** |
|
372 | + * check if a file or folder has been updated since $time |
|
373 | + * |
|
374 | + * @param string $path |
|
375 | + * @param int $time |
|
376 | + * @return bool |
|
377 | + * |
|
378 | + * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed. |
|
379 | + * returning true for other changes in the folder is optional |
|
380 | + */ |
|
381 | + public function hasUpdated($path, $time) { |
|
382 | + return $this->getWrapperStorage()->hasUpdated($path, $time); |
|
383 | + } |
|
384 | + |
|
385 | + /** |
|
386 | + * get a cache instance for the storage |
|
387 | + * |
|
388 | + * @param string $path |
|
389 | + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the cache |
|
390 | + * @return \OC\Files\Cache\Cache |
|
391 | + */ |
|
392 | + public function getCache($path = '', $storage = null) { |
|
393 | + if (!$storage) { |
|
394 | + $storage = $this; |
|
395 | + } |
|
396 | + return $this->getWrapperStorage()->getCache($path, $storage); |
|
397 | + } |
|
398 | + |
|
399 | + /** |
|
400 | + * get a scanner instance for the storage |
|
401 | + * |
|
402 | + * @param string $path |
|
403 | + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner |
|
404 | + * @return \OC\Files\Cache\Scanner |
|
405 | + */ |
|
406 | + public function getScanner($path = '', $storage = null) { |
|
407 | + if (!$storage) { |
|
408 | + $storage = $this; |
|
409 | + } |
|
410 | + return $this->getWrapperStorage()->getScanner($path, $storage); |
|
411 | + } |
|
412 | + |
|
413 | + |
|
414 | + /** |
|
415 | + * get the user id of the owner of a file or folder |
|
416 | + * |
|
417 | + * @param string $path |
|
418 | + * @return string |
|
419 | + */ |
|
420 | + public function getOwner($path) { |
|
421 | + return $this->getWrapperStorage()->getOwner($path); |
|
422 | + } |
|
423 | + |
|
424 | + /** |
|
425 | + * get a watcher instance for the cache |
|
426 | + * |
|
427 | + * @param string $path |
|
428 | + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher |
|
429 | + * @return \OC\Files\Cache\Watcher |
|
430 | + */ |
|
431 | + public function getWatcher($path = '', $storage = null) { |
|
432 | + if (!$storage) { |
|
433 | + $storage = $this; |
|
434 | + } |
|
435 | + return $this->getWrapperStorage()->getWatcher($path, $storage); |
|
436 | + } |
|
437 | + |
|
438 | + public function getPropagator($storage = null) { |
|
439 | + if (!$storage) { |
|
440 | + $storage = $this; |
|
441 | + } |
|
442 | + return $this->getWrapperStorage()->getPropagator($storage); |
|
443 | + } |
|
444 | + |
|
445 | + public function getUpdater($storage = null) { |
|
446 | + if (!$storage) { |
|
447 | + $storage = $this; |
|
448 | + } |
|
449 | + return $this->getWrapperStorage()->getUpdater($storage); |
|
450 | + } |
|
451 | + |
|
452 | + /** |
|
453 | + * @return \OC\Files\Cache\Storage |
|
454 | + */ |
|
455 | + public function getStorageCache() { |
|
456 | + return $this->getWrapperStorage()->getStorageCache(); |
|
457 | + } |
|
458 | + |
|
459 | + /** |
|
460 | + * get the ETag for a file or folder |
|
461 | + * |
|
462 | + * @param string $path |
|
463 | + * @return string|bool |
|
464 | + */ |
|
465 | + public function getETag($path) { |
|
466 | + return $this->getWrapperStorage()->getETag($path); |
|
467 | + } |
|
468 | + |
|
469 | + /** |
|
470 | + * Returns true |
|
471 | + * |
|
472 | + * @return true |
|
473 | + */ |
|
474 | + public function test() { |
|
475 | + return $this->getWrapperStorage()->test(); |
|
476 | + } |
|
477 | + |
|
478 | + /** |
|
479 | + * Returns the wrapped storage's value for isLocal() |
|
480 | + * |
|
481 | + * @return bool wrapped storage's isLocal() value |
|
482 | + */ |
|
483 | + public function isLocal() { |
|
484 | + return $this->getWrapperStorage()->isLocal(); |
|
485 | + } |
|
486 | + |
|
487 | + /** |
|
488 | + * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class |
|
489 | + * |
|
490 | + * @param string $class |
|
491 | + * @return bool |
|
492 | + */ |
|
493 | + public function instanceOfStorage($class) { |
|
494 | + if (ltrim($class, '\\') === 'OC\Files\Storage\Shared') { |
|
495 | + // FIXME Temporary fix to keep existing checks working |
|
496 | + $class = '\OCA\Files_Sharing\SharedStorage'; |
|
497 | + } |
|
498 | + return is_a($this, $class) or $this->getWrapperStorage()->instanceOfStorage($class); |
|
499 | + } |
|
500 | + |
|
501 | + /** |
|
502 | + * Pass any methods custom to specific storage implementations to the wrapped storage |
|
503 | + * |
|
504 | + * @param string $method |
|
505 | + * @param array $args |
|
506 | + * @return mixed |
|
507 | + */ |
|
508 | + public function __call($method, $args) { |
|
509 | + return call_user_func_array([$this->getWrapperStorage(), $method], $args); |
|
510 | + } |
|
511 | + |
|
512 | + /** |
|
513 | + * A custom storage implementation can return an url for direct download of a give file. |
|
514 | + * |
|
515 | + * For now the returned array can hold the parameter url - in future more attributes might follow. |
|
516 | + * |
|
517 | + * @param string $path |
|
518 | + * @return array|bool |
|
519 | + */ |
|
520 | + public function getDirectDownload($path) { |
|
521 | + return $this->getWrapperStorage()->getDirectDownload($path); |
|
522 | + } |
|
523 | + |
|
524 | + /** |
|
525 | + * Get availability of the storage |
|
526 | + * |
|
527 | + * @return array [ available, last_checked ] |
|
528 | + */ |
|
529 | + public function getAvailability() { |
|
530 | + return $this->getWrapperStorage()->getAvailability(); |
|
531 | + } |
|
532 | + |
|
533 | + /** |
|
534 | + * Set availability of the storage |
|
535 | + * |
|
536 | + * @param bool $isAvailable |
|
537 | + */ |
|
538 | + public function setAvailability($isAvailable) { |
|
539 | + $this->getWrapperStorage()->setAvailability($isAvailable); |
|
540 | + } |
|
541 | + |
|
542 | + /** |
|
543 | + * @param string $path the path of the target folder |
|
544 | + * @param string $fileName the name of the file itself |
|
545 | + * @return void |
|
546 | + * @throws InvalidPathException |
|
547 | + */ |
|
548 | + public function verifyPath($path, $fileName) { |
|
549 | + $this->getWrapperStorage()->verifyPath($path, $fileName); |
|
550 | + } |
|
551 | + |
|
552 | + /** |
|
553 | + * @param IStorage $sourceStorage |
|
554 | + * @param string $sourceInternalPath |
|
555 | + * @param string $targetInternalPath |
|
556 | + * @return bool |
|
557 | + */ |
|
558 | + public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { |
|
559 | + if ($sourceStorage === $this) { |
|
560 | + return $this->copy($sourceInternalPath, $targetInternalPath); |
|
561 | + } |
|
562 | + |
|
563 | + return $this->getWrapperStorage()->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); |
|
564 | + } |
|
565 | + |
|
566 | + /** |
|
567 | + * @param IStorage $sourceStorage |
|
568 | + * @param string $sourceInternalPath |
|
569 | + * @param string $targetInternalPath |
|
570 | + * @return bool |
|
571 | + */ |
|
572 | + public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { |
|
573 | + if ($sourceStorage === $this) { |
|
574 | + return $this->rename($sourceInternalPath, $targetInternalPath); |
|
575 | + } |
|
576 | + |
|
577 | + return $this->getWrapperStorage()->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); |
|
578 | + } |
|
579 | + |
|
580 | + /** |
|
581 | + * @param string $path |
|
582 | + * @return array |
|
583 | + */ |
|
584 | + public function getMetaData($path) { |
|
585 | + return $this->getWrapperStorage()->getMetaData($path); |
|
586 | + } |
|
587 | + |
|
588 | + /** |
|
589 | + * @param string $path |
|
590 | + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
|
591 | + * @param \OCP\Lock\ILockingProvider $provider |
|
592 | + * @throws \OCP\Lock\LockedException |
|
593 | + */ |
|
594 | + public function acquireLock($path, $type, ILockingProvider $provider) { |
|
595 | + if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { |
|
596 | + $this->getWrapperStorage()->acquireLock($path, $type, $provider); |
|
597 | + } |
|
598 | + } |
|
599 | + |
|
600 | + /** |
|
601 | + * @param string $path |
|
602 | + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
|
603 | + * @param \OCP\Lock\ILockingProvider $provider |
|
604 | + */ |
|
605 | + public function releaseLock($path, $type, ILockingProvider $provider) { |
|
606 | + if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { |
|
607 | + $this->getWrapperStorage()->releaseLock($path, $type, $provider); |
|
608 | + } |
|
609 | + } |
|
610 | + |
|
611 | + /** |
|
612 | + * @param string $path |
|
613 | + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE |
|
614 | + * @param \OCP\Lock\ILockingProvider $provider |
|
615 | + */ |
|
616 | + public function changeLock($path, $type, ILockingProvider $provider) { |
|
617 | + if ($this->getWrapperStorage()->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { |
|
618 | + $this->getWrapperStorage()->changeLock($path, $type, $provider); |
|
619 | + } |
|
620 | + } |
|
621 | + |
|
622 | + /** |
|
623 | + * @return bool |
|
624 | + */ |
|
625 | + public function needsPartFile() { |
|
626 | + return $this->getWrapperStorage()->needsPartFile(); |
|
627 | + } |
|
628 | + |
|
629 | + public function writeStream(string $path, $stream, int $size = null): int { |
|
630 | + $storage = $this->getWrapperStorage(); |
|
631 | + if ($storage->instanceOfStorage(IWriteStreamStorage::class)) { |
|
632 | + /** @var IWriteStreamStorage $storage */ |
|
633 | + return $storage->writeStream($path, $stream, $size); |
|
634 | + } else { |
|
635 | + $target = $this->fopen($path, 'w'); |
|
636 | + [$count, $result] = \OC_Helper::streamCopy($stream, $target); |
|
637 | + fclose($stream); |
|
638 | + fclose($target); |
|
639 | + return $count; |
|
640 | + } |
|
641 | + } |
|
642 | + |
|
643 | + public function getDirectoryContent($directory): \Traversable { |
|
644 | + return $this->getWrapperStorage()->getDirectoryContent($directory); |
|
645 | + } |
|
646 | 646 | } |