Completed
Push — stable12 ( c7e4bd...b91394 )
by
unknown
32:05 queued 21:31
created
lib/private/Files/ObjectStore/ObjectStoreStorage.php 3 patches
Doc Comments   +6 added lines patch added patch discarded remove patch
@@ -162,6 +162,9 @@  discard block
 block discarded – undo
162 162
 		return true;
163 163
 	}
164 164
 
165
+	/**
166
+	 * @param string $path
167
+	 */
165 168
 	private function rmObjects($path) {
166 169
 		$children = $this->getCache()->getFolderContents($path);
167 170
 		foreach ($children as $child) {
@@ -364,6 +367,9 @@  discard block
 block discarded – undo
364 367
 		return true;
365 368
 	}
366 369
 
370
+	/**
371
+	 * @param string $path
372
+	 */
367 373
 	public function writeBack($tmpFile, $path) {
368 374
 		$stat = $this->stat($path);
369 375
 		if (empty($stat)) {
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -55,9 +55,9 @@  discard block
 block discarded – undo
55 55
 			throw new \Exception('missing IObjectStore instance');
56 56
 		}
57 57
 		if (isset($params['storageid'])) {
58
-			$this->id = 'object::store:' . $params['storageid'];
58
+			$this->id = 'object::store:'.$params['storageid'];
59 59
 		} else {
60
-			$this->id = 'object::store:' . $this->objectStore->getStorageId();
60
+			$this->id = 'object::store:'.$this->objectStore->getStorageId();
61 61
 		}
62 62
 		if (isset($params['objectPrefix'])) {
63 63
 			$this->objectPrefix = $params['objectPrefix'];
@@ -191,7 +191,7 @@  discard block
 block discarded – undo
191 191
 				if ($ex->getCode() !== 404) {
192 192
 					$this->logger->logException($ex, [
193 193
 						'app' => 'objectstore',
194
-						'message' => 'Could not delete object ' . $this->getURN($stat['fileid']) . ' for ' . $path,
194
+						'message' => 'Could not delete object '.$this->getURN($stat['fileid']).' for '.$path,
195 195
 					]);
196 196
 					return false;
197 197
 				} else {
@@ -224,7 +224,7 @@  discard block
 block discarded – undo
224 224
 	 */
225 225
 	protected function getURN($fileId) {
226 226
 		if (is_numeric($fileId)) {
227
-			return $this->objectPrefix . $fileId;
227
+			return $this->objectPrefix.$fileId;
228 228
 		}
229 229
 		return null;
230 230
 	}
@@ -272,7 +272,7 @@  discard block
 block discarded – undo
272 272
 					} catch (\Exception $ex) {
273 273
 						$this->logger->logException($ex, [
274 274
 							'app' => 'objectstore',
275
-							'message' => 'Count not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
275
+							'message' => 'Count not get object '.$this->getURN($stat['fileid']).' for file '.$path,
276 276
 						]);
277 277
 						return false;
278 278
 					}
@@ -302,7 +302,7 @@  discard block
 block discarded – undo
302 302
 					file_put_contents($tmpFile, $source);
303 303
 				}
304 304
 				$handle = fopen($tmpFile, $mode);
305
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
305
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
306 306
 					$this->writeBack($tmpFile, $path);
307 307
 				});
308 308
 		}
@@ -311,7 +311,7 @@  discard block
 block discarded – undo
311 311
 
312 312
 	public function file_exists($path) {
313 313
 		$path = $this->normalizePath($path);
314
-		return (bool)$this->stat($path);
314
+		return (bool) $this->stat($path);
315 315
 	}
316 316
 
317 317
 	public function rename($source, $target) {
@@ -367,7 +367,7 @@  discard block
 block discarded – undo
367 367
 			} catch (\Exception $ex) {
368 368
 				$this->logger->logException($ex, [
369 369
 					'app' => 'objectstore',
370
-					'message' => 'Could not create object for ' . $path,
370
+					'message' => 'Could not create object for '.$path,
371 371
 				]);
372 372
 				return false;
373 373
 			}
@@ -407,7 +407,7 @@  discard block
 block discarded – undo
407 407
 			$this->getCache()->remove($path);
408 408
 			$this->logger->logException($ex, [
409 409
 				'app' => 'objectstore',
410
-				'message' => 'Could not create object ' . $this->getURN($fileId) . ' for ' . $path,
410
+				'message' => 'Could not create object '.$this->getURN($fileId).' for '.$path,
411 411
 			]);
412 412
 			throw $ex; // make this bubble up
413 413
 		}
Please login to merge, or discard this patch.
Indentation   +397 added lines, -397 removed lines patch added patch discarded remove patch
@@ -31,401 +31,401 @@
 block discarded – undo
31 31
 use OCP\Files\ObjectStore\IObjectStore;
32 32
 
33 33
 class ObjectStoreStorage extends \OC\Files\Storage\Common {
34
-	/**
35
-	 * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
36
-	 */
37
-	protected $objectStore;
38
-	/**
39
-	 * @var string $id
40
-	 */
41
-	protected $id;
42
-	/**
43
-	 * @var \OC\User\User $user
44
-	 */
45
-	protected $user;
46
-
47
-	private $objectPrefix = 'urn:oid:';
48
-
49
-	private $logger;
50
-
51
-	public function __construct($params) {
52
-		if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
53
-			$this->objectStore = $params['objectstore'];
54
-		} else {
55
-			throw new \Exception('missing IObjectStore instance');
56
-		}
57
-		if (isset($params['storageid'])) {
58
-			$this->id = 'object::store:' . $params['storageid'];
59
-		} else {
60
-			$this->id = 'object::store:' . $this->objectStore->getStorageId();
61
-		}
62
-		if (isset($params['objectPrefix'])) {
63
-			$this->objectPrefix = $params['objectPrefix'];
64
-		}
65
-		//initialize cache with root directory in cache
66
-		if (!$this->is_dir('/')) {
67
-			$this->mkdir('/');
68
-		}
69
-
70
-		$this->logger = \OC::$server->getLogger();
71
-	}
72
-
73
-	public function mkdir($path) {
74
-		$path = $this->normalizePath($path);
75
-
76
-		if ($this->file_exists($path)) {
77
-			return false;
78
-		}
79
-
80
-		$mTime = time();
81
-		$data = [
82
-			'mimetype' => 'httpd/unix-directory',
83
-			'size' => 0,
84
-			'mtime' => $mTime,
85
-			'storage_mtime' => $mTime,
86
-			'permissions' => \OCP\Constants::PERMISSION_ALL,
87
-		];
88
-		if ($path === '') {
89
-			//create root on the fly
90
-			$data['etag'] = $this->getETag('');
91
-			$this->getCache()->put('', $data);
92
-			return true;
93
-		} else {
94
-			// if parent does not exist, create it
95
-			$parent = $this->normalizePath(dirname($path));
96
-			$parentType = $this->filetype($parent);
97
-			if ($parentType === false) {
98
-				if (!$this->mkdir($parent)) {
99
-					// something went wrong
100
-					return false;
101
-				}
102
-			} else if ($parentType === 'file') {
103
-				// parent is a file
104
-				return false;
105
-			}
106
-			// finally create the new dir
107
-			$mTime = time(); // update mtime
108
-			$data['mtime'] = $mTime;
109
-			$data['storage_mtime'] = $mTime;
110
-			$data['etag'] = $this->getETag($path);
111
-			$this->getCache()->put($path, $data);
112
-			return true;
113
-		}
114
-	}
115
-
116
-	/**
117
-	 * @param string $path
118
-	 * @return string
119
-	 */
120
-	private function normalizePath($path) {
121
-		$path = trim($path, '/');
122
-		//FIXME why do we sometimes get a path like 'files//username'?
123
-		$path = str_replace('//', '/', $path);
124
-
125
-		// dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
126
-		if (!$path || $path === '.') {
127
-			$path = '';
128
-		}
129
-
130
-		return $path;
131
-	}
132
-
133
-	/**
134
-	 * Object Stores use a NoopScanner because metadata is directly stored in
135
-	 * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
136
-	 *
137
-	 * @param string $path
138
-	 * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
139
-	 * @return \OC\Files\ObjectStore\NoopScanner
140
-	 */
141
-	public function getScanner($path = '', $storage = null) {
142
-		if (!$storage) {
143
-			$storage = $this;
144
-		}
145
-		if (!isset($this->scanner)) {
146
-			$this->scanner = new NoopScanner($storage);
147
-		}
148
-		return $this->scanner;
149
-	}
150
-
151
-	public function getId() {
152
-		return $this->id;
153
-	}
154
-
155
-	public function rmdir($path) {
156
-		$path = $this->normalizePath($path);
157
-
158
-		if (!$this->is_dir($path)) {
159
-			return false;
160
-		}
161
-
162
-		$this->rmObjects($path);
163
-
164
-		$this->getCache()->remove($path);
165
-
166
-		return true;
167
-	}
168
-
169
-	private function rmObjects($path) {
170
-		$children = $this->getCache()->getFolderContents($path);
171
-		foreach ($children as $child) {
172
-			if ($child['mimetype'] === 'httpd/unix-directory') {
173
-				$this->rmObjects($child['path']);
174
-			} else {
175
-				$this->unlink($child['path']);
176
-			}
177
-		}
178
-	}
179
-
180
-	public function unlink($path) {
181
-		$path = $this->normalizePath($path);
182
-		$stat = $this->stat($path);
183
-
184
-		if ($stat && isset($stat['fileid'])) {
185
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
186
-				return $this->rmdir($path);
187
-			}
188
-			try {
189
-				$this->objectStore->deleteObject($this->getURN($stat['fileid']));
190
-			} catch (\Exception $ex) {
191
-				if ($ex->getCode() !== 404) {
192
-					$this->logger->logException($ex, [
193
-						'app' => 'objectstore',
194
-						'message' => 'Could not delete object ' . $this->getURN($stat['fileid']) . ' for ' . $path,
195
-					]);
196
-					return false;
197
-				} else {
198
-					//removing from cache is ok as it does not exist in the objectstore anyway
199
-				}
200
-			}
201
-			$this->getCache()->remove($path);
202
-			return true;
203
-		}
204
-		return false;
205
-	}
206
-
207
-	public function stat($path) {
208
-		$path = $this->normalizePath($path);
209
-		$cacheEntry = $this->getCache()->get($path);
210
-		if ($cacheEntry instanceof CacheEntry) {
211
-			return $cacheEntry->getData();
212
-		} else {
213
-			return false;
214
-		}
215
-	}
216
-
217
-	/**
218
-	 * Override this method if you need a different unique resource identifier for your object storage implementation.
219
-	 * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
220
-	 * You may need a mapping table to store your URN if it cannot be generated from the fileid.
221
-	 *
222
-	 * @param int $fileId the fileid
223
-	 * @return null|string the unified resource name used to identify the object
224
-	 */
225
-	protected function getURN($fileId) {
226
-		if (is_numeric($fileId)) {
227
-			return $this->objectPrefix . $fileId;
228
-		}
229
-		return null;
230
-	}
231
-
232
-	public function opendir($path) {
233
-		$path = $this->normalizePath($path);
234
-
235
-		try {
236
-			$files = array();
237
-			$folderContents = $this->getCache()->getFolderContents($path);
238
-			foreach ($folderContents as $file) {
239
-				$files[] = $file['name'];
240
-			}
241
-
242
-			return IteratorDirectory::wrap($files);
243
-		} catch (\Exception $e) {
244
-			$this->logger->logException($e);
245
-			return false;
246
-		}
247
-	}
248
-
249
-	public function filetype($path) {
250
-		$path = $this->normalizePath($path);
251
-		$stat = $this->stat($path);
252
-		if ($stat) {
253
-			if ($stat['mimetype'] === 'httpd/unix-directory') {
254
-				return 'dir';
255
-			}
256
-			return 'file';
257
-		} else {
258
-			return false;
259
-		}
260
-	}
261
-
262
-	public function fopen($path, $mode) {
263
-		$path = $this->normalizePath($path);
264
-
265
-		switch ($mode) {
266
-			case 'r':
267
-			case 'rb':
268
-				$stat = $this->stat($path);
269
-				if (is_array($stat)) {
270
-					try {
271
-						return $this->objectStore->readObject($this->getURN($stat['fileid']));
272
-					} catch (\Exception $ex) {
273
-						$this->logger->logException($ex, [
274
-							'app' => 'objectstore',
275
-							'message' => 'Count not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
276
-						]);
277
-						return false;
278
-					}
279
-				} else {
280
-					return false;
281
-				}
282
-			case 'w':
283
-			case 'wb':
284
-			case 'a':
285
-			case 'ab':
286
-			case 'r+':
287
-			case 'w+':
288
-			case 'wb+':
289
-			case 'a+':
290
-			case 'x':
291
-			case 'x+':
292
-			case 'c':
293
-			case 'c+':
294
-				if (strrpos($path, '.') !== false) {
295
-					$ext = substr($path, strrpos($path, '.'));
296
-				} else {
297
-					$ext = '';
298
-				}
299
-				$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
300
-				if ($this->file_exists($path)) {
301
-					$source = $this->fopen($path, 'r');
302
-					file_put_contents($tmpFile, $source);
303
-				}
304
-				$handle = fopen($tmpFile, $mode);
305
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
306
-					$this->writeBack($tmpFile, $path);
307
-				});
308
-		}
309
-		return false;
310
-	}
311
-
312
-	public function file_exists($path) {
313
-		$path = $this->normalizePath($path);
314
-		return (bool)$this->stat($path);
315
-	}
316
-
317
-	public function rename($source, $target) {
318
-		$source = $this->normalizePath($source);
319
-		$target = $this->normalizePath($target);
320
-		$this->remove($target);
321
-		$this->getCache()->move($source, $target);
322
-		$this->touch(dirname($target));
323
-		return true;
324
-	}
325
-
326
-	public function getMimeType($path) {
327
-		$path = $this->normalizePath($path);
328
-		$stat = $this->stat($path);
329
-		if (is_array($stat)) {
330
-			return $stat['mimetype'];
331
-		} else {
332
-			return false;
333
-		}
334
-	}
335
-
336
-	public function touch($path, $mtime = null) {
337
-		if (is_null($mtime)) {
338
-			$mtime = time();
339
-		}
340
-
341
-		$path = $this->normalizePath($path);
342
-		$dirName = dirname($path);
343
-		$parentExists = $this->is_dir($dirName);
344
-		if (!$parentExists) {
345
-			return false;
346
-		}
347
-
348
-		$stat = $this->stat($path);
349
-		if (is_array($stat)) {
350
-			// update existing mtime in db
351
-			$stat['mtime'] = $mtime;
352
-			$this->getCache()->update($stat['fileid'], $stat);
353
-		} else {
354
-			try {
355
-				//create a empty file, need to have at least on char to make it
356
-				// work with all object storage implementations
357
-				$this->file_put_contents($path, ' ');
358
-				$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
359
-				$stat = array(
360
-					'etag' => $this->getETag($path),
361
-					'mimetype' => $mimeType,
362
-					'size' => 0,
363
-					'mtime' => $mtime,
364
-					'storage_mtime' => $mtime,
365
-					'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
366
-				);
367
-				$this->getCache()->put($path, $stat);
368
-			} catch (\Exception $ex) {
369
-				$this->logger->logException($ex, [
370
-					'app' => 'objectstore',
371
-					'message' => 'Could not create object for ' . $path,
372
-				]);
373
-				return false;
374
-			}
375
-		}
376
-		return true;
377
-	}
378
-
379
-	public function writeBack($tmpFile, $path) {
380
-		$stat = $this->stat($path);
381
-		if (empty($stat)) {
382
-			// create new file
383
-			$stat = array(
384
-				'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
385
-			);
386
-		}
387
-		// update stat with new data
388
-		$mTime = time();
389
-		$stat['size'] = filesize($tmpFile);
390
-		$stat['mtime'] = $mTime;
391
-		$stat['storage_mtime'] = $mTime;
392
-
393
-		// run path based detection first, to use file extension because $tmpFile is only a random string
394
-		$mimetypeDetector = \OC::$server->getMimeTypeDetector();
395
-		$mimetype = $mimetypeDetector->detectPath($path);
396
-		if ($mimetype === 'application/octet-stream') {
397
-			$mimetype = $mimetypeDetector->detect($tmpFile);
398
-		}
399
-
400
-		$stat['mimetype'] = $mimetype;
401
-		$stat['etag'] = $this->getETag($path);
402
-
403
-		$fileId = $this->getCache()->put($path, $stat);
404
-		try {
405
-			//upload to object storage
406
-			$this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
407
-		} catch (\Exception $ex) {
408
-			$this->getCache()->remove($path);
409
-			$this->logger->logException($ex, [
410
-				'app' => 'objectstore',
411
-				'message' => 'Could not create object ' . $this->getURN($fileId) . ' for ' . $path,
412
-			]);
413
-			throw $ex; // make this bubble up
414
-		}
415
-	}
416
-
417
-	/**
418
-	 * external changes are not supported, exclusive access to the object storage is assumed
419
-	 *
420
-	 * @param string $path
421
-	 * @param int $time
422
-	 * @return false
423
-	 */
424
-	public function hasUpdated($path, $time) {
425
-		return false;
426
-	}
427
-
428
-	public function needsPartFile() {
429
-		return false;
430
-	}
34
+    /**
35
+     * @var \OCP\Files\ObjectStore\IObjectStore $objectStore
36
+     */
37
+    protected $objectStore;
38
+    /**
39
+     * @var string $id
40
+     */
41
+    protected $id;
42
+    /**
43
+     * @var \OC\User\User $user
44
+     */
45
+    protected $user;
46
+
47
+    private $objectPrefix = 'urn:oid:';
48
+
49
+    private $logger;
50
+
51
+    public function __construct($params) {
52
+        if (isset($params['objectstore']) && $params['objectstore'] instanceof IObjectStore) {
53
+            $this->objectStore = $params['objectstore'];
54
+        } else {
55
+            throw new \Exception('missing IObjectStore instance');
56
+        }
57
+        if (isset($params['storageid'])) {
58
+            $this->id = 'object::store:' . $params['storageid'];
59
+        } else {
60
+            $this->id = 'object::store:' . $this->objectStore->getStorageId();
61
+        }
62
+        if (isset($params['objectPrefix'])) {
63
+            $this->objectPrefix = $params['objectPrefix'];
64
+        }
65
+        //initialize cache with root directory in cache
66
+        if (!$this->is_dir('/')) {
67
+            $this->mkdir('/');
68
+        }
69
+
70
+        $this->logger = \OC::$server->getLogger();
71
+    }
72
+
73
+    public function mkdir($path) {
74
+        $path = $this->normalizePath($path);
75
+
76
+        if ($this->file_exists($path)) {
77
+            return false;
78
+        }
79
+
80
+        $mTime = time();
81
+        $data = [
82
+            'mimetype' => 'httpd/unix-directory',
83
+            'size' => 0,
84
+            'mtime' => $mTime,
85
+            'storage_mtime' => $mTime,
86
+            'permissions' => \OCP\Constants::PERMISSION_ALL,
87
+        ];
88
+        if ($path === '') {
89
+            //create root on the fly
90
+            $data['etag'] = $this->getETag('');
91
+            $this->getCache()->put('', $data);
92
+            return true;
93
+        } else {
94
+            // if parent does not exist, create it
95
+            $parent = $this->normalizePath(dirname($path));
96
+            $parentType = $this->filetype($parent);
97
+            if ($parentType === false) {
98
+                if (!$this->mkdir($parent)) {
99
+                    // something went wrong
100
+                    return false;
101
+                }
102
+            } else if ($parentType === 'file') {
103
+                // parent is a file
104
+                return false;
105
+            }
106
+            // finally create the new dir
107
+            $mTime = time(); // update mtime
108
+            $data['mtime'] = $mTime;
109
+            $data['storage_mtime'] = $mTime;
110
+            $data['etag'] = $this->getETag($path);
111
+            $this->getCache()->put($path, $data);
112
+            return true;
113
+        }
114
+    }
115
+
116
+    /**
117
+     * @param string $path
118
+     * @return string
119
+     */
120
+    private function normalizePath($path) {
121
+        $path = trim($path, '/');
122
+        //FIXME why do we sometimes get a path like 'files//username'?
123
+        $path = str_replace('//', '/', $path);
124
+
125
+        // dirname('/folder') returns '.' but internally (in the cache) we store the root as ''
126
+        if (!$path || $path === '.') {
127
+            $path = '';
128
+        }
129
+
130
+        return $path;
131
+    }
132
+
133
+    /**
134
+     * Object Stores use a NoopScanner because metadata is directly stored in
135
+     * the file cache and cannot really scan the filesystem. The storage passed in is not used anywhere.
136
+     *
137
+     * @param string $path
138
+     * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner
139
+     * @return \OC\Files\ObjectStore\NoopScanner
140
+     */
141
+    public function getScanner($path = '', $storage = null) {
142
+        if (!$storage) {
143
+            $storage = $this;
144
+        }
145
+        if (!isset($this->scanner)) {
146
+            $this->scanner = new NoopScanner($storage);
147
+        }
148
+        return $this->scanner;
149
+    }
150
+
151
+    public function getId() {
152
+        return $this->id;
153
+    }
154
+
155
+    public function rmdir($path) {
156
+        $path = $this->normalizePath($path);
157
+
158
+        if (!$this->is_dir($path)) {
159
+            return false;
160
+        }
161
+
162
+        $this->rmObjects($path);
163
+
164
+        $this->getCache()->remove($path);
165
+
166
+        return true;
167
+    }
168
+
169
+    private function rmObjects($path) {
170
+        $children = $this->getCache()->getFolderContents($path);
171
+        foreach ($children as $child) {
172
+            if ($child['mimetype'] === 'httpd/unix-directory') {
173
+                $this->rmObjects($child['path']);
174
+            } else {
175
+                $this->unlink($child['path']);
176
+            }
177
+        }
178
+    }
179
+
180
+    public function unlink($path) {
181
+        $path = $this->normalizePath($path);
182
+        $stat = $this->stat($path);
183
+
184
+        if ($stat && isset($stat['fileid'])) {
185
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
186
+                return $this->rmdir($path);
187
+            }
188
+            try {
189
+                $this->objectStore->deleteObject($this->getURN($stat['fileid']));
190
+            } catch (\Exception $ex) {
191
+                if ($ex->getCode() !== 404) {
192
+                    $this->logger->logException($ex, [
193
+                        'app' => 'objectstore',
194
+                        'message' => 'Could not delete object ' . $this->getURN($stat['fileid']) . ' for ' . $path,
195
+                    ]);
196
+                    return false;
197
+                } else {
198
+                    //removing from cache is ok as it does not exist in the objectstore anyway
199
+                }
200
+            }
201
+            $this->getCache()->remove($path);
202
+            return true;
203
+        }
204
+        return false;
205
+    }
206
+
207
+    public function stat($path) {
208
+        $path = $this->normalizePath($path);
209
+        $cacheEntry = $this->getCache()->get($path);
210
+        if ($cacheEntry instanceof CacheEntry) {
211
+            return $cacheEntry->getData();
212
+        } else {
213
+            return false;
214
+        }
215
+    }
216
+
217
+    /**
218
+     * Override this method if you need a different unique resource identifier for your object storage implementation.
219
+     * The default implementations just appends the fileId to 'urn:oid:'. Make sure the URN is unique over all users.
220
+     * You may need a mapping table to store your URN if it cannot be generated from the fileid.
221
+     *
222
+     * @param int $fileId the fileid
223
+     * @return null|string the unified resource name used to identify the object
224
+     */
225
+    protected function getURN($fileId) {
226
+        if (is_numeric($fileId)) {
227
+            return $this->objectPrefix . $fileId;
228
+        }
229
+        return null;
230
+    }
231
+
232
+    public function opendir($path) {
233
+        $path = $this->normalizePath($path);
234
+
235
+        try {
236
+            $files = array();
237
+            $folderContents = $this->getCache()->getFolderContents($path);
238
+            foreach ($folderContents as $file) {
239
+                $files[] = $file['name'];
240
+            }
241
+
242
+            return IteratorDirectory::wrap($files);
243
+        } catch (\Exception $e) {
244
+            $this->logger->logException($e);
245
+            return false;
246
+        }
247
+    }
248
+
249
+    public function filetype($path) {
250
+        $path = $this->normalizePath($path);
251
+        $stat = $this->stat($path);
252
+        if ($stat) {
253
+            if ($stat['mimetype'] === 'httpd/unix-directory') {
254
+                return 'dir';
255
+            }
256
+            return 'file';
257
+        } else {
258
+            return false;
259
+        }
260
+    }
261
+
262
+    public function fopen($path, $mode) {
263
+        $path = $this->normalizePath($path);
264
+
265
+        switch ($mode) {
266
+            case 'r':
267
+            case 'rb':
268
+                $stat = $this->stat($path);
269
+                if (is_array($stat)) {
270
+                    try {
271
+                        return $this->objectStore->readObject($this->getURN($stat['fileid']));
272
+                    } catch (\Exception $ex) {
273
+                        $this->logger->logException($ex, [
274
+                            'app' => 'objectstore',
275
+                            'message' => 'Count not get object ' . $this->getURN($stat['fileid']) . ' for file ' . $path,
276
+                        ]);
277
+                        return false;
278
+                    }
279
+                } else {
280
+                    return false;
281
+                }
282
+            case 'w':
283
+            case 'wb':
284
+            case 'a':
285
+            case 'ab':
286
+            case 'r+':
287
+            case 'w+':
288
+            case 'wb+':
289
+            case 'a+':
290
+            case 'x':
291
+            case 'x+':
292
+            case 'c':
293
+            case 'c+':
294
+                if (strrpos($path, '.') !== false) {
295
+                    $ext = substr($path, strrpos($path, '.'));
296
+                } else {
297
+                    $ext = '';
298
+                }
299
+                $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext);
300
+                if ($this->file_exists($path)) {
301
+                    $source = $this->fopen($path, 'r');
302
+                    file_put_contents($tmpFile, $source);
303
+                }
304
+                $handle = fopen($tmpFile, $mode);
305
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
306
+                    $this->writeBack($tmpFile, $path);
307
+                });
308
+        }
309
+        return false;
310
+    }
311
+
312
+    public function file_exists($path) {
313
+        $path = $this->normalizePath($path);
314
+        return (bool)$this->stat($path);
315
+    }
316
+
317
+    public function rename($source, $target) {
318
+        $source = $this->normalizePath($source);
319
+        $target = $this->normalizePath($target);
320
+        $this->remove($target);
321
+        $this->getCache()->move($source, $target);
322
+        $this->touch(dirname($target));
323
+        return true;
324
+    }
325
+
326
+    public function getMimeType($path) {
327
+        $path = $this->normalizePath($path);
328
+        $stat = $this->stat($path);
329
+        if (is_array($stat)) {
330
+            return $stat['mimetype'];
331
+        } else {
332
+            return false;
333
+        }
334
+    }
335
+
336
+    public function touch($path, $mtime = null) {
337
+        if (is_null($mtime)) {
338
+            $mtime = time();
339
+        }
340
+
341
+        $path = $this->normalizePath($path);
342
+        $dirName = dirname($path);
343
+        $parentExists = $this->is_dir($dirName);
344
+        if (!$parentExists) {
345
+            return false;
346
+        }
347
+
348
+        $stat = $this->stat($path);
349
+        if (is_array($stat)) {
350
+            // update existing mtime in db
351
+            $stat['mtime'] = $mtime;
352
+            $this->getCache()->update($stat['fileid'], $stat);
353
+        } else {
354
+            try {
355
+                //create a empty file, need to have at least on char to make it
356
+                // work with all object storage implementations
357
+                $this->file_put_contents($path, ' ');
358
+                $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
359
+                $stat = array(
360
+                    'etag' => $this->getETag($path),
361
+                    'mimetype' => $mimeType,
362
+                    'size' => 0,
363
+                    'mtime' => $mtime,
364
+                    'storage_mtime' => $mtime,
365
+                    'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
366
+                );
367
+                $this->getCache()->put($path, $stat);
368
+            } catch (\Exception $ex) {
369
+                $this->logger->logException($ex, [
370
+                    'app' => 'objectstore',
371
+                    'message' => 'Could not create object for ' . $path,
372
+                ]);
373
+                return false;
374
+            }
375
+        }
376
+        return true;
377
+    }
378
+
379
+    public function writeBack($tmpFile, $path) {
380
+        $stat = $this->stat($path);
381
+        if (empty($stat)) {
382
+            // create new file
383
+            $stat = array(
384
+                'permissions' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_CREATE,
385
+            );
386
+        }
387
+        // update stat with new data
388
+        $mTime = time();
389
+        $stat['size'] = filesize($tmpFile);
390
+        $stat['mtime'] = $mTime;
391
+        $stat['storage_mtime'] = $mTime;
392
+
393
+        // run path based detection first, to use file extension because $tmpFile is only a random string
394
+        $mimetypeDetector = \OC::$server->getMimeTypeDetector();
395
+        $mimetype = $mimetypeDetector->detectPath($path);
396
+        if ($mimetype === 'application/octet-stream') {
397
+            $mimetype = $mimetypeDetector->detect($tmpFile);
398
+        }
399
+
400
+        $stat['mimetype'] = $mimetype;
401
+        $stat['etag'] = $this->getETag($path);
402
+
403
+        $fileId = $this->getCache()->put($path, $stat);
404
+        try {
405
+            //upload to object storage
406
+            $this->objectStore->writeObject($this->getURN($fileId), fopen($tmpFile, 'r'));
407
+        } catch (\Exception $ex) {
408
+            $this->getCache()->remove($path);
409
+            $this->logger->logException($ex, [
410
+                'app' => 'objectstore',
411
+                'message' => 'Could not create object ' . $this->getURN($fileId) . ' for ' . $path,
412
+            ]);
413
+            throw $ex; // make this bubble up
414
+        }
415
+    }
416
+
417
+    /**
418
+     * external changes are not supported, exclusive access to the object storage is assumed
419
+     *
420
+     * @param string $path
421
+     * @param int $time
422
+     * @return false
423
+     */
424
+    public function hasUpdated($path, $time) {
425
+        return false;
426
+    }
427
+
428
+    public function needsPartFile() {
429
+        return false;
430
+    }
431 431
 }
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Notify/SMBNotifyHandler.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -102,7 +102,7 @@
 block discarded – undo
102 102
 
103 103
 	/**
104 104
 	 * @param \Icewind\SMB\Change $change
105
-	 * @return IChange|null
105
+	 * @return null|Change
106 106
 	 */
107 107
 	private function mapChange(\Icewind\SMB\Change $change) {
108 108
 		$path = $this->relativePath($change->getPath());
Please login to merge, or discard this patch.
Indentation   +109 added lines, -109 removed lines patch added patch discarded remove patch
@@ -29,122 +29,122 @@
 block discarded – undo
29 29
 use OCP\Files\Notify\INotifyHandler;
30 30
 
31 31
 class SMBNotifyHandler implements INotifyHandler {
32
-	/**
33
-	 * @var \Icewind\SMB\INotifyHandler
34
-	 */
35
-	private $shareNotifyHandler;
32
+    /**
33
+     * @var \Icewind\SMB\INotifyHandler
34
+     */
35
+    private $shareNotifyHandler;
36 36
 
37
-	/**
38
-	 * @var string
39
-	 */
40
-	private $root;
37
+    /**
38
+     * @var string
39
+     */
40
+    private $root;
41 41
 
42
-	private $oldRenamePath = null;
42
+    private $oldRenamePath = null;
43 43
 
44
-	/**
45
-	 * SMBNotifyHandler constructor.
46
-	 *
47
-	 * @param \Icewind\SMB\INotifyHandler $shareNotifyHandler
48
-	 * @param string $root
49
-	 */
50
-	public function __construct(\Icewind\SMB\INotifyHandler $shareNotifyHandler, $root) {
51
-		$this->shareNotifyHandler = $shareNotifyHandler;
52
-		$this->root = $root;
53
-	}
44
+    /**
45
+     * SMBNotifyHandler constructor.
46
+     *
47
+     * @param \Icewind\SMB\INotifyHandler $shareNotifyHandler
48
+     * @param string $root
49
+     */
50
+    public function __construct(\Icewind\SMB\INotifyHandler $shareNotifyHandler, $root) {
51
+        $this->shareNotifyHandler = $shareNotifyHandler;
52
+        $this->root = $root;
53
+    }
54 54
 
55
-	private function relativePath($fullPath) {
56
-		if ($fullPath === $this->root) {
57
-			return '';
58
-		} else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
59
-			return substr($fullPath, strlen($this->root));
60
-		} else {
61
-			return null;
62
-		}
63
-	}
55
+    private function relativePath($fullPath) {
56
+        if ($fullPath === $this->root) {
57
+            return '';
58
+        } else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
59
+            return substr($fullPath, strlen($this->root));
60
+        } else {
61
+            return null;
62
+        }
63
+    }
64 64
 
65
-	public function listen(callable $callback) {
66
-		$oldRenamePath = null;
67
-		$this->shareNotifyHandler->listen(function (\Icewind\SMB\Change $shareChange) use ($callback) {
68
-			$change = $this->mapChange($shareChange);
69
-			if (!is_null($change)) {
70
-				return $callback($change);
71
-			} else {
72
-				return true;
73
-			}
74
-		});
75
-	}
65
+    public function listen(callable $callback) {
66
+        $oldRenamePath = null;
67
+        $this->shareNotifyHandler->listen(function (\Icewind\SMB\Change $shareChange) use ($callback) {
68
+            $change = $this->mapChange($shareChange);
69
+            if (!is_null($change)) {
70
+                return $callback($change);
71
+            } else {
72
+                return true;
73
+            }
74
+        });
75
+    }
76 76
 
77
-	/**
78
-	 * Get all changes detected since the start of the notify process or the last call to getChanges
79
-	 *
80
-	 * @return IChange[]
81
-	 */
82
-	public function getChanges() {
83
-		$shareChanges = $this->shareNotifyHandler->getChanges();
84
-		$changes = [];
85
-		foreach ($shareChanges as $shareChange) {
86
-			$change = $this->mapChange($shareChange);
87
-			if ($change) {
88
-				$changes[] = $change;
89
-			}
90
-		}
91
-		return $changes;
92
-	}
77
+    /**
78
+     * Get all changes detected since the start of the notify process or the last call to getChanges
79
+     *
80
+     * @return IChange[]
81
+     */
82
+    public function getChanges() {
83
+        $shareChanges = $this->shareNotifyHandler->getChanges();
84
+        $changes = [];
85
+        foreach ($shareChanges as $shareChange) {
86
+            $change = $this->mapChange($shareChange);
87
+            if ($change) {
88
+                $changes[] = $change;
89
+            }
90
+        }
91
+        return $changes;
92
+    }
93 93
 
94
-	/**
95
-	 * Stop listening for changes
96
-	 *
97
-	 * Note that any pending changes will be discarded
98
-	 */
99
-	public function stop() {
100
-		$this->shareNotifyHandler->stop();
101
-	}
94
+    /**
95
+     * Stop listening for changes
96
+     *
97
+     * Note that any pending changes will be discarded
98
+     */
99
+    public function stop() {
100
+        $this->shareNotifyHandler->stop();
101
+    }
102 102
 
103
-	/**
104
-	 * @param \Icewind\SMB\Change $change
105
-	 * @return IChange|null
106
-	 */
107
-	private function mapChange(\Icewind\SMB\Change $change) {
108
-		$path = $this->relativePath($change->getPath());
109
-		if (is_null($path)) {
110
-			return null;
111
-		}
112
-		if ($change->getCode() === \Icewind\SMB\INotifyHandler::NOTIFY_RENAMED_OLD) {
113
-			$this->oldRenamePath = $path;
114
-			return null;
115
-		}
116
-		$type = $this->mapNotifyType($change->getCode());
117
-		if (is_null($type)) {
118
-			return null;
119
-		}
120
-		if ($type === IChange::RENAMED) {
121
-			if (!is_null($this->oldRenamePath)) {
122
-				$result = new RenameChange($type, $this->oldRenamePath, $path);
123
-				$this->oldRenamePath = null;
124
-			} else {
125
-				$result = null;
126
-			}
127
-		} else {
128
-			$result = new Change($type, $path);
129
-		}
130
-		return $result;
131
-	}
103
+    /**
104
+     * @param \Icewind\SMB\Change $change
105
+     * @return IChange|null
106
+     */
107
+    private function mapChange(\Icewind\SMB\Change $change) {
108
+        $path = $this->relativePath($change->getPath());
109
+        if (is_null($path)) {
110
+            return null;
111
+        }
112
+        if ($change->getCode() === \Icewind\SMB\INotifyHandler::NOTIFY_RENAMED_OLD) {
113
+            $this->oldRenamePath = $path;
114
+            return null;
115
+        }
116
+        $type = $this->mapNotifyType($change->getCode());
117
+        if (is_null($type)) {
118
+            return null;
119
+        }
120
+        if ($type === IChange::RENAMED) {
121
+            if (!is_null($this->oldRenamePath)) {
122
+                $result = new RenameChange($type, $this->oldRenamePath, $path);
123
+                $this->oldRenamePath = null;
124
+            } else {
125
+                $result = null;
126
+            }
127
+        } else {
128
+            $result = new Change($type, $path);
129
+        }
130
+        return $result;
131
+    }
132 132
 
133
-	private function mapNotifyType($smbType) {
134
-		switch ($smbType) {
135
-			case \Icewind\SMB\INotifyHandler::NOTIFY_ADDED:
136
-				return IChange::ADDED;
137
-			case \Icewind\SMB\INotifyHandler::NOTIFY_REMOVED:
138
-				return IChange::REMOVED;
139
-			case \Icewind\SMB\INotifyHandler::NOTIFY_MODIFIED:
140
-			case \Icewind\SMB\INotifyHandler::NOTIFY_ADDED_STREAM:
141
-			case \Icewind\SMB\INotifyHandler::NOTIFY_MODIFIED_STREAM:
142
-			case \Icewind\SMB\INotifyHandler::NOTIFY_REMOVED_STREAM:
143
-				return IChange::MODIFIED;
144
-			case \Icewind\SMB\INotifyHandler::NOTIFY_RENAMED_NEW:
145
-				return IChange::RENAMED;
146
-			default:
147
-				return null;
148
-		}
149
-	}
133
+    private function mapNotifyType($smbType) {
134
+        switch ($smbType) {
135
+            case \Icewind\SMB\INotifyHandler::NOTIFY_ADDED:
136
+                return IChange::ADDED;
137
+            case \Icewind\SMB\INotifyHandler::NOTIFY_REMOVED:
138
+                return IChange::REMOVED;
139
+            case \Icewind\SMB\INotifyHandler::NOTIFY_MODIFIED:
140
+            case \Icewind\SMB\INotifyHandler::NOTIFY_ADDED_STREAM:
141
+            case \Icewind\SMB\INotifyHandler::NOTIFY_MODIFIED_STREAM:
142
+            case \Icewind\SMB\INotifyHandler::NOTIFY_REMOVED_STREAM:
143
+                return IChange::MODIFIED;
144
+            case \Icewind\SMB\INotifyHandler::NOTIFY_RENAMED_NEW:
145
+                return IChange::RENAMED;
146
+            default:
147
+                return null;
148
+        }
149
+    }
150 150
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -64,7 +64,7 @@
 block discarded – undo
64 64
 
65 65
 	public function listen(callable $callback) {
66 66
 		$oldRenamePath = null;
67
-		$this->shareNotifyHandler->listen(function (\Icewind\SMB\Change $shareChange) use ($callback) {
67
+		$this->shareNotifyHandler->listen(function(\Icewind\SMB\Change $shareChange) use ($callback) {
68 68
 			$change = $this->mapChange($shareChange);
69 69
 			if (!is_null($change)) {
70 70
 				return $callback($change);
Please login to merge, or discard this patch.
lib/private/legacy/app.php 3 patches
Doc Comments   +6 added lines, -1 removed lines patch added patch discarded remove patch
@@ -1063,7 +1063,7 @@  discard block
 block discarded – undo
1063 1063
 	 * @param string $app
1064 1064
 	 * @param \OCP\IConfig $config
1065 1065
 	 * @param \OCP\IL10N $l
1066
-	 * @return bool
1066
+	 * @return string
1067 1067
 	 *
1068 1068
 	 * @throws Exception if app is not compatible with this version of ownCloud
1069 1069
 	 * @throws Exception if no app-name was specified
@@ -1243,6 +1243,11 @@  discard block
 block discarded – undo
1243 1243
 		}
1244 1244
 	}
1245 1245
 
1246
+	/**
1247
+	 * @param string $lang
1248
+	 *
1249
+	 * @return string
1250
+	 */
1246 1251
 	protected static function findBestL10NOption($options, $lang) {
1247 1252
 		$fallback = $similarLangFallback = $englishFallback = false;
1248 1253
 
Please login to merge, or discard this patch.
Indentation   +1186 added lines, -1186 removed lines patch added patch discarded remove patch
@@ -60,1190 +60,1190 @@
 block discarded – undo
60 60
  * upgrading and removing apps.
61 61
  */
62 62
 class OC_App {
63
-	static private $appVersion = [];
64
-	static private $adminForms = array();
65
-	static private $personalForms = array();
66
-	static private $appInfo = array();
67
-	static private $appTypes = array();
68
-	static private $loadedApps = array();
69
-	static private $altLogin = array();
70
-	static private $alreadyRegistered = [];
71
-	const officialApp = 200;
72
-
73
-	/**
74
-	 * clean the appId
75
-	 *
76
-	 * @param string|boolean $app AppId that needs to be cleaned
77
-	 * @return string
78
-	 */
79
-	public static function cleanAppId($app) {
80
-		return str_replace(array('\0', '/', '\\', '..'), '', $app);
81
-	}
82
-
83
-	/**
84
-	 * Check if an app is loaded
85
-	 *
86
-	 * @param string $app
87
-	 * @return bool
88
-	 */
89
-	public static function isAppLoaded($app) {
90
-		return in_array($app, self::$loadedApps, true);
91
-	}
92
-
93
-	/**
94
-	 * loads all apps
95
-	 *
96
-	 * @param string[] | string | null $types
97
-	 * @return bool
98
-	 *
99
-	 * This function walks through the ownCloud directory and loads all apps
100
-	 * it can find. A directory contains an app if the file /appinfo/info.xml
101
-	 * exists.
102
-	 *
103
-	 * if $types is set, only apps of those types will be loaded
104
-	 */
105
-	public static function loadApps($types = null) {
106
-		if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
107
-			return false;
108
-		}
109
-		// Load the enabled apps here
110
-		$apps = self::getEnabledApps();
111
-
112
-		// Add each apps' folder as allowed class path
113
-		foreach($apps as $app) {
114
-			$path = self::getAppPath($app);
115
-			if($path !== false) {
116
-				self::registerAutoloading($app, $path);
117
-			}
118
-		}
119
-
120
-		// prevent app.php from printing output
121
-		ob_start();
122
-		foreach ($apps as $app) {
123
-			if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
124
-				self::loadApp($app);
125
-			}
126
-		}
127
-		ob_end_clean();
128
-
129
-		return true;
130
-	}
131
-
132
-	/**
133
-	 * load a single app
134
-	 *
135
-	 * @param string $app
136
-	 * @throws Exception
137
-	 */
138
-	public static function loadApp($app) {
139
-		self::$loadedApps[] = $app;
140
-		$appPath = self::getAppPath($app);
141
-		if($appPath === false) {
142
-			return;
143
-		}
144
-
145
-		// in case someone calls loadApp() directly
146
-		self::registerAutoloading($app, $appPath);
147
-
148
-		if (is_file($appPath . '/appinfo/app.php')) {
149
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
150
-			try {
151
-				self::requireAppFile($app);
152
-			} catch (Error $ex) {
153
-				\OC::$server->getLogger()->logException($ex);
154
-				if (!\OC::$server->getAppManager()->isShipped($app)) {
155
-					// Only disable apps which are not shipped
156
-					self::disable($app);
157
-				}
158
-			}
159
-			if (self::isType($app, array('authentication'))) {
160
-				// since authentication apps affect the "is app enabled for group" check,
161
-				// the enabled apps cache needs to be cleared to make sure that the
162
-				// next time getEnableApps() is called it will also include apps that were
163
-				// enabled for groups
164
-				self::$enabledAppsCache = array();
165
-			}
166
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
167
-		}
168
-
169
-		$info = self::getAppInfo($app);
170
-		if (!empty($info['activity']['filters'])) {
171
-			foreach ($info['activity']['filters'] as $filter) {
172
-				\OC::$server->getActivityManager()->registerFilter($filter);
173
-			}
174
-		}
175
-		if (!empty($info['activity']['settings'])) {
176
-			foreach ($info['activity']['settings'] as $setting) {
177
-				\OC::$server->getActivityManager()->registerSetting($setting);
178
-			}
179
-		}
180
-		if (!empty($info['activity']['providers'])) {
181
-			foreach ($info['activity']['providers'] as $provider) {
182
-				\OC::$server->getActivityManager()->registerProvider($provider);
183
-			}
184
-		}
185
-	}
186
-
187
-	/**
188
-	 * @internal
189
-	 * @param string $app
190
-	 * @param string $path
191
-	 */
192
-	public static function registerAutoloading($app, $path) {
193
-		$key = $app . '-' . $path;
194
-		if(isset(self::$alreadyRegistered[$key])) {
195
-			return;
196
-		}
197
-		self::$alreadyRegistered[$key] = true;
198
-		// Register on PSR-4 composer autoloader
199
-		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
200
-		\OC::$server->registerNamespace($app, $appNamespace);
201
-		\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
202
-		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
203
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
204
-		}
205
-
206
-		// Register on legacy autoloader
207
-		\OC::$loader->addValidRoot($path);
208
-	}
209
-
210
-	/**
211
-	 * Load app.php from the given app
212
-	 *
213
-	 * @param string $app app name
214
-	 * @throws Error
215
-	 */
216
-	private static function requireAppFile($app) {
217
-		// encapsulated here to avoid variable scope conflicts
218
-		require_once $app . '/appinfo/app.php';
219
-	}
220
-
221
-	/**
222
-	 * check if an app is of a specific type
223
-	 *
224
-	 * @param string $app
225
-	 * @param string|array $types
226
-	 * @return bool
227
-	 */
228
-	public static function isType($app, $types) {
229
-		if (is_string($types)) {
230
-			$types = array($types);
231
-		}
232
-		$appTypes = self::getAppTypes($app);
233
-		foreach ($types as $type) {
234
-			if (array_search($type, $appTypes) !== false) {
235
-				return true;
236
-			}
237
-		}
238
-		return false;
239
-	}
240
-
241
-	/**
242
-	 * get the types of an app
243
-	 *
244
-	 * @param string $app
245
-	 * @return array
246
-	 */
247
-	private static function getAppTypes($app) {
248
-		//load the cache
249
-		if (count(self::$appTypes) == 0) {
250
-			self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
251
-		}
252
-
253
-		if (isset(self::$appTypes[$app])) {
254
-			return explode(',', self::$appTypes[$app]);
255
-		} else {
256
-			return array();
257
-		}
258
-	}
259
-
260
-	/**
261
-	 * read app types from info.xml and cache them in the database
262
-	 */
263
-	public static function setAppTypes($app) {
264
-		$appData = self::getAppInfo($app);
265
-		if(!is_array($appData)) {
266
-			return;
267
-		}
268
-
269
-		if (isset($appData['types'])) {
270
-			$appTypes = implode(',', $appData['types']);
271
-		} else {
272
-			$appTypes = '';
273
-			$appData['types'] = [];
274
-		}
275
-
276
-		\OC::$server->getAppConfig()->setValue($app, 'types', $appTypes);
277
-
278
-		if (\OC::$server->getAppManager()->hasProtectedAppType($appData['types'])) {
279
-			$enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'yes');
280
-			if ($enabled !== 'yes' && $enabled !== 'no') {
281
-				\OC::$server->getAppConfig()->setValue($app, 'enabled', 'yes');
282
-			}
283
-		}
284
-	}
285
-
286
-	/**
287
-	 * check if app is shipped
288
-	 *
289
-	 * @param string $appId the id of the app to check
290
-	 * @return bool
291
-	 *
292
-	 * Check if an app that is installed is a shipped app or installed from the appstore.
293
-	 */
294
-	public static function isShipped($appId) {
295
-		return \OC::$server->getAppManager()->isShipped($appId);
296
-	}
297
-
298
-	/**
299
-	 * get all enabled apps
300
-	 */
301
-	protected static $enabledAppsCache = array();
302
-
303
-	/**
304
-	 * Returns apps enabled for the current user.
305
-	 *
306
-	 * @param bool $forceRefresh whether to refresh the cache
307
-	 * @param bool $all whether to return apps for all users, not only the
308
-	 * currently logged in one
309
-	 * @return string[]
310
-	 */
311
-	public static function getEnabledApps($forceRefresh = false, $all = false) {
312
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
313
-			return array();
314
-		}
315
-		// in incognito mode or when logged out, $user will be false,
316
-		// which is also the case during an upgrade
317
-		$appManager = \OC::$server->getAppManager();
318
-		if ($all) {
319
-			$user = null;
320
-		} else {
321
-			$user = \OC::$server->getUserSession()->getUser();
322
-		}
323
-
324
-		if (is_null($user)) {
325
-			$apps = $appManager->getInstalledApps();
326
-		} else {
327
-			$apps = $appManager->getEnabledAppsForUser($user);
328
-		}
329
-		$apps = array_filter($apps, function ($app) {
330
-			return $app !== 'files';//we add this manually
331
-		});
332
-		sort($apps);
333
-		array_unshift($apps, 'files');
334
-		return $apps;
335
-	}
336
-
337
-	/**
338
-	 * checks whether or not an app is enabled
339
-	 *
340
-	 * @param string $app app
341
-	 * @return bool
342
-	 *
343
-	 * This function checks whether or not an app is enabled.
344
-	 */
345
-	public static function isEnabled($app) {
346
-		return \OC::$server->getAppManager()->isEnabledForUser($app);
347
-	}
348
-
349
-	/**
350
-	 * enables an app
351
-	 *
352
-	 * @param string $appId
353
-	 * @param array $groups (optional) when set, only these groups will have access to the app
354
-	 * @throws \Exception
355
-	 * @return void
356
-	 *
357
-	 * This function set an app as enabled in appconfig.
358
-	 */
359
-	public function enable($appId,
360
-						   $groups = null) {
361
-		self::$enabledAppsCache = []; // flush
362
-
363
-		// Check if app is already downloaded
364
-		$installer = new Installer(
365
-			\OC::$server->getAppFetcher(),
366
-			\OC::$server->getHTTPClientService(),
367
-			\OC::$server->getTempManager(),
368
-			\OC::$server->getLogger(),
369
-			\OC::$server->getConfig()
370
-		);
371
-		$isDownloaded = $installer->isDownloaded($appId);
372
-
373
-		if(!$isDownloaded) {
374
-			$installer->downloadApp($appId);
375
-		}
376
-
377
-		$installer->installApp($appId);
378
-
379
-		$appManager = \OC::$server->getAppManager();
380
-		if (!is_null($groups)) {
381
-			$groupManager = \OC::$server->getGroupManager();
382
-			$groupsList = [];
383
-			foreach ($groups as $group) {
384
-				$groupItem = $groupManager->get($group);
385
-				if ($groupItem instanceof \OCP\IGroup) {
386
-					$groupsList[] = $groupManager->get($group);
387
-				}
388
-			}
389
-			$appManager->enableAppForGroups($appId, $groupsList);
390
-		} else {
391
-			$appManager->enableApp($appId);
392
-		}
393
-	}
394
-
395
-	/**
396
-	 * @param string $app
397
-	 * @return bool
398
-	 */
399
-	public static function removeApp($app) {
400
-		if (self::isShipped($app)) {
401
-			return false;
402
-		}
403
-
404
-		$installer = new Installer(
405
-			\OC::$server->getAppFetcher(),
406
-			\OC::$server->getHTTPClientService(),
407
-			\OC::$server->getTempManager(),
408
-			\OC::$server->getLogger(),
409
-			\OC::$server->getConfig()
410
-		);
411
-		return $installer->removeApp($app);
412
-	}
413
-
414
-	/**
415
-	 * This function set an app as disabled in appconfig.
416
-	 *
417
-	 * @param string $app app
418
-	 * @throws Exception
419
-	 */
420
-	public static function disable($app) {
421
-		// flush
422
-		self::$enabledAppsCache = array();
423
-
424
-		// run uninstall steps
425
-		$appData = OC_App::getAppInfo($app);
426
-		if (!is_null($appData)) {
427
-			OC_App::executeRepairSteps($app, $appData['repair-steps']['uninstall']);
428
-		}
429
-
430
-		// emit disable hook - needed anymore ?
431
-		\OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
432
-
433
-		// finally disable it
434
-		$appManager = \OC::$server->getAppManager();
435
-		$appManager->disableApp($app);
436
-	}
437
-
438
-	// This is private as well. It simply works, so don't ask for more details
439
-	private static function proceedNavigation($list) {
440
-		usort($list, function($a, $b) {
441
-			if (isset($a['order']) && isset($b['order'])) {
442
-				return ($a['order'] < $b['order']) ? -1 : 1;
443
-			} else if (isset($a['order']) || isset($b['order'])) {
444
-				return isset($a['order']) ? -1 : 1;
445
-			} else {
446
-				return ($a['name'] < $b['name']) ? -1 : 1;
447
-			}
448
-		});
449
-
450
-		$activeApp = OC::$server->getNavigationManager()->getActiveEntry();
451
-		foreach ($list as $index => &$navEntry) {
452
-			if ($navEntry['id'] == $activeApp) {
453
-				$navEntry['active'] = true;
454
-			} else {
455
-				$navEntry['active'] = false;
456
-			}
457
-		}
458
-		unset($navEntry);
459
-
460
-		return $list;
461
-	}
462
-
463
-	/**
464
-	 * Get the path where to install apps
465
-	 *
466
-	 * @return string|false
467
-	 */
468
-	public static function getInstallPath() {
469
-		if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
470
-			return false;
471
-		}
472
-
473
-		foreach (OC::$APPSROOTS as $dir) {
474
-			if (isset($dir['writable']) && $dir['writable'] === true) {
475
-				return $dir['path'];
476
-			}
477
-		}
478
-
479
-		\OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
480
-		return null;
481
-	}
482
-
483
-
484
-	/**
485
-	 * search for an app in all app-directories
486
-	 *
487
-	 * @param string $appId
488
-	 * @return false|string
489
-	 */
490
-	public static function findAppInDirectories($appId) {
491
-		$sanitizedAppId = self::cleanAppId($appId);
492
-		if($sanitizedAppId !== $appId) {
493
-			return false;
494
-		}
495
-		static $app_dir = array();
496
-
497
-		if (isset($app_dir[$appId])) {
498
-			return $app_dir[$appId];
499
-		}
500
-
501
-		$possibleApps = array();
502
-		foreach (OC::$APPSROOTS as $dir) {
503
-			if (file_exists($dir['path'] . '/' . $appId)) {
504
-				$possibleApps[] = $dir;
505
-			}
506
-		}
507
-
508
-		if (empty($possibleApps)) {
509
-			return false;
510
-		} elseif (count($possibleApps) === 1) {
511
-			$dir = array_shift($possibleApps);
512
-			$app_dir[$appId] = $dir;
513
-			return $dir;
514
-		} else {
515
-			$versionToLoad = array();
516
-			foreach ($possibleApps as $possibleApp) {
517
-				$version = self::getAppVersionByPath($possibleApp['path']);
518
-				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
519
-					$versionToLoad = array(
520
-						'dir' => $possibleApp,
521
-						'version' => $version,
522
-					);
523
-				}
524
-			}
525
-			$app_dir[$appId] = $versionToLoad['dir'];
526
-			return $versionToLoad['dir'];
527
-			//TODO - write test
528
-		}
529
-	}
530
-
531
-	/**
532
-	 * Get the directory for the given app.
533
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
534
-	 *
535
-	 * @param string $appId
536
-	 * @return string|false
537
-	 */
538
-	public static function getAppPath($appId) {
539
-		if ($appId === null || trim($appId) === '') {
540
-			return false;
541
-		}
542
-
543
-		if (($dir = self::findAppInDirectories($appId)) != false) {
544
-			return $dir['path'] . '/' . $appId;
545
-		}
546
-		return false;
547
-	}
548
-
549
-	/**
550
-	 * Get the path for the given app on the access
551
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
552
-	 *
553
-	 * @param string $appId
554
-	 * @return string|false
555
-	 */
556
-	public static function getAppWebPath($appId) {
557
-		if (($dir = self::findAppInDirectories($appId)) != false) {
558
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
559
-		}
560
-		return false;
561
-	}
562
-
563
-	/**
564
-	 * get the last version of the app from appinfo/info.xml
565
-	 *
566
-	 * @param string $appId
567
-	 * @param bool $useCache
568
-	 * @return string
569
-	 */
570
-	public static function getAppVersion($appId, $useCache = true) {
571
-		if($useCache && isset(self::$appVersion[$appId])) {
572
-			return self::$appVersion[$appId];
573
-		}
574
-
575
-		$file = self::getAppPath($appId);
576
-		self::$appVersion[$appId] = ($file !== false) ? self::getAppVersionByPath($file) : '0';
577
-		return self::$appVersion[$appId];
578
-	}
579
-
580
-	/**
581
-	 * get app's version based on it's path
582
-	 *
583
-	 * @param string $path
584
-	 * @return string
585
-	 */
586
-	public static function getAppVersionByPath($path) {
587
-		$infoFile = $path . '/appinfo/info.xml';
588
-		$appData = self::getAppInfo($infoFile, true);
589
-		return isset($appData['version']) ? $appData['version'] : '';
590
-	}
591
-
592
-
593
-	/**
594
-	 * Read all app metadata from the info.xml file
595
-	 *
596
-	 * @param string $appId id of the app or the path of the info.xml file
597
-	 * @param bool $path
598
-	 * @param string $lang
599
-	 * @return array|null
600
-	 * @note all data is read from info.xml, not just pre-defined fields
601
-	 */
602
-	public static function getAppInfo($appId, $path = false, $lang = null) {
603
-		if ($path) {
604
-			$file = $appId;
605
-		} else {
606
-			if ($lang === null && isset(self::$appInfo[$appId])) {
607
-				return self::$appInfo[$appId];
608
-			}
609
-			$appPath = self::getAppPath($appId);
610
-			if($appPath === false) {
611
-				return null;
612
-			}
613
-			$file = $appPath . '/appinfo/info.xml';
614
-		}
615
-
616
-		$parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
617
-		$data = $parser->parse($file);
618
-
619
-		if (is_array($data)) {
620
-			$data = OC_App::parseAppInfo($data, $lang);
621
-		}
622
-		if(isset($data['ocsid'])) {
623
-			$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
624
-			if($storedId !== '' && $storedId !== $data['ocsid']) {
625
-				$data['ocsid'] = $storedId;
626
-			}
627
-		}
628
-
629
-		if ($lang === null) {
630
-			self::$appInfo[$appId] = $data;
631
-		}
632
-
633
-		return $data;
634
-	}
635
-
636
-	/**
637
-	 * Returns the navigation
638
-	 *
639
-	 * @return array
640
-	 *
641
-	 * This function returns an array containing all entries added. The
642
-	 * entries are sorted by the key 'order' ascending. Additional to the keys
643
-	 * given for each app the following keys exist:
644
-	 *   - active: boolean, signals if the user is on this navigation entry
645
-	 */
646
-	public static function getNavigation() {
647
-		$entries = OC::$server->getNavigationManager()->getAll();
648
-		return self::proceedNavigation($entries);
649
-	}
650
-
651
-	/**
652
-	 * Returns the Settings Navigation
653
-	 *
654
-	 * @return string[]
655
-	 *
656
-	 * This function returns an array containing all settings pages added. The
657
-	 * entries are sorted by the key 'order' ascending.
658
-	 */
659
-	public static function getSettingsNavigation() {
660
-		$entries = OC::$server->getNavigationManager()->getAll('settings');
661
-		return self::proceedNavigation($entries);
662
-	}
663
-
664
-	/**
665
-	 * get the id of loaded app
666
-	 *
667
-	 * @return string
668
-	 */
669
-	public static function getCurrentApp() {
670
-		$request = \OC::$server->getRequest();
671
-		$script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
672
-		$topFolder = substr($script, 0, strpos($script, '/'));
673
-		if (empty($topFolder)) {
674
-			$path_info = $request->getPathInfo();
675
-			if ($path_info) {
676
-				$topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
677
-			}
678
-		}
679
-		if ($topFolder == 'apps') {
680
-			$length = strlen($topFolder);
681
-			return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
682
-		} else {
683
-			return $topFolder;
684
-		}
685
-	}
686
-
687
-	/**
688
-	 * @param string $type
689
-	 * @return array
690
-	 */
691
-	public static function getForms($type) {
692
-		$forms = array();
693
-		switch ($type) {
694
-			case 'admin':
695
-				$source = self::$adminForms;
696
-				break;
697
-			case 'personal':
698
-				$source = self::$personalForms;
699
-				break;
700
-			default:
701
-				return array();
702
-		}
703
-		foreach ($source as $form) {
704
-			$forms[] = include $form;
705
-		}
706
-		return $forms;
707
-	}
708
-
709
-	/**
710
-	 * register an admin form to be shown
711
-	 *
712
-	 * @param string $app
713
-	 * @param string $page
714
-	 */
715
-	public static function registerAdmin($app, $page) {
716
-		self::$adminForms[] = $app . '/' . $page . '.php';
717
-	}
718
-
719
-	/**
720
-	 * register a personal form to be shown
721
-	 * @param string $app
722
-	 * @param string $page
723
-	 */
724
-	public static function registerPersonal($app, $page) {
725
-		self::$personalForms[] = $app . '/' . $page . '.php';
726
-	}
727
-
728
-	/**
729
-	 * @param array $entry
730
-	 */
731
-	public static function registerLogIn(array $entry) {
732
-		self::$altLogin[] = $entry;
733
-	}
734
-
735
-	/**
736
-	 * @return array
737
-	 */
738
-	public static function getAlternativeLogIns() {
739
-		return self::$altLogin;
740
-	}
741
-
742
-	/**
743
-	 * get a list of all apps in the apps folder
744
-	 *
745
-	 * @return array an array of app names (string IDs)
746
-	 * @todo: change the name of this method to getInstalledApps, which is more accurate
747
-	 */
748
-	public static function getAllApps() {
749
-
750
-		$apps = array();
751
-
752
-		foreach (OC::$APPSROOTS as $apps_dir) {
753
-			if (!is_readable($apps_dir['path'])) {
754
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
755
-				continue;
756
-			}
757
-			$dh = opendir($apps_dir['path']);
758
-
759
-			if (is_resource($dh)) {
760
-				while (($file = readdir($dh)) !== false) {
761
-
762
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
763
-
764
-						$apps[] = $file;
765
-					}
766
-				}
767
-			}
768
-		}
769
-
770
-		return $apps;
771
-	}
772
-
773
-	/**
774
-	 * List all apps, this is used in apps.php
775
-	 *
776
-	 * @return array
777
-	 */
778
-	public function listAllApps() {
779
-		$installedApps = OC_App::getAllApps();
780
-
781
-		//we don't want to show configuration for these
782
-		$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
783
-		$appList = array();
784
-		$langCode = \OC::$server->getL10N('core')->getLanguageCode();
785
-		$urlGenerator = \OC::$server->getURLGenerator();
786
-
787
-		foreach ($installedApps as $app) {
788
-			if (array_search($app, $blacklist) === false) {
789
-
790
-				$info = OC_App::getAppInfo($app, false, $langCode);
791
-				if (!is_array($info)) {
792
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
793
-					continue;
794
-				}
795
-
796
-				if (!isset($info['name'])) {
797
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
798
-					continue;
799
-				}
800
-
801
-				$enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'no');
802
-				$info['groups'] = null;
803
-				if ($enabled === 'yes') {
804
-					$active = true;
805
-				} else if ($enabled === 'no') {
806
-					$active = false;
807
-				} else {
808
-					$active = true;
809
-					$info['groups'] = $enabled;
810
-				}
811
-
812
-				$info['active'] = $active;
813
-
814
-				if (self::isShipped($app)) {
815
-					$info['internal'] = true;
816
-					$info['level'] = self::officialApp;
817
-					$info['removable'] = false;
818
-				} else {
819
-					$info['internal'] = false;
820
-					$info['removable'] = true;
821
-				}
822
-
823
-				$appPath = self::getAppPath($app);
824
-				if($appPath !== false) {
825
-					$appIcon = $appPath . '/img/' . $app . '.svg';
826
-					if (file_exists($appIcon)) {
827
-						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
828
-						$info['previewAsIcon'] = true;
829
-					} else {
830
-						$appIcon = $appPath . '/img/app.svg';
831
-						if (file_exists($appIcon)) {
832
-							$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
833
-							$info['previewAsIcon'] = true;
834
-						}
835
-					}
836
-				}
837
-				// fix documentation
838
-				if (isset($info['documentation']) && is_array($info['documentation'])) {
839
-					foreach ($info['documentation'] as $key => $url) {
840
-						// If it is not an absolute URL we assume it is a key
841
-						// i.e. admin-ldap will get converted to go.php?to=admin-ldap
842
-						if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
843
-							$url = $urlGenerator->linkToDocs($url);
844
-						}
845
-
846
-						$info['documentation'][$key] = $url;
847
-					}
848
-				}
849
-
850
-				$info['version'] = OC_App::getAppVersion($app);
851
-				$appList[] = $info;
852
-			}
853
-		}
854
-
855
-		return $appList;
856
-	}
857
-
858
-	/**
859
-	 * Returns the internal app ID or false
860
-	 * @param string $ocsID
861
-	 * @return string|false
862
-	 */
863
-	public static function getInternalAppIdByOcs($ocsID) {
864
-		if(is_numeric($ocsID)) {
865
-			$idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
866
-			if(array_search($ocsID, $idArray)) {
867
-				return array_search($ocsID, $idArray);
868
-			}
869
-		}
870
-		return false;
871
-	}
872
-
873
-	public static function shouldUpgrade($app) {
874
-		$versions = self::getAppVersions();
875
-		$currentVersion = OC_App::getAppVersion($app);
876
-		if ($currentVersion && isset($versions[$app])) {
877
-			$installedVersion = $versions[$app];
878
-			if (!version_compare($currentVersion, $installedVersion, '=')) {
879
-				return true;
880
-			}
881
-		}
882
-		return false;
883
-	}
884
-
885
-	/**
886
-	 * Adjust the number of version parts of $version1 to match
887
-	 * the number of version parts of $version2.
888
-	 *
889
-	 * @param string $version1 version to adjust
890
-	 * @param string $version2 version to take the number of parts from
891
-	 * @return string shortened $version1
892
-	 */
893
-	private static function adjustVersionParts($version1, $version2) {
894
-		$version1 = explode('.', $version1);
895
-		$version2 = explode('.', $version2);
896
-		// reduce $version1 to match the number of parts in $version2
897
-		while (count($version1) > count($version2)) {
898
-			array_pop($version1);
899
-		}
900
-		// if $version1 does not have enough parts, add some
901
-		while (count($version1) < count($version2)) {
902
-			$version1[] = '0';
903
-		}
904
-		return implode('.', $version1);
905
-	}
906
-
907
-	/**
908
-	 * Check whether the current ownCloud version matches the given
909
-	 * application's version requirements.
910
-	 *
911
-	 * The comparison is made based on the number of parts that the
912
-	 * app info version has. For example for ownCloud 6.0.3 if the
913
-	 * app info version is expecting version 6.0, the comparison is
914
-	 * made on the first two parts of the ownCloud version.
915
-	 * This means that it's possible to specify "requiremin" => 6
916
-	 * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
917
-	 *
918
-	 * @param string $ocVersion ownCloud version to check against
919
-	 * @param array $appInfo app info (from xml)
920
-	 *
921
-	 * @return boolean true if compatible, otherwise false
922
-	 */
923
-	public static function isAppCompatible($ocVersion, $appInfo) {
924
-		$requireMin = '';
925
-		$requireMax = '';
926
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
927
-			$requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
928
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
929
-			$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
930
-		} else if (isset($appInfo['requiremin'])) {
931
-			$requireMin = $appInfo['requiremin'];
932
-		} else if (isset($appInfo['require'])) {
933
-			$requireMin = $appInfo['require'];
934
-		}
935
-
936
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
937
-			$requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
938
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
939
-			$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
940
-		} else if (isset($appInfo['requiremax'])) {
941
-			$requireMax = $appInfo['requiremax'];
942
-		}
943
-
944
-		if (is_array($ocVersion)) {
945
-			$ocVersion = implode('.', $ocVersion);
946
-		}
947
-
948
-		if (!empty($requireMin)
949
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
950
-		) {
951
-
952
-			return false;
953
-		}
954
-
955
-		if (!empty($requireMax)
956
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
957
-		) {
958
-			return false;
959
-		}
960
-
961
-		return true;
962
-	}
963
-
964
-	/**
965
-	 * get the installed version of all apps
966
-	 */
967
-	public static function getAppVersions() {
968
-		static $versions;
969
-
970
-		if(!$versions) {
971
-			$appConfig = \OC::$server->getAppConfig();
972
-			$versions = $appConfig->getValues(false, 'installed_version');
973
-		}
974
-		return $versions;
975
-	}
976
-
977
-	/**
978
-	 * @param string $app
979
-	 * @param \OCP\IConfig $config
980
-	 * @param \OCP\IL10N $l
981
-	 * @return bool
982
-	 *
983
-	 * @throws Exception if app is not compatible with this version of ownCloud
984
-	 * @throws Exception if no app-name was specified
985
-	 */
986
-	public function installApp($app,
987
-							   \OCP\IConfig $config,
988
-							   \OCP\IL10N $l) {
989
-		if ($app !== false) {
990
-			// check if the app is compatible with this version of ownCloud
991
-			$info = self::getAppInfo($app);
992
-			if(!is_array($info)) {
993
-				throw new \Exception(
994
-					$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
995
-						[$info['name']]
996
-					)
997
-				);
998
-			}
999
-
1000
-			$version = \OCP\Util::getVersion();
1001
-			if (!self::isAppCompatible($version, $info)) {
1002
-				throw new \Exception(
1003
-					$l->t('App "%s" cannot be installed because it is not compatible with this version of the server.',
1004
-						array($info['name'])
1005
-					)
1006
-				);
1007
-			}
1008
-
1009
-			// check for required dependencies
1010
-			self::checkAppDependencies($config, $l, $info);
1011
-
1012
-			$config->setAppValue($app, 'enabled', 'yes');
1013
-			if (isset($appData['id'])) {
1014
-				$config->setAppValue($app, 'ocsid', $appData['id']);
1015
-			}
1016
-
1017
-			if(isset($info['settings']) && is_array($info['settings'])) {
1018
-				$appPath = self::getAppPath($app);
1019
-				self::registerAutoloading($app, $appPath);
1020
-				\OC::$server->getSettingsManager()->setupSettings($info['settings']);
1021
-			}
1022
-
1023
-			\OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1024
-		} else {
1025
-			if(empty($appName) ) {
1026
-				throw new \Exception($l->t("No app name specified"));
1027
-			} else {
1028
-				throw new \Exception($l->t("App '%s' could not be installed!", $appName));
1029
-			}
1030
-		}
1031
-
1032
-		return $app;
1033
-	}
1034
-
1035
-	/**
1036
-	 * update the database for the app and call the update script
1037
-	 *
1038
-	 * @param string $appId
1039
-	 * @return bool
1040
-	 */
1041
-	public static function updateApp($appId) {
1042
-		$appPath = self::getAppPath($appId);
1043
-		if($appPath === false) {
1044
-			return false;
1045
-		}
1046
-		$appData = self::getAppInfo($appId);
1047
-		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1048
-		if (file_exists($appPath . '/appinfo/database.xml')) {
1049
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1050
-		}
1051
-		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1052
-		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1053
-		unset(self::$appVersion[$appId]);
1054
-		// run upgrade code
1055
-		if (file_exists($appPath . '/appinfo/update.php')) {
1056
-			self::loadApp($appId);
1057
-			include $appPath . '/appinfo/update.php';
1058
-		}
1059
-		self::registerAutoloading($appId, $appPath);
1060
-		self::setupBackgroundJobs($appData['background-jobs']);
1061
-		if(isset($appData['settings']) && is_array($appData['settings'])) {
1062
-			\OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1063
-		}
1064
-
1065
-		//set remote/public handlers
1066
-		if (array_key_exists('ocsid', $appData)) {
1067
-			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1068
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1069
-			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1070
-		}
1071
-		foreach ($appData['remote'] as $name => $path) {
1072
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1073
-		}
1074
-		foreach ($appData['public'] as $name => $path) {
1075
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1076
-		}
1077
-
1078
-		self::setAppTypes($appId);
1079
-
1080
-		$version = \OC_App::getAppVersion($appId);
1081
-		\OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
1082
-
1083
-		\OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
1084
-			ManagerEvent::EVENT_APP_UPDATE, $appId
1085
-		));
1086
-
1087
-		return true;
1088
-	}
1089
-
1090
-	/**
1091
-	 * @param string $appId
1092
-	 * @param string[] $steps
1093
-	 * @throws \OC\NeedsUpdateException
1094
-	 */
1095
-	public static function executeRepairSteps($appId, array $steps) {
1096
-		if (empty($steps)) {
1097
-			return;
1098
-		}
1099
-		// load the app
1100
-		self::loadApp($appId);
1101
-
1102
-		$dispatcher = OC::$server->getEventDispatcher();
1103
-
1104
-		// load the steps
1105
-		$r = new Repair([], $dispatcher);
1106
-		foreach ($steps as $step) {
1107
-			try {
1108
-				$r->addStep($step);
1109
-			} catch (Exception $ex) {
1110
-				$r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1111
-				\OC::$server->getLogger()->logException($ex);
1112
-			}
1113
-		}
1114
-		// run the steps
1115
-		$r->run();
1116
-	}
1117
-
1118
-	public static function setupBackgroundJobs(array $jobs) {
1119
-		$queue = \OC::$server->getJobList();
1120
-		foreach ($jobs as $job) {
1121
-			$queue->add($job);
1122
-		}
1123
-	}
1124
-
1125
-	/**
1126
-	 * @param string $appId
1127
-	 * @param string[] $steps
1128
-	 */
1129
-	private static function setupLiveMigrations($appId, array $steps) {
1130
-		$queue = \OC::$server->getJobList();
1131
-		foreach ($steps as $step) {
1132
-			$queue->add('OC\Migration\BackgroundRepair', [
1133
-				'app' => $appId,
1134
-				'step' => $step]);
1135
-		}
1136
-	}
1137
-
1138
-	/**
1139
-	 * @param string $appId
1140
-	 * @return \OC\Files\View|false
1141
-	 */
1142
-	public static function getStorage($appId) {
1143
-		if (OC_App::isEnabled($appId)) { //sanity check
1144
-			if (\OC::$server->getUserSession()->isLoggedIn()) {
1145
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1146
-				if (!$view->file_exists($appId)) {
1147
-					$view->mkdir($appId);
1148
-				}
1149
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1150
-			} else {
1151
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1152
-				return false;
1153
-			}
1154
-		} else {
1155
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1156
-			return false;
1157
-		}
1158
-	}
1159
-
1160
-	protected static function findBestL10NOption($options, $lang) {
1161
-		$fallback = $similarLangFallback = $englishFallback = false;
1162
-
1163
-		$lang = strtolower($lang);
1164
-		$similarLang = $lang;
1165
-		if (strpos($similarLang, '_')) {
1166
-			// For "de_DE" we want to find "de" and the other way around
1167
-			$similarLang = substr($lang, 0, strpos($lang, '_'));
1168
-		}
1169
-
1170
-		foreach ($options as $option) {
1171
-			if (is_array($option)) {
1172
-				if ($fallback === false) {
1173
-					$fallback = $option['@value'];
1174
-				}
1175
-
1176
-				if (!isset($option['@attributes']['lang'])) {
1177
-					continue;
1178
-				}
1179
-
1180
-				$attributeLang = strtolower($option['@attributes']['lang']);
1181
-				if ($attributeLang === $lang) {
1182
-					return $option['@value'];
1183
-				}
1184
-
1185
-				if ($attributeLang === $similarLang) {
1186
-					$similarLangFallback = $option['@value'];
1187
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1188
-					if ($similarLangFallback === false) {
1189
-						$similarLangFallback =  $option['@value'];
1190
-					}
1191
-				}
1192
-			} else {
1193
-				$englishFallback = $option;
1194
-			}
1195
-		}
1196
-
1197
-		if ($similarLangFallback !== false) {
1198
-			return $similarLangFallback;
1199
-		} else if ($englishFallback !== false) {
1200
-			return $englishFallback;
1201
-		}
1202
-		return (string) $fallback;
1203
-	}
1204
-
1205
-	/**
1206
-	 * parses the app data array and enhanced the 'description' value
1207
-	 *
1208
-	 * @param array $data the app data
1209
-	 * @param string $lang
1210
-	 * @return array improved app data
1211
-	 */
1212
-	public static function parseAppInfo(array $data, $lang = null) {
1213
-
1214
-		if ($lang && isset($data['name']) && is_array($data['name'])) {
1215
-			$data['name'] = self::findBestL10NOption($data['name'], $lang);
1216
-		}
1217
-		if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1218
-			$data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1219
-		}
1220
-		if ($lang && isset($data['description']) && is_array($data['description'])) {
1221
-			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1222
-		} else if (isset($data['description']) && is_string($data['description'])) {
1223
-			$data['description'] = trim($data['description']);
1224
-		} else  {
1225
-			$data['description'] = '';
1226
-		}
1227
-
1228
-		return $data;
1229
-	}
1230
-
1231
-	/**
1232
-	 * @param \OCP\IConfig $config
1233
-	 * @param \OCP\IL10N $l
1234
-	 * @param array $info
1235
-	 * @throws \Exception
1236
-	 */
1237
-	public static function checkAppDependencies($config, $l, $info) {
1238
-		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1239
-		$missing = $dependencyAnalyzer->analyze($info);
1240
-		if (!empty($missing)) {
1241
-			$missingMsg = join(PHP_EOL, $missing);
1242
-			throw new \Exception(
1243
-				$l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1244
-					[$info['name'], $missingMsg]
1245
-				)
1246
-			);
1247
-		}
1248
-	}
63
+    static private $appVersion = [];
64
+    static private $adminForms = array();
65
+    static private $personalForms = array();
66
+    static private $appInfo = array();
67
+    static private $appTypes = array();
68
+    static private $loadedApps = array();
69
+    static private $altLogin = array();
70
+    static private $alreadyRegistered = [];
71
+    const officialApp = 200;
72
+
73
+    /**
74
+     * clean the appId
75
+     *
76
+     * @param string|boolean $app AppId that needs to be cleaned
77
+     * @return string
78
+     */
79
+    public static function cleanAppId($app) {
80
+        return str_replace(array('\0', '/', '\\', '..'), '', $app);
81
+    }
82
+
83
+    /**
84
+     * Check if an app is loaded
85
+     *
86
+     * @param string $app
87
+     * @return bool
88
+     */
89
+    public static function isAppLoaded($app) {
90
+        return in_array($app, self::$loadedApps, true);
91
+    }
92
+
93
+    /**
94
+     * loads all apps
95
+     *
96
+     * @param string[] | string | null $types
97
+     * @return bool
98
+     *
99
+     * This function walks through the ownCloud directory and loads all apps
100
+     * it can find. A directory contains an app if the file /appinfo/info.xml
101
+     * exists.
102
+     *
103
+     * if $types is set, only apps of those types will be loaded
104
+     */
105
+    public static function loadApps($types = null) {
106
+        if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
107
+            return false;
108
+        }
109
+        // Load the enabled apps here
110
+        $apps = self::getEnabledApps();
111
+
112
+        // Add each apps' folder as allowed class path
113
+        foreach($apps as $app) {
114
+            $path = self::getAppPath($app);
115
+            if($path !== false) {
116
+                self::registerAutoloading($app, $path);
117
+            }
118
+        }
119
+
120
+        // prevent app.php from printing output
121
+        ob_start();
122
+        foreach ($apps as $app) {
123
+            if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
124
+                self::loadApp($app);
125
+            }
126
+        }
127
+        ob_end_clean();
128
+
129
+        return true;
130
+    }
131
+
132
+    /**
133
+     * load a single app
134
+     *
135
+     * @param string $app
136
+     * @throws Exception
137
+     */
138
+    public static function loadApp($app) {
139
+        self::$loadedApps[] = $app;
140
+        $appPath = self::getAppPath($app);
141
+        if($appPath === false) {
142
+            return;
143
+        }
144
+
145
+        // in case someone calls loadApp() directly
146
+        self::registerAutoloading($app, $appPath);
147
+
148
+        if (is_file($appPath . '/appinfo/app.php')) {
149
+            \OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
150
+            try {
151
+                self::requireAppFile($app);
152
+            } catch (Error $ex) {
153
+                \OC::$server->getLogger()->logException($ex);
154
+                if (!\OC::$server->getAppManager()->isShipped($app)) {
155
+                    // Only disable apps which are not shipped
156
+                    self::disable($app);
157
+                }
158
+            }
159
+            if (self::isType($app, array('authentication'))) {
160
+                // since authentication apps affect the "is app enabled for group" check,
161
+                // the enabled apps cache needs to be cleared to make sure that the
162
+                // next time getEnableApps() is called it will also include apps that were
163
+                // enabled for groups
164
+                self::$enabledAppsCache = array();
165
+            }
166
+            \OC::$server->getEventLogger()->end('load_app_' . $app);
167
+        }
168
+
169
+        $info = self::getAppInfo($app);
170
+        if (!empty($info['activity']['filters'])) {
171
+            foreach ($info['activity']['filters'] as $filter) {
172
+                \OC::$server->getActivityManager()->registerFilter($filter);
173
+            }
174
+        }
175
+        if (!empty($info['activity']['settings'])) {
176
+            foreach ($info['activity']['settings'] as $setting) {
177
+                \OC::$server->getActivityManager()->registerSetting($setting);
178
+            }
179
+        }
180
+        if (!empty($info['activity']['providers'])) {
181
+            foreach ($info['activity']['providers'] as $provider) {
182
+                \OC::$server->getActivityManager()->registerProvider($provider);
183
+            }
184
+        }
185
+    }
186
+
187
+    /**
188
+     * @internal
189
+     * @param string $app
190
+     * @param string $path
191
+     */
192
+    public static function registerAutoloading($app, $path) {
193
+        $key = $app . '-' . $path;
194
+        if(isset(self::$alreadyRegistered[$key])) {
195
+            return;
196
+        }
197
+        self::$alreadyRegistered[$key] = true;
198
+        // Register on PSR-4 composer autoloader
199
+        $appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
200
+        \OC::$server->registerNamespace($app, $appNamespace);
201
+        \OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
202
+        if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
203
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
204
+        }
205
+
206
+        // Register on legacy autoloader
207
+        \OC::$loader->addValidRoot($path);
208
+    }
209
+
210
+    /**
211
+     * Load app.php from the given app
212
+     *
213
+     * @param string $app app name
214
+     * @throws Error
215
+     */
216
+    private static function requireAppFile($app) {
217
+        // encapsulated here to avoid variable scope conflicts
218
+        require_once $app . '/appinfo/app.php';
219
+    }
220
+
221
+    /**
222
+     * check if an app is of a specific type
223
+     *
224
+     * @param string $app
225
+     * @param string|array $types
226
+     * @return bool
227
+     */
228
+    public static function isType($app, $types) {
229
+        if (is_string($types)) {
230
+            $types = array($types);
231
+        }
232
+        $appTypes = self::getAppTypes($app);
233
+        foreach ($types as $type) {
234
+            if (array_search($type, $appTypes) !== false) {
235
+                return true;
236
+            }
237
+        }
238
+        return false;
239
+    }
240
+
241
+    /**
242
+     * get the types of an app
243
+     *
244
+     * @param string $app
245
+     * @return array
246
+     */
247
+    private static function getAppTypes($app) {
248
+        //load the cache
249
+        if (count(self::$appTypes) == 0) {
250
+            self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
251
+        }
252
+
253
+        if (isset(self::$appTypes[$app])) {
254
+            return explode(',', self::$appTypes[$app]);
255
+        } else {
256
+            return array();
257
+        }
258
+    }
259
+
260
+    /**
261
+     * read app types from info.xml and cache them in the database
262
+     */
263
+    public static function setAppTypes($app) {
264
+        $appData = self::getAppInfo($app);
265
+        if(!is_array($appData)) {
266
+            return;
267
+        }
268
+
269
+        if (isset($appData['types'])) {
270
+            $appTypes = implode(',', $appData['types']);
271
+        } else {
272
+            $appTypes = '';
273
+            $appData['types'] = [];
274
+        }
275
+
276
+        \OC::$server->getAppConfig()->setValue($app, 'types', $appTypes);
277
+
278
+        if (\OC::$server->getAppManager()->hasProtectedAppType($appData['types'])) {
279
+            $enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'yes');
280
+            if ($enabled !== 'yes' && $enabled !== 'no') {
281
+                \OC::$server->getAppConfig()->setValue($app, 'enabled', 'yes');
282
+            }
283
+        }
284
+    }
285
+
286
+    /**
287
+     * check if app is shipped
288
+     *
289
+     * @param string $appId the id of the app to check
290
+     * @return bool
291
+     *
292
+     * Check if an app that is installed is a shipped app or installed from the appstore.
293
+     */
294
+    public static function isShipped($appId) {
295
+        return \OC::$server->getAppManager()->isShipped($appId);
296
+    }
297
+
298
+    /**
299
+     * get all enabled apps
300
+     */
301
+    protected static $enabledAppsCache = array();
302
+
303
+    /**
304
+     * Returns apps enabled for the current user.
305
+     *
306
+     * @param bool $forceRefresh whether to refresh the cache
307
+     * @param bool $all whether to return apps for all users, not only the
308
+     * currently logged in one
309
+     * @return string[]
310
+     */
311
+    public static function getEnabledApps($forceRefresh = false, $all = false) {
312
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
313
+            return array();
314
+        }
315
+        // in incognito mode or when logged out, $user will be false,
316
+        // which is also the case during an upgrade
317
+        $appManager = \OC::$server->getAppManager();
318
+        if ($all) {
319
+            $user = null;
320
+        } else {
321
+            $user = \OC::$server->getUserSession()->getUser();
322
+        }
323
+
324
+        if (is_null($user)) {
325
+            $apps = $appManager->getInstalledApps();
326
+        } else {
327
+            $apps = $appManager->getEnabledAppsForUser($user);
328
+        }
329
+        $apps = array_filter($apps, function ($app) {
330
+            return $app !== 'files';//we add this manually
331
+        });
332
+        sort($apps);
333
+        array_unshift($apps, 'files');
334
+        return $apps;
335
+    }
336
+
337
+    /**
338
+     * checks whether or not an app is enabled
339
+     *
340
+     * @param string $app app
341
+     * @return bool
342
+     *
343
+     * This function checks whether or not an app is enabled.
344
+     */
345
+    public static function isEnabled($app) {
346
+        return \OC::$server->getAppManager()->isEnabledForUser($app);
347
+    }
348
+
349
+    /**
350
+     * enables an app
351
+     *
352
+     * @param string $appId
353
+     * @param array $groups (optional) when set, only these groups will have access to the app
354
+     * @throws \Exception
355
+     * @return void
356
+     *
357
+     * This function set an app as enabled in appconfig.
358
+     */
359
+    public function enable($appId,
360
+                            $groups = null) {
361
+        self::$enabledAppsCache = []; // flush
362
+
363
+        // Check if app is already downloaded
364
+        $installer = new Installer(
365
+            \OC::$server->getAppFetcher(),
366
+            \OC::$server->getHTTPClientService(),
367
+            \OC::$server->getTempManager(),
368
+            \OC::$server->getLogger(),
369
+            \OC::$server->getConfig()
370
+        );
371
+        $isDownloaded = $installer->isDownloaded($appId);
372
+
373
+        if(!$isDownloaded) {
374
+            $installer->downloadApp($appId);
375
+        }
376
+
377
+        $installer->installApp($appId);
378
+
379
+        $appManager = \OC::$server->getAppManager();
380
+        if (!is_null($groups)) {
381
+            $groupManager = \OC::$server->getGroupManager();
382
+            $groupsList = [];
383
+            foreach ($groups as $group) {
384
+                $groupItem = $groupManager->get($group);
385
+                if ($groupItem instanceof \OCP\IGroup) {
386
+                    $groupsList[] = $groupManager->get($group);
387
+                }
388
+            }
389
+            $appManager->enableAppForGroups($appId, $groupsList);
390
+        } else {
391
+            $appManager->enableApp($appId);
392
+        }
393
+    }
394
+
395
+    /**
396
+     * @param string $app
397
+     * @return bool
398
+     */
399
+    public static function removeApp($app) {
400
+        if (self::isShipped($app)) {
401
+            return false;
402
+        }
403
+
404
+        $installer = new Installer(
405
+            \OC::$server->getAppFetcher(),
406
+            \OC::$server->getHTTPClientService(),
407
+            \OC::$server->getTempManager(),
408
+            \OC::$server->getLogger(),
409
+            \OC::$server->getConfig()
410
+        );
411
+        return $installer->removeApp($app);
412
+    }
413
+
414
+    /**
415
+     * This function set an app as disabled in appconfig.
416
+     *
417
+     * @param string $app app
418
+     * @throws Exception
419
+     */
420
+    public static function disable($app) {
421
+        // flush
422
+        self::$enabledAppsCache = array();
423
+
424
+        // run uninstall steps
425
+        $appData = OC_App::getAppInfo($app);
426
+        if (!is_null($appData)) {
427
+            OC_App::executeRepairSteps($app, $appData['repair-steps']['uninstall']);
428
+        }
429
+
430
+        // emit disable hook - needed anymore ?
431
+        \OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
432
+
433
+        // finally disable it
434
+        $appManager = \OC::$server->getAppManager();
435
+        $appManager->disableApp($app);
436
+    }
437
+
438
+    // This is private as well. It simply works, so don't ask for more details
439
+    private static function proceedNavigation($list) {
440
+        usort($list, function($a, $b) {
441
+            if (isset($a['order']) && isset($b['order'])) {
442
+                return ($a['order'] < $b['order']) ? -1 : 1;
443
+            } else if (isset($a['order']) || isset($b['order'])) {
444
+                return isset($a['order']) ? -1 : 1;
445
+            } else {
446
+                return ($a['name'] < $b['name']) ? -1 : 1;
447
+            }
448
+        });
449
+
450
+        $activeApp = OC::$server->getNavigationManager()->getActiveEntry();
451
+        foreach ($list as $index => &$navEntry) {
452
+            if ($navEntry['id'] == $activeApp) {
453
+                $navEntry['active'] = true;
454
+            } else {
455
+                $navEntry['active'] = false;
456
+            }
457
+        }
458
+        unset($navEntry);
459
+
460
+        return $list;
461
+    }
462
+
463
+    /**
464
+     * Get the path where to install apps
465
+     *
466
+     * @return string|false
467
+     */
468
+    public static function getInstallPath() {
469
+        if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
470
+            return false;
471
+        }
472
+
473
+        foreach (OC::$APPSROOTS as $dir) {
474
+            if (isset($dir['writable']) && $dir['writable'] === true) {
475
+                return $dir['path'];
476
+            }
477
+        }
478
+
479
+        \OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
480
+        return null;
481
+    }
482
+
483
+
484
+    /**
485
+     * search for an app in all app-directories
486
+     *
487
+     * @param string $appId
488
+     * @return false|string
489
+     */
490
+    public static function findAppInDirectories($appId) {
491
+        $sanitizedAppId = self::cleanAppId($appId);
492
+        if($sanitizedAppId !== $appId) {
493
+            return false;
494
+        }
495
+        static $app_dir = array();
496
+
497
+        if (isset($app_dir[$appId])) {
498
+            return $app_dir[$appId];
499
+        }
500
+
501
+        $possibleApps = array();
502
+        foreach (OC::$APPSROOTS as $dir) {
503
+            if (file_exists($dir['path'] . '/' . $appId)) {
504
+                $possibleApps[] = $dir;
505
+            }
506
+        }
507
+
508
+        if (empty($possibleApps)) {
509
+            return false;
510
+        } elseif (count($possibleApps) === 1) {
511
+            $dir = array_shift($possibleApps);
512
+            $app_dir[$appId] = $dir;
513
+            return $dir;
514
+        } else {
515
+            $versionToLoad = array();
516
+            foreach ($possibleApps as $possibleApp) {
517
+                $version = self::getAppVersionByPath($possibleApp['path']);
518
+                if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
519
+                    $versionToLoad = array(
520
+                        'dir' => $possibleApp,
521
+                        'version' => $version,
522
+                    );
523
+                }
524
+            }
525
+            $app_dir[$appId] = $versionToLoad['dir'];
526
+            return $versionToLoad['dir'];
527
+            //TODO - write test
528
+        }
529
+    }
530
+
531
+    /**
532
+     * Get the directory for the given app.
533
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
534
+     *
535
+     * @param string $appId
536
+     * @return string|false
537
+     */
538
+    public static function getAppPath($appId) {
539
+        if ($appId === null || trim($appId) === '') {
540
+            return false;
541
+        }
542
+
543
+        if (($dir = self::findAppInDirectories($appId)) != false) {
544
+            return $dir['path'] . '/' . $appId;
545
+        }
546
+        return false;
547
+    }
548
+
549
+    /**
550
+     * Get the path for the given app on the access
551
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
552
+     *
553
+     * @param string $appId
554
+     * @return string|false
555
+     */
556
+    public static function getAppWebPath($appId) {
557
+        if (($dir = self::findAppInDirectories($appId)) != false) {
558
+            return OC::$WEBROOT . $dir['url'] . '/' . $appId;
559
+        }
560
+        return false;
561
+    }
562
+
563
+    /**
564
+     * get the last version of the app from appinfo/info.xml
565
+     *
566
+     * @param string $appId
567
+     * @param bool $useCache
568
+     * @return string
569
+     */
570
+    public static function getAppVersion($appId, $useCache = true) {
571
+        if($useCache && isset(self::$appVersion[$appId])) {
572
+            return self::$appVersion[$appId];
573
+        }
574
+
575
+        $file = self::getAppPath($appId);
576
+        self::$appVersion[$appId] = ($file !== false) ? self::getAppVersionByPath($file) : '0';
577
+        return self::$appVersion[$appId];
578
+    }
579
+
580
+    /**
581
+     * get app's version based on it's path
582
+     *
583
+     * @param string $path
584
+     * @return string
585
+     */
586
+    public static function getAppVersionByPath($path) {
587
+        $infoFile = $path . '/appinfo/info.xml';
588
+        $appData = self::getAppInfo($infoFile, true);
589
+        return isset($appData['version']) ? $appData['version'] : '';
590
+    }
591
+
592
+
593
+    /**
594
+     * Read all app metadata from the info.xml file
595
+     *
596
+     * @param string $appId id of the app or the path of the info.xml file
597
+     * @param bool $path
598
+     * @param string $lang
599
+     * @return array|null
600
+     * @note all data is read from info.xml, not just pre-defined fields
601
+     */
602
+    public static function getAppInfo($appId, $path = false, $lang = null) {
603
+        if ($path) {
604
+            $file = $appId;
605
+        } else {
606
+            if ($lang === null && isset(self::$appInfo[$appId])) {
607
+                return self::$appInfo[$appId];
608
+            }
609
+            $appPath = self::getAppPath($appId);
610
+            if($appPath === false) {
611
+                return null;
612
+            }
613
+            $file = $appPath . '/appinfo/info.xml';
614
+        }
615
+
616
+        $parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
617
+        $data = $parser->parse($file);
618
+
619
+        if (is_array($data)) {
620
+            $data = OC_App::parseAppInfo($data, $lang);
621
+        }
622
+        if(isset($data['ocsid'])) {
623
+            $storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
624
+            if($storedId !== '' && $storedId !== $data['ocsid']) {
625
+                $data['ocsid'] = $storedId;
626
+            }
627
+        }
628
+
629
+        if ($lang === null) {
630
+            self::$appInfo[$appId] = $data;
631
+        }
632
+
633
+        return $data;
634
+    }
635
+
636
+    /**
637
+     * Returns the navigation
638
+     *
639
+     * @return array
640
+     *
641
+     * This function returns an array containing all entries added. The
642
+     * entries are sorted by the key 'order' ascending. Additional to the keys
643
+     * given for each app the following keys exist:
644
+     *   - active: boolean, signals if the user is on this navigation entry
645
+     */
646
+    public static function getNavigation() {
647
+        $entries = OC::$server->getNavigationManager()->getAll();
648
+        return self::proceedNavigation($entries);
649
+    }
650
+
651
+    /**
652
+     * Returns the Settings Navigation
653
+     *
654
+     * @return string[]
655
+     *
656
+     * This function returns an array containing all settings pages added. The
657
+     * entries are sorted by the key 'order' ascending.
658
+     */
659
+    public static function getSettingsNavigation() {
660
+        $entries = OC::$server->getNavigationManager()->getAll('settings');
661
+        return self::proceedNavigation($entries);
662
+    }
663
+
664
+    /**
665
+     * get the id of loaded app
666
+     *
667
+     * @return string
668
+     */
669
+    public static function getCurrentApp() {
670
+        $request = \OC::$server->getRequest();
671
+        $script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
672
+        $topFolder = substr($script, 0, strpos($script, '/'));
673
+        if (empty($topFolder)) {
674
+            $path_info = $request->getPathInfo();
675
+            if ($path_info) {
676
+                $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
677
+            }
678
+        }
679
+        if ($topFolder == 'apps') {
680
+            $length = strlen($topFolder);
681
+            return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
682
+        } else {
683
+            return $topFolder;
684
+        }
685
+    }
686
+
687
+    /**
688
+     * @param string $type
689
+     * @return array
690
+     */
691
+    public static function getForms($type) {
692
+        $forms = array();
693
+        switch ($type) {
694
+            case 'admin':
695
+                $source = self::$adminForms;
696
+                break;
697
+            case 'personal':
698
+                $source = self::$personalForms;
699
+                break;
700
+            default:
701
+                return array();
702
+        }
703
+        foreach ($source as $form) {
704
+            $forms[] = include $form;
705
+        }
706
+        return $forms;
707
+    }
708
+
709
+    /**
710
+     * register an admin form to be shown
711
+     *
712
+     * @param string $app
713
+     * @param string $page
714
+     */
715
+    public static function registerAdmin($app, $page) {
716
+        self::$adminForms[] = $app . '/' . $page . '.php';
717
+    }
718
+
719
+    /**
720
+     * register a personal form to be shown
721
+     * @param string $app
722
+     * @param string $page
723
+     */
724
+    public static function registerPersonal($app, $page) {
725
+        self::$personalForms[] = $app . '/' . $page . '.php';
726
+    }
727
+
728
+    /**
729
+     * @param array $entry
730
+     */
731
+    public static function registerLogIn(array $entry) {
732
+        self::$altLogin[] = $entry;
733
+    }
734
+
735
+    /**
736
+     * @return array
737
+     */
738
+    public static function getAlternativeLogIns() {
739
+        return self::$altLogin;
740
+    }
741
+
742
+    /**
743
+     * get a list of all apps in the apps folder
744
+     *
745
+     * @return array an array of app names (string IDs)
746
+     * @todo: change the name of this method to getInstalledApps, which is more accurate
747
+     */
748
+    public static function getAllApps() {
749
+
750
+        $apps = array();
751
+
752
+        foreach (OC::$APPSROOTS as $apps_dir) {
753
+            if (!is_readable($apps_dir['path'])) {
754
+                \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
755
+                continue;
756
+            }
757
+            $dh = opendir($apps_dir['path']);
758
+
759
+            if (is_resource($dh)) {
760
+                while (($file = readdir($dh)) !== false) {
761
+
762
+                    if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
763
+
764
+                        $apps[] = $file;
765
+                    }
766
+                }
767
+            }
768
+        }
769
+
770
+        return $apps;
771
+    }
772
+
773
+    /**
774
+     * List all apps, this is used in apps.php
775
+     *
776
+     * @return array
777
+     */
778
+    public function listAllApps() {
779
+        $installedApps = OC_App::getAllApps();
780
+
781
+        //we don't want to show configuration for these
782
+        $blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
783
+        $appList = array();
784
+        $langCode = \OC::$server->getL10N('core')->getLanguageCode();
785
+        $urlGenerator = \OC::$server->getURLGenerator();
786
+
787
+        foreach ($installedApps as $app) {
788
+            if (array_search($app, $blacklist) === false) {
789
+
790
+                $info = OC_App::getAppInfo($app, false, $langCode);
791
+                if (!is_array($info)) {
792
+                    \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
793
+                    continue;
794
+                }
795
+
796
+                if (!isset($info['name'])) {
797
+                    \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
798
+                    continue;
799
+                }
800
+
801
+                $enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'no');
802
+                $info['groups'] = null;
803
+                if ($enabled === 'yes') {
804
+                    $active = true;
805
+                } else if ($enabled === 'no') {
806
+                    $active = false;
807
+                } else {
808
+                    $active = true;
809
+                    $info['groups'] = $enabled;
810
+                }
811
+
812
+                $info['active'] = $active;
813
+
814
+                if (self::isShipped($app)) {
815
+                    $info['internal'] = true;
816
+                    $info['level'] = self::officialApp;
817
+                    $info['removable'] = false;
818
+                } else {
819
+                    $info['internal'] = false;
820
+                    $info['removable'] = true;
821
+                }
822
+
823
+                $appPath = self::getAppPath($app);
824
+                if($appPath !== false) {
825
+                    $appIcon = $appPath . '/img/' . $app . '.svg';
826
+                    if (file_exists($appIcon)) {
827
+                        $info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
828
+                        $info['previewAsIcon'] = true;
829
+                    } else {
830
+                        $appIcon = $appPath . '/img/app.svg';
831
+                        if (file_exists($appIcon)) {
832
+                            $info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
833
+                            $info['previewAsIcon'] = true;
834
+                        }
835
+                    }
836
+                }
837
+                // fix documentation
838
+                if (isset($info['documentation']) && is_array($info['documentation'])) {
839
+                    foreach ($info['documentation'] as $key => $url) {
840
+                        // If it is not an absolute URL we assume it is a key
841
+                        // i.e. admin-ldap will get converted to go.php?to=admin-ldap
842
+                        if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
843
+                            $url = $urlGenerator->linkToDocs($url);
844
+                        }
845
+
846
+                        $info['documentation'][$key] = $url;
847
+                    }
848
+                }
849
+
850
+                $info['version'] = OC_App::getAppVersion($app);
851
+                $appList[] = $info;
852
+            }
853
+        }
854
+
855
+        return $appList;
856
+    }
857
+
858
+    /**
859
+     * Returns the internal app ID or false
860
+     * @param string $ocsID
861
+     * @return string|false
862
+     */
863
+    public static function getInternalAppIdByOcs($ocsID) {
864
+        if(is_numeric($ocsID)) {
865
+            $idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
866
+            if(array_search($ocsID, $idArray)) {
867
+                return array_search($ocsID, $idArray);
868
+            }
869
+        }
870
+        return false;
871
+    }
872
+
873
+    public static function shouldUpgrade($app) {
874
+        $versions = self::getAppVersions();
875
+        $currentVersion = OC_App::getAppVersion($app);
876
+        if ($currentVersion && isset($versions[$app])) {
877
+            $installedVersion = $versions[$app];
878
+            if (!version_compare($currentVersion, $installedVersion, '=')) {
879
+                return true;
880
+            }
881
+        }
882
+        return false;
883
+    }
884
+
885
+    /**
886
+     * Adjust the number of version parts of $version1 to match
887
+     * the number of version parts of $version2.
888
+     *
889
+     * @param string $version1 version to adjust
890
+     * @param string $version2 version to take the number of parts from
891
+     * @return string shortened $version1
892
+     */
893
+    private static function adjustVersionParts($version1, $version2) {
894
+        $version1 = explode('.', $version1);
895
+        $version2 = explode('.', $version2);
896
+        // reduce $version1 to match the number of parts in $version2
897
+        while (count($version1) > count($version2)) {
898
+            array_pop($version1);
899
+        }
900
+        // if $version1 does not have enough parts, add some
901
+        while (count($version1) < count($version2)) {
902
+            $version1[] = '0';
903
+        }
904
+        return implode('.', $version1);
905
+    }
906
+
907
+    /**
908
+     * Check whether the current ownCloud version matches the given
909
+     * application's version requirements.
910
+     *
911
+     * The comparison is made based on the number of parts that the
912
+     * app info version has. For example for ownCloud 6.0.3 if the
913
+     * app info version is expecting version 6.0, the comparison is
914
+     * made on the first two parts of the ownCloud version.
915
+     * This means that it's possible to specify "requiremin" => 6
916
+     * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
917
+     *
918
+     * @param string $ocVersion ownCloud version to check against
919
+     * @param array $appInfo app info (from xml)
920
+     *
921
+     * @return boolean true if compatible, otherwise false
922
+     */
923
+    public static function isAppCompatible($ocVersion, $appInfo) {
924
+        $requireMin = '';
925
+        $requireMax = '';
926
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
927
+            $requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
928
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
929
+            $requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
930
+        } else if (isset($appInfo['requiremin'])) {
931
+            $requireMin = $appInfo['requiremin'];
932
+        } else if (isset($appInfo['require'])) {
933
+            $requireMin = $appInfo['require'];
934
+        }
935
+
936
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
937
+            $requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
938
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
939
+            $requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
940
+        } else if (isset($appInfo['requiremax'])) {
941
+            $requireMax = $appInfo['requiremax'];
942
+        }
943
+
944
+        if (is_array($ocVersion)) {
945
+            $ocVersion = implode('.', $ocVersion);
946
+        }
947
+
948
+        if (!empty($requireMin)
949
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
950
+        ) {
951
+
952
+            return false;
953
+        }
954
+
955
+        if (!empty($requireMax)
956
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
957
+        ) {
958
+            return false;
959
+        }
960
+
961
+        return true;
962
+    }
963
+
964
+    /**
965
+     * get the installed version of all apps
966
+     */
967
+    public static function getAppVersions() {
968
+        static $versions;
969
+
970
+        if(!$versions) {
971
+            $appConfig = \OC::$server->getAppConfig();
972
+            $versions = $appConfig->getValues(false, 'installed_version');
973
+        }
974
+        return $versions;
975
+    }
976
+
977
+    /**
978
+     * @param string $app
979
+     * @param \OCP\IConfig $config
980
+     * @param \OCP\IL10N $l
981
+     * @return bool
982
+     *
983
+     * @throws Exception if app is not compatible with this version of ownCloud
984
+     * @throws Exception if no app-name was specified
985
+     */
986
+    public function installApp($app,
987
+                                \OCP\IConfig $config,
988
+                                \OCP\IL10N $l) {
989
+        if ($app !== false) {
990
+            // check if the app is compatible with this version of ownCloud
991
+            $info = self::getAppInfo($app);
992
+            if(!is_array($info)) {
993
+                throw new \Exception(
994
+                    $l->t('App "%s" cannot be installed because appinfo file cannot be read.',
995
+                        [$info['name']]
996
+                    )
997
+                );
998
+            }
999
+
1000
+            $version = \OCP\Util::getVersion();
1001
+            if (!self::isAppCompatible($version, $info)) {
1002
+                throw new \Exception(
1003
+                    $l->t('App "%s" cannot be installed because it is not compatible with this version of the server.',
1004
+                        array($info['name'])
1005
+                    )
1006
+                );
1007
+            }
1008
+
1009
+            // check for required dependencies
1010
+            self::checkAppDependencies($config, $l, $info);
1011
+
1012
+            $config->setAppValue($app, 'enabled', 'yes');
1013
+            if (isset($appData['id'])) {
1014
+                $config->setAppValue($app, 'ocsid', $appData['id']);
1015
+            }
1016
+
1017
+            if(isset($info['settings']) && is_array($info['settings'])) {
1018
+                $appPath = self::getAppPath($app);
1019
+                self::registerAutoloading($app, $appPath);
1020
+                \OC::$server->getSettingsManager()->setupSettings($info['settings']);
1021
+            }
1022
+
1023
+            \OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1024
+        } else {
1025
+            if(empty($appName) ) {
1026
+                throw new \Exception($l->t("No app name specified"));
1027
+            } else {
1028
+                throw new \Exception($l->t("App '%s' could not be installed!", $appName));
1029
+            }
1030
+        }
1031
+
1032
+        return $app;
1033
+    }
1034
+
1035
+    /**
1036
+     * update the database for the app and call the update script
1037
+     *
1038
+     * @param string $appId
1039
+     * @return bool
1040
+     */
1041
+    public static function updateApp($appId) {
1042
+        $appPath = self::getAppPath($appId);
1043
+        if($appPath === false) {
1044
+            return false;
1045
+        }
1046
+        $appData = self::getAppInfo($appId);
1047
+        self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1048
+        if (file_exists($appPath . '/appinfo/database.xml')) {
1049
+            OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1050
+        }
1051
+        self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1052
+        self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1053
+        unset(self::$appVersion[$appId]);
1054
+        // run upgrade code
1055
+        if (file_exists($appPath . '/appinfo/update.php')) {
1056
+            self::loadApp($appId);
1057
+            include $appPath . '/appinfo/update.php';
1058
+        }
1059
+        self::registerAutoloading($appId, $appPath);
1060
+        self::setupBackgroundJobs($appData['background-jobs']);
1061
+        if(isset($appData['settings']) && is_array($appData['settings'])) {
1062
+            \OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1063
+        }
1064
+
1065
+        //set remote/public handlers
1066
+        if (array_key_exists('ocsid', $appData)) {
1067
+            \OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1068
+        } elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1069
+            \OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1070
+        }
1071
+        foreach ($appData['remote'] as $name => $path) {
1072
+            \OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1073
+        }
1074
+        foreach ($appData['public'] as $name => $path) {
1075
+            \OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1076
+        }
1077
+
1078
+        self::setAppTypes($appId);
1079
+
1080
+        $version = \OC_App::getAppVersion($appId);
1081
+        \OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
1082
+
1083
+        \OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
1084
+            ManagerEvent::EVENT_APP_UPDATE, $appId
1085
+        ));
1086
+
1087
+        return true;
1088
+    }
1089
+
1090
+    /**
1091
+     * @param string $appId
1092
+     * @param string[] $steps
1093
+     * @throws \OC\NeedsUpdateException
1094
+     */
1095
+    public static function executeRepairSteps($appId, array $steps) {
1096
+        if (empty($steps)) {
1097
+            return;
1098
+        }
1099
+        // load the app
1100
+        self::loadApp($appId);
1101
+
1102
+        $dispatcher = OC::$server->getEventDispatcher();
1103
+
1104
+        // load the steps
1105
+        $r = new Repair([], $dispatcher);
1106
+        foreach ($steps as $step) {
1107
+            try {
1108
+                $r->addStep($step);
1109
+            } catch (Exception $ex) {
1110
+                $r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1111
+                \OC::$server->getLogger()->logException($ex);
1112
+            }
1113
+        }
1114
+        // run the steps
1115
+        $r->run();
1116
+    }
1117
+
1118
+    public static function setupBackgroundJobs(array $jobs) {
1119
+        $queue = \OC::$server->getJobList();
1120
+        foreach ($jobs as $job) {
1121
+            $queue->add($job);
1122
+        }
1123
+    }
1124
+
1125
+    /**
1126
+     * @param string $appId
1127
+     * @param string[] $steps
1128
+     */
1129
+    private static function setupLiveMigrations($appId, array $steps) {
1130
+        $queue = \OC::$server->getJobList();
1131
+        foreach ($steps as $step) {
1132
+            $queue->add('OC\Migration\BackgroundRepair', [
1133
+                'app' => $appId,
1134
+                'step' => $step]);
1135
+        }
1136
+    }
1137
+
1138
+    /**
1139
+     * @param string $appId
1140
+     * @return \OC\Files\View|false
1141
+     */
1142
+    public static function getStorage($appId) {
1143
+        if (OC_App::isEnabled($appId)) { //sanity check
1144
+            if (\OC::$server->getUserSession()->isLoggedIn()) {
1145
+                $view = new \OC\Files\View('/' . OC_User::getUser());
1146
+                if (!$view->file_exists($appId)) {
1147
+                    $view->mkdir($appId);
1148
+                }
1149
+                return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1150
+            } else {
1151
+                \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1152
+                return false;
1153
+            }
1154
+        } else {
1155
+            \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1156
+            return false;
1157
+        }
1158
+    }
1159
+
1160
+    protected static function findBestL10NOption($options, $lang) {
1161
+        $fallback = $similarLangFallback = $englishFallback = false;
1162
+
1163
+        $lang = strtolower($lang);
1164
+        $similarLang = $lang;
1165
+        if (strpos($similarLang, '_')) {
1166
+            // For "de_DE" we want to find "de" and the other way around
1167
+            $similarLang = substr($lang, 0, strpos($lang, '_'));
1168
+        }
1169
+
1170
+        foreach ($options as $option) {
1171
+            if (is_array($option)) {
1172
+                if ($fallback === false) {
1173
+                    $fallback = $option['@value'];
1174
+                }
1175
+
1176
+                if (!isset($option['@attributes']['lang'])) {
1177
+                    continue;
1178
+                }
1179
+
1180
+                $attributeLang = strtolower($option['@attributes']['lang']);
1181
+                if ($attributeLang === $lang) {
1182
+                    return $option['@value'];
1183
+                }
1184
+
1185
+                if ($attributeLang === $similarLang) {
1186
+                    $similarLangFallback = $option['@value'];
1187
+                } else if (strpos($attributeLang, $similarLang . '_') === 0) {
1188
+                    if ($similarLangFallback === false) {
1189
+                        $similarLangFallback =  $option['@value'];
1190
+                    }
1191
+                }
1192
+            } else {
1193
+                $englishFallback = $option;
1194
+            }
1195
+        }
1196
+
1197
+        if ($similarLangFallback !== false) {
1198
+            return $similarLangFallback;
1199
+        } else if ($englishFallback !== false) {
1200
+            return $englishFallback;
1201
+        }
1202
+        return (string) $fallback;
1203
+    }
1204
+
1205
+    /**
1206
+     * parses the app data array and enhanced the 'description' value
1207
+     *
1208
+     * @param array $data the app data
1209
+     * @param string $lang
1210
+     * @return array improved app data
1211
+     */
1212
+    public static function parseAppInfo(array $data, $lang = null) {
1213
+
1214
+        if ($lang && isset($data['name']) && is_array($data['name'])) {
1215
+            $data['name'] = self::findBestL10NOption($data['name'], $lang);
1216
+        }
1217
+        if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1218
+            $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1219
+        }
1220
+        if ($lang && isset($data['description']) && is_array($data['description'])) {
1221
+            $data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1222
+        } else if (isset($data['description']) && is_string($data['description'])) {
1223
+            $data['description'] = trim($data['description']);
1224
+        } else  {
1225
+            $data['description'] = '';
1226
+        }
1227
+
1228
+        return $data;
1229
+    }
1230
+
1231
+    /**
1232
+     * @param \OCP\IConfig $config
1233
+     * @param \OCP\IL10N $l
1234
+     * @param array $info
1235
+     * @throws \Exception
1236
+     */
1237
+    public static function checkAppDependencies($config, $l, $info) {
1238
+        $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1239
+        $missing = $dependencyAnalyzer->analyze($info);
1240
+        if (!empty($missing)) {
1241
+            $missingMsg = join(PHP_EOL, $missing);
1242
+            throw new \Exception(
1243
+                $l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1244
+                    [$info['name'], $missingMsg]
1245
+                )
1246
+            );
1247
+        }
1248
+    }
1249 1249
 }
Please login to merge, or discard this patch.
Spacing   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -110,9 +110,9 @@  discard block
 block discarded – undo
110 110
 		$apps = self::getEnabledApps();
111 111
 
112 112
 		// Add each apps' folder as allowed class path
113
-		foreach($apps as $app) {
113
+		foreach ($apps as $app) {
114 114
 			$path = self::getAppPath($app);
115
-			if($path !== false) {
115
+			if ($path !== false) {
116 116
 				self::registerAutoloading($app, $path);
117 117
 			}
118 118
 		}
@@ -138,15 +138,15 @@  discard block
 block discarded – undo
138 138
 	public static function loadApp($app) {
139 139
 		self::$loadedApps[] = $app;
140 140
 		$appPath = self::getAppPath($app);
141
-		if($appPath === false) {
141
+		if ($appPath === false) {
142 142
 			return;
143 143
 		}
144 144
 
145 145
 		// in case someone calls loadApp() directly
146 146
 		self::registerAutoloading($app, $appPath);
147 147
 
148
-		if (is_file($appPath . '/appinfo/app.php')) {
149
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
148
+		if (is_file($appPath.'/appinfo/app.php')) {
149
+			\OC::$server->getEventLogger()->start('load_app_'.$app, 'Load app: '.$app);
150 150
 			try {
151 151
 				self::requireAppFile($app);
152 152
 			} catch (Error $ex) {
@@ -163,7 +163,7 @@  discard block
 block discarded – undo
163 163
 				// enabled for groups
164 164
 				self::$enabledAppsCache = array();
165 165
 			}
166
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
166
+			\OC::$server->getEventLogger()->end('load_app_'.$app);
167 167
 		}
168 168
 
169 169
 		$info = self::getAppInfo($app);
@@ -190,17 +190,17 @@  discard block
 block discarded – undo
190 190
 	 * @param string $path
191 191
 	 */
192 192
 	public static function registerAutoloading($app, $path) {
193
-		$key = $app . '-' . $path;
194
-		if(isset(self::$alreadyRegistered[$key])) {
193
+		$key = $app.'-'.$path;
194
+		if (isset(self::$alreadyRegistered[$key])) {
195 195
 			return;
196 196
 		}
197 197
 		self::$alreadyRegistered[$key] = true;
198 198
 		// Register on PSR-4 composer autoloader
199 199
 		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
200 200
 		\OC::$server->registerNamespace($app, $appNamespace);
201
-		\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
201
+		\OC::$composerAutoloader->addPsr4($appNamespace.'\\', $path.'/lib/', true);
202 202
 		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
203
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
203
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\Tests\\', $path.'/tests/', true);
204 204
 		}
205 205
 
206 206
 		// Register on legacy autoloader
@@ -215,7 +215,7 @@  discard block
 block discarded – undo
215 215
 	 */
216 216
 	private static function requireAppFile($app) {
217 217
 		// encapsulated here to avoid variable scope conflicts
218
-		require_once $app . '/appinfo/app.php';
218
+		require_once $app.'/appinfo/app.php';
219 219
 	}
220 220
 
221 221
 	/**
@@ -262,7 +262,7 @@  discard block
 block discarded – undo
262 262
 	 */
263 263
 	public static function setAppTypes($app) {
264 264
 		$appData = self::getAppInfo($app);
265
-		if(!is_array($appData)) {
265
+		if (!is_array($appData)) {
266 266
 			return;
267 267
 		}
268 268
 
@@ -326,8 +326,8 @@  discard block
 block discarded – undo
326 326
 		} else {
327 327
 			$apps = $appManager->getEnabledAppsForUser($user);
328 328
 		}
329
-		$apps = array_filter($apps, function ($app) {
330
-			return $app !== 'files';//we add this manually
329
+		$apps = array_filter($apps, function($app) {
330
+			return $app !== 'files'; //we add this manually
331 331
 		});
332 332
 		sort($apps);
333 333
 		array_unshift($apps, 'files');
@@ -370,7 +370,7 @@  discard block
 block discarded – undo
370 370
 		);
371 371
 		$isDownloaded = $installer->isDownloaded($appId);
372 372
 
373
-		if(!$isDownloaded) {
373
+		if (!$isDownloaded) {
374 374
 			$installer->downloadApp($appId);
375 375
 		}
376 376
 
@@ -489,7 +489,7 @@  discard block
 block discarded – undo
489 489
 	 */
490 490
 	public static function findAppInDirectories($appId) {
491 491
 		$sanitizedAppId = self::cleanAppId($appId);
492
-		if($sanitizedAppId !== $appId) {
492
+		if ($sanitizedAppId !== $appId) {
493 493
 			return false;
494 494
 		}
495 495
 		static $app_dir = array();
@@ -500,7 +500,7 @@  discard block
 block discarded – undo
500 500
 
501 501
 		$possibleApps = array();
502 502
 		foreach (OC::$APPSROOTS as $dir) {
503
-			if (file_exists($dir['path'] . '/' . $appId)) {
503
+			if (file_exists($dir['path'].'/'.$appId)) {
504 504
 				$possibleApps[] = $dir;
505 505
 			}
506 506
 		}
@@ -541,7 +541,7 @@  discard block
 block discarded – undo
541 541
 		}
542 542
 
543 543
 		if (($dir = self::findAppInDirectories($appId)) != false) {
544
-			return $dir['path'] . '/' . $appId;
544
+			return $dir['path'].'/'.$appId;
545 545
 		}
546 546
 		return false;
547 547
 	}
@@ -555,7 +555,7 @@  discard block
 block discarded – undo
555 555
 	 */
556 556
 	public static function getAppWebPath($appId) {
557 557
 		if (($dir = self::findAppInDirectories($appId)) != false) {
558
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
558
+			return OC::$WEBROOT.$dir['url'].'/'.$appId;
559 559
 		}
560 560
 		return false;
561 561
 	}
@@ -568,7 +568,7 @@  discard block
 block discarded – undo
568 568
 	 * @return string
569 569
 	 */
570 570
 	public static function getAppVersion($appId, $useCache = true) {
571
-		if($useCache && isset(self::$appVersion[$appId])) {
571
+		if ($useCache && isset(self::$appVersion[$appId])) {
572 572
 			return self::$appVersion[$appId];
573 573
 		}
574 574
 
@@ -584,7 +584,7 @@  discard block
 block discarded – undo
584 584
 	 * @return string
585 585
 	 */
586 586
 	public static function getAppVersionByPath($path) {
587
-		$infoFile = $path . '/appinfo/info.xml';
587
+		$infoFile = $path.'/appinfo/info.xml';
588 588
 		$appData = self::getAppInfo($infoFile, true);
589 589
 		return isset($appData['version']) ? $appData['version'] : '';
590 590
 	}
@@ -607,10 +607,10 @@  discard block
 block discarded – undo
607 607
 				return self::$appInfo[$appId];
608 608
 			}
609 609
 			$appPath = self::getAppPath($appId);
610
-			if($appPath === false) {
610
+			if ($appPath === false) {
611 611
 				return null;
612 612
 			}
613
-			$file = $appPath . '/appinfo/info.xml';
613
+			$file = $appPath.'/appinfo/info.xml';
614 614
 		}
615 615
 
616 616
 		$parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
@@ -619,9 +619,9 @@  discard block
 block discarded – undo
619 619
 		if (is_array($data)) {
620 620
 			$data = OC_App::parseAppInfo($data, $lang);
621 621
 		}
622
-		if(isset($data['ocsid'])) {
622
+		if (isset($data['ocsid'])) {
623 623
 			$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
624
-			if($storedId !== '' && $storedId !== $data['ocsid']) {
624
+			if ($storedId !== '' && $storedId !== $data['ocsid']) {
625 625
 				$data['ocsid'] = $storedId;
626 626
 			}
627 627
 		}
@@ -713,7 +713,7 @@  discard block
 block discarded – undo
713 713
 	 * @param string $page
714 714
 	 */
715 715
 	public static function registerAdmin($app, $page) {
716
-		self::$adminForms[] = $app . '/' . $page . '.php';
716
+		self::$adminForms[] = $app.'/'.$page.'.php';
717 717
 	}
718 718
 
719 719
 	/**
@@ -722,7 +722,7 @@  discard block
 block discarded – undo
722 722
 	 * @param string $page
723 723
 	 */
724 724
 	public static function registerPersonal($app, $page) {
725
-		self::$personalForms[] = $app . '/' . $page . '.php';
725
+		self::$personalForms[] = $app.'/'.$page.'.php';
726 726
 	}
727 727
 
728 728
 	/**
@@ -751,7 +751,7 @@  discard block
 block discarded – undo
751 751
 
752 752
 		foreach (OC::$APPSROOTS as $apps_dir) {
753 753
 			if (!is_readable($apps_dir['path'])) {
754
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
754
+				\OCP\Util::writeLog('core', 'unable to read app folder : '.$apps_dir['path'], \OCP\Util::WARN);
755 755
 				continue;
756 756
 			}
757 757
 			$dh = opendir($apps_dir['path']);
@@ -759,7 +759,7 @@  discard block
 block discarded – undo
759 759
 			if (is_resource($dh)) {
760 760
 				while (($file = readdir($dh)) !== false) {
761 761
 
762
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
762
+					if ($file[0] != '.' and is_dir($apps_dir['path'].'/'.$file) and is_file($apps_dir['path'].'/'.$file.'/appinfo/info.xml')) {
763 763
 
764 764
 						$apps[] = $file;
765 765
 					}
@@ -789,12 +789,12 @@  discard block
 block discarded – undo
789 789
 
790 790
 				$info = OC_App::getAppInfo($app, false, $langCode);
791 791
 				if (!is_array($info)) {
792
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
792
+					\OCP\Util::writeLog('core', 'Could not read app info file for app "'.$app.'"', \OCP\Util::ERROR);
793 793
 					continue;
794 794
 				}
795 795
 
796 796
 				if (!isset($info['name'])) {
797
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
797
+					\OCP\Util::writeLog('core', 'App id "'.$app.'" has no name in appinfo', \OCP\Util::ERROR);
798 798
 					continue;
799 799
 				}
800 800
 
@@ -821,13 +821,13 @@  discard block
 block discarded – undo
821 821
 				}
822 822
 
823 823
 				$appPath = self::getAppPath($app);
824
-				if($appPath !== false) {
825
-					$appIcon = $appPath . '/img/' . $app . '.svg';
824
+				if ($appPath !== false) {
825
+					$appIcon = $appPath.'/img/'.$app.'.svg';
826 826
 					if (file_exists($appIcon)) {
827
-						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
827
+						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app.'.svg');
828 828
 						$info['previewAsIcon'] = true;
829 829
 					} else {
830
-						$appIcon = $appPath . '/img/app.svg';
830
+						$appIcon = $appPath.'/img/app.svg';
831 831
 						if (file_exists($appIcon)) {
832 832
 							$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
833 833
 							$info['previewAsIcon'] = true;
@@ -861,9 +861,9 @@  discard block
 block discarded – undo
861 861
 	 * @return string|false
862 862
 	 */
863 863
 	public static function getInternalAppIdByOcs($ocsID) {
864
-		if(is_numeric($ocsID)) {
864
+		if (is_numeric($ocsID)) {
865 865
 			$idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
866
-			if(array_search($ocsID, $idArray)) {
866
+			if (array_search($ocsID, $idArray)) {
867 867
 				return array_search($ocsID, $idArray);
868 868
 			}
869 869
 		}
@@ -967,7 +967,7 @@  discard block
 block discarded – undo
967 967
 	public static function getAppVersions() {
968 968
 		static $versions;
969 969
 
970
-		if(!$versions) {
970
+		if (!$versions) {
971 971
 			$appConfig = \OC::$server->getAppConfig();
972 972
 			$versions = $appConfig->getValues(false, 'installed_version');
973 973
 		}
@@ -989,7 +989,7 @@  discard block
 block discarded – undo
989 989
 		if ($app !== false) {
990 990
 			// check if the app is compatible with this version of ownCloud
991 991
 			$info = self::getAppInfo($app);
992
-			if(!is_array($info)) {
992
+			if (!is_array($info)) {
993 993
 				throw new \Exception(
994 994
 					$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
995 995
 						[$info['name']]
@@ -1014,7 +1014,7 @@  discard block
 block discarded – undo
1014 1014
 				$config->setAppValue($app, 'ocsid', $appData['id']);
1015 1015
 			}
1016 1016
 
1017
-			if(isset($info['settings']) && is_array($info['settings'])) {
1017
+			if (isset($info['settings']) && is_array($info['settings'])) {
1018 1018
 				$appPath = self::getAppPath($app);
1019 1019
 				self::registerAutoloading($app, $appPath);
1020 1020
 				\OC::$server->getSettingsManager()->setupSettings($info['settings']);
@@ -1022,7 +1022,7 @@  discard block
 block discarded – undo
1022 1022
 
1023 1023
 			\OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1024 1024
 		} else {
1025
-			if(empty($appName) ) {
1025
+			if (empty($appName)) {
1026 1026
 				throw new \Exception($l->t("No app name specified"));
1027 1027
 			} else {
1028 1028
 				throw new \Exception($l->t("App '%s' could not be installed!", $appName));
@@ -1040,39 +1040,39 @@  discard block
 block discarded – undo
1040 1040
 	 */
1041 1041
 	public static function updateApp($appId) {
1042 1042
 		$appPath = self::getAppPath($appId);
1043
-		if($appPath === false) {
1043
+		if ($appPath === false) {
1044 1044
 			return false;
1045 1045
 		}
1046 1046
 		$appData = self::getAppInfo($appId);
1047 1047
 		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1048
-		if (file_exists($appPath . '/appinfo/database.xml')) {
1049
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1048
+		if (file_exists($appPath.'/appinfo/database.xml')) {
1049
+			OC_DB::updateDbFromStructure($appPath.'/appinfo/database.xml');
1050 1050
 		}
1051 1051
 		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1052 1052
 		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1053 1053
 		unset(self::$appVersion[$appId]);
1054 1054
 		// run upgrade code
1055
-		if (file_exists($appPath . '/appinfo/update.php')) {
1055
+		if (file_exists($appPath.'/appinfo/update.php')) {
1056 1056
 			self::loadApp($appId);
1057
-			include $appPath . '/appinfo/update.php';
1057
+			include $appPath.'/appinfo/update.php';
1058 1058
 		}
1059 1059
 		self::registerAutoloading($appId, $appPath);
1060 1060
 		self::setupBackgroundJobs($appData['background-jobs']);
1061
-		if(isset($appData['settings']) && is_array($appData['settings'])) {
1061
+		if (isset($appData['settings']) && is_array($appData['settings'])) {
1062 1062
 			\OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1063 1063
 		}
1064 1064
 
1065 1065
 		//set remote/public handlers
1066 1066
 		if (array_key_exists('ocsid', $appData)) {
1067 1067
 			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1068
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1068
+		} elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1069 1069
 			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1070 1070
 		}
1071 1071
 		foreach ($appData['remote'] as $name => $path) {
1072
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1072
+			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $appId.'/'.$path);
1073 1073
 		}
1074 1074
 		foreach ($appData['public'] as $name => $path) {
1075
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1075
+			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $appId.'/'.$path);
1076 1076
 		}
1077 1077
 
1078 1078
 		self::setAppTypes($appId);
@@ -1142,17 +1142,17 @@  discard block
 block discarded – undo
1142 1142
 	public static function getStorage($appId) {
1143 1143
 		if (OC_App::isEnabled($appId)) { //sanity check
1144 1144
 			if (\OC::$server->getUserSession()->isLoggedIn()) {
1145
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1145
+				$view = new \OC\Files\View('/'.OC_User::getUser());
1146 1146
 				if (!$view->file_exists($appId)) {
1147 1147
 					$view->mkdir($appId);
1148 1148
 				}
1149
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1149
+				return new \OC\Files\View('/'.OC_User::getUser().'/'.$appId);
1150 1150
 			} else {
1151
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1151
+				\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.', user not logged in', \OCP\Util::ERROR);
1152 1152
 				return false;
1153 1153
 			}
1154 1154
 		} else {
1155
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1155
+			\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.' not enabled', \OCP\Util::ERROR);
1156 1156
 			return false;
1157 1157
 		}
1158 1158
 	}
@@ -1184,9 +1184,9 @@  discard block
 block discarded – undo
1184 1184
 
1185 1185
 				if ($attributeLang === $similarLang) {
1186 1186
 					$similarLangFallback = $option['@value'];
1187
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1187
+				} else if (strpos($attributeLang, $similarLang.'_') === 0) {
1188 1188
 					if ($similarLangFallback === false) {
1189
-						$similarLangFallback =  $option['@value'];
1189
+						$similarLangFallback = $option['@value'];
1190 1190
 					}
1191 1191
 				}
1192 1192
 			} else {
@@ -1221,7 +1221,7 @@  discard block
 block discarded – undo
1221 1221
 			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1222 1222
 		} else if (isset($data['description']) && is_string($data['description'])) {
1223 1223
 			$data['description'] = trim($data['description']);
1224
-		} else  {
1224
+		} else {
1225 1225
 			$data['description'] = '';
1226 1226
 		}
1227 1227
 
Please login to merge, or discard this patch.
lib/private/Files/Node/File.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -31,7 +31,7 @@
 block discarded – undo
31 31
 	 * Creates a Folder that represents a non-existing path
32 32
 	 *
33 33
 	 * @param string $path path
34
-	 * @return string non-existing node class
34
+	 * @return NonExistingFile non-existing node class
35 35
 	 */
36 36
 	protected function createNonExistingNode($path) {
37 37
 		return new NonExistingFile($this->root, $this->view, $path);
Please login to merge, or discard this patch.
Indentation   +102 added lines, -102 removed lines patch added patch discarded remove patch
@@ -29,113 +29,113 @@
 block discarded – undo
29 29
 use OCP\Files\NotPermittedException;
30 30
 
31 31
 class File extends Node implements \OCP\Files\File {
32
-	/**
33
-	 * Creates a Folder that represents a non-existing path
34
-	 *
35
-	 * @param string $path path
36
-	 * @return string non-existing node class
37
-	 */
38
-	protected function createNonExistingNode($path) {
39
-		return new NonExistingFile($this->root, $this->view, $path);
40
-	}
32
+    /**
33
+     * Creates a Folder that represents a non-existing path
34
+     *
35
+     * @param string $path path
36
+     * @return string non-existing node class
37
+     */
38
+    protected function createNonExistingNode($path) {
39
+        return new NonExistingFile($this->root, $this->view, $path);
40
+    }
41 41
 
42
-	/**
43
-	 * @return string
44
-	 * @throws \OCP\Files\NotPermittedException
45
-	 */
46
-	public function getContent() {
47
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_READ)) {
48
-			/**
49
-			 * @var \OC\Files\Storage\Storage $storage;
50
-			 */
51
-			return $this->view->file_get_contents($this->path);
52
-		} else {
53
-			throw new NotPermittedException();
54
-		}
55
-	}
42
+    /**
43
+     * @return string
44
+     * @throws \OCP\Files\NotPermittedException
45
+     */
46
+    public function getContent() {
47
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_READ)) {
48
+            /**
49
+             * @var \OC\Files\Storage\Storage $storage;
50
+             */
51
+            return $this->view->file_get_contents($this->path);
52
+        } else {
53
+            throw new NotPermittedException();
54
+        }
55
+    }
56 56
 
57
-	/**
58
-	 * @param string $data
59
-	 * @throws \OCP\Files\NotPermittedException
60
-	 */
61
-	public function putContent($data) {
62
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE)) {
63
-			$this->sendHooks(array('preWrite'));
64
-			$this->view->file_put_contents($this->path, $data);
65
-			$this->fileInfo = null;
66
-			$this->sendHooks(array('postWrite'));
67
-		} else {
68
-			throw new NotPermittedException();
69
-		}
70
-	}
57
+    /**
58
+     * @param string $data
59
+     * @throws \OCP\Files\NotPermittedException
60
+     */
61
+    public function putContent($data) {
62
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_UPDATE)) {
63
+            $this->sendHooks(array('preWrite'));
64
+            $this->view->file_put_contents($this->path, $data);
65
+            $this->fileInfo = null;
66
+            $this->sendHooks(array('postWrite'));
67
+        } else {
68
+            throw new NotPermittedException();
69
+        }
70
+    }
71 71
 
72
-	/**
73
-	 * @param string $mode
74
-	 * @return resource
75
-	 * @throws \OCP\Files\NotPermittedException
76
-	 */
77
-	public function fopen($mode) {
78
-		$preHooks = array();
79
-		$postHooks = array();
80
-		$requiredPermissions = \OCP\Constants::PERMISSION_READ;
81
-		switch ($mode) {
82
-			case 'r+':
83
-			case 'rb+':
84
-			case 'w+':
85
-			case 'wb+':
86
-			case 'x+':
87
-			case 'xb+':
88
-			case 'a+':
89
-			case 'ab+':
90
-			case 'w':
91
-			case 'wb':
92
-			case 'x':
93
-			case 'xb':
94
-			case 'a':
95
-			case 'ab':
96
-				$preHooks[] = 'preWrite';
97
-				$postHooks[] = 'postWrite';
98
-				$requiredPermissions |= \OCP\Constants::PERMISSION_UPDATE;
99
-				break;
100
-		}
72
+    /**
73
+     * @param string $mode
74
+     * @return resource
75
+     * @throws \OCP\Files\NotPermittedException
76
+     */
77
+    public function fopen($mode) {
78
+        $preHooks = array();
79
+        $postHooks = array();
80
+        $requiredPermissions = \OCP\Constants::PERMISSION_READ;
81
+        switch ($mode) {
82
+            case 'r+':
83
+            case 'rb+':
84
+            case 'w+':
85
+            case 'wb+':
86
+            case 'x+':
87
+            case 'xb+':
88
+            case 'a+':
89
+            case 'ab+':
90
+            case 'w':
91
+            case 'wb':
92
+            case 'x':
93
+            case 'xb':
94
+            case 'a':
95
+            case 'ab':
96
+                $preHooks[] = 'preWrite';
97
+                $postHooks[] = 'postWrite';
98
+                $requiredPermissions |= \OCP\Constants::PERMISSION_UPDATE;
99
+                break;
100
+        }
101 101
 
102
-		if ($this->checkPermissions($requiredPermissions)) {
103
-			$this->sendHooks($preHooks);
104
-			$result = $this->view->fopen($this->path, $mode);
105
-			$this->sendHooks($postHooks);
106
-			return $result;
107
-		} else {
108
-			throw new NotPermittedException();
109
-		}
110
-	}
102
+        if ($this->checkPermissions($requiredPermissions)) {
103
+            $this->sendHooks($preHooks);
104
+            $result = $this->view->fopen($this->path, $mode);
105
+            $this->sendHooks($postHooks);
106
+            return $result;
107
+        } else {
108
+            throw new NotPermittedException();
109
+        }
110
+    }
111 111
 
112
-	public function delete() {
113
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
114
-			$this->sendHooks(array('preDelete'));
115
-			$fileInfo = $this->getFileInfo();
116
-			$this->view->unlink($this->path);
117
-			$nonExisting = new NonExistingFile($this->root, $this->view, $this->path, $fileInfo);
118
-			$this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
119
-			$this->exists = false;
120
-			$this->fileInfo = null;
121
-		} else {
122
-			throw new NotPermittedException();
123
-		}
124
-	}
112
+    public function delete() {
113
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
114
+            $this->sendHooks(array('preDelete'));
115
+            $fileInfo = $this->getFileInfo();
116
+            $this->view->unlink($this->path);
117
+            $nonExisting = new NonExistingFile($this->root, $this->view, $this->path, $fileInfo);
118
+            $this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
119
+            $this->exists = false;
120
+            $this->fileInfo = null;
121
+        } else {
122
+            throw new NotPermittedException();
123
+        }
124
+    }
125 125
 
126
-	/**
127
-	 * @param string $type
128
-	 * @param bool $raw
129
-	 * @return string
130
-	 */
131
-	public function hash($type, $raw = false) {
132
-		return $this->view->hash($type, $this->path, $raw);
133
-	}
126
+    /**
127
+     * @param string $type
128
+     * @param bool $raw
129
+     * @return string
130
+     */
131
+    public function hash($type, $raw = false) {
132
+        return $this->view->hash($type, $this->path, $raw);
133
+    }
134 134
 
135
-	/**
136
-	 * @inheritdoc
137
-	 */
138
-	public function getChecksum() {
139
-		return $this->getFileInfo()->getChecksum();
140
-	}
135
+    /**
136
+     * @inheritdoc
137
+     */
138
+    public function getChecksum() {
139
+        return $this->getFileInfo()->getChecksum();
140
+    }
141 141
 }
Please login to merge, or discard this patch.
lib/private/Files/Node/Folder.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -37,7 +37,7 @@
 block discarded – undo
37 37
 	 * Creates a Folder that represents a non-existing path
38 38
 	 *
39 39
 	 * @param string $path path
40
-	 * @return string non-existing node class
40
+	 * @return NonExistingFolder non-existing node class
41 41
 	 */
42 42
 	protected function createNonExistingNode($path) {
43 43
 		return new NonExistingFolder($this->root, $this->view, $path);
Please login to merge, or discard this patch.
Indentation   +395 added lines, -395 removed lines patch added patch discarded remove patch
@@ -36,399 +36,399 @@
 block discarded – undo
36 36
 use OCP\Files\Search\ISearchOperator;
37 37
 
38 38
 class Folder extends Node implements \OCP\Files\Folder {
39
-	/**
40
-	 * Creates a Folder that represents a non-existing path
41
-	 *
42
-	 * @param string $path path
43
-	 * @return string non-existing node class
44
-	 */
45
-	protected function createNonExistingNode($path) {
46
-		return new NonExistingFolder($this->root, $this->view, $path);
47
-	}
48
-
49
-	/**
50
-	 * @param string $path path relative to the folder
51
-	 * @return string
52
-	 * @throws \OCP\Files\NotPermittedException
53
-	 */
54
-	public function getFullPath($path) {
55
-		if (!$this->isValidPath($path)) {
56
-			throw new NotPermittedException('Invalid path');
57
-		}
58
-		return $this->path . $this->normalizePath($path);
59
-	}
60
-
61
-	/**
62
-	 * @param string $path
63
-	 * @return string
64
-	 */
65
-	public function getRelativePath($path) {
66
-		if ($this->path === '' or $this->path === '/') {
67
-			return $this->normalizePath($path);
68
-		}
69
-		if ($path === $this->path) {
70
-			return '/';
71
-		} else if (strpos($path, $this->path . '/') !== 0) {
72
-			return null;
73
-		} else {
74
-			$path = substr($path, strlen($this->path));
75
-			return $this->normalizePath($path);
76
-		}
77
-	}
78
-
79
-	/**
80
-	 * check if a node is a (grand-)child of the folder
81
-	 *
82
-	 * @param \OC\Files\Node\Node $node
83
-	 * @return bool
84
-	 */
85
-	public function isSubNode($node) {
86
-		return strpos($node->getPath(), $this->path . '/') === 0;
87
-	}
88
-
89
-	/**
90
-	 * get the content of this directory
91
-	 *
92
-	 * @throws \OCP\Files\NotFoundException
93
-	 * @return Node[]
94
-	 */
95
-	public function getDirectoryListing() {
96
-		$folderContent = $this->view->getDirectoryContent($this->path);
97
-
98
-		return array_map(function (FileInfo $info) {
99
-			if ($info->getMimetype() === 'httpd/unix-directory') {
100
-				return new Folder($this->root, $this->view, $info->getPath(), $info);
101
-			} else {
102
-				return new File($this->root, $this->view, $info->getPath(), $info);
103
-			}
104
-		}, $folderContent);
105
-	}
106
-
107
-	/**
108
-	 * @param string $path
109
-	 * @param FileInfo $info
110
-	 * @return File|Folder
111
-	 */
112
-	protected function createNode($path, FileInfo $info = null) {
113
-		if (is_null($info)) {
114
-			$isDir = $this->view->is_dir($path);
115
-		} else {
116
-			$isDir = $info->getType() === FileInfo::TYPE_FOLDER;
117
-		}
118
-		if ($isDir) {
119
-			return new Folder($this->root, $this->view, $path, $info);
120
-		} else {
121
-			return new File($this->root, $this->view, $path, $info);
122
-		}
123
-	}
124
-
125
-	/**
126
-	 * Get the node at $path
127
-	 *
128
-	 * @param string $path
129
-	 * @return \OC\Files\Node\Node
130
-	 * @throws \OCP\Files\NotFoundException
131
-	 */
132
-	public function get($path) {
133
-		return $this->root->get($this->getFullPath($path));
134
-	}
135
-
136
-	/**
137
-	 * @param string $path
138
-	 * @return bool
139
-	 */
140
-	public function nodeExists($path) {
141
-		try {
142
-			$this->get($path);
143
-			return true;
144
-		} catch (NotFoundException $e) {
145
-			return false;
146
-		}
147
-	}
148
-
149
-	/**
150
-	 * @param string $path
151
-	 * @return \OC\Files\Node\Folder
152
-	 * @throws \OCP\Files\NotPermittedException
153
-	 */
154
-	public function newFolder($path) {
155
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
156
-			$fullPath = $this->getFullPath($path);
157
-			$nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
158
-			$this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
159
-			$this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
160
-			$this->view->mkdir($fullPath);
161
-			$node = new Folder($this->root, $this->view, $fullPath);
162
-			$this->root->emit('\OC\Files', 'postWrite', array($node));
163
-			$this->root->emit('\OC\Files', 'postCreate', array($node));
164
-			return $node;
165
-		} else {
166
-			throw new NotPermittedException('No create permission for folder');
167
-		}
168
-	}
169
-
170
-	/**
171
-	 * @param string $path
172
-	 * @return \OC\Files\Node\File
173
-	 * @throws \OCP\Files\NotPermittedException
174
-	 */
175
-	public function newFile($path) {
176
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
177
-			$fullPath = $this->getFullPath($path);
178
-			$nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
179
-			$this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
180
-			$this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
181
-			$this->view->touch($fullPath);
182
-			$node = new File($this->root, $this->view, $fullPath);
183
-			$this->root->emit('\OC\Files', 'postWrite', array($node));
184
-			$this->root->emit('\OC\Files', 'postCreate', array($node));
185
-			return $node;
186
-		} else {
187
-			throw new NotPermittedException('No create permission for path');
188
-		}
189
-	}
190
-
191
-	/**
192
-	 * search for files with the name matching $query
193
-	 *
194
-	 * @param string|ISearchOperator $query
195
-	 * @return \OC\Files\Node\Node[]
196
-	 */
197
-	public function search($query) {
198
-		if (is_string($query)) {
199
-			return $this->searchCommon('search', array('%' . $query . '%'));
200
-		} else {
201
-			return $this->searchCommon('searchQuery', array($query));
202
-		}
203
-	}
204
-
205
-	/**
206
-	 * search for files by mimetype
207
-	 *
208
-	 * @param string $mimetype
209
-	 * @return Node[]
210
-	 */
211
-	public function searchByMime($mimetype) {
212
-		return $this->searchCommon('searchByMime', array($mimetype));
213
-	}
214
-
215
-	/**
216
-	 * search for files by tag
217
-	 *
218
-	 * @param string|int $tag name or tag id
219
-	 * @param string $userId owner of the tags
220
-	 * @return Node[]
221
-	 */
222
-	public function searchByTag($tag, $userId) {
223
-		return $this->searchCommon('searchByTag', array($tag, $userId));
224
-	}
225
-
226
-	/**
227
-	 * @param string $method cache method
228
-	 * @param array $args call args
229
-	 * @return \OC\Files\Node\Node[]
230
-	 */
231
-	private function searchCommon($method, $args) {
232
-		$files = array();
233
-		$rootLength = strlen($this->path);
234
-		$mount = $this->root->getMount($this->path);
235
-		$storage = $mount->getStorage();
236
-		$internalPath = $mount->getInternalPath($this->path);
237
-		$internalPath = rtrim($internalPath, '/');
238
-		if ($internalPath !== '') {
239
-			$internalPath = $internalPath . '/';
240
-		}
241
-		$internalRootLength = strlen($internalPath);
242
-
243
-		$cache = $storage->getCache('');
244
-
245
-		$results = call_user_func_array(array($cache, $method), $args);
246
-		foreach ($results as $result) {
247
-			if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) {
248
-				$result['internalPath'] = $result['path'];
249
-				$result['path'] = substr($result['path'], $internalRootLength);
250
-				$result['storage'] = $storage;
251
-				$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
252
-			}
253
-		}
254
-
255
-		$mounts = $this->root->getMountsIn($this->path);
256
-		foreach ($mounts as $mount) {
257
-			$storage = $mount->getStorage();
258
-			if ($storage) {
259
-				$cache = $storage->getCache('');
260
-
261
-				$relativeMountPoint = substr($mount->getMountPoint(), $rootLength);
262
-				$results = call_user_func_array(array($cache, $method), $args);
263
-				foreach ($results as $result) {
264
-					$result['internalPath'] = $result['path'];
265
-					$result['path'] = $relativeMountPoint . $result['path'];
266
-					$result['storage'] = $storage;
267
-					$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
268
-				}
269
-			}
270
-		}
271
-
272
-		return array_map(function (FileInfo $file) {
273
-			return $this->createNode($file->getPath(), $file);
274
-		}, $files);
275
-	}
276
-
277
-	/**
278
-	 * @param int $id
279
-	 * @return \OC\Files\Node\Node[]
280
-	 */
281
-	public function getById($id) {
282
-		$mountCache = $this->root->getUserMountCache();
283
-		if (strpos($this->getPath(), '/', 1) > 0) {
284
-			list(, $user) = explode('/', $this->getPath());
285
-		} else {
286
-			$user = null;
287
-		}
288
-		$mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
289
-		$mounts = $this->root->getMountsIn($this->path);
290
-		$mounts[] = $this->root->getMount($this->path);
291
-		/** @var IMountPoint[] $folderMounts */
292
-		$folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
293
-			return $mountPoint->getMountPoint();
294
-		}, $mounts), $mounts);
295
-
296
-		/** @var ICachedMountInfo[] $mountsContainingFile */
297
-		$mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
298
-			return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
299
-		}));
300
-
301
-		if (count($mountsContainingFile) === 0) {
302
-			return [];
303
-		}
304
-
305
-		// we only need to get the cache info once, since all mounts we found point to the same storage
306
-
307
-		$mount = $folderMounts[$mountsContainingFile[0]->getMountPoint()];
308
-		$cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
309
-		if (!$cacheEntry) {
310
-			return [];
311
-		}
312
-		// cache jails will hide the "true" internal path
313
-		$internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
314
-
315
-		$nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
316
-			$mount = $folderMounts[$cachedMountInfo->getMountPoint()];
317
-			$pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
318
-			$pathRelativeToMount = ltrim($pathRelativeToMount, '/');
319
-			$absolutePath = $cachedMountInfo->getMountPoint() . $pathRelativeToMount;
320
-			return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
321
-				$absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
322
-				\OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
323
-			));
324
-		}, $mountsContainingFile);
325
-
326
-		return array_filter($nodes, function (Node $node) {
327
-			return $this->getRelativePath($node->getPath());
328
-		});
329
-	}
330
-
331
-	public function getFreeSpace() {
332
-		return $this->view->free_space($this->path);
333
-	}
334
-
335
-	public function delete() {
336
-		if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
337
-			$this->sendHooks(array('preDelete'));
338
-			$fileInfo = $this->getFileInfo();
339
-			$this->view->rmdir($this->path);
340
-			$nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
341
-			$this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
342
-			$this->exists = false;
343
-		} else {
344
-			throw new NotPermittedException('No delete permission for path');
345
-		}
346
-	}
347
-
348
-	/**
349
-	 * Add a suffix to the name in case the file exists
350
-	 *
351
-	 * @param string $name
352
-	 * @return string
353
-	 * @throws NotPermittedException
354
-	 */
355
-	public function getNonExistingName($name) {
356
-		$uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
357
-		return trim($this->getRelativePath($uniqueName), '/');
358
-	}
359
-
360
-	/**
361
-	 * @param int $limit
362
-	 * @param int $offset
363
-	 * @return \OCP\Files\Node[]
364
-	 */
365
-	public function getRecent($limit, $offset = 0) {
366
-		$mimetypeLoader = \OC::$server->getMimeTypeLoader();
367
-		$mounts = $this->root->getMountsIn($this->path);
368
-		$mounts[] = $this->getMountPoint();
369
-
370
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
371
-			return $mount->getStorage();
372
-		});
373
-		$storageIds = array_map(function (IMountPoint $mount) {
374
-			return $mount->getStorage()->getCache()->getNumericStorageId();
375
-		}, $mounts);
376
-		/** @var IMountPoint[] $mountMap */
377
-		$mountMap = array_combine($storageIds, $mounts);
378
-		$folderMimetype = $mimetypeLoader->getId(FileInfo::MIMETYPE_FOLDER);
379
-
380
-		//todo look into options of filtering path based on storage id (only search in files/ for home storage, filter by share root for shared, etc)
381
-
382
-		$builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
383
-		$query = $builder
384
-			->select('f.*')
385
-			->from('filecache', 'f')
386
-			->andWhere($builder->expr()->in('f.storage', $builder->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)))
387
-			->andWhere($builder->expr()->orX(
388
-			// handle non empty folders separate
389
-				$builder->expr()->neq('f.mimetype', $builder->createNamedParameter($folderMimetype, IQueryBuilder::PARAM_INT)),
390
-				$builder->expr()->eq('f.size', new Literal(0))
391
-			))
392
-			->orderBy('f.mtime', 'DESC')
393
-			->setMaxResults($limit)
394
-			->setFirstResult($offset);
395
-
396
-		$result = $query->execute()->fetchAll();
397
-
398
-		$files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
399
-			$mount = $mountMap[$entry['storage']];
400
-			$entry['internalPath'] = $entry['path'];
401
-			$entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
402
-			$entry['mimepart'] = $mimetypeLoader->getMimetypeById($entry['mimepart']);
403
-			$path = $this->getAbsolutePath($mount, $entry['path']);
404
-			if (is_null($path)) {
405
-				return null;
406
-			}
407
-			$fileInfo = new \OC\Files\FileInfo($path, $mount->getStorage(), $entry['internalPath'], $entry, $mount);
408
-			return $this->root->createNode($fileInfo->getPath(), $fileInfo);
409
-		}, $result));
410
-
411
-		return array_values(array_filter($files, function (Node $node) {
412
-			$relative = $this->getRelativePath($node->getPath());
413
-			return $relative !== null && $relative !== '/';
414
-		}));
415
-	}
416
-
417
-	private function getAbsolutePath(IMountPoint $mount, $path) {
418
-		$storage = $mount->getStorage();
419
-		if ($storage->instanceOfStorage('\OC\Files\Storage\Wrapper\Jail')) {
420
-			/** @var \OC\Files\Storage\Wrapper\Jail $storage */
421
-			$jailRoot = $storage->getUnjailedPath('');
422
-			$rootLength = strlen($jailRoot) + 1;
423
-			if ($path === $jailRoot) {
424
-				return $mount->getMountPoint();
425
-			} else if (substr($path, 0, $rootLength) === $jailRoot . '/') {
426
-				return $mount->getMountPoint() . substr($path, $rootLength);
427
-			} else {
428
-				return null;
429
-			}
430
-		} else {
431
-			return $mount->getMountPoint() . $path;
432
-		}
433
-	}
39
+    /**
40
+     * Creates a Folder that represents a non-existing path
41
+     *
42
+     * @param string $path path
43
+     * @return string non-existing node class
44
+     */
45
+    protected function createNonExistingNode($path) {
46
+        return new NonExistingFolder($this->root, $this->view, $path);
47
+    }
48
+
49
+    /**
50
+     * @param string $path path relative to the folder
51
+     * @return string
52
+     * @throws \OCP\Files\NotPermittedException
53
+     */
54
+    public function getFullPath($path) {
55
+        if (!$this->isValidPath($path)) {
56
+            throw new NotPermittedException('Invalid path');
57
+        }
58
+        return $this->path . $this->normalizePath($path);
59
+    }
60
+
61
+    /**
62
+     * @param string $path
63
+     * @return string
64
+     */
65
+    public function getRelativePath($path) {
66
+        if ($this->path === '' or $this->path === '/') {
67
+            return $this->normalizePath($path);
68
+        }
69
+        if ($path === $this->path) {
70
+            return '/';
71
+        } else if (strpos($path, $this->path . '/') !== 0) {
72
+            return null;
73
+        } else {
74
+            $path = substr($path, strlen($this->path));
75
+            return $this->normalizePath($path);
76
+        }
77
+    }
78
+
79
+    /**
80
+     * check if a node is a (grand-)child of the folder
81
+     *
82
+     * @param \OC\Files\Node\Node $node
83
+     * @return bool
84
+     */
85
+    public function isSubNode($node) {
86
+        return strpos($node->getPath(), $this->path . '/') === 0;
87
+    }
88
+
89
+    /**
90
+     * get the content of this directory
91
+     *
92
+     * @throws \OCP\Files\NotFoundException
93
+     * @return Node[]
94
+     */
95
+    public function getDirectoryListing() {
96
+        $folderContent = $this->view->getDirectoryContent($this->path);
97
+
98
+        return array_map(function (FileInfo $info) {
99
+            if ($info->getMimetype() === 'httpd/unix-directory') {
100
+                return new Folder($this->root, $this->view, $info->getPath(), $info);
101
+            } else {
102
+                return new File($this->root, $this->view, $info->getPath(), $info);
103
+            }
104
+        }, $folderContent);
105
+    }
106
+
107
+    /**
108
+     * @param string $path
109
+     * @param FileInfo $info
110
+     * @return File|Folder
111
+     */
112
+    protected function createNode($path, FileInfo $info = null) {
113
+        if (is_null($info)) {
114
+            $isDir = $this->view->is_dir($path);
115
+        } else {
116
+            $isDir = $info->getType() === FileInfo::TYPE_FOLDER;
117
+        }
118
+        if ($isDir) {
119
+            return new Folder($this->root, $this->view, $path, $info);
120
+        } else {
121
+            return new File($this->root, $this->view, $path, $info);
122
+        }
123
+    }
124
+
125
+    /**
126
+     * Get the node at $path
127
+     *
128
+     * @param string $path
129
+     * @return \OC\Files\Node\Node
130
+     * @throws \OCP\Files\NotFoundException
131
+     */
132
+    public function get($path) {
133
+        return $this->root->get($this->getFullPath($path));
134
+    }
135
+
136
+    /**
137
+     * @param string $path
138
+     * @return bool
139
+     */
140
+    public function nodeExists($path) {
141
+        try {
142
+            $this->get($path);
143
+            return true;
144
+        } catch (NotFoundException $e) {
145
+            return false;
146
+        }
147
+    }
148
+
149
+    /**
150
+     * @param string $path
151
+     * @return \OC\Files\Node\Folder
152
+     * @throws \OCP\Files\NotPermittedException
153
+     */
154
+    public function newFolder($path) {
155
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
156
+            $fullPath = $this->getFullPath($path);
157
+            $nonExisting = new NonExistingFolder($this->root, $this->view, $fullPath);
158
+            $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
159
+            $this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
160
+            $this->view->mkdir($fullPath);
161
+            $node = new Folder($this->root, $this->view, $fullPath);
162
+            $this->root->emit('\OC\Files', 'postWrite', array($node));
163
+            $this->root->emit('\OC\Files', 'postCreate', array($node));
164
+            return $node;
165
+        } else {
166
+            throw new NotPermittedException('No create permission for folder');
167
+        }
168
+    }
169
+
170
+    /**
171
+     * @param string $path
172
+     * @return \OC\Files\Node\File
173
+     * @throws \OCP\Files\NotPermittedException
174
+     */
175
+    public function newFile($path) {
176
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_CREATE)) {
177
+            $fullPath = $this->getFullPath($path);
178
+            $nonExisting = new NonExistingFile($this->root, $this->view, $fullPath);
179
+            $this->root->emit('\OC\Files', 'preWrite', array($nonExisting));
180
+            $this->root->emit('\OC\Files', 'preCreate', array($nonExisting));
181
+            $this->view->touch($fullPath);
182
+            $node = new File($this->root, $this->view, $fullPath);
183
+            $this->root->emit('\OC\Files', 'postWrite', array($node));
184
+            $this->root->emit('\OC\Files', 'postCreate', array($node));
185
+            return $node;
186
+        } else {
187
+            throw new NotPermittedException('No create permission for path');
188
+        }
189
+    }
190
+
191
+    /**
192
+     * search for files with the name matching $query
193
+     *
194
+     * @param string|ISearchOperator $query
195
+     * @return \OC\Files\Node\Node[]
196
+     */
197
+    public function search($query) {
198
+        if (is_string($query)) {
199
+            return $this->searchCommon('search', array('%' . $query . '%'));
200
+        } else {
201
+            return $this->searchCommon('searchQuery', array($query));
202
+        }
203
+    }
204
+
205
+    /**
206
+     * search for files by mimetype
207
+     *
208
+     * @param string $mimetype
209
+     * @return Node[]
210
+     */
211
+    public function searchByMime($mimetype) {
212
+        return $this->searchCommon('searchByMime', array($mimetype));
213
+    }
214
+
215
+    /**
216
+     * search for files by tag
217
+     *
218
+     * @param string|int $tag name or tag id
219
+     * @param string $userId owner of the tags
220
+     * @return Node[]
221
+     */
222
+    public function searchByTag($tag, $userId) {
223
+        return $this->searchCommon('searchByTag', array($tag, $userId));
224
+    }
225
+
226
+    /**
227
+     * @param string $method cache method
228
+     * @param array $args call args
229
+     * @return \OC\Files\Node\Node[]
230
+     */
231
+    private function searchCommon($method, $args) {
232
+        $files = array();
233
+        $rootLength = strlen($this->path);
234
+        $mount = $this->root->getMount($this->path);
235
+        $storage = $mount->getStorage();
236
+        $internalPath = $mount->getInternalPath($this->path);
237
+        $internalPath = rtrim($internalPath, '/');
238
+        if ($internalPath !== '') {
239
+            $internalPath = $internalPath . '/';
240
+        }
241
+        $internalRootLength = strlen($internalPath);
242
+
243
+        $cache = $storage->getCache('');
244
+
245
+        $results = call_user_func_array(array($cache, $method), $args);
246
+        foreach ($results as $result) {
247
+            if ($internalRootLength === 0 or substr($result['path'], 0, $internalRootLength) === $internalPath) {
248
+                $result['internalPath'] = $result['path'];
249
+                $result['path'] = substr($result['path'], $internalRootLength);
250
+                $result['storage'] = $storage;
251
+                $files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
252
+            }
253
+        }
254
+
255
+        $mounts = $this->root->getMountsIn($this->path);
256
+        foreach ($mounts as $mount) {
257
+            $storage = $mount->getStorage();
258
+            if ($storage) {
259
+                $cache = $storage->getCache('');
260
+
261
+                $relativeMountPoint = substr($mount->getMountPoint(), $rootLength);
262
+                $results = call_user_func_array(array($cache, $method), $args);
263
+                foreach ($results as $result) {
264
+                    $result['internalPath'] = $result['path'];
265
+                    $result['path'] = $relativeMountPoint . $result['path'];
266
+                    $result['storage'] = $storage;
267
+                    $files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
268
+                }
269
+            }
270
+        }
271
+
272
+        return array_map(function (FileInfo $file) {
273
+            return $this->createNode($file->getPath(), $file);
274
+        }, $files);
275
+    }
276
+
277
+    /**
278
+     * @param int $id
279
+     * @return \OC\Files\Node\Node[]
280
+     */
281
+    public function getById($id) {
282
+        $mountCache = $this->root->getUserMountCache();
283
+        if (strpos($this->getPath(), '/', 1) > 0) {
284
+            list(, $user) = explode('/', $this->getPath());
285
+        } else {
286
+            $user = null;
287
+        }
288
+        $mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
289
+        $mounts = $this->root->getMountsIn($this->path);
290
+        $mounts[] = $this->root->getMount($this->path);
291
+        /** @var IMountPoint[] $folderMounts */
292
+        $folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
293
+            return $mountPoint->getMountPoint();
294
+        }, $mounts), $mounts);
295
+
296
+        /** @var ICachedMountInfo[] $mountsContainingFile */
297
+        $mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
298
+            return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
299
+        }));
300
+
301
+        if (count($mountsContainingFile) === 0) {
302
+            return [];
303
+        }
304
+
305
+        // we only need to get the cache info once, since all mounts we found point to the same storage
306
+
307
+        $mount = $folderMounts[$mountsContainingFile[0]->getMountPoint()];
308
+        $cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
309
+        if (!$cacheEntry) {
310
+            return [];
311
+        }
312
+        // cache jails will hide the "true" internal path
313
+        $internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
314
+
315
+        $nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
316
+            $mount = $folderMounts[$cachedMountInfo->getMountPoint()];
317
+            $pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
318
+            $pathRelativeToMount = ltrim($pathRelativeToMount, '/');
319
+            $absolutePath = $cachedMountInfo->getMountPoint() . $pathRelativeToMount;
320
+            return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
321
+                $absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
322
+                \OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
323
+            ));
324
+        }, $mountsContainingFile);
325
+
326
+        return array_filter($nodes, function (Node $node) {
327
+            return $this->getRelativePath($node->getPath());
328
+        });
329
+    }
330
+
331
+    public function getFreeSpace() {
332
+        return $this->view->free_space($this->path);
333
+    }
334
+
335
+    public function delete() {
336
+        if ($this->checkPermissions(\OCP\Constants::PERMISSION_DELETE)) {
337
+            $this->sendHooks(array('preDelete'));
338
+            $fileInfo = $this->getFileInfo();
339
+            $this->view->rmdir($this->path);
340
+            $nonExisting = new NonExistingFolder($this->root, $this->view, $this->path, $fileInfo);
341
+            $this->root->emit('\OC\Files', 'postDelete', array($nonExisting));
342
+            $this->exists = false;
343
+        } else {
344
+            throw new NotPermittedException('No delete permission for path');
345
+        }
346
+    }
347
+
348
+    /**
349
+     * Add a suffix to the name in case the file exists
350
+     *
351
+     * @param string $name
352
+     * @return string
353
+     * @throws NotPermittedException
354
+     */
355
+    public function getNonExistingName($name) {
356
+        $uniqueName = \OC_Helper::buildNotExistingFileNameForView($this->getPath(), $name, $this->view);
357
+        return trim($this->getRelativePath($uniqueName), '/');
358
+    }
359
+
360
+    /**
361
+     * @param int $limit
362
+     * @param int $offset
363
+     * @return \OCP\Files\Node[]
364
+     */
365
+    public function getRecent($limit, $offset = 0) {
366
+        $mimetypeLoader = \OC::$server->getMimeTypeLoader();
367
+        $mounts = $this->root->getMountsIn($this->path);
368
+        $mounts[] = $this->getMountPoint();
369
+
370
+        $mounts = array_filter($mounts, function (IMountPoint $mount) {
371
+            return $mount->getStorage();
372
+        });
373
+        $storageIds = array_map(function (IMountPoint $mount) {
374
+            return $mount->getStorage()->getCache()->getNumericStorageId();
375
+        }, $mounts);
376
+        /** @var IMountPoint[] $mountMap */
377
+        $mountMap = array_combine($storageIds, $mounts);
378
+        $folderMimetype = $mimetypeLoader->getId(FileInfo::MIMETYPE_FOLDER);
379
+
380
+        //todo look into options of filtering path based on storage id (only search in files/ for home storage, filter by share root for shared, etc)
381
+
382
+        $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
383
+        $query = $builder
384
+            ->select('f.*')
385
+            ->from('filecache', 'f')
386
+            ->andWhere($builder->expr()->in('f.storage', $builder->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)))
387
+            ->andWhere($builder->expr()->orX(
388
+            // handle non empty folders separate
389
+                $builder->expr()->neq('f.mimetype', $builder->createNamedParameter($folderMimetype, IQueryBuilder::PARAM_INT)),
390
+                $builder->expr()->eq('f.size', new Literal(0))
391
+            ))
392
+            ->orderBy('f.mtime', 'DESC')
393
+            ->setMaxResults($limit)
394
+            ->setFirstResult($offset);
395
+
396
+        $result = $query->execute()->fetchAll();
397
+
398
+        $files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
399
+            $mount = $mountMap[$entry['storage']];
400
+            $entry['internalPath'] = $entry['path'];
401
+            $entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
402
+            $entry['mimepart'] = $mimetypeLoader->getMimetypeById($entry['mimepart']);
403
+            $path = $this->getAbsolutePath($mount, $entry['path']);
404
+            if (is_null($path)) {
405
+                return null;
406
+            }
407
+            $fileInfo = new \OC\Files\FileInfo($path, $mount->getStorage(), $entry['internalPath'], $entry, $mount);
408
+            return $this->root->createNode($fileInfo->getPath(), $fileInfo);
409
+        }, $result));
410
+
411
+        return array_values(array_filter($files, function (Node $node) {
412
+            $relative = $this->getRelativePath($node->getPath());
413
+            return $relative !== null && $relative !== '/';
414
+        }));
415
+    }
416
+
417
+    private function getAbsolutePath(IMountPoint $mount, $path) {
418
+        $storage = $mount->getStorage();
419
+        if ($storage->instanceOfStorage('\OC\Files\Storage\Wrapper\Jail')) {
420
+            /** @var \OC\Files\Storage\Wrapper\Jail $storage */
421
+            $jailRoot = $storage->getUnjailedPath('');
422
+            $rootLength = strlen($jailRoot) + 1;
423
+            if ($path === $jailRoot) {
424
+                return $mount->getMountPoint();
425
+            } else if (substr($path, 0, $rootLength) === $jailRoot . '/') {
426
+                return $mount->getMountPoint() . substr($path, $rootLength);
427
+            } else {
428
+                return null;
429
+            }
430
+        } else {
431
+            return $mount->getMountPoint() . $path;
432
+        }
433
+    }
434 434
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -55,7 +55,7 @@  discard block
 block discarded – undo
55 55
 		if (!$this->isValidPath($path)) {
56 56
 			throw new NotPermittedException('Invalid path');
57 57
 		}
58
-		return $this->path . $this->normalizePath($path);
58
+		return $this->path.$this->normalizePath($path);
59 59
 	}
60 60
 
61 61
 	/**
@@ -68,7 +68,7 @@  discard block
 block discarded – undo
68 68
 		}
69 69
 		if ($path === $this->path) {
70 70
 			return '/';
71
-		} else if (strpos($path, $this->path . '/') !== 0) {
71
+		} else if (strpos($path, $this->path.'/') !== 0) {
72 72
 			return null;
73 73
 		} else {
74 74
 			$path = substr($path, strlen($this->path));
@@ -83,7 +83,7 @@  discard block
 block discarded – undo
83 83
 	 * @return bool
84 84
 	 */
85 85
 	public function isSubNode($node) {
86
-		return strpos($node->getPath(), $this->path . '/') === 0;
86
+		return strpos($node->getPath(), $this->path.'/') === 0;
87 87
 	}
88 88
 
89 89
 	/**
@@ -95,7 +95,7 @@  discard block
 block discarded – undo
95 95
 	public function getDirectoryListing() {
96 96
 		$folderContent = $this->view->getDirectoryContent($this->path);
97 97
 
98
-		return array_map(function (FileInfo $info) {
98
+		return array_map(function(FileInfo $info) {
99 99
 			if ($info->getMimetype() === 'httpd/unix-directory') {
100 100
 				return new Folder($this->root, $this->view, $info->getPath(), $info);
101 101
 			} else {
@@ -196,7 +196,7 @@  discard block
 block discarded – undo
196 196
 	 */
197 197
 	public function search($query) {
198 198
 		if (is_string($query)) {
199
-			return $this->searchCommon('search', array('%' . $query . '%'));
199
+			return $this->searchCommon('search', array('%'.$query.'%'));
200 200
 		} else {
201 201
 			return $this->searchCommon('searchQuery', array($query));
202 202
 		}
@@ -236,7 +236,7 @@  discard block
 block discarded – undo
236 236
 		$internalPath = $mount->getInternalPath($this->path);
237 237
 		$internalPath = rtrim($internalPath, '/');
238 238
 		if ($internalPath !== '') {
239
-			$internalPath = $internalPath . '/';
239
+			$internalPath = $internalPath.'/';
240 240
 		}
241 241
 		$internalRootLength = strlen($internalPath);
242 242
 
@@ -248,7 +248,7 @@  discard block
 block discarded – undo
248 248
 				$result['internalPath'] = $result['path'];
249 249
 				$result['path'] = substr($result['path'], $internalRootLength);
250 250
 				$result['storage'] = $storage;
251
-				$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
251
+				$files[] = new \OC\Files\FileInfo($this->path.'/'.$result['path'], $storage, $result['internalPath'], $result, $mount);
252 252
 			}
253 253
 		}
254 254
 
@@ -262,14 +262,14 @@  discard block
 block discarded – undo
262 262
 				$results = call_user_func_array(array($cache, $method), $args);
263 263
 				foreach ($results as $result) {
264 264
 					$result['internalPath'] = $result['path'];
265
-					$result['path'] = $relativeMountPoint . $result['path'];
265
+					$result['path'] = $relativeMountPoint.$result['path'];
266 266
 					$result['storage'] = $storage;
267
-					$files[] = new \OC\Files\FileInfo($this->path . '/' . $result['path'], $storage, $result['internalPath'], $result, $mount);
267
+					$files[] = new \OC\Files\FileInfo($this->path.'/'.$result['path'], $storage, $result['internalPath'], $result, $mount);
268 268
 				}
269 269
 			}
270 270
 		}
271 271
 
272
-		return array_map(function (FileInfo $file) {
272
+		return array_map(function(FileInfo $file) {
273 273
 			return $this->createNode($file->getPath(), $file);
274 274
 		}, $files);
275 275
 	}
@@ -285,16 +285,16 @@  discard block
 block discarded – undo
285 285
 		} else {
286 286
 			$user = null;
287 287
 		}
288
-		$mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
288
+		$mountsContainingFile = $mountCache->getMountsForFileId((int) $id, $user);
289 289
 		$mounts = $this->root->getMountsIn($this->path);
290 290
 		$mounts[] = $this->root->getMount($this->path);
291 291
 		/** @var IMountPoint[] $folderMounts */
292
-		$folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) {
292
+		$folderMounts = array_combine(array_map(function(IMountPoint $mountPoint) {
293 293
 			return $mountPoint->getMountPoint();
294 294
 		}, $mounts), $mounts);
295 295
 
296 296
 		/** @var ICachedMountInfo[] $mountsContainingFile */
297
-		$mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
297
+		$mountsContainingFile = array_values(array_filter($mountsContainingFile, function(ICachedMountInfo $cachedMountInfo) use ($folderMounts) {
298 298
 			return isset($folderMounts[$cachedMountInfo->getMountPoint()]);
299 299
 		}));
300 300
 
@@ -305,25 +305,25 @@  discard block
 block discarded – undo
305 305
 		// we only need to get the cache info once, since all mounts we found point to the same storage
306 306
 
307 307
 		$mount = $folderMounts[$mountsContainingFile[0]->getMountPoint()];
308
-		$cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
308
+		$cacheEntry = $mount->getStorage()->getCache()->get((int) $id);
309 309
 		if (!$cacheEntry) {
310 310
 			return [];
311 311
 		}
312 312
 		// cache jails will hide the "true" internal path
313
-		$internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/');
313
+		$internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath().'/'.$cacheEntry->getPath(), '/');
314 314
 
315
-		$nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
315
+		$nodes = array_map(function(ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) {
316 316
 			$mount = $folderMounts[$cachedMountInfo->getMountPoint()];
317 317
 			$pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath()));
318 318
 			$pathRelativeToMount = ltrim($pathRelativeToMount, '/');
319
-			$absolutePath = $cachedMountInfo->getMountPoint() . $pathRelativeToMount;
319
+			$absolutePath = $cachedMountInfo->getMountPoint().$pathRelativeToMount;
320 320
 			return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
321 321
 				$absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
322 322
 				\OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
323 323
 			));
324 324
 		}, $mountsContainingFile);
325 325
 
326
-		return array_filter($nodes, function (Node $node) {
326
+		return array_filter($nodes, function(Node $node) {
327 327
 			return $this->getRelativePath($node->getPath());
328 328
 		});
329 329
 	}
@@ -367,10 +367,10 @@  discard block
 block discarded – undo
367 367
 		$mounts = $this->root->getMountsIn($this->path);
368 368
 		$mounts[] = $this->getMountPoint();
369 369
 
370
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
370
+		$mounts = array_filter($mounts, function(IMountPoint $mount) {
371 371
 			return $mount->getStorage();
372 372
 		});
373
-		$storageIds = array_map(function (IMountPoint $mount) {
373
+		$storageIds = array_map(function(IMountPoint $mount) {
374 374
 			return $mount->getStorage()->getCache()->getNumericStorageId();
375 375
 		}, $mounts);
376 376
 		/** @var IMountPoint[] $mountMap */
@@ -395,7 +395,7 @@  discard block
 block discarded – undo
395 395
 
396 396
 		$result = $query->execute()->fetchAll();
397 397
 
398
-		$files = array_filter(array_map(function (array $entry) use ($mountMap, $mimetypeLoader) {
398
+		$files = array_filter(array_map(function(array $entry) use ($mountMap, $mimetypeLoader) {
399 399
 			$mount = $mountMap[$entry['storage']];
400 400
 			$entry['internalPath'] = $entry['path'];
401 401
 			$entry['mimetype'] = $mimetypeLoader->getMimetypeById($entry['mimetype']);
@@ -408,7 +408,7 @@  discard block
 block discarded – undo
408 408
 			return $this->root->createNode($fileInfo->getPath(), $fileInfo);
409 409
 		}, $result));
410 410
 
411
-		return array_values(array_filter($files, function (Node $node) {
411
+		return array_values(array_filter($files, function(Node $node) {
412 412
 			$relative = $this->getRelativePath($node->getPath());
413 413
 			return $relative !== null && $relative !== '/';
414 414
 		}));
@@ -422,13 +422,13 @@  discard block
 block discarded – undo
422 422
 			$rootLength = strlen($jailRoot) + 1;
423 423
 			if ($path === $jailRoot) {
424 424
 				return $mount->getMountPoint();
425
-			} else if (substr($path, 0, $rootLength) === $jailRoot . '/') {
426
-				return $mount->getMountPoint() . substr($path, $rootLength);
425
+			} else if (substr($path, 0, $rootLength) === $jailRoot.'/') {
426
+				return $mount->getMountPoint().substr($path, $rootLength);
427 427
 			} else {
428 428
 				return null;
429 429
 			}
430 430
 		} else {
431
-			return $mount->getMountPoint() . $path;
431
+			return $mount->getMountPoint().$path;
432 432
 		}
433 433
 	}
434 434
 }
Please login to merge, or discard this patch.
lib/public/Settings/IIconSection.php 2 patches
Doc Comments   +1 added lines patch added patch discarded remove patch
@@ -33,6 +33,7 @@
 block discarded – undo
33 33
 	 *
34 34
 	 * @returns string
35 35
 	 * @since 12
36
+	 * @return string
36 37
 	 */
37 38
 	public function getIcon();
38 39
 }
Please login to merge, or discard this patch.
Indentation   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -27,12 +27,12 @@
 block discarded – undo
27 27
  * @since 12
28 28
  */
29 29
 interface IIconSection extends ISection {
30
-	/**
31
-	 * returns the relative path to an 16*16 icon describing the section.
32
-	 * e.g. '/core/img/places/files.svg'
33
-	 *
34
-	 * @returns string
35
-	 * @since 12
36
-	 */
37
-	public function getIcon();
30
+    /**
31
+     * returns the relative path to an 16*16 icon describing the section.
32
+     * e.g. '/core/img/places/files.svg'
33
+     *
34
+     * @returns string
35
+     * @since 12
36
+     */
37
+    public function getIcon();
38 38
 }
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Storage/FTP.php 4 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -139,6 +139,9 @@
 block discarded – undo
139 139
 		return false;
140 140
 	}
141 141
 
142
+	/**
143
+	 * @param string $path
144
+	 */
142 145
 	public function writeBack($tmpFile, $path) {
143 146
 		$this->uploadFile($tmpFile, $path);
144 147
 		unlink($tmpFile);
Please login to merge, or discard this patch.
Indentation   +109 added lines, -109 removed lines patch added patch discarded remove patch
@@ -37,122 +37,122 @@
 block discarded – undo
37 37
 use Icewind\Streams\RetryWrapper;
38 38
 
39 39
 class FTP extends StreamWrapper{
40
-	private $password;
41
-	private $user;
42
-	private $host;
43
-	private $secure;
44
-	private $root;
40
+    private $password;
41
+    private $user;
42
+    private $host;
43
+    private $secure;
44
+    private $root;
45 45
 
46
-	private static $tempFiles=array();
46
+    private static $tempFiles=array();
47 47
 
48
-	public function __construct($params) {
49
-		if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
50
-			$this->host=$params['host'];
51
-			$this->user=$params['user'];
52
-			$this->password=$params['password'];
53
-			if (isset($params['secure'])) {
54
-				$this->secure = $params['secure'];
55
-			} else {
56
-				$this->secure = false;
57
-			}
58
-			$this->root=isset($params['root'])?$params['root']:'/';
59
-			if ( ! $this->root || $this->root[0]!='/') {
60
-				$this->root='/'.$this->root;
61
-			}
62
-			if (substr($this->root, -1) !== '/') {
63
-				$this->root .= '/';
64
-			}
65
-		} else {
66
-			throw new \Exception('Creating FTP storage failed');
67
-		}
48
+    public function __construct($params) {
49
+        if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
50
+            $this->host=$params['host'];
51
+            $this->user=$params['user'];
52
+            $this->password=$params['password'];
53
+            if (isset($params['secure'])) {
54
+                $this->secure = $params['secure'];
55
+            } else {
56
+                $this->secure = false;
57
+            }
58
+            $this->root=isset($params['root'])?$params['root']:'/';
59
+            if ( ! $this->root || $this->root[0]!='/') {
60
+                $this->root='/'.$this->root;
61
+            }
62
+            if (substr($this->root, -1) !== '/') {
63
+                $this->root .= '/';
64
+            }
65
+        } else {
66
+            throw new \Exception('Creating FTP storage failed');
67
+        }
68 68
 		
69
-	}
69
+    }
70 70
 
71
-	public function getId(){
72
-		return 'ftp::' . $this->user . '@' . $this->host . '/' . $this->root;
73
-	}
71
+    public function getId(){
72
+        return 'ftp::' . $this->user . '@' . $this->host . '/' . $this->root;
73
+    }
74 74
 
75
-	/**
76
-	 * construct the ftp url
77
-	 * @param string $path
78
-	 * @return string
79
-	 */
80
-	public function constructUrl($path) {
81
-		$url='ftp';
82
-		if ($this->secure) {
83
-			$url.='s';
84
-		}
85
-		$url.='://'.urlencode($this->user).':'.urlencode($this->password).'@'.$this->host.$this->root.$path;
86
-		return $url;
87
-	}
75
+    /**
76
+     * construct the ftp url
77
+     * @param string $path
78
+     * @return string
79
+     */
80
+    public function constructUrl($path) {
81
+        $url='ftp';
82
+        if ($this->secure) {
83
+            $url.='s';
84
+        }
85
+        $url.='://'.urlencode($this->user).':'.urlencode($this->password).'@'.$this->host.$this->root.$path;
86
+        return $url;
87
+    }
88 88
 
89
-	/**
90
-	 * Unlinks file or directory
91
-	 * @param string $path
92
-	 */
93
-	public function unlink($path) {
94
-		if ($this->is_dir($path)) {
95
-			return $this->rmdir($path);
96
-		}
97
-		else {
98
-			$url = $this->constructUrl($path);
99
-			$result = unlink($url);
100
-			clearstatcache(true, $url);
101
-			return $result;
102
-		}
103
-	}
104
-	public function fopen($path,$mode) {
105
-		switch($mode) {
106
-			case 'r':
107
-			case 'rb':
108
-			case 'w':
109
-			case 'wb':
110
-			case 'a':
111
-			case 'ab':
112
-				//these are supported by the wrapper
113
-				$context = stream_context_create(array('ftp' => array('overwrite' => true)));
114
-				$handle = fopen($this->constructUrl($path), $mode, false, $context);
115
-				return RetryWrapper::wrap($handle);
116
-			case 'r+':
117
-			case 'w+':
118
-			case 'wb+':
119
-			case 'a+':
120
-			case 'x':
121
-			case 'x+':
122
-			case 'c':
123
-			case 'c+':
124
-				//emulate these
125
-				if (strrpos($path, '.')!==false) {
126
-					$ext=substr($path, strrpos($path, '.'));
127
-				} else {
128
-					$ext='';
129
-				}
130
-				$tmpFile=\OCP\Files::tmpFile($ext);
131
-				if ($this->file_exists($path)) {
132
-					$this->getFile($path, $tmpFile);
133
-				}
134
-				$handle = fopen($tmpFile, $mode);
135
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
136
-					$this->writeBack($tmpFile, $path);
137
-				});
138
-		}
139
-		return false;
140
-	}
89
+    /**
90
+     * Unlinks file or directory
91
+     * @param string $path
92
+     */
93
+    public function unlink($path) {
94
+        if ($this->is_dir($path)) {
95
+            return $this->rmdir($path);
96
+        }
97
+        else {
98
+            $url = $this->constructUrl($path);
99
+            $result = unlink($url);
100
+            clearstatcache(true, $url);
101
+            return $result;
102
+        }
103
+    }
104
+    public function fopen($path,$mode) {
105
+        switch($mode) {
106
+            case 'r':
107
+            case 'rb':
108
+            case 'w':
109
+            case 'wb':
110
+            case 'a':
111
+            case 'ab':
112
+                //these are supported by the wrapper
113
+                $context = stream_context_create(array('ftp' => array('overwrite' => true)));
114
+                $handle = fopen($this->constructUrl($path), $mode, false, $context);
115
+                return RetryWrapper::wrap($handle);
116
+            case 'r+':
117
+            case 'w+':
118
+            case 'wb+':
119
+            case 'a+':
120
+            case 'x':
121
+            case 'x+':
122
+            case 'c':
123
+            case 'c+':
124
+                //emulate these
125
+                if (strrpos($path, '.')!==false) {
126
+                    $ext=substr($path, strrpos($path, '.'));
127
+                } else {
128
+                    $ext='';
129
+                }
130
+                $tmpFile=\OCP\Files::tmpFile($ext);
131
+                if ($this->file_exists($path)) {
132
+                    $this->getFile($path, $tmpFile);
133
+                }
134
+                $handle = fopen($tmpFile, $mode);
135
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
136
+                    $this->writeBack($tmpFile, $path);
137
+                });
138
+        }
139
+        return false;
140
+    }
141 141
 
142
-	public function writeBack($tmpFile, $path) {
143
-		$this->uploadFile($tmpFile, $path);
144
-		unlink($tmpFile);
145
-	}
142
+    public function writeBack($tmpFile, $path) {
143
+        $this->uploadFile($tmpFile, $path);
144
+        unlink($tmpFile);
145
+    }
146 146
 
147
-	/**
148
-	 * check if php-ftp is installed
149
-	 */
150
-	public static function checkDependencies() {
151
-		if (function_exists('ftp_login')) {
152
-			return(true);
153
-		} else {
154
-			return array('ftp');
155
-		}
156
-	}
147
+    /**
148
+     * check if php-ftp is installed
149
+     */
150
+    public static function checkDependencies() {
151
+        if (function_exists('ftp_login')) {
152
+            return(true);
153
+        } else {
154
+            return array('ftp');
155
+        }
156
+    }
157 157
 
158 158
 }
Please login to merge, or discard this patch.
Spacing   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -36,28 +36,28 @@  discard block
 block discarded – undo
36 36
 use Icewind\Streams\CallbackWrapper;
37 37
 use Icewind\Streams\RetryWrapper;
38 38
 
39
-class FTP extends StreamWrapper{
39
+class FTP extends StreamWrapper {
40 40
 	private $password;
41 41
 	private $user;
42 42
 	private $host;
43 43
 	private $secure;
44 44
 	private $root;
45 45
 
46
-	private static $tempFiles=array();
46
+	private static $tempFiles = array();
47 47
 
48 48
 	public function __construct($params) {
49 49
 		if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
50
-			$this->host=$params['host'];
51
-			$this->user=$params['user'];
52
-			$this->password=$params['password'];
50
+			$this->host = $params['host'];
51
+			$this->user = $params['user'];
52
+			$this->password = $params['password'];
53 53
 			if (isset($params['secure'])) {
54 54
 				$this->secure = $params['secure'];
55 55
 			} else {
56 56
 				$this->secure = false;
57 57
 			}
58
-			$this->root=isset($params['root'])?$params['root']:'/';
59
-			if ( ! $this->root || $this->root[0]!='/') {
60
-				$this->root='/'.$this->root;
58
+			$this->root = isset($params['root']) ? $params['root'] : '/';
59
+			if (!$this->root || $this->root[0] != '/') {
60
+				$this->root = '/'.$this->root;
61 61
 			}
62 62
 			if (substr($this->root, -1) !== '/') {
63 63
 				$this->root .= '/';
@@ -68,8 +68,8 @@  discard block
 block discarded – undo
68 68
 		
69 69
 	}
70 70
 
71
-	public function getId(){
72
-		return 'ftp::' . $this->user . '@' . $this->host . '/' . $this->root;
71
+	public function getId() {
72
+		return 'ftp::'.$this->user.'@'.$this->host.'/'.$this->root;
73 73
 	}
74 74
 
75 75
 	/**
@@ -78,11 +78,11 @@  discard block
 block discarded – undo
78 78
 	 * @return string
79 79
 	 */
80 80
 	public function constructUrl($path) {
81
-		$url='ftp';
81
+		$url = 'ftp';
82 82
 		if ($this->secure) {
83
-			$url.='s';
83
+			$url .= 's';
84 84
 		}
85
-		$url.='://'.urlencode($this->user).':'.urlencode($this->password).'@'.$this->host.$this->root.$path;
85
+		$url .= '://'.urlencode($this->user).':'.urlencode($this->password).'@'.$this->host.$this->root.$path;
86 86
 		return $url;
87 87
 	}
88 88
 
@@ -101,8 +101,8 @@  discard block
 block discarded – undo
101 101
 			return $result;
102 102
 		}
103 103
 	}
104
-	public function fopen($path,$mode) {
105
-		switch($mode) {
104
+	public function fopen($path, $mode) {
105
+		switch ($mode) {
106 106
 			case 'r':
107 107
 			case 'rb':
108 108
 			case 'w':
@@ -122,17 +122,17 @@  discard block
 block discarded – undo
122 122
 			case 'c':
123 123
 			case 'c+':
124 124
 				//emulate these
125
-				if (strrpos($path, '.')!==false) {
126
-					$ext=substr($path, strrpos($path, '.'));
125
+				if (strrpos($path, '.') !== false) {
126
+					$ext = substr($path, strrpos($path, '.'));
127 127
 				} else {
128
-					$ext='';
128
+					$ext = '';
129 129
 				}
130
-				$tmpFile=\OCP\Files::tmpFile($ext);
130
+				$tmpFile = \OCP\Files::tmpFile($ext);
131 131
 				if ($this->file_exists($path)) {
132 132
 					$this->getFile($path, $tmpFile);
133 133
 				}
134 134
 				$handle = fopen($tmpFile, $mode);
135
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
135
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
136 136
 					$this->writeBack($tmpFile, $path);
137 137
 				});
138 138
 		}
Please login to merge, or discard this patch.
Braces   +1 added lines, -2 removed lines patch added patch discarded remove patch
@@ -93,8 +93,7 @@
 block discarded – undo
93 93
 	public function unlink($path) {
94 94
 		if ($this->is_dir($path)) {
95 95
 			return $this->rmdir($path);
96
-		}
97
-		else {
96
+		} else {
98 97
 			$url = $this->constructUrl($path);
99 98
 			$result = unlink($url);
100 99
 			clearstatcache(true, $url);
Please login to merge, or discard this patch.
apps/files_external/lib/Lib/Storage/Swift.php 3 patches
Doc Comments   +3 added lines patch added patch discarded remove patch
@@ -616,6 +616,9 @@
 block discarded – undo
616 616
 		return $this->container;
617 617
 	}
618 618
 
619
+	/**
620
+	 * @param string $path
621
+	 */
619 622
 	public function writeBack($tmpFile, $path) {
620 623
 		$fileData = fopen($tmpFile, 'r');
621 624
 		$this->getContainer()->uploadObject($path, $fileData);
Please login to merge, or discard this patch.
Indentation   +596 added lines, -596 removed lines patch added patch discarded remove patch
@@ -49,601 +49,601 @@
 block discarded – undo
49 49
 
50 50
 class Swift extends \OC\Files\Storage\Common {
51 51
 
52
-	/**
53
-	 * @var \OpenCloud\ObjectStore\Service
54
-	 */
55
-	private $connection;
56
-	/**
57
-	 * @var \OpenCloud\ObjectStore\Resource\Container
58
-	 */
59
-	private $container;
60
-	/**
61
-	 * @var \OpenCloud\OpenStack
62
-	 */
63
-	private $anchor;
64
-	/**
65
-	 * @var string
66
-	 */
67
-	private $bucket;
68
-	/**
69
-	 * Connection parameters
70
-	 *
71
-	 * @var array
72
-	 */
73
-	private $params;
74
-
75
-	/** @var string  */
76
-	private $id;
77
-
78
-	/**
79
-	 * Key value cache mapping path to data object. Maps path to
80
-	 * \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject for existing
81
-	 * paths and path to false for not existing paths.
82
-	 * @var \OCP\ICache
83
-	 */
84
-	private $objectCache;
85
-
86
-	/**
87
-	 * @param string $path
88
-	 */
89
-	private function normalizePath($path) {
90
-		$path = trim($path, '/');
91
-
92
-		if (!$path) {
93
-			$path = '.';
94
-		}
95
-
96
-		$path = str_replace('#', '%23', $path);
97
-
98
-		return $path;
99
-	}
100
-
101
-	const SUBCONTAINER_FILE = '.subcontainers';
102
-
103
-	/**
104
-	 * translate directory path to container name
105
-	 *
106
-	 * @param string $path
107
-	 * @return string
108
-	 */
109
-
110
-	/**
111
-	 * Fetches an object from the API.
112
-	 * If the object is cached already or a
113
-	 * failed "doesn't exist" response was cached,
114
-	 * that one will be returned.
115
-	 *
116
-	 * @param string $path
117
-	 * @return \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject|bool object
118
-	 * or false if the object did not exist
119
-	 */
120
-	private function fetchObject($path) {
121
-		if ($this->objectCache->hasKey($path)) {
122
-			// might be "false" if object did not exist from last check
123
-			return $this->objectCache->get($path);
124
-		}
125
-		try {
126
-			$object = $this->getContainer()->getPartialObject($path);
127
-			$this->objectCache->set($path, $object);
128
-			return $object;
129
-		} catch (ClientErrorResponseException $e) {
130
-			// this exception happens when the object does not exist, which
131
-			// is expected in most cases
132
-			$this->objectCache->set($path, false);
133
-			return false;
134
-		} catch (ClientErrorResponseException $e) {
135
-			// Expected response is "404 Not Found", so only log if it isn't
136
-			if ($e->getResponse()->getStatusCode() !== 404) {
137
-				\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
138
-			}
139
-			return false;
140
-		}
141
-	}
142
-
143
-	/**
144
-	 * Returns whether the given path exists.
145
-	 *
146
-	 * @param string $path
147
-	 *
148
-	 * @return bool true if the object exist, false otherwise
149
-	 */
150
-	private function doesObjectExist($path) {
151
-		return $this->fetchObject($path) !== false;
152
-	}
153
-
154
-	public function __construct($params) {
155
-		if ((empty($params['key']) and empty($params['password']))
156
-			or empty($params['user']) or empty($params['bucket'])
157
-			or empty($params['region'])
158
-		) {
159
-			throw new \Exception("API Key or password, Username, Bucket and Region have to be configured.");
160
-		}
161
-
162
-		$this->id = 'swift::' . $params['user'] . md5($params['bucket']);
163
-
164
-		$bucketUrl = Url::factory($params['bucket']);
165
-		if ($bucketUrl->isAbsolute()) {
166
-			$this->bucket = end(($bucketUrl->getPathSegments()));
167
-			$params['endpoint_url'] = $bucketUrl->addPath('..')->normalizePath();
168
-		} else {
169
-			$this->bucket = $params['bucket'];
170
-		}
171
-
172
-		if (empty($params['url'])) {
173
-			$params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
174
-		}
175
-
176
-		if (empty($params['service_name'])) {
177
-			$params['service_name'] = 'cloudFiles';
178
-		}
179
-
180
-		$this->params = $params;
181
-		// FIXME: private class...
182
-		$this->objectCache = new \OC\Cache\CappedMemoryCache();
183
-	}
184
-
185
-	public function mkdir($path) {
186
-		$path = $this->normalizePath($path);
187
-
188
-		if ($this->is_dir($path)) {
189
-			return false;
190
-		}
191
-
192
-		if ($path !== '.') {
193
-			$path .= '/';
194
-		}
195
-
196
-		try {
197
-			$customHeaders = array('content-type' => 'httpd/unix-directory');
198
-			$metadataHeaders = DataObject::stockHeaders(array());
199
-			$allHeaders = $customHeaders + $metadataHeaders;
200
-			$this->getContainer()->uploadObject($path, '', $allHeaders);
201
-			// invalidate so that the next access gets the real object
202
-			// with all properties
203
-			$this->objectCache->remove($path);
204
-		} catch (Exceptions\CreateUpdateError $e) {
205
-			\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
206
-			return false;
207
-		}
208
-
209
-		return true;
210
-	}
211
-
212
-	public function file_exists($path) {
213
-		$path = $this->normalizePath($path);
214
-
215
-		if ($path !== '.' && $this->is_dir($path)) {
216
-			$path .= '/';
217
-		}
218
-
219
-		return $this->doesObjectExist($path);
220
-	}
221
-
222
-	public function rmdir($path) {
223
-		$path = $this->normalizePath($path);
224
-
225
-		if (!$this->is_dir($path) || !$this->isDeletable($path)) {
226
-			return false;
227
-		}
228
-
229
-		$dh = $this->opendir($path);
230
-		while ($file = readdir($dh)) {
231
-			if (\OC\Files\Filesystem::isIgnoredDir($file)) {
232
-				continue;
233
-			}
234
-
235
-			if ($this->is_dir($path . '/' . $file)) {
236
-				$this->rmdir($path . '/' . $file);
237
-			} else {
238
-				$this->unlink($path . '/' . $file);
239
-			}
240
-		}
241
-
242
-		try {
243
-			$this->getContainer()->dataObject()->setName($path . '/')->delete();
244
-			$this->objectCache->remove($path . '/');
245
-		} catch (Exceptions\DeleteError $e) {
246
-			\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
247
-			return false;
248
-		}
249
-
250
-		return true;
251
-	}
252
-
253
-	public function opendir($path) {
254
-		$path = $this->normalizePath($path);
255
-
256
-		if ($path === '.') {
257
-			$path = '';
258
-		} else {
259
-			$path .= '/';
260
-		}
261
-
262
-		$path = str_replace('%23', '#', $path); // the prefix is sent as a query param, so revert the encoding of #
263
-
264
-		try {
265
-			$files = array();
266
-			/** @var OpenCloud\Common\Collection $objects */
267
-			$objects = $this->getContainer()->objectList(array(
268
-				'prefix' => $path,
269
-				'delimiter' => '/'
270
-			));
271
-
272
-			/** @var OpenCloud\ObjectStore\Resource\DataObject $object */
273
-			foreach ($objects as $object) {
274
-				$file = basename($object->getName());
275
-				if ($file !== basename($path) && $file !== '.') {
276
-					$files[] = $file;
277
-				}
278
-			}
279
-
280
-			return IteratorDirectory::wrap($files);
281
-		} catch (\Exception $e) {
282
-			\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
283
-			return false;
284
-		}
285
-
286
-	}
287
-
288
-	public function stat($path) {
289
-		$path = $this->normalizePath($path);
290
-
291
-		if ($path === '.') {
292
-			$path = '';
293
-		} else if ($this->is_dir($path)) {
294
-			$path .= '/';
295
-		}
296
-
297
-		try {
298
-			/** @var DataObject $object */
299
-			$object = $this->fetchObject($path);
300
-			if (!$object) {
301
-				return false;
302
-			}
303
-		} catch (ClientErrorResponseException $e) {
304
-			\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
305
-			return false;
306
-		}
307
-
308
-		$dateTime = \DateTime::createFromFormat(\DateTime::RFC1123, $object->getLastModified());
309
-		if ($dateTime !== false) {
310
-			$mtime = $dateTime->getTimestamp();
311
-		} else {
312
-			$mtime = null;
313
-		}
314
-		$objectMetadata = $object->getMetadata();
315
-		$metaTimestamp = $objectMetadata->getProperty('timestamp');
316
-		if (isset($metaTimestamp)) {
317
-			$mtime = $metaTimestamp;
318
-		}
319
-
320
-		if (!empty($mtime)) {
321
-			$mtime = floor($mtime);
322
-		}
323
-
324
-		$stat = array();
325
-		$stat['size'] = (int)$object->getContentLength();
326
-		$stat['mtime'] = $mtime;
327
-		$stat['atime'] = time();
328
-		return $stat;
329
-	}
330
-
331
-	public function filetype($path) {
332
-		$path = $this->normalizePath($path);
333
-
334
-		if ($path !== '.' && $this->doesObjectExist($path)) {
335
-			return 'file';
336
-		}
337
-
338
-		if ($path !== '.') {
339
-			$path .= '/';
340
-		}
341
-
342
-		if ($this->doesObjectExist($path)) {
343
-			return 'dir';
344
-		}
345
-	}
346
-
347
-	public function unlink($path) {
348
-		$path = $this->normalizePath($path);
349
-
350
-		if ($this->is_dir($path)) {
351
-			return $this->rmdir($path);
352
-		}
353
-
354
-		try {
355
-			$this->getContainer()->dataObject()->setName($path)->delete();
356
-			$this->objectCache->remove($path);
357
-			$this->objectCache->remove($path . '/');
358
-		} catch (ClientErrorResponseException $e) {
359
-			if ($e->getResponse()->getStatusCode() !== 404) {
360
-				\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
361
-			}
362
-			return false;
363
-		}
364
-
365
-		return true;
366
-	}
367
-
368
-	public function fopen($path, $mode) {
369
-		$path = $this->normalizePath($path);
370
-
371
-		switch ($mode) {
372
-			case 'a':
373
-			case 'ab':
374
-			case 'a+':
375
-				return false;
376
-			case 'r':
377
-			case 'rb':
378
-				try {
379
-					$c = $this->getContainer();
380
-					$streamFactory = new \Guzzle\Stream\PhpStreamRequestFactory();
381
-					$streamInterface = $streamFactory->fromRequest(
382
-						$c->getClient()
383
-							->get($c->getUrl($path)));
384
-					$streamInterface->rewind();
385
-					$stream = $streamInterface->getStream();
386
-					stream_context_set_option($stream, 'swift','content', $streamInterface);
387
-					if(!strrpos($streamInterface
388
-						->getMetaData('wrapper_data')[0], '404 Not Found')) {
389
-						return RetryWrapper::wrap($stream);
390
-					}
391
-					return false;
392
-				} catch (\Guzzle\Http\Exception\BadResponseException $e) {
393
-					\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
394
-					return false;
395
-				}
396
-			case 'w':
397
-			case 'wb':
398
-			case 'r+':
399
-			case 'w+':
400
-			case 'wb+':
401
-			case 'x':
402
-			case 'x+':
403
-			case 'c':
404
-			case 'c+':
405
-				if (strrpos($path, '.') !== false) {
406
-					$ext = substr($path, strrpos($path, '.'));
407
-				} else {
408
-					$ext = '';
409
-				}
410
-				$tmpFile = \OCP\Files::tmpFile($ext);
411
-				// Fetch existing file if required
412
-				if ($mode[0] !== 'w' && $this->file_exists($path)) {
413
-					if ($mode[0] === 'x') {
414
-						// File cannot already exist
415
-						return false;
416
-					}
417
-					$source = $this->fopen($path, 'r');
418
-					file_put_contents($tmpFile, $source);
419
-				}
420
-				$handle = fopen($tmpFile, $mode);
421
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
422
-					$this->writeBack($tmpFile, $path);
423
-				});
424
-		}
425
-	}
426
-
427
-	public function touch($path, $mtime = null) {
428
-		$path = $this->normalizePath($path);
429
-		if (is_null($mtime)) {
430
-			$mtime = time();
431
-		}
432
-		$metadata = array('timestamp' => $mtime);
433
-		if ($this->file_exists($path)) {
434
-			if ($this->is_dir($path) && $path != '.') {
435
-				$path .= '/';
436
-			}
437
-
438
-			$object = $this->fetchObject($path);
439
-			if ($object->saveMetadata($metadata)) {
440
-				// invalidate target object to force repopulation on fetch
441
-				$this->objectCache->remove($path);
442
-			}
443
-			return true;
444
-		} else {
445
-			$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
446
-			$customHeaders = array('content-type' => $mimeType);
447
-			$metadataHeaders = DataObject::stockHeaders($metadata);
448
-			$allHeaders = $customHeaders + $metadataHeaders;
449
-			$this->getContainer()->uploadObject($path, '', $allHeaders);
450
-			// invalidate target object to force repopulation on fetch
451
-			$this->objectCache->remove($path);
452
-			return true;
453
-		}
454
-	}
455
-
456
-	public function copy($path1, $path2) {
457
-		$path1 = $this->normalizePath($path1);
458
-		$path2 = $this->normalizePath($path2);
459
-
460
-		$fileType = $this->filetype($path1);
461
-		if ($fileType === 'file') {
462
-
463
-			// make way
464
-			$this->unlink($path2);
465
-
466
-			try {
467
-				$source = $this->fetchObject($path1);
468
-				$source->copy($this->bucket . '/' . $path2);
469
-				// invalidate target object to force repopulation on fetch
470
-				$this->objectCache->remove($path2);
471
-				$this->objectCache->remove($path2 . '/');
472
-			} catch (ClientErrorResponseException $e) {
473
-				\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
474
-				return false;
475
-			}
476
-
477
-		} else if ($fileType === 'dir') {
478
-
479
-			// make way
480
-			$this->unlink($path2);
481
-
482
-			try {
483
-				$source = $this->fetchObject($path1 . '/');
484
-				$source->copy($this->bucket . '/' . $path2 . '/');
485
-				// invalidate target object to force repopulation on fetch
486
-				$this->objectCache->remove($path2);
487
-				$this->objectCache->remove($path2 . '/');
488
-			} catch (ClientErrorResponseException $e) {
489
-				\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
490
-				return false;
491
-			}
492
-
493
-			$dh = $this->opendir($path1);
494
-			while ($file = readdir($dh)) {
495
-				if (\OC\Files\Filesystem::isIgnoredDir($file)) {
496
-					continue;
497
-				}
498
-
499
-				$source = $path1 . '/' . $file;
500
-				$target = $path2 . '/' . $file;
501
-				$this->copy($source, $target);
502
-			}
503
-
504
-		} else {
505
-			//file does not exist
506
-			return false;
507
-		}
508
-
509
-		return true;
510
-	}
511
-
512
-	public function rename($path1, $path2) {
513
-		$path1 = $this->normalizePath($path1);
514
-		$path2 = $this->normalizePath($path2);
515
-
516
-		$fileType = $this->filetype($path1);
517
-
518
-		if ($fileType === 'dir' || $fileType === 'file') {
519
-			// copy
520
-			if ($this->copy($path1, $path2) === false) {
521
-				return false;
522
-			}
523
-
524
-			// cleanup
525
-			if ($this->unlink($path1) === false) {
526
-				$this->unlink($path2);
527
-				return false;
528
-			}
529
-
530
-			return true;
531
-		}
532
-
533
-		return false;
534
-	}
535
-
536
-	public function getId() {
537
-		return $this->id;
538
-	}
539
-
540
-	/**
541
-	 * Returns the connection
542
-	 *
543
-	 * @return OpenCloud\ObjectStore\Service connected client
544
-	 * @throws \Exception if connection could not be made
545
-	 */
546
-	public function getConnection() {
547
-		if (!is_null($this->connection)) {
548
-			return $this->connection;
549
-		}
550
-
551
-		$settings = array(
552
-			'username' => $this->params['user'],
553
-		);
554
-
555
-		if (!empty($this->params['password'])) {
556
-			$settings['password'] = $this->params['password'];
557
-		} else if (!empty($this->params['key'])) {
558
-			$settings['apiKey'] = $this->params['key'];
559
-		}
560
-
561
-		if (!empty($this->params['tenant'])) {
562
-			$settings['tenantName'] = $this->params['tenant'];
563
-		}
564
-
565
-		if (!empty($this->params['timeout'])) {
566
-			$settings['timeout'] = $this->params['timeout'];
567
-		}
568
-
569
-		if (isset($settings['apiKey'])) {
570
-			$this->anchor = new Rackspace($this->params['url'], $settings);
571
-		} else {
572
-			$this->anchor = new OpenStack($this->params['url'], $settings);
573
-		}
574
-
575
-		$connection = $this->anchor->objectStoreService($this->params['service_name'], $this->params['region']);
576
-
577
-		if (!empty($this->params['endpoint_url'])) {
578
-			$endpoint = $connection->getEndpoint();
579
-			$endpoint->setPublicUrl($this->params['endpoint_url']);
580
-			$endpoint->setPrivateUrl($this->params['endpoint_url']);
581
-			$connection->setEndpoint($endpoint);
582
-		}
583
-
584
-		$this->connection = $connection;
585
-
586
-		return $this->connection;
587
-	}
588
-
589
-	/**
590
-	 * Returns the initialized object store container.
591
-	 *
592
-	 * @return OpenCloud\ObjectStore\Resource\Container
593
-	 */
594
-	public function getContainer() {
595
-		if (!is_null($this->container)) {
596
-			return $this->container;
597
-		}
598
-
599
-		try {
600
-			$this->container = $this->getConnection()->getContainer($this->bucket);
601
-		} catch (ClientErrorResponseException $e) {
602
-			$this->container = $this->getConnection()->createContainer($this->bucket);
603
-		}
604
-
605
-		if (!$this->file_exists('.')) {
606
-			$this->mkdir('.');
607
-		}
608
-
609
-		return $this->container;
610
-	}
611
-
612
-	public function writeBack($tmpFile, $path) {
613
-		$fileData = fopen($tmpFile, 'r');
614
-		$this->getContainer()->uploadObject($path, $fileData);
615
-		// invalidate target object to force repopulation on fetch
616
-		$this->objectCache->remove($path);
617
-		unlink($tmpFile);
618
-	}
619
-
620
-	public function hasUpdated($path, $time) {
621
-		if ($this->is_file($path)) {
622
-			return parent::hasUpdated($path, $time);
623
-		}
624
-		$path = $this->normalizePath($path);
625
-		$dh = $this->opendir($path);
626
-		$content = array();
627
-		while (($file = readdir($dh)) !== false) {
628
-			$content[] = $file;
629
-		}
630
-		if ($path === '.') {
631
-			$path = '';
632
-		}
633
-		$cachedContent = $this->getCache()->getFolderContents($path);
634
-		$cachedNames = array_map(function ($content) {
635
-			return $content['name'];
636
-		}, $cachedContent);
637
-		sort($cachedNames);
638
-		sort($content);
639
-		return $cachedNames != $content;
640
-	}
641
-
642
-	/**
643
-	 * check if curl is installed
644
-	 */
645
-	public static function checkDependencies() {
646
-		return true;
647
-	}
52
+    /**
53
+     * @var \OpenCloud\ObjectStore\Service
54
+     */
55
+    private $connection;
56
+    /**
57
+     * @var \OpenCloud\ObjectStore\Resource\Container
58
+     */
59
+    private $container;
60
+    /**
61
+     * @var \OpenCloud\OpenStack
62
+     */
63
+    private $anchor;
64
+    /**
65
+     * @var string
66
+     */
67
+    private $bucket;
68
+    /**
69
+     * Connection parameters
70
+     *
71
+     * @var array
72
+     */
73
+    private $params;
74
+
75
+    /** @var string  */
76
+    private $id;
77
+
78
+    /**
79
+     * Key value cache mapping path to data object. Maps path to
80
+     * \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject for existing
81
+     * paths and path to false for not existing paths.
82
+     * @var \OCP\ICache
83
+     */
84
+    private $objectCache;
85
+
86
+    /**
87
+     * @param string $path
88
+     */
89
+    private function normalizePath($path) {
90
+        $path = trim($path, '/');
91
+
92
+        if (!$path) {
93
+            $path = '.';
94
+        }
95
+
96
+        $path = str_replace('#', '%23', $path);
97
+
98
+        return $path;
99
+    }
100
+
101
+    const SUBCONTAINER_FILE = '.subcontainers';
102
+
103
+    /**
104
+     * translate directory path to container name
105
+     *
106
+     * @param string $path
107
+     * @return string
108
+     */
109
+
110
+    /**
111
+     * Fetches an object from the API.
112
+     * If the object is cached already or a
113
+     * failed "doesn't exist" response was cached,
114
+     * that one will be returned.
115
+     *
116
+     * @param string $path
117
+     * @return \OpenCloud\OpenStack\ObjectStorage\Resource\DataObject|bool object
118
+     * or false if the object did not exist
119
+     */
120
+    private function fetchObject($path) {
121
+        if ($this->objectCache->hasKey($path)) {
122
+            // might be "false" if object did not exist from last check
123
+            return $this->objectCache->get($path);
124
+        }
125
+        try {
126
+            $object = $this->getContainer()->getPartialObject($path);
127
+            $this->objectCache->set($path, $object);
128
+            return $object;
129
+        } catch (ClientErrorResponseException $e) {
130
+            // this exception happens when the object does not exist, which
131
+            // is expected in most cases
132
+            $this->objectCache->set($path, false);
133
+            return false;
134
+        } catch (ClientErrorResponseException $e) {
135
+            // Expected response is "404 Not Found", so only log if it isn't
136
+            if ($e->getResponse()->getStatusCode() !== 404) {
137
+                \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
138
+            }
139
+            return false;
140
+        }
141
+    }
142
+
143
+    /**
144
+     * Returns whether the given path exists.
145
+     *
146
+     * @param string $path
147
+     *
148
+     * @return bool true if the object exist, false otherwise
149
+     */
150
+    private function doesObjectExist($path) {
151
+        return $this->fetchObject($path) !== false;
152
+    }
153
+
154
+    public function __construct($params) {
155
+        if ((empty($params['key']) and empty($params['password']))
156
+            or empty($params['user']) or empty($params['bucket'])
157
+            or empty($params['region'])
158
+        ) {
159
+            throw new \Exception("API Key or password, Username, Bucket and Region have to be configured.");
160
+        }
161
+
162
+        $this->id = 'swift::' . $params['user'] . md5($params['bucket']);
163
+
164
+        $bucketUrl = Url::factory($params['bucket']);
165
+        if ($bucketUrl->isAbsolute()) {
166
+            $this->bucket = end(($bucketUrl->getPathSegments()));
167
+            $params['endpoint_url'] = $bucketUrl->addPath('..')->normalizePath();
168
+        } else {
169
+            $this->bucket = $params['bucket'];
170
+        }
171
+
172
+        if (empty($params['url'])) {
173
+            $params['url'] = 'https://identity.api.rackspacecloud.com/v2.0/';
174
+        }
175
+
176
+        if (empty($params['service_name'])) {
177
+            $params['service_name'] = 'cloudFiles';
178
+        }
179
+
180
+        $this->params = $params;
181
+        // FIXME: private class...
182
+        $this->objectCache = new \OC\Cache\CappedMemoryCache();
183
+    }
184
+
185
+    public function mkdir($path) {
186
+        $path = $this->normalizePath($path);
187
+
188
+        if ($this->is_dir($path)) {
189
+            return false;
190
+        }
191
+
192
+        if ($path !== '.') {
193
+            $path .= '/';
194
+        }
195
+
196
+        try {
197
+            $customHeaders = array('content-type' => 'httpd/unix-directory');
198
+            $metadataHeaders = DataObject::stockHeaders(array());
199
+            $allHeaders = $customHeaders + $metadataHeaders;
200
+            $this->getContainer()->uploadObject($path, '', $allHeaders);
201
+            // invalidate so that the next access gets the real object
202
+            // with all properties
203
+            $this->objectCache->remove($path);
204
+        } catch (Exceptions\CreateUpdateError $e) {
205
+            \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
206
+            return false;
207
+        }
208
+
209
+        return true;
210
+    }
211
+
212
+    public function file_exists($path) {
213
+        $path = $this->normalizePath($path);
214
+
215
+        if ($path !== '.' && $this->is_dir($path)) {
216
+            $path .= '/';
217
+        }
218
+
219
+        return $this->doesObjectExist($path);
220
+    }
221
+
222
+    public function rmdir($path) {
223
+        $path = $this->normalizePath($path);
224
+
225
+        if (!$this->is_dir($path) || !$this->isDeletable($path)) {
226
+            return false;
227
+        }
228
+
229
+        $dh = $this->opendir($path);
230
+        while ($file = readdir($dh)) {
231
+            if (\OC\Files\Filesystem::isIgnoredDir($file)) {
232
+                continue;
233
+            }
234
+
235
+            if ($this->is_dir($path . '/' . $file)) {
236
+                $this->rmdir($path . '/' . $file);
237
+            } else {
238
+                $this->unlink($path . '/' . $file);
239
+            }
240
+        }
241
+
242
+        try {
243
+            $this->getContainer()->dataObject()->setName($path . '/')->delete();
244
+            $this->objectCache->remove($path . '/');
245
+        } catch (Exceptions\DeleteError $e) {
246
+            \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
247
+            return false;
248
+        }
249
+
250
+        return true;
251
+    }
252
+
253
+    public function opendir($path) {
254
+        $path = $this->normalizePath($path);
255
+
256
+        if ($path === '.') {
257
+            $path = '';
258
+        } else {
259
+            $path .= '/';
260
+        }
261
+
262
+        $path = str_replace('%23', '#', $path); // the prefix is sent as a query param, so revert the encoding of #
263
+
264
+        try {
265
+            $files = array();
266
+            /** @var OpenCloud\Common\Collection $objects */
267
+            $objects = $this->getContainer()->objectList(array(
268
+                'prefix' => $path,
269
+                'delimiter' => '/'
270
+            ));
271
+
272
+            /** @var OpenCloud\ObjectStore\Resource\DataObject $object */
273
+            foreach ($objects as $object) {
274
+                $file = basename($object->getName());
275
+                if ($file !== basename($path) && $file !== '.') {
276
+                    $files[] = $file;
277
+                }
278
+            }
279
+
280
+            return IteratorDirectory::wrap($files);
281
+        } catch (\Exception $e) {
282
+            \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
283
+            return false;
284
+        }
285
+
286
+    }
287
+
288
+    public function stat($path) {
289
+        $path = $this->normalizePath($path);
290
+
291
+        if ($path === '.') {
292
+            $path = '';
293
+        } else if ($this->is_dir($path)) {
294
+            $path .= '/';
295
+        }
296
+
297
+        try {
298
+            /** @var DataObject $object */
299
+            $object = $this->fetchObject($path);
300
+            if (!$object) {
301
+                return false;
302
+            }
303
+        } catch (ClientErrorResponseException $e) {
304
+            \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
305
+            return false;
306
+        }
307
+
308
+        $dateTime = \DateTime::createFromFormat(\DateTime::RFC1123, $object->getLastModified());
309
+        if ($dateTime !== false) {
310
+            $mtime = $dateTime->getTimestamp();
311
+        } else {
312
+            $mtime = null;
313
+        }
314
+        $objectMetadata = $object->getMetadata();
315
+        $metaTimestamp = $objectMetadata->getProperty('timestamp');
316
+        if (isset($metaTimestamp)) {
317
+            $mtime = $metaTimestamp;
318
+        }
319
+
320
+        if (!empty($mtime)) {
321
+            $mtime = floor($mtime);
322
+        }
323
+
324
+        $stat = array();
325
+        $stat['size'] = (int)$object->getContentLength();
326
+        $stat['mtime'] = $mtime;
327
+        $stat['atime'] = time();
328
+        return $stat;
329
+    }
330
+
331
+    public function filetype($path) {
332
+        $path = $this->normalizePath($path);
333
+
334
+        if ($path !== '.' && $this->doesObjectExist($path)) {
335
+            return 'file';
336
+        }
337
+
338
+        if ($path !== '.') {
339
+            $path .= '/';
340
+        }
341
+
342
+        if ($this->doesObjectExist($path)) {
343
+            return 'dir';
344
+        }
345
+    }
346
+
347
+    public function unlink($path) {
348
+        $path = $this->normalizePath($path);
349
+
350
+        if ($this->is_dir($path)) {
351
+            return $this->rmdir($path);
352
+        }
353
+
354
+        try {
355
+            $this->getContainer()->dataObject()->setName($path)->delete();
356
+            $this->objectCache->remove($path);
357
+            $this->objectCache->remove($path . '/');
358
+        } catch (ClientErrorResponseException $e) {
359
+            if ($e->getResponse()->getStatusCode() !== 404) {
360
+                \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
361
+            }
362
+            return false;
363
+        }
364
+
365
+        return true;
366
+    }
367
+
368
+    public function fopen($path, $mode) {
369
+        $path = $this->normalizePath($path);
370
+
371
+        switch ($mode) {
372
+            case 'a':
373
+            case 'ab':
374
+            case 'a+':
375
+                return false;
376
+            case 'r':
377
+            case 'rb':
378
+                try {
379
+                    $c = $this->getContainer();
380
+                    $streamFactory = new \Guzzle\Stream\PhpStreamRequestFactory();
381
+                    $streamInterface = $streamFactory->fromRequest(
382
+                        $c->getClient()
383
+                            ->get($c->getUrl($path)));
384
+                    $streamInterface->rewind();
385
+                    $stream = $streamInterface->getStream();
386
+                    stream_context_set_option($stream, 'swift','content', $streamInterface);
387
+                    if(!strrpos($streamInterface
388
+                        ->getMetaData('wrapper_data')[0], '404 Not Found')) {
389
+                        return RetryWrapper::wrap($stream);
390
+                    }
391
+                    return false;
392
+                } catch (\Guzzle\Http\Exception\BadResponseException $e) {
393
+                    \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
394
+                    return false;
395
+                }
396
+            case 'w':
397
+            case 'wb':
398
+            case 'r+':
399
+            case 'w+':
400
+            case 'wb+':
401
+            case 'x':
402
+            case 'x+':
403
+            case 'c':
404
+            case 'c+':
405
+                if (strrpos($path, '.') !== false) {
406
+                    $ext = substr($path, strrpos($path, '.'));
407
+                } else {
408
+                    $ext = '';
409
+                }
410
+                $tmpFile = \OCP\Files::tmpFile($ext);
411
+                // Fetch existing file if required
412
+                if ($mode[0] !== 'w' && $this->file_exists($path)) {
413
+                    if ($mode[0] === 'x') {
414
+                        // File cannot already exist
415
+                        return false;
416
+                    }
417
+                    $source = $this->fopen($path, 'r');
418
+                    file_put_contents($tmpFile, $source);
419
+                }
420
+                $handle = fopen($tmpFile, $mode);
421
+                return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
422
+                    $this->writeBack($tmpFile, $path);
423
+                });
424
+        }
425
+    }
426
+
427
+    public function touch($path, $mtime = null) {
428
+        $path = $this->normalizePath($path);
429
+        if (is_null($mtime)) {
430
+            $mtime = time();
431
+        }
432
+        $metadata = array('timestamp' => $mtime);
433
+        if ($this->file_exists($path)) {
434
+            if ($this->is_dir($path) && $path != '.') {
435
+                $path .= '/';
436
+            }
437
+
438
+            $object = $this->fetchObject($path);
439
+            if ($object->saveMetadata($metadata)) {
440
+                // invalidate target object to force repopulation on fetch
441
+                $this->objectCache->remove($path);
442
+            }
443
+            return true;
444
+        } else {
445
+            $mimeType = \OC::$server->getMimeTypeDetector()->detectPath($path);
446
+            $customHeaders = array('content-type' => $mimeType);
447
+            $metadataHeaders = DataObject::stockHeaders($metadata);
448
+            $allHeaders = $customHeaders + $metadataHeaders;
449
+            $this->getContainer()->uploadObject($path, '', $allHeaders);
450
+            // invalidate target object to force repopulation on fetch
451
+            $this->objectCache->remove($path);
452
+            return true;
453
+        }
454
+    }
455
+
456
+    public function copy($path1, $path2) {
457
+        $path1 = $this->normalizePath($path1);
458
+        $path2 = $this->normalizePath($path2);
459
+
460
+        $fileType = $this->filetype($path1);
461
+        if ($fileType === 'file') {
462
+
463
+            // make way
464
+            $this->unlink($path2);
465
+
466
+            try {
467
+                $source = $this->fetchObject($path1);
468
+                $source->copy($this->bucket . '/' . $path2);
469
+                // invalidate target object to force repopulation on fetch
470
+                $this->objectCache->remove($path2);
471
+                $this->objectCache->remove($path2 . '/');
472
+            } catch (ClientErrorResponseException $e) {
473
+                \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
474
+                return false;
475
+            }
476
+
477
+        } else if ($fileType === 'dir') {
478
+
479
+            // make way
480
+            $this->unlink($path2);
481
+
482
+            try {
483
+                $source = $this->fetchObject($path1 . '/');
484
+                $source->copy($this->bucket . '/' . $path2 . '/');
485
+                // invalidate target object to force repopulation on fetch
486
+                $this->objectCache->remove($path2);
487
+                $this->objectCache->remove($path2 . '/');
488
+            } catch (ClientErrorResponseException $e) {
489
+                \OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
490
+                return false;
491
+            }
492
+
493
+            $dh = $this->opendir($path1);
494
+            while ($file = readdir($dh)) {
495
+                if (\OC\Files\Filesystem::isIgnoredDir($file)) {
496
+                    continue;
497
+                }
498
+
499
+                $source = $path1 . '/' . $file;
500
+                $target = $path2 . '/' . $file;
501
+                $this->copy($source, $target);
502
+            }
503
+
504
+        } else {
505
+            //file does not exist
506
+            return false;
507
+        }
508
+
509
+        return true;
510
+    }
511
+
512
+    public function rename($path1, $path2) {
513
+        $path1 = $this->normalizePath($path1);
514
+        $path2 = $this->normalizePath($path2);
515
+
516
+        $fileType = $this->filetype($path1);
517
+
518
+        if ($fileType === 'dir' || $fileType === 'file') {
519
+            // copy
520
+            if ($this->copy($path1, $path2) === false) {
521
+                return false;
522
+            }
523
+
524
+            // cleanup
525
+            if ($this->unlink($path1) === false) {
526
+                $this->unlink($path2);
527
+                return false;
528
+            }
529
+
530
+            return true;
531
+        }
532
+
533
+        return false;
534
+    }
535
+
536
+    public function getId() {
537
+        return $this->id;
538
+    }
539
+
540
+    /**
541
+     * Returns the connection
542
+     *
543
+     * @return OpenCloud\ObjectStore\Service connected client
544
+     * @throws \Exception if connection could not be made
545
+     */
546
+    public function getConnection() {
547
+        if (!is_null($this->connection)) {
548
+            return $this->connection;
549
+        }
550
+
551
+        $settings = array(
552
+            'username' => $this->params['user'],
553
+        );
554
+
555
+        if (!empty($this->params['password'])) {
556
+            $settings['password'] = $this->params['password'];
557
+        } else if (!empty($this->params['key'])) {
558
+            $settings['apiKey'] = $this->params['key'];
559
+        }
560
+
561
+        if (!empty($this->params['tenant'])) {
562
+            $settings['tenantName'] = $this->params['tenant'];
563
+        }
564
+
565
+        if (!empty($this->params['timeout'])) {
566
+            $settings['timeout'] = $this->params['timeout'];
567
+        }
568
+
569
+        if (isset($settings['apiKey'])) {
570
+            $this->anchor = new Rackspace($this->params['url'], $settings);
571
+        } else {
572
+            $this->anchor = new OpenStack($this->params['url'], $settings);
573
+        }
574
+
575
+        $connection = $this->anchor->objectStoreService($this->params['service_name'], $this->params['region']);
576
+
577
+        if (!empty($this->params['endpoint_url'])) {
578
+            $endpoint = $connection->getEndpoint();
579
+            $endpoint->setPublicUrl($this->params['endpoint_url']);
580
+            $endpoint->setPrivateUrl($this->params['endpoint_url']);
581
+            $connection->setEndpoint($endpoint);
582
+        }
583
+
584
+        $this->connection = $connection;
585
+
586
+        return $this->connection;
587
+    }
588
+
589
+    /**
590
+     * Returns the initialized object store container.
591
+     *
592
+     * @return OpenCloud\ObjectStore\Resource\Container
593
+     */
594
+    public function getContainer() {
595
+        if (!is_null($this->container)) {
596
+            return $this->container;
597
+        }
598
+
599
+        try {
600
+            $this->container = $this->getConnection()->getContainer($this->bucket);
601
+        } catch (ClientErrorResponseException $e) {
602
+            $this->container = $this->getConnection()->createContainer($this->bucket);
603
+        }
604
+
605
+        if (!$this->file_exists('.')) {
606
+            $this->mkdir('.');
607
+        }
608
+
609
+        return $this->container;
610
+    }
611
+
612
+    public function writeBack($tmpFile, $path) {
613
+        $fileData = fopen($tmpFile, 'r');
614
+        $this->getContainer()->uploadObject($path, $fileData);
615
+        // invalidate target object to force repopulation on fetch
616
+        $this->objectCache->remove($path);
617
+        unlink($tmpFile);
618
+    }
619
+
620
+    public function hasUpdated($path, $time) {
621
+        if ($this->is_file($path)) {
622
+            return parent::hasUpdated($path, $time);
623
+        }
624
+        $path = $this->normalizePath($path);
625
+        $dh = $this->opendir($path);
626
+        $content = array();
627
+        while (($file = readdir($dh)) !== false) {
628
+            $content[] = $file;
629
+        }
630
+        if ($path === '.') {
631
+            $path = '';
632
+        }
633
+        $cachedContent = $this->getCache()->getFolderContents($path);
634
+        $cachedNames = array_map(function ($content) {
635
+            return $content['name'];
636
+        }, $cachedContent);
637
+        sort($cachedNames);
638
+        sort($content);
639
+        return $cachedNames != $content;
640
+    }
641
+
642
+    /**
643
+     * check if curl is installed
644
+     */
645
+    public static function checkDependencies() {
646
+        return true;
647
+    }
648 648
 
649 649
 }
Please login to merge, or discard this patch.
Spacing   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -159,7 +159,7 @@  discard block
 block discarded – undo
159 159
 			throw new \Exception("API Key or password, Username, Bucket and Region have to be configured.");
160 160
 		}
161 161
 
162
-		$this->id = 'swift::' . $params['user'] . md5($params['bucket']);
162
+		$this->id = 'swift::'.$params['user'].md5($params['bucket']);
163 163
 
164 164
 		$bucketUrl = Url::factory($params['bucket']);
165 165
 		if ($bucketUrl->isAbsolute()) {
@@ -232,16 +232,16 @@  discard block
 block discarded – undo
232 232
 				continue;
233 233
 			}
234 234
 
235
-			if ($this->is_dir($path . '/' . $file)) {
236
-				$this->rmdir($path . '/' . $file);
235
+			if ($this->is_dir($path.'/'.$file)) {
236
+				$this->rmdir($path.'/'.$file);
237 237
 			} else {
238
-				$this->unlink($path . '/' . $file);
238
+				$this->unlink($path.'/'.$file);
239 239
 			}
240 240
 		}
241 241
 
242 242
 		try {
243
-			$this->getContainer()->dataObject()->setName($path . '/')->delete();
244
-			$this->objectCache->remove($path . '/');
243
+			$this->getContainer()->dataObject()->setName($path.'/')->delete();
244
+			$this->objectCache->remove($path.'/');
245 245
 		} catch (Exceptions\DeleteError $e) {
246 246
 			\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
247 247
 			return false;
@@ -322,7 +322,7 @@  discard block
 block discarded – undo
322 322
 		}
323 323
 
324 324
 		$stat = array();
325
-		$stat['size'] = (int)$object->getContentLength();
325
+		$stat['size'] = (int) $object->getContentLength();
326 326
 		$stat['mtime'] = $mtime;
327 327
 		$stat['atime'] = time();
328 328
 		return $stat;
@@ -354,7 +354,7 @@  discard block
 block discarded – undo
354 354
 		try {
355 355
 			$this->getContainer()->dataObject()->setName($path)->delete();
356 356
 			$this->objectCache->remove($path);
357
-			$this->objectCache->remove($path . '/');
357
+			$this->objectCache->remove($path.'/');
358 358
 		} catch (ClientErrorResponseException $e) {
359 359
 			if ($e->getResponse()->getStatusCode() !== 404) {
360 360
 				\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
@@ -383,8 +383,8 @@  discard block
 block discarded – undo
383 383
 							->get($c->getUrl($path)));
384 384
 					$streamInterface->rewind();
385 385
 					$stream = $streamInterface->getStream();
386
-					stream_context_set_option($stream, 'swift','content', $streamInterface);
387
-					if(!strrpos($streamInterface
386
+					stream_context_set_option($stream, 'swift', 'content', $streamInterface);
387
+					if (!strrpos($streamInterface
388 388
 						->getMetaData('wrapper_data')[0], '404 Not Found')) {
389 389
 						return RetryWrapper::wrap($stream);
390 390
 					}
@@ -418,7 +418,7 @@  discard block
 block discarded – undo
418 418
 					file_put_contents($tmpFile, $source);
419 419
 				}
420 420
 				$handle = fopen($tmpFile, $mode);
421
-				return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) {
421
+				return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) {
422 422
 					$this->writeBack($tmpFile, $path);
423 423
 				});
424 424
 		}
@@ -465,10 +465,10 @@  discard block
 block discarded – undo
465 465
 
466 466
 			try {
467 467
 				$source = $this->fetchObject($path1);
468
-				$source->copy($this->bucket . '/' . $path2);
468
+				$source->copy($this->bucket.'/'.$path2);
469 469
 				// invalidate target object to force repopulation on fetch
470 470
 				$this->objectCache->remove($path2);
471
-				$this->objectCache->remove($path2 . '/');
471
+				$this->objectCache->remove($path2.'/');
472 472
 			} catch (ClientErrorResponseException $e) {
473 473
 				\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
474 474
 				return false;
@@ -480,11 +480,11 @@  discard block
 block discarded – undo
480 480
 			$this->unlink($path2);
481 481
 
482 482
 			try {
483
-				$source = $this->fetchObject($path1 . '/');
484
-				$source->copy($this->bucket . '/' . $path2 . '/');
483
+				$source = $this->fetchObject($path1.'/');
484
+				$source->copy($this->bucket.'/'.$path2.'/');
485 485
 				// invalidate target object to force repopulation on fetch
486 486
 				$this->objectCache->remove($path2);
487
-				$this->objectCache->remove($path2 . '/');
487
+				$this->objectCache->remove($path2.'/');
488 488
 			} catch (ClientErrorResponseException $e) {
489 489
 				\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
490 490
 				return false;
@@ -496,8 +496,8 @@  discard block
 block discarded – undo
496 496
 					continue;
497 497
 				}
498 498
 
499
-				$source = $path1 . '/' . $file;
500
-				$target = $path2 . '/' . $file;
499
+				$source = $path1.'/'.$file;
500
+				$target = $path2.'/'.$file;
501 501
 				$this->copy($source, $target);
502 502
 			}
503 503
 
@@ -631,7 +631,7 @@  discard block
 block discarded – undo
631 631
 			$path = '';
632 632
 		}
633 633
 		$cachedContent = $this->getCache()->getFolderContents($path);
634
-		$cachedNames = array_map(function ($content) {
634
+		$cachedNames = array_map(function($content) {
635 635
 			return $content['name'];
636 636
 		}, $cachedContent);
637 637
 		sort($cachedNames);
Please login to merge, or discard this patch.
apps/files_sharing/lib/Controller/ShareController.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -597,7 +597,7 @@
 block discarded – undo
597 597
 	 * publish activity
598 598
 	 *
599 599
 	 * @param string $subject
600
-	 * @param array $parameters
600
+	 * @param string[] $parameters
601 601
 	 * @param string $affectedUser
602 602
 	 * @param int $fileId
603 603
 	 * @param string $filePath
Please login to merge, or discard this patch.
Indentation   +551 added lines, -551 removed lines patch added patch discarded remove patch
@@ -64,559 +64,559 @@
 block discarded – undo
64 64
  */
65 65
 class ShareController extends Controller {
66 66
 
67
-	/** @var IConfig */
68
-	protected $config;
69
-	/** @var IURLGenerator */
70
-	protected $urlGenerator;
71
-	/** @var IUserManager */
72
-	protected $userManager;
73
-	/** @var ILogger */
74
-	protected $logger;
75
-	/** @var \OCP\Activity\IManager */
76
-	protected $activityManager;
77
-	/** @var \OCP\Share\IManager */
78
-	protected $shareManager;
79
-	/** @var ISession */
80
-	protected $session;
81
-	/** @var IPreview */
82
-	protected $previewManager;
83
-	/** @var IRootFolder */
84
-	protected $rootFolder;
85
-	/** @var FederatedShareProvider */
86
-	protected $federatedShareProvider;
87
-	/** @var EventDispatcherInterface */
88
-	protected $eventDispatcher;
89
-	/** @var IL10N */
90
-	protected $l10n;
91
-	/** @var Defaults */
92
-	protected $defaults;
93
-
94
-	/**
95
-	 * @param string $appName
96
-	 * @param IRequest $request
97
-	 * @param IConfig $config
98
-	 * @param IURLGenerator $urlGenerator
99
-	 * @param IUserManager $userManager
100
-	 * @param ILogger $logger
101
-	 * @param \OCP\Activity\IManager $activityManager
102
-	 * @param \OCP\Share\IManager $shareManager
103
-	 * @param ISession $session
104
-	 * @param IPreview $previewManager
105
-	 * @param IRootFolder $rootFolder
106
-	 * @param FederatedShareProvider $federatedShareProvider
107
-	 * @param EventDispatcherInterface $eventDispatcher
108
-	 * @param IL10N $l10n
109
-	 * @param Defaults $defaults
110
-	 */
111
-	public function __construct($appName,
112
-								IRequest $request,
113
-								IConfig $config,
114
-								IURLGenerator $urlGenerator,
115
-								IUserManager $userManager,
116
-								ILogger $logger,
117
-								\OCP\Activity\IManager $activityManager,
118
-								\OCP\Share\IManager $shareManager,
119
-								ISession $session,
120
-								IPreview $previewManager,
121
-								IRootFolder $rootFolder,
122
-								FederatedShareProvider $federatedShareProvider,
123
-								EventDispatcherInterface $eventDispatcher,
124
-								IL10N $l10n,
125
-								Defaults $defaults) {
126
-		parent::__construct($appName, $request);
127
-
128
-		$this->config = $config;
129
-		$this->urlGenerator = $urlGenerator;
130
-		$this->userManager = $userManager;
131
-		$this->logger = $logger;
132
-		$this->activityManager = $activityManager;
133
-		$this->shareManager = $shareManager;
134
-		$this->session = $session;
135
-		$this->previewManager = $previewManager;
136
-		$this->rootFolder = $rootFolder;
137
-		$this->federatedShareProvider = $federatedShareProvider;
138
-		$this->eventDispatcher = $eventDispatcher;
139
-		$this->l10n = $l10n;
140
-		$this->defaults = $defaults;
141
-	}
142
-
143
-	/**
144
-	 * @PublicPage
145
-	 * @NoCSRFRequired
146
-	 *
147
-	 * @param string $token
148
-	 * @return TemplateResponse|RedirectResponse
149
-	 */
150
-	public function showAuthenticate($token) {
151
-		$share = $this->shareManager->getShareByToken($token);
152
-
153
-		if($this->linkShareAuth($share)) {
154
-			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
155
-		}
156
-
157
-		return new TemplateResponse($this->appName, 'authenticate', array(), 'guest');
158
-	}
159
-
160
-	/**
161
-	 * @PublicPage
162
-	 * @UseSession
163
-	 * @BruteForceProtection(action=publicLinkAuth)
164
-	 *
165
-	 * Authenticates against password-protected shares
166
-	 * @param string $token
167
-	 * @param string $password
168
-	 * @return RedirectResponse|TemplateResponse|NotFoundResponse
169
-	 */
170
-	public function authenticate($token, $password = '') {
171
-
172
-		// Check whether share exists
173
-		try {
174
-			$share = $this->shareManager->getShareByToken($token);
175
-		} catch (ShareNotFound $e) {
176
-			return new NotFoundResponse();
177
-		}
178
-
179
-		$authenticate = $this->linkShareAuth($share, $password);
180
-
181
-		if($authenticate === true) {
182
-			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
183
-		}
184
-
185
-		$response = new TemplateResponse($this->appName, 'authenticate', array('wrongpw' => true), 'guest');
186
-		$response->throttle();
187
-		return $response;
188
-	}
189
-
190
-	/**
191
-	 * Authenticate a link item with the given password.
192
-	 * Or use the session if no password is provided.
193
-	 *
194
-	 * This is a modified version of Helper::authenticate
195
-	 * TODO: Try to merge back eventually with Helper::authenticate
196
-	 *
197
-	 * @param \OCP\Share\IShare $share
198
-	 * @param string|null $password
199
-	 * @return bool
200
-	 */
201
-	private function linkShareAuth(\OCP\Share\IShare $share, $password = null) {
202
-		if ($password !== null) {
203
-			if ($this->shareManager->checkPassword($share, $password)) {
204
-				$this->session->regenerateId();
205
-				$this->session->set('public_link_authenticated', (string)$share->getId());
206
-			} else {
207
-				$this->emitAccessShareHook($share, 403, 'Wrong password');
208
-				return false;
209
-			}
210
-		} else {
211
-			// not authenticated ?
212
-			if ( ! $this->session->exists('public_link_authenticated')
213
-				|| $this->session->get('public_link_authenticated') !== (string)$share->getId()) {
214
-				return false;
215
-			}
216
-		}
217
-		return true;
218
-	}
219
-
220
-	/**
221
-	 * throws hooks when a share is attempted to be accessed
222
-	 *
223
-	 * @param \OCP\Share\IShare|string $share the Share instance if available,
224
-	 * otherwise token
225
-	 * @param int $errorCode
226
-	 * @param string $errorMessage
227
-	 * @throws \OC\HintException
228
-	 * @throws \OC\ServerNotAvailableException
229
-	 */
230
-	protected function emitAccessShareHook($share, $errorCode = 200, $errorMessage = '') {
231
-		$itemType = $itemSource = $uidOwner = '';
232
-		$token = $share;
233
-		$exception = null;
234
-		if($share instanceof \OCP\Share\IShare) {
235
-			try {
236
-				$token = $share->getToken();
237
-				$uidOwner = $share->getSharedBy();
238
-				$itemType = $share->getNodeType();
239
-				$itemSource = $share->getNodeId();
240
-			} catch (\Exception $e) {
241
-				// we log what we know and pass on the exception afterwards
242
-				$exception = $e;
243
-			}
244
-		}
245
-		\OC_Hook::emit('OCP\Share', 'share_link_access', [
246
-			'itemType' => $itemType,
247
-			'itemSource' => $itemSource,
248
-			'uidOwner' => $uidOwner,
249
-			'token' => $token,
250
-			'errorCode' => $errorCode,
251
-			'errorMessage' => $errorMessage,
252
-		]);
253
-		if(!is_null($exception)) {
254
-			throw $exception;
255
-		}
256
-	}
257
-
258
-	/**
259
-	 * Validate the permissions of the share
260
-	 *
261
-	 * @param Share\IShare $share
262
-	 * @return bool
263
-	 */
264
-	private function validateShare(\OCP\Share\IShare $share) {
265
-		return $share->getNode()->isReadable() && $share->getNode()->isShareable();
266
-	}
267
-
268
-	/**
269
-	 * @PublicPage
270
-	 * @NoCSRFRequired
271
-	 *
272
-	 * @param string $token
273
-	 * @param string $path
274
-	 * @return TemplateResponse|RedirectResponse|NotFoundResponse
275
-	 * @throws NotFoundException
276
-	 * @throws \Exception
277
-	 */
278
-	public function showShare($token, $path = '') {
279
-		\OC_User::setIncognitoMode(true);
280
-
281
-		// Check whether share exists
282
-		try {
283
-			$share = $this->shareManager->getShareByToken($token);
284
-		} catch (ShareNotFound $e) {
285
-			$this->emitAccessShareHook($token, 404, 'Share not found');
286
-			return new NotFoundResponse();
287
-		}
288
-
289
-		// Share is password protected - check whether the user is permitted to access the share
290
-		if ($share->getPassword() !== null && !$this->linkShareAuth($share)) {
291
-			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
292
-				array('token' => $token)));
293
-		}
294
-
295
-		if (!$this->validateShare($share)) {
296
-			throw new NotFoundException();
297
-		}
298
-		// We can't get the path of a file share
299
-		try {
300
-			if ($share->getNode() instanceof \OCP\Files\File && $path !== '') {
301
-				$this->emitAccessShareHook($share, 404, 'Share not found');
302
-				throw new NotFoundException();
303
-			}
304
-		} catch (\Exception $e) {
305
-			$this->emitAccessShareHook($share, 404, 'Share not found');
306
-			throw $e;
307
-		}
308
-
309
-		$shareTmpl = [];
310
-		$shareTmpl['displayName'] = $this->userManager->get($share->getShareOwner())->getDisplayName();
311
-		$shareTmpl['owner'] = $share->getShareOwner();
312
-		$shareTmpl['filename'] = $share->getNode()->getName();
313
-		$shareTmpl['directory_path'] = $share->getTarget();
314
-		$shareTmpl['mimetype'] = $share->getNode()->getMimetype();
315
-		$shareTmpl['previewSupported'] = $this->previewManager->isMimeSupported($share->getNode()->getMimetype());
316
-		$shareTmpl['dirToken'] = $token;
317
-		$shareTmpl['sharingToken'] = $token;
318
-		$shareTmpl['server2serversharing'] = $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
319
-		$shareTmpl['protected'] = $share->getPassword() !== null ? 'true' : 'false';
320
-		$shareTmpl['dir'] = '';
321
-		$shareTmpl['nonHumanFileSize'] = $share->getNode()->getSize();
322
-		$shareTmpl['fileSize'] = \OCP\Util::humanFileSize($share->getNode()->getSize());
323
-
324
-		// Show file list
325
-		$hideFileList = false;
326
-		if ($share->getNode() instanceof \OCP\Files\Folder) {
327
-			/** @var \OCP\Files\Folder $rootFolder */
328
-			$rootFolder = $share->getNode();
329
-
330
-			try {
331
-				$folderNode = $rootFolder->get($path);
332
-			} catch (\OCP\Files\NotFoundException $e) {
333
-				$this->emitAccessShareHook($share, 404, 'Share not found');
334
-				throw new NotFoundException();
335
-			}
336
-
337
-			$shareTmpl['dir'] = $rootFolder->getRelativePath($folderNode->getPath());
338
-
339
-			/*
67
+    /** @var IConfig */
68
+    protected $config;
69
+    /** @var IURLGenerator */
70
+    protected $urlGenerator;
71
+    /** @var IUserManager */
72
+    protected $userManager;
73
+    /** @var ILogger */
74
+    protected $logger;
75
+    /** @var \OCP\Activity\IManager */
76
+    protected $activityManager;
77
+    /** @var \OCP\Share\IManager */
78
+    protected $shareManager;
79
+    /** @var ISession */
80
+    protected $session;
81
+    /** @var IPreview */
82
+    protected $previewManager;
83
+    /** @var IRootFolder */
84
+    protected $rootFolder;
85
+    /** @var FederatedShareProvider */
86
+    protected $federatedShareProvider;
87
+    /** @var EventDispatcherInterface */
88
+    protected $eventDispatcher;
89
+    /** @var IL10N */
90
+    protected $l10n;
91
+    /** @var Defaults */
92
+    protected $defaults;
93
+
94
+    /**
95
+     * @param string $appName
96
+     * @param IRequest $request
97
+     * @param IConfig $config
98
+     * @param IURLGenerator $urlGenerator
99
+     * @param IUserManager $userManager
100
+     * @param ILogger $logger
101
+     * @param \OCP\Activity\IManager $activityManager
102
+     * @param \OCP\Share\IManager $shareManager
103
+     * @param ISession $session
104
+     * @param IPreview $previewManager
105
+     * @param IRootFolder $rootFolder
106
+     * @param FederatedShareProvider $federatedShareProvider
107
+     * @param EventDispatcherInterface $eventDispatcher
108
+     * @param IL10N $l10n
109
+     * @param Defaults $defaults
110
+     */
111
+    public function __construct($appName,
112
+                                IRequest $request,
113
+                                IConfig $config,
114
+                                IURLGenerator $urlGenerator,
115
+                                IUserManager $userManager,
116
+                                ILogger $logger,
117
+                                \OCP\Activity\IManager $activityManager,
118
+                                \OCP\Share\IManager $shareManager,
119
+                                ISession $session,
120
+                                IPreview $previewManager,
121
+                                IRootFolder $rootFolder,
122
+                                FederatedShareProvider $federatedShareProvider,
123
+                                EventDispatcherInterface $eventDispatcher,
124
+                                IL10N $l10n,
125
+                                Defaults $defaults) {
126
+        parent::__construct($appName, $request);
127
+
128
+        $this->config = $config;
129
+        $this->urlGenerator = $urlGenerator;
130
+        $this->userManager = $userManager;
131
+        $this->logger = $logger;
132
+        $this->activityManager = $activityManager;
133
+        $this->shareManager = $shareManager;
134
+        $this->session = $session;
135
+        $this->previewManager = $previewManager;
136
+        $this->rootFolder = $rootFolder;
137
+        $this->federatedShareProvider = $federatedShareProvider;
138
+        $this->eventDispatcher = $eventDispatcher;
139
+        $this->l10n = $l10n;
140
+        $this->defaults = $defaults;
141
+    }
142
+
143
+    /**
144
+     * @PublicPage
145
+     * @NoCSRFRequired
146
+     *
147
+     * @param string $token
148
+     * @return TemplateResponse|RedirectResponse
149
+     */
150
+    public function showAuthenticate($token) {
151
+        $share = $this->shareManager->getShareByToken($token);
152
+
153
+        if($this->linkShareAuth($share)) {
154
+            return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
155
+        }
156
+
157
+        return new TemplateResponse($this->appName, 'authenticate', array(), 'guest');
158
+    }
159
+
160
+    /**
161
+     * @PublicPage
162
+     * @UseSession
163
+     * @BruteForceProtection(action=publicLinkAuth)
164
+     *
165
+     * Authenticates against password-protected shares
166
+     * @param string $token
167
+     * @param string $password
168
+     * @return RedirectResponse|TemplateResponse|NotFoundResponse
169
+     */
170
+    public function authenticate($token, $password = '') {
171
+
172
+        // Check whether share exists
173
+        try {
174
+            $share = $this->shareManager->getShareByToken($token);
175
+        } catch (ShareNotFound $e) {
176
+            return new NotFoundResponse();
177
+        }
178
+
179
+        $authenticate = $this->linkShareAuth($share, $password);
180
+
181
+        if($authenticate === true) {
182
+            return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
183
+        }
184
+
185
+        $response = new TemplateResponse($this->appName, 'authenticate', array('wrongpw' => true), 'guest');
186
+        $response->throttle();
187
+        return $response;
188
+    }
189
+
190
+    /**
191
+     * Authenticate a link item with the given password.
192
+     * Or use the session if no password is provided.
193
+     *
194
+     * This is a modified version of Helper::authenticate
195
+     * TODO: Try to merge back eventually with Helper::authenticate
196
+     *
197
+     * @param \OCP\Share\IShare $share
198
+     * @param string|null $password
199
+     * @return bool
200
+     */
201
+    private function linkShareAuth(\OCP\Share\IShare $share, $password = null) {
202
+        if ($password !== null) {
203
+            if ($this->shareManager->checkPassword($share, $password)) {
204
+                $this->session->regenerateId();
205
+                $this->session->set('public_link_authenticated', (string)$share->getId());
206
+            } else {
207
+                $this->emitAccessShareHook($share, 403, 'Wrong password');
208
+                return false;
209
+            }
210
+        } else {
211
+            // not authenticated ?
212
+            if ( ! $this->session->exists('public_link_authenticated')
213
+                || $this->session->get('public_link_authenticated') !== (string)$share->getId()) {
214
+                return false;
215
+            }
216
+        }
217
+        return true;
218
+    }
219
+
220
+    /**
221
+     * throws hooks when a share is attempted to be accessed
222
+     *
223
+     * @param \OCP\Share\IShare|string $share the Share instance if available,
224
+     * otherwise token
225
+     * @param int $errorCode
226
+     * @param string $errorMessage
227
+     * @throws \OC\HintException
228
+     * @throws \OC\ServerNotAvailableException
229
+     */
230
+    protected function emitAccessShareHook($share, $errorCode = 200, $errorMessage = '') {
231
+        $itemType = $itemSource = $uidOwner = '';
232
+        $token = $share;
233
+        $exception = null;
234
+        if($share instanceof \OCP\Share\IShare) {
235
+            try {
236
+                $token = $share->getToken();
237
+                $uidOwner = $share->getSharedBy();
238
+                $itemType = $share->getNodeType();
239
+                $itemSource = $share->getNodeId();
240
+            } catch (\Exception $e) {
241
+                // we log what we know and pass on the exception afterwards
242
+                $exception = $e;
243
+            }
244
+        }
245
+        \OC_Hook::emit('OCP\Share', 'share_link_access', [
246
+            'itemType' => $itemType,
247
+            'itemSource' => $itemSource,
248
+            'uidOwner' => $uidOwner,
249
+            'token' => $token,
250
+            'errorCode' => $errorCode,
251
+            'errorMessage' => $errorMessage,
252
+        ]);
253
+        if(!is_null($exception)) {
254
+            throw $exception;
255
+        }
256
+    }
257
+
258
+    /**
259
+     * Validate the permissions of the share
260
+     *
261
+     * @param Share\IShare $share
262
+     * @return bool
263
+     */
264
+    private function validateShare(\OCP\Share\IShare $share) {
265
+        return $share->getNode()->isReadable() && $share->getNode()->isShareable();
266
+    }
267
+
268
+    /**
269
+     * @PublicPage
270
+     * @NoCSRFRequired
271
+     *
272
+     * @param string $token
273
+     * @param string $path
274
+     * @return TemplateResponse|RedirectResponse|NotFoundResponse
275
+     * @throws NotFoundException
276
+     * @throws \Exception
277
+     */
278
+    public function showShare($token, $path = '') {
279
+        \OC_User::setIncognitoMode(true);
280
+
281
+        // Check whether share exists
282
+        try {
283
+            $share = $this->shareManager->getShareByToken($token);
284
+        } catch (ShareNotFound $e) {
285
+            $this->emitAccessShareHook($token, 404, 'Share not found');
286
+            return new NotFoundResponse();
287
+        }
288
+
289
+        // Share is password protected - check whether the user is permitted to access the share
290
+        if ($share->getPassword() !== null && !$this->linkShareAuth($share)) {
291
+            return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
292
+                array('token' => $token)));
293
+        }
294
+
295
+        if (!$this->validateShare($share)) {
296
+            throw new NotFoundException();
297
+        }
298
+        // We can't get the path of a file share
299
+        try {
300
+            if ($share->getNode() instanceof \OCP\Files\File && $path !== '') {
301
+                $this->emitAccessShareHook($share, 404, 'Share not found');
302
+                throw new NotFoundException();
303
+            }
304
+        } catch (\Exception $e) {
305
+            $this->emitAccessShareHook($share, 404, 'Share not found');
306
+            throw $e;
307
+        }
308
+
309
+        $shareTmpl = [];
310
+        $shareTmpl['displayName'] = $this->userManager->get($share->getShareOwner())->getDisplayName();
311
+        $shareTmpl['owner'] = $share->getShareOwner();
312
+        $shareTmpl['filename'] = $share->getNode()->getName();
313
+        $shareTmpl['directory_path'] = $share->getTarget();
314
+        $shareTmpl['mimetype'] = $share->getNode()->getMimetype();
315
+        $shareTmpl['previewSupported'] = $this->previewManager->isMimeSupported($share->getNode()->getMimetype());
316
+        $shareTmpl['dirToken'] = $token;
317
+        $shareTmpl['sharingToken'] = $token;
318
+        $shareTmpl['server2serversharing'] = $this->federatedShareProvider->isOutgoingServer2serverShareEnabled();
319
+        $shareTmpl['protected'] = $share->getPassword() !== null ? 'true' : 'false';
320
+        $shareTmpl['dir'] = '';
321
+        $shareTmpl['nonHumanFileSize'] = $share->getNode()->getSize();
322
+        $shareTmpl['fileSize'] = \OCP\Util::humanFileSize($share->getNode()->getSize());
323
+
324
+        // Show file list
325
+        $hideFileList = false;
326
+        if ($share->getNode() instanceof \OCP\Files\Folder) {
327
+            /** @var \OCP\Files\Folder $rootFolder */
328
+            $rootFolder = $share->getNode();
329
+
330
+            try {
331
+                $folderNode = $rootFolder->get($path);
332
+            } catch (\OCP\Files\NotFoundException $e) {
333
+                $this->emitAccessShareHook($share, 404, 'Share not found');
334
+                throw new NotFoundException();
335
+            }
336
+
337
+            $shareTmpl['dir'] = $rootFolder->getRelativePath($folderNode->getPath());
338
+
339
+            /*
340 340
 			 * The OC_Util methods require a view. This just uses the node API
341 341
 			 */
342
-			$freeSpace = $share->getNode()->getStorage()->free_space($share->getNode()->getInternalPath());
343
-			if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) {
344
-				$freeSpace = max($freeSpace, 0);
345
-			} else {
346
-				$freeSpace = (INF > 0) ? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188
347
-			}
348
-
349
-			$hideFileList = $share->getPermissions() & \OCP\Constants::PERMISSION_READ ? false : true;
350
-			$maxUploadFilesize = $freeSpace;
351
-
352
-			$folder = new Template('files', 'list', '');
353
-			$folder->assign('dir', $rootFolder->getRelativePath($folderNode->getPath()));
354
-			$folder->assign('dirToken', $token);
355
-			$folder->assign('permissions', \OCP\Constants::PERMISSION_READ);
356
-			$folder->assign('isPublic', true);
357
-			$folder->assign('hideFileList', $hideFileList);
358
-			$folder->assign('publicUploadEnabled', 'no');
359
-			$folder->assign('uploadMaxFilesize', $maxUploadFilesize);
360
-			$folder->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize($maxUploadFilesize));
361
-			$folder->assign('freeSpace', $freeSpace);
362
-			$folder->assign('usedSpacePercent', 0);
363
-			$folder->assign('trash', false);
364
-			$shareTmpl['folder'] = $folder->fetchPage();
365
-		}
366
-
367
-		$shareTmpl['hideFileList'] = $hideFileList;
368
-		$shareTmpl['shareOwner'] = $this->userManager->get($share->getShareOwner())->getDisplayName();
369
-		$shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', ['token' => $token]);
370
-		$shareTmpl['shareUrl'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $token]);
371
-		$shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
372
-		$shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
373
-		$shareTmpl['previewMaxX'] = $this->config->getSystemValue('preview_max_x', 1024);
374
-		$shareTmpl['previewMaxY'] = $this->config->getSystemValue('preview_max_y', 1024);
375
-		$shareTmpl['disclaimer'] = $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null);
376
-		if ($shareTmpl['previewSupported']) {
377
-			$shareTmpl['previewImage'] = $this->urlGenerator->linkToRouteAbsolute( 'files_sharing.PublicPreview.getPreview',
378
-				['x' => 200, 'y' => 200, 'file' => $shareTmpl['directory_path'], 't' => $shareTmpl['dirToken']]);
379
-		} else {
380
-			$shareTmpl['previewImage'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-fb.png'));
381
-		}
382
-
383
-		// Load files we need
384
-		\OCP\Util::addScript('files', 'file-upload');
385
-		\OCP\Util::addStyle('files_sharing', 'publicView');
386
-		\OCP\Util::addScript('files_sharing', 'public');
387
-		\OCP\Util::addScript('files', 'fileactions');
388
-		\OCP\Util::addScript('files', 'fileactionsmenu');
389
-		\OCP\Util::addScript('files', 'jquery.fileupload');
390
-		\OCP\Util::addScript('files_sharing', 'files_drop');
391
-
392
-		if (isset($shareTmpl['folder'])) {
393
-			// JS required for folders
394
-			\OCP\Util::addStyle('files', 'merged');
395
-			\OCP\Util::addScript('files', 'filesummary');
396
-			\OCP\Util::addScript('files', 'breadcrumb');
397
-			\OCP\Util::addScript('files', 'fileinfomodel');
398
-			\OCP\Util::addScript('files', 'newfilemenu');
399
-			\OCP\Util::addScript('files', 'files');
400
-			\OCP\Util::addScript('files', 'filelist');
401
-			\OCP\Util::addScript('files', 'keyboardshortcuts');
402
-		}
403
-
404
-		// OpenGraph Support: http://ogp.me/
405
-		\OCP\Util::addHeader('meta', ['property' => "og:title", 'content' => $this->defaults->getName() . ' - ' . $this->defaults->getSlogan()]);
406
-		\OCP\Util::addHeader('meta', ['property' => "og:description", 'content' => $this->l10n->t('%s is publicly shared', [$shareTmpl['filename']])]);
407
-		\OCP\Util::addHeader('meta', ['property' => "og:site_name", 'content' => $this->defaults->getName()]);
408
-		\OCP\Util::addHeader('meta', ['property' => "og:url", 'content' => $shareTmpl['shareUrl']]);
409
-		\OCP\Util::addHeader('meta', ['property' => "og:type", 'content' => "object"]);
410
-		\OCP\Util::addHeader('meta', ['property' => "og:image", 'content' => $shareTmpl['previewImage']]);
411
-
412
-		$this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts');
413
-
414
-		$csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
415
-		$csp->addAllowedFrameDomain('\'self\'');
416
-		$response = new TemplateResponse($this->appName, 'public', $shareTmpl, 'base');
417
-		$response->setContentSecurityPolicy($csp);
418
-
419
-		$this->emitAccessShareHook($share);
420
-
421
-		return $response;
422
-	}
423
-
424
-	/**
425
-	 * @PublicPage
426
-	 * @NoCSRFRequired
427
-	 *
428
-	 * @param string $token
429
-	 * @param string $files
430
-	 * @param string $path
431
-	 * @param string $downloadStartSecret
432
-	 * @return void|\OCP\AppFramework\Http\Response
433
-	 * @throws NotFoundException
434
-	 */
435
-	public function downloadShare($token, $files = null, $path = '', $downloadStartSecret = '') {
436
-		\OC_User::setIncognitoMode(true);
437
-
438
-		$share = $this->shareManager->getShareByToken($token);
439
-
440
-		if(!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) {
441
-			return new \OCP\AppFramework\Http\DataResponse('Share is read-only');
442
-		}
443
-
444
-		// Share is password protected - check whether the user is permitted to access the share
445
-		if ($share->getPassword() !== null && !$this->linkShareAuth($share)) {
446
-			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
447
-				['token' => $token]));
448
-		}
449
-
450
-		$files_list = null;
451
-		if (!is_null($files)) { // download selected files
452
-			$files_list = json_decode($files);
453
-			// in case we get only a single file
454
-			if ($files_list === null) {
455
-				$files_list = [$files];
456
-			}
457
-		}
458
-
459
-		$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
460
-		$originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath());
461
-
462
-		if (!$this->validateShare($share)) {
463
-			throw new NotFoundException();
464
-		}
465
-
466
-		// Single file share
467
-		if ($share->getNode() instanceof \OCP\Files\File) {
468
-			// Single file download
469
-			$this->singleFileDownloaded($share, $share->getNode());
470
-		}
471
-		// Directory share
472
-		else {
473
-			/** @var \OCP\Files\Folder $node */
474
-			$node = $share->getNode();
475
-
476
-			// Try to get the path
477
-			if ($path !== '') {
478
-				try {
479
-					$node = $node->get($path);
480
-				} catch (NotFoundException $e) {
481
-					$this->emitAccessShareHook($share, 404, 'Share not found');
482
-					return new NotFoundResponse();
483
-				}
484
-			}
485
-
486
-			$originalSharePath = $userFolder->getRelativePath($node->getPath());
487
-
488
-			if ($node instanceof \OCP\Files\File) {
489
-				// Single file download
490
-				$this->singleFileDownloaded($share, $share->getNode());
491
-			} else if (!empty($files_list)) {
492
-				$this->fileListDownloaded($share, $files_list, $node);
493
-			} else {
494
-				// The folder is downloaded
495
-				$this->singleFileDownloaded($share, $share->getNode());
496
-			}
497
-		}
498
-
499
-		/* FIXME: We should do this all nicely in OCP */
500
-		OC_Util::tearDownFS();
501
-		OC_Util::setupFS($share->getShareOwner());
502
-
503
-		/**
504
-		 * this sets a cookie to be able to recognize the start of the download
505
-		 * the content must not be longer than 32 characters and must only contain
506
-		 * alphanumeric characters
507
-		 */
508
-		if (!empty($downloadStartSecret)
509
-			&& !isset($downloadStartSecret[32])
510
-			&& preg_match('!^[a-zA-Z0-9]+$!', $downloadStartSecret) === 1) {
511
-
512
-			// FIXME: set on the response once we use an actual app framework response
513
-			setcookie('ocDownloadStarted', $downloadStartSecret, time() + 20, '/');
514
-		}
515
-
516
-		$this->emitAccessShareHook($share);
517
-
518
-		$server_params = array( 'head' => $this->request->getMethod() == 'HEAD' );
519
-
520
-		/**
521
-		 * Http range requests support
522
-		 */
523
-		if (isset($_SERVER['HTTP_RANGE'])) {
524
-			$server_params['range'] = $this->request->getHeader('Range');
525
-		}
526
-
527
-		// download selected files
528
-		if (!is_null($files) && $files !== '') {
529
-			// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
530
-			// after dispatching the request which results in a "Cannot modify header information" notice.
531
-			OC_Files::get($originalSharePath, $files_list, $server_params);
532
-			exit();
533
-		} else {
534
-			// FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
535
-			// after dispatching the request which results in a "Cannot modify header information" notice.
536
-			OC_Files::get(dirname($originalSharePath), basename($originalSharePath), $server_params);
537
-			exit();
538
-		}
539
-	}
540
-
541
-	/**
542
-	 * create activity for every downloaded file
543
-	 *
544
-	 * @param Share\IShare $share
545
-	 * @param array $files_list
546
-	 * @param \OCP\Files\Folder $node
547
-	 */
548
-	protected function fileListDownloaded(Share\IShare $share, array $files_list, \OCP\Files\Folder $node) {
549
-		foreach ($files_list as $file) {
550
-			$subNode = $node->get($file);
551
-			$this->singleFileDownloaded($share, $subNode);
552
-		}
553
-
554
-	}
555
-
556
-	/**
557
-	 * create activity if a single file was downloaded from a link share
558
-	 *
559
-	 * @param Share\IShare $share
560
-	 */
561
-	protected function singleFileDownloaded(Share\IShare $share, \OCP\Files\Node $node) {
562
-
563
-		$fileId = $node->getId();
564
-
565
-		$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
566
-		$userNodeList = $userFolder->getById($fileId);
567
-		$userNode = $userNodeList[0];
568
-		$ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
569
-		$userPath = $userFolder->getRelativePath($userNode->getPath());
570
-		$ownerPath = $ownerFolder->getRelativePath($node->getPath());
571
-
572
-		$parameters = [$userPath];
573
-
574
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
575
-			if ($node instanceof \OCP\Files\File) {
576
-				$subject = Downloads::SUBJECT_SHARED_FILE_BY_EMAIL_DOWNLOADED;
577
-			} else {
578
-				$subject = Downloads::SUBJECT_SHARED_FOLDER_BY_EMAIL_DOWNLOADED;
579
-			}
580
-			$parameters[] = $share->getSharedWith();
581
-		} else {
582
-			if ($node instanceof \OCP\Files\File) {
583
-				$subject = Downloads::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
584
-			} else {
585
-				$subject = Downloads::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED;
586
-			}
587
-		}
588
-
589
-		$this->publishActivity($subject, $parameters, $share->getSharedBy(), $fileId, $userPath);
590
-
591
-		if ($share->getShareOwner() !== $share->getSharedBy()) {
592
-			$parameters[0] = $ownerPath;
593
-			$this->publishActivity($subject, $parameters, $share->getShareOwner(), $fileId, $ownerPath);
594
-		}
595
-	}
596
-
597
-	/**
598
-	 * publish activity
599
-	 *
600
-	 * @param string $subject
601
-	 * @param array $parameters
602
-	 * @param string $affectedUser
603
-	 * @param int $fileId
604
-	 * @param string $filePath
605
-	 */
606
-	protected function publishActivity($subject,
607
-										array $parameters,
608
-										$affectedUser,
609
-										$fileId,
610
-										$filePath) {
611
-
612
-		$event = $this->activityManager->generateEvent();
613
-		$event->setApp('files_sharing')
614
-			->setType('public_links')
615
-			->setSubject($subject, $parameters)
616
-			->setAffectedUser($affectedUser)
617
-			->setObject('files', $fileId, $filePath);
618
-		$this->activityManager->publish($event);
619
-	}
342
+            $freeSpace = $share->getNode()->getStorage()->free_space($share->getNode()->getInternalPath());
343
+            if ($freeSpace < \OCP\Files\FileInfo::SPACE_UNLIMITED) {
344
+                $freeSpace = max($freeSpace, 0);
345
+            } else {
346
+                $freeSpace = (INF > 0) ? INF: PHP_INT_MAX; // work around https://bugs.php.net/bug.php?id=69188
347
+            }
348
+
349
+            $hideFileList = $share->getPermissions() & \OCP\Constants::PERMISSION_READ ? false : true;
350
+            $maxUploadFilesize = $freeSpace;
351
+
352
+            $folder = new Template('files', 'list', '');
353
+            $folder->assign('dir', $rootFolder->getRelativePath($folderNode->getPath()));
354
+            $folder->assign('dirToken', $token);
355
+            $folder->assign('permissions', \OCP\Constants::PERMISSION_READ);
356
+            $folder->assign('isPublic', true);
357
+            $folder->assign('hideFileList', $hideFileList);
358
+            $folder->assign('publicUploadEnabled', 'no');
359
+            $folder->assign('uploadMaxFilesize', $maxUploadFilesize);
360
+            $folder->assign('uploadMaxHumanFilesize', \OCP\Util::humanFileSize($maxUploadFilesize));
361
+            $folder->assign('freeSpace', $freeSpace);
362
+            $folder->assign('usedSpacePercent', 0);
363
+            $folder->assign('trash', false);
364
+            $shareTmpl['folder'] = $folder->fetchPage();
365
+        }
366
+
367
+        $shareTmpl['hideFileList'] = $hideFileList;
368
+        $shareTmpl['shareOwner'] = $this->userManager->get($share->getShareOwner())->getDisplayName();
369
+        $shareTmpl['downloadURL'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.downloadShare', ['token' => $token]);
370
+        $shareTmpl['shareUrl'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $token]);
371
+        $shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
372
+        $shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
373
+        $shareTmpl['previewMaxX'] = $this->config->getSystemValue('preview_max_x', 1024);
374
+        $shareTmpl['previewMaxY'] = $this->config->getSystemValue('preview_max_y', 1024);
375
+        $shareTmpl['disclaimer'] = $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null);
376
+        if ($shareTmpl['previewSupported']) {
377
+            $shareTmpl['previewImage'] = $this->urlGenerator->linkToRouteAbsolute( 'files_sharing.PublicPreview.getPreview',
378
+                ['x' => 200, 'y' => 200, 'file' => $shareTmpl['directory_path'], 't' => $shareTmpl['dirToken']]);
379
+        } else {
380
+            $shareTmpl['previewImage'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-fb.png'));
381
+        }
382
+
383
+        // Load files we need
384
+        \OCP\Util::addScript('files', 'file-upload');
385
+        \OCP\Util::addStyle('files_sharing', 'publicView');
386
+        \OCP\Util::addScript('files_sharing', 'public');
387
+        \OCP\Util::addScript('files', 'fileactions');
388
+        \OCP\Util::addScript('files', 'fileactionsmenu');
389
+        \OCP\Util::addScript('files', 'jquery.fileupload');
390
+        \OCP\Util::addScript('files_sharing', 'files_drop');
391
+
392
+        if (isset($shareTmpl['folder'])) {
393
+            // JS required for folders
394
+            \OCP\Util::addStyle('files', 'merged');
395
+            \OCP\Util::addScript('files', 'filesummary');
396
+            \OCP\Util::addScript('files', 'breadcrumb');
397
+            \OCP\Util::addScript('files', 'fileinfomodel');
398
+            \OCP\Util::addScript('files', 'newfilemenu');
399
+            \OCP\Util::addScript('files', 'files');
400
+            \OCP\Util::addScript('files', 'filelist');
401
+            \OCP\Util::addScript('files', 'keyboardshortcuts');
402
+        }
403
+
404
+        // OpenGraph Support: http://ogp.me/
405
+        \OCP\Util::addHeader('meta', ['property' => "og:title", 'content' => $this->defaults->getName() . ' - ' . $this->defaults->getSlogan()]);
406
+        \OCP\Util::addHeader('meta', ['property' => "og:description", 'content' => $this->l10n->t('%s is publicly shared', [$shareTmpl['filename']])]);
407
+        \OCP\Util::addHeader('meta', ['property' => "og:site_name", 'content' => $this->defaults->getName()]);
408
+        \OCP\Util::addHeader('meta', ['property' => "og:url", 'content' => $shareTmpl['shareUrl']]);
409
+        \OCP\Util::addHeader('meta', ['property' => "og:type", 'content' => "object"]);
410
+        \OCP\Util::addHeader('meta', ['property' => "og:image", 'content' => $shareTmpl['previewImage']]);
411
+
412
+        $this->eventDispatcher->dispatch('OCA\Files_Sharing::loadAdditionalScripts');
413
+
414
+        $csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
415
+        $csp->addAllowedFrameDomain('\'self\'');
416
+        $response = new TemplateResponse($this->appName, 'public', $shareTmpl, 'base');
417
+        $response->setContentSecurityPolicy($csp);
418
+
419
+        $this->emitAccessShareHook($share);
420
+
421
+        return $response;
422
+    }
423
+
424
+    /**
425
+     * @PublicPage
426
+     * @NoCSRFRequired
427
+     *
428
+     * @param string $token
429
+     * @param string $files
430
+     * @param string $path
431
+     * @param string $downloadStartSecret
432
+     * @return void|\OCP\AppFramework\Http\Response
433
+     * @throws NotFoundException
434
+     */
435
+    public function downloadShare($token, $files = null, $path = '', $downloadStartSecret = '') {
436
+        \OC_User::setIncognitoMode(true);
437
+
438
+        $share = $this->shareManager->getShareByToken($token);
439
+
440
+        if(!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) {
441
+            return new \OCP\AppFramework\Http\DataResponse('Share is read-only');
442
+        }
443
+
444
+        // Share is password protected - check whether the user is permitted to access the share
445
+        if ($share->getPassword() !== null && !$this->linkShareAuth($share)) {
446
+            return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.authenticate',
447
+                ['token' => $token]));
448
+        }
449
+
450
+        $files_list = null;
451
+        if (!is_null($files)) { // download selected files
452
+            $files_list = json_decode($files);
453
+            // in case we get only a single file
454
+            if ($files_list === null) {
455
+                $files_list = [$files];
456
+            }
457
+        }
458
+
459
+        $userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
460
+        $originalSharePath = $userFolder->getRelativePath($share->getNode()->getPath());
461
+
462
+        if (!$this->validateShare($share)) {
463
+            throw new NotFoundException();
464
+        }
465
+
466
+        // Single file share
467
+        if ($share->getNode() instanceof \OCP\Files\File) {
468
+            // Single file download
469
+            $this->singleFileDownloaded($share, $share->getNode());
470
+        }
471
+        // Directory share
472
+        else {
473
+            /** @var \OCP\Files\Folder $node */
474
+            $node = $share->getNode();
475
+
476
+            // Try to get the path
477
+            if ($path !== '') {
478
+                try {
479
+                    $node = $node->get($path);
480
+                } catch (NotFoundException $e) {
481
+                    $this->emitAccessShareHook($share, 404, 'Share not found');
482
+                    return new NotFoundResponse();
483
+                }
484
+            }
485
+
486
+            $originalSharePath = $userFolder->getRelativePath($node->getPath());
487
+
488
+            if ($node instanceof \OCP\Files\File) {
489
+                // Single file download
490
+                $this->singleFileDownloaded($share, $share->getNode());
491
+            } else if (!empty($files_list)) {
492
+                $this->fileListDownloaded($share, $files_list, $node);
493
+            } else {
494
+                // The folder is downloaded
495
+                $this->singleFileDownloaded($share, $share->getNode());
496
+            }
497
+        }
498
+
499
+        /* FIXME: We should do this all nicely in OCP */
500
+        OC_Util::tearDownFS();
501
+        OC_Util::setupFS($share->getShareOwner());
502
+
503
+        /**
504
+         * this sets a cookie to be able to recognize the start of the download
505
+         * the content must not be longer than 32 characters and must only contain
506
+         * alphanumeric characters
507
+         */
508
+        if (!empty($downloadStartSecret)
509
+            && !isset($downloadStartSecret[32])
510
+            && preg_match('!^[a-zA-Z0-9]+$!', $downloadStartSecret) === 1) {
511
+
512
+            // FIXME: set on the response once we use an actual app framework response
513
+            setcookie('ocDownloadStarted', $downloadStartSecret, time() + 20, '/');
514
+        }
515
+
516
+        $this->emitAccessShareHook($share);
517
+
518
+        $server_params = array( 'head' => $this->request->getMethod() == 'HEAD' );
519
+
520
+        /**
521
+         * Http range requests support
522
+         */
523
+        if (isset($_SERVER['HTTP_RANGE'])) {
524
+            $server_params['range'] = $this->request->getHeader('Range');
525
+        }
526
+
527
+        // download selected files
528
+        if (!is_null($files) && $files !== '') {
529
+            // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
530
+            // after dispatching the request which results in a "Cannot modify header information" notice.
531
+            OC_Files::get($originalSharePath, $files_list, $server_params);
532
+            exit();
533
+        } else {
534
+            // FIXME: The exit is required here because otherwise the AppFramework is trying to add headers as well
535
+            // after dispatching the request which results in a "Cannot modify header information" notice.
536
+            OC_Files::get(dirname($originalSharePath), basename($originalSharePath), $server_params);
537
+            exit();
538
+        }
539
+    }
540
+
541
+    /**
542
+     * create activity for every downloaded file
543
+     *
544
+     * @param Share\IShare $share
545
+     * @param array $files_list
546
+     * @param \OCP\Files\Folder $node
547
+     */
548
+    protected function fileListDownloaded(Share\IShare $share, array $files_list, \OCP\Files\Folder $node) {
549
+        foreach ($files_list as $file) {
550
+            $subNode = $node->get($file);
551
+            $this->singleFileDownloaded($share, $subNode);
552
+        }
553
+
554
+    }
555
+
556
+    /**
557
+     * create activity if a single file was downloaded from a link share
558
+     *
559
+     * @param Share\IShare $share
560
+     */
561
+    protected function singleFileDownloaded(Share\IShare $share, \OCP\Files\Node $node) {
562
+
563
+        $fileId = $node->getId();
564
+
565
+        $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
566
+        $userNodeList = $userFolder->getById($fileId);
567
+        $userNode = $userNodeList[0];
568
+        $ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
569
+        $userPath = $userFolder->getRelativePath($userNode->getPath());
570
+        $ownerPath = $ownerFolder->getRelativePath($node->getPath());
571
+
572
+        $parameters = [$userPath];
573
+
574
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_EMAIL) {
575
+            if ($node instanceof \OCP\Files\File) {
576
+                $subject = Downloads::SUBJECT_SHARED_FILE_BY_EMAIL_DOWNLOADED;
577
+            } else {
578
+                $subject = Downloads::SUBJECT_SHARED_FOLDER_BY_EMAIL_DOWNLOADED;
579
+            }
580
+            $parameters[] = $share->getSharedWith();
581
+        } else {
582
+            if ($node instanceof \OCP\Files\File) {
583
+                $subject = Downloads::SUBJECT_PUBLIC_SHARED_FILE_DOWNLOADED;
584
+            } else {
585
+                $subject = Downloads::SUBJECT_PUBLIC_SHARED_FOLDER_DOWNLOADED;
586
+            }
587
+        }
588
+
589
+        $this->publishActivity($subject, $parameters, $share->getSharedBy(), $fileId, $userPath);
590
+
591
+        if ($share->getShareOwner() !== $share->getSharedBy()) {
592
+            $parameters[0] = $ownerPath;
593
+            $this->publishActivity($subject, $parameters, $share->getShareOwner(), $fileId, $ownerPath);
594
+        }
595
+    }
596
+
597
+    /**
598
+     * publish activity
599
+     *
600
+     * @param string $subject
601
+     * @param array $parameters
602
+     * @param string $affectedUser
603
+     * @param int $fileId
604
+     * @param string $filePath
605
+     */
606
+    protected function publishActivity($subject,
607
+                                        array $parameters,
608
+                                        $affectedUser,
609
+                                        $fileId,
610
+                                        $filePath) {
611
+
612
+        $event = $this->activityManager->generateEvent();
613
+        $event->setApp('files_sharing')
614
+            ->setType('public_links')
615
+            ->setSubject($subject, $parameters)
616
+            ->setAffectedUser($affectedUser)
617
+            ->setObject('files', $fileId, $filePath);
618
+        $this->activityManager->publish($event);
619
+    }
620 620
 
621 621
 
622 622
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -150,7 +150,7 @@  discard block
 block discarded – undo
150 150
 	public function showAuthenticate($token) {
151 151
 		$share = $this->shareManager->getShareByToken($token);
152 152
 
153
-		if($this->linkShareAuth($share)) {
153
+		if ($this->linkShareAuth($share)) {
154 154
 			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
155 155
 		}
156 156
 
@@ -178,7 +178,7 @@  discard block
 block discarded – undo
178 178
 
179 179
 		$authenticate = $this->linkShareAuth($share, $password);
180 180
 
181
-		if($authenticate === true) {
181
+		if ($authenticate === true) {
182 182
 			return new RedirectResponse($this->urlGenerator->linkToRoute('files_sharing.sharecontroller.showShare', array('token' => $token)));
183 183
 		}
184 184
 
@@ -202,15 +202,15 @@  discard block
 block discarded – undo
202 202
 		if ($password !== null) {
203 203
 			if ($this->shareManager->checkPassword($share, $password)) {
204 204
 				$this->session->regenerateId();
205
-				$this->session->set('public_link_authenticated', (string)$share->getId());
205
+				$this->session->set('public_link_authenticated', (string) $share->getId());
206 206
 			} else {
207 207
 				$this->emitAccessShareHook($share, 403, 'Wrong password');
208 208
 				return false;
209 209
 			}
210 210
 		} else {
211 211
 			// not authenticated ?
212
-			if ( ! $this->session->exists('public_link_authenticated')
213
-				|| $this->session->get('public_link_authenticated') !== (string)$share->getId()) {
212
+			if (!$this->session->exists('public_link_authenticated')
213
+				|| $this->session->get('public_link_authenticated') !== (string) $share->getId()) {
214 214
 				return false;
215 215
 			}
216 216
 		}
@@ -231,7 +231,7 @@  discard block
 block discarded – undo
231 231
 		$itemType = $itemSource = $uidOwner = '';
232 232
 		$token = $share;
233 233
 		$exception = null;
234
-		if($share instanceof \OCP\Share\IShare) {
234
+		if ($share instanceof \OCP\Share\IShare) {
235 235
 			try {
236 236
 				$token = $share->getToken();
237 237
 				$uidOwner = $share->getSharedBy();
@@ -250,7 +250,7 @@  discard block
 block discarded – undo
250 250
 			'errorCode' => $errorCode,
251 251
 			'errorMessage' => $errorMessage,
252 252
 		]);
253
-		if(!is_null($exception)) {
253
+		if (!is_null($exception)) {
254 254
 			throw $exception;
255 255
 		}
256 256
 	}
@@ -374,7 +374,7 @@  discard block
 block discarded – undo
374 374
 		$shareTmpl['previewMaxY'] = $this->config->getSystemValue('preview_max_y', 1024);
375 375
 		$shareTmpl['disclaimer'] = $this->config->getAppValue('core', 'shareapi_public_link_disclaimertext', null);
376 376
 		if ($shareTmpl['previewSupported']) {
377
-			$shareTmpl['previewImage'] = $this->urlGenerator->linkToRouteAbsolute( 'files_sharing.PublicPreview.getPreview',
377
+			$shareTmpl['previewImage'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.PublicPreview.getPreview',
378 378
 				['x' => 200, 'y' => 200, 'file' => $shareTmpl['directory_path'], 't' => $shareTmpl['dirToken']]);
379 379
 		} else {
380 380
 			$shareTmpl['previewImage'] = $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-fb.png'));
@@ -402,7 +402,7 @@  discard block
 block discarded – undo
402 402
 		}
403 403
 
404 404
 		// OpenGraph Support: http://ogp.me/
405
-		\OCP\Util::addHeader('meta', ['property' => "og:title", 'content' => $this->defaults->getName() . ' - ' . $this->defaults->getSlogan()]);
405
+		\OCP\Util::addHeader('meta', ['property' => "og:title", 'content' => $this->defaults->getName().' - '.$this->defaults->getSlogan()]);
406 406
 		\OCP\Util::addHeader('meta', ['property' => "og:description", 'content' => $this->l10n->t('%s is publicly shared', [$shareTmpl['filename']])]);
407 407
 		\OCP\Util::addHeader('meta', ['property' => "og:site_name", 'content' => $this->defaults->getName()]);
408 408
 		\OCP\Util::addHeader('meta', ['property' => "og:url", 'content' => $shareTmpl['shareUrl']]);
@@ -437,7 +437,7 @@  discard block
 block discarded – undo
437 437
 
438 438
 		$share = $this->shareManager->getShareByToken($token);
439 439
 
440
-		if(!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) {
440
+		if (!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) {
441 441
 			return new \OCP\AppFramework\Http\DataResponse('Share is read-only');
442 442
 		}
443 443
 
@@ -515,7 +515,7 @@  discard block
 block discarded – undo
515 515
 
516 516
 		$this->emitAccessShareHook($share);
517 517
 
518
-		$server_params = array( 'head' => $this->request->getMethod() == 'HEAD' );
518
+		$server_params = array('head' => $this->request->getMethod() == 'HEAD');
519 519
 
520 520
 		/**
521 521
 		 * Http range requests support
Please login to merge, or discard this patch.