Completed
Pull Request — master (#4520)
by Joas
24:27
created
apps/dav/lib/Connector/Sabre/File.php 3 patches
Doc Comments   +4 added lines, -1 removed lines patch added patch discarded remove patch
@@ -245,6 +245,9 @@  discard block
 block discarded – undo
245 245
 		return '"' . $this->info->getEtag() . '"';
246 246
 	}
247 247
 
248
+	/**
249
+	 * @param string $path
250
+	 */
248 251
 	private function getPartFileBasePath($path) {
249 252
 		$partFileInStorage = \OC::$server->getConfig()->getSystemValue('part_file_in_storage', true);
250 253
 		if ($partFileInStorage) {
@@ -607,7 +610,7 @@  discard block
 block discarded – undo
607 610
 	/**
608 611
 	 * Set $algo to get a specific checksum, leave null to get all checksums
609 612
 	 * (space seperated)
610
-	 * @param null $algo
613
+	 * @param string $algo
611 614
 	 * @return string
612 615
 	 */
613 616
 	public function getChecksum($algo = null) {
Please login to merge, or discard this patch.
Indentation   +570 added lines, -570 removed lines patch added patch discarded remove patch
@@ -58,575 +58,575 @@
 block discarded – undo
58 58
 
59 59
 class File extends Node implements IFile {
60 60
 
61
-	/**
62
-	 * Updates the data
63
-	 *
64
-	 * The data argument is a readable stream resource.
65
-	 *
66
-	 * After a successful put operation, you may choose to return an ETag. The
67
-	 * etag must always be surrounded by double-quotes. These quotes must
68
-	 * appear in the actual string you're returning.
69
-	 *
70
-	 * Clients may use the ETag from a PUT request to later on make sure that
71
-	 * when they update the file, the contents haven't changed in the mean
72
-	 * time.
73
-	 *
74
-	 * If you don't plan to store the file byte-by-byte, and you return a
75
-	 * different object on a subsequent GET you are strongly recommended to not
76
-	 * return an ETag, and just return null.
77
-	 *
78
-	 * @param resource $data
79
-	 *
80
-	 * @throws Forbidden
81
-	 * @throws UnsupportedMediaType
82
-	 * @throws BadRequest
83
-	 * @throws Exception
84
-	 * @throws EntityTooLarge
85
-	 * @throws ServiceUnavailable
86
-	 * @throws FileLocked
87
-	 * @return string|null
88
-	 */
89
-	public function put($data) {
90
-		try {
91
-			$exists = $this->fileView->file_exists($this->path);
92
-			if ($this->info && $exists && !$this->info->isUpdateable()) {
93
-				throw new Forbidden();
94
-			}
95
-		} catch (StorageNotAvailableException $e) {
96
-			throw new ServiceUnavailable("File is not updatable: " . $e->getMessage());
97
-		}
98
-
99
-		// verify path of the target
100
-		$this->verifyPath();
101
-
102
-		// chunked handling
103
-		if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
104
-			try {
105
-				return $this->createFileChunked($data);
106
-			} catch (\Exception $e) {
107
-				$this->convertToSabreException($e);
108
-			}
109
-		}
110
-
111
-		list($partStorage) = $this->fileView->resolvePath($this->path);
112
-		$needsPartFile = $this->needsPartFile($partStorage) && (strlen($this->path) > 1);
113
-
114
-		if ($needsPartFile) {
115
-			// mark file as partial while uploading (ignored by the scanner)
116
-			$partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part';
117
-		} else {
118
-			// upload file directly as the final path
119
-			$partFilePath = $this->path;
120
-		}
121
-
122
-		// the part file and target file might be on a different storage in case of a single file storage (e.g. single file share)
123
-		/** @var \OC\Files\Storage\Storage $partStorage */
124
-		list($partStorage, $internalPartPath) = $this->fileView->resolvePath($partFilePath);
125
-		/** @var \OC\Files\Storage\Storage $storage */
126
-		list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
127
-		try {
128
-			$target = $partStorage->fopen($internalPartPath, 'wb');
129
-			if ($target === false) {
130
-				\OCP\Util::writeLog('webdav', '\OC\Files\Filesystem::fopen() failed', \OCP\Util::ERROR);
131
-				// because we have no clue about the cause we can only throw back a 500/Internal Server Error
132
-				throw new Exception('Could not write file contents');
133
-			}
134
-			list($count, $result) = \OC_Helper::streamCopy($data, $target);
135
-			fclose($target);
136
-
137
-			if (!self::isChecksumValid($partStorage, $internalPartPath)) {
138
-				throw new BadRequest('The computed checksum does not match the one received from the client.');
139
-			}
140
-
141
-			if ($result === false) {
142
-				$expected = -1;
143
-				if (isset($_SERVER['CONTENT_LENGTH'])) {
144
-					$expected = $_SERVER['CONTENT_LENGTH'];
145
-				}
146
-				throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )');
147
-			}
148
-
149
-			// if content length is sent by client:
150
-			// double check if the file was fully received
151
-			// compare expected and actual size
152
-			if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
153
-				$expected = $_SERVER['CONTENT_LENGTH'];
154
-				if ($count != $expected) {
155
-					throw new BadRequest('expected filesize ' . $expected . ' got ' . $count);
156
-				}
157
-			}
158
-
159
-		} catch (\Exception $e) {
160
-			if ($needsPartFile) {
161
-				$partStorage->unlink($internalPartPath);
162
-			}
163
-			$this->convertToSabreException($e);
164
-		}
165
-
166
-		try {
167
-			$view = \OC\Files\Filesystem::getView();
168
-			if ($view) {
169
-				$run = $this->emitPreHooks($exists);
170
-			} else {
171
-				$run = true;
172
-			}
173
-
174
-			try {
175
-				$this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
176
-			} catch (LockedException $e) {
177
-				if ($needsPartFile) {
178
-					$partStorage->unlink($internalPartPath);
179
-				}
180
-				throw new FileLocked($e->getMessage(), $e->getCode(), $e);
181
-			}
182
-
183
-			if ($needsPartFile) {
184
-				// rename to correct path
185
-				try {
186
-					if ($run) {
187
-						$renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath);
188
-						$fileExists = $storage->file_exists($internalPath);
189
-					}
190
-					if (!$run || $renameOkay === false || $fileExists === false) {
191
-						\OCP\Util::writeLog('webdav', 'renaming part file to final file failed', \OCP\Util::ERROR);
192
-						throw new Exception('Could not rename part file to final file');
193
-					}
194
-				} catch (ForbiddenException $ex) {
195
-					throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
196
-				} catch (\Exception $e) {
197
-					$partStorage->unlink($internalPartPath);
198
-					$this->convertToSabreException($e);
199
-				}
200
-			}
201
-
202
-			// since we skipped the view we need to scan and emit the hooks ourselves
203
-			$storage->getUpdater()->update($internalPath);
204
-
205
-			try {
206
-				$this->changeLock(ILockingProvider::LOCK_SHARED);
207
-			} catch (LockedException $e) {
208
-				throw new FileLocked($e->getMessage(), $e->getCode(), $e);
209
-			}
210
-
211
-			// allow sync clients to send the mtime along in a header
212
-			$request = \OC::$server->getRequest();
213
-			if (isset($request->server['HTTP_X_OC_MTIME'])) {
214
-				$mtimeStr = $request->server['HTTP_X_OC_MTIME'];
215
-				if (!is_numeric($mtimeStr)) {
216
-					throw new \InvalidArgumentException('X-OC-Mtime header must be an integer (unix timestamp).');
217
-				}
218
-				$mtime = intval($mtimeStr);
219
-				if ($this->fileView->touch($this->path, $mtime)) {
220
-					header('X-OC-MTime: accepted');
221
-				}
222
-			}
61
+    /**
62
+     * Updates the data
63
+     *
64
+     * The data argument is a readable stream resource.
65
+     *
66
+     * After a successful put operation, you may choose to return an ETag. The
67
+     * etag must always be surrounded by double-quotes. These quotes must
68
+     * appear in the actual string you're returning.
69
+     *
70
+     * Clients may use the ETag from a PUT request to later on make sure that
71
+     * when they update the file, the contents haven't changed in the mean
72
+     * time.
73
+     *
74
+     * If you don't plan to store the file byte-by-byte, and you return a
75
+     * different object on a subsequent GET you are strongly recommended to not
76
+     * return an ETag, and just return null.
77
+     *
78
+     * @param resource $data
79
+     *
80
+     * @throws Forbidden
81
+     * @throws UnsupportedMediaType
82
+     * @throws BadRequest
83
+     * @throws Exception
84
+     * @throws EntityTooLarge
85
+     * @throws ServiceUnavailable
86
+     * @throws FileLocked
87
+     * @return string|null
88
+     */
89
+    public function put($data) {
90
+        try {
91
+            $exists = $this->fileView->file_exists($this->path);
92
+            if ($this->info && $exists && !$this->info->isUpdateable()) {
93
+                throw new Forbidden();
94
+            }
95
+        } catch (StorageNotAvailableException $e) {
96
+            throw new ServiceUnavailable("File is not updatable: " . $e->getMessage());
97
+        }
98
+
99
+        // verify path of the target
100
+        $this->verifyPath();
101
+
102
+        // chunked handling
103
+        if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
104
+            try {
105
+                return $this->createFileChunked($data);
106
+            } catch (\Exception $e) {
107
+                $this->convertToSabreException($e);
108
+            }
109
+        }
110
+
111
+        list($partStorage) = $this->fileView->resolvePath($this->path);
112
+        $needsPartFile = $this->needsPartFile($partStorage) && (strlen($this->path) > 1);
113
+
114
+        if ($needsPartFile) {
115
+            // mark file as partial while uploading (ignored by the scanner)
116
+            $partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part';
117
+        } else {
118
+            // upload file directly as the final path
119
+            $partFilePath = $this->path;
120
+        }
121
+
122
+        // the part file and target file might be on a different storage in case of a single file storage (e.g. single file share)
123
+        /** @var \OC\Files\Storage\Storage $partStorage */
124
+        list($partStorage, $internalPartPath) = $this->fileView->resolvePath($partFilePath);
125
+        /** @var \OC\Files\Storage\Storage $storage */
126
+        list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
127
+        try {
128
+            $target = $partStorage->fopen($internalPartPath, 'wb');
129
+            if ($target === false) {
130
+                \OCP\Util::writeLog('webdav', '\OC\Files\Filesystem::fopen() failed', \OCP\Util::ERROR);
131
+                // because we have no clue about the cause we can only throw back a 500/Internal Server Error
132
+                throw new Exception('Could not write file contents');
133
+            }
134
+            list($count, $result) = \OC_Helper::streamCopy($data, $target);
135
+            fclose($target);
136
+
137
+            if (!self::isChecksumValid($partStorage, $internalPartPath)) {
138
+                throw new BadRequest('The computed checksum does not match the one received from the client.');
139
+            }
140
+
141
+            if ($result === false) {
142
+                $expected = -1;
143
+                if (isset($_SERVER['CONTENT_LENGTH'])) {
144
+                    $expected = $_SERVER['CONTENT_LENGTH'];
145
+                }
146
+                throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )');
147
+            }
148
+
149
+            // if content length is sent by client:
150
+            // double check if the file was fully received
151
+            // compare expected and actual size
152
+            if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
153
+                $expected = $_SERVER['CONTENT_LENGTH'];
154
+                if ($count != $expected) {
155
+                    throw new BadRequest('expected filesize ' . $expected . ' got ' . $count);
156
+                }
157
+            }
158
+
159
+        } catch (\Exception $e) {
160
+            if ($needsPartFile) {
161
+                $partStorage->unlink($internalPartPath);
162
+            }
163
+            $this->convertToSabreException($e);
164
+        }
165
+
166
+        try {
167
+            $view = \OC\Files\Filesystem::getView();
168
+            if ($view) {
169
+                $run = $this->emitPreHooks($exists);
170
+            } else {
171
+                $run = true;
172
+            }
173
+
174
+            try {
175
+                $this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
176
+            } catch (LockedException $e) {
177
+                if ($needsPartFile) {
178
+                    $partStorage->unlink($internalPartPath);
179
+                }
180
+                throw new FileLocked($e->getMessage(), $e->getCode(), $e);
181
+            }
182
+
183
+            if ($needsPartFile) {
184
+                // rename to correct path
185
+                try {
186
+                    if ($run) {
187
+                        $renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath);
188
+                        $fileExists = $storage->file_exists($internalPath);
189
+                    }
190
+                    if (!$run || $renameOkay === false || $fileExists === false) {
191
+                        \OCP\Util::writeLog('webdav', 'renaming part file to final file failed', \OCP\Util::ERROR);
192
+                        throw new Exception('Could not rename part file to final file');
193
+                    }
194
+                } catch (ForbiddenException $ex) {
195
+                    throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
196
+                } catch (\Exception $e) {
197
+                    $partStorage->unlink($internalPartPath);
198
+                    $this->convertToSabreException($e);
199
+                }
200
+            }
201
+
202
+            // since we skipped the view we need to scan and emit the hooks ourselves
203
+            $storage->getUpdater()->update($internalPath);
204
+
205
+            try {
206
+                $this->changeLock(ILockingProvider::LOCK_SHARED);
207
+            } catch (LockedException $e) {
208
+                throw new FileLocked($e->getMessage(), $e->getCode(), $e);
209
+            }
210
+
211
+            // allow sync clients to send the mtime along in a header
212
+            $request = \OC::$server->getRequest();
213
+            if (isset($request->server['HTTP_X_OC_MTIME'])) {
214
+                $mtimeStr = $request->server['HTTP_X_OC_MTIME'];
215
+                if (!is_numeric($mtimeStr)) {
216
+                    throw new \InvalidArgumentException('X-OC-Mtime header must be an integer (unix timestamp).');
217
+                }
218
+                $mtime = intval($mtimeStr);
219
+                if ($this->fileView->touch($this->path, $mtime)) {
220
+                    header('X-OC-MTime: accepted');
221
+                }
222
+            }
223 223
 					
224
-			if ($view) {
225
-				$this->emitPostHooks($exists);
226
-			}
227
-
228
-			$this->refreshInfo();
229
-
230
-			$meta = $partStorage->getMetaData($internalPartPath);
231
-
232
-			if (isset($meta['checksum'])) {
233
-				$this->fileView->putFileInfo(
234
-					$this->path,
235
-					['checksum' => $meta['checksum']]
236
-				);
237
-			}
238
-
239
-			$this->refreshInfo();
240
-
241
-		} catch (StorageNotAvailableException $e) {
242
-			throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
243
-		}
244
-
245
-		return '"' . $this->info->getEtag() . '"';
246
-	}
247
-
248
-	private function getPartFileBasePath($path) {
249
-		$partFileInStorage = \OC::$server->getConfig()->getSystemValue('part_file_in_storage', true);
250
-		if ($partFileInStorage) {
251
-			return $path;
252
-		} else {
253
-			return md5($path); // will place it in the root of the view with a unique name
254
-		}
255
-	}
256
-
257
-	/**
258
-	 * @param string $path
259
-	 */
260
-	private function emitPreHooks($exists, $path = null) {
261
-		if (is_null($path)) {
262
-			$path = $this->path;
263
-		}
264
-		$hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
265
-		$run = true;
266
-
267
-		if (!$exists) {
268
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_create, array(
269
-				\OC\Files\Filesystem::signal_param_path => $hookPath,
270
-				\OC\Files\Filesystem::signal_param_run => &$run,
271
-			));
272
-		} else {
273
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_update, array(
274
-				\OC\Files\Filesystem::signal_param_path => $hookPath,
275
-				\OC\Files\Filesystem::signal_param_run => &$run,
276
-			));
277
-		}
278
-		\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_write, array(
279
-			\OC\Files\Filesystem::signal_param_path => $hookPath,
280
-			\OC\Files\Filesystem::signal_param_run => &$run,
281
-		));
282
-		return $run;
283
-	}
284
-
285
-	/**
286
-	 * @param string $path
287
-	 */
288
-	private function emitPostHooks($exists, $path = null) {
289
-		if (is_null($path)) {
290
-			$path = $this->path;
291
-		}
292
-		$hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
293
-		if (!$exists) {
294
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_create, array(
295
-				\OC\Files\Filesystem::signal_param_path => $hookPath
296
-			));
297
-		} else {
298
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_update, array(
299
-				\OC\Files\Filesystem::signal_param_path => $hookPath
300
-			));
301
-		}
302
-		\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_write, array(
303
-			\OC\Files\Filesystem::signal_param_path => $hookPath
304
-		));
305
-	}
306
-
307
-	/**
308
-	 * Returns the data
309
-	 *
310
-	 * @return resource
311
-	 * @throws Forbidden
312
-	 * @throws ServiceUnavailable
313
-	 */
314
-	public function get() {
315
-		//throw exception if encryption is disabled but files are still encrypted
316
-		try {
317
-			$res = $this->fileView->fopen(ltrim($this->path, '/'), 'rb');
318
-			if ($res === false) {
319
-				throw new ServiceUnavailable("Could not open file");
320
-			}
321
-			return $res;
322
-		} catch (GenericEncryptionException $e) {
323
-			// returning 503 will allow retry of the operation at a later point in time
324
-			throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage());
325
-		} catch (StorageNotAvailableException $e) {
326
-			throw new ServiceUnavailable("Failed to open file: " . $e->getMessage());
327
-		} catch (ForbiddenException $ex) {
328
-			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
329
-		} catch (LockedException $e) {
330
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
331
-		}
332
-	}
333
-
334
-	/**
335
-	 * Delete the current file
336
-	 *
337
-	 * @throws Forbidden
338
-	 * @throws ServiceUnavailable
339
-	 */
340
-	public function delete() {
341
-		if (!$this->info->isDeletable()) {
342
-			throw new Forbidden();
343
-		}
344
-
345
-		try {
346
-			if (!$this->fileView->unlink($this->path)) {
347
-				// assume it wasn't possible to delete due to permissions
348
-				throw new Forbidden();
349
-			}
350
-		} catch (StorageNotAvailableException $e) {
351
-			throw new ServiceUnavailable("Failed to unlink: " . $e->getMessage());
352
-		} catch (ForbiddenException $ex) {
353
-			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
354
-		} catch (LockedException $e) {
355
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
356
-		}
357
-	}
358
-
359
-	/**
360
-	 * Returns the mime-type for a file
361
-	 *
362
-	 * If null is returned, we'll assume application/octet-stream
363
-	 *
364
-	 * @return string
365
-	 */
366
-	public function getContentType() {
367
-		$mimeType = $this->info->getMimetype();
368
-
369
-		// PROPFIND needs to return the correct mime type, for consistency with the web UI
370
-		if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
371
-			return $mimeType;
372
-		}
373
-		return \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType);
374
-	}
375
-
376
-	/**
377
-	 * @return array|false
378
-	 */
379
-	public function getDirectDownload() {
380
-		if (\OCP\App::isEnabled('encryption')) {
381
-			return [];
382
-		}
383
-		/** @var \OCP\Files\Storage $storage */
384
-		list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
385
-		if (is_null($storage)) {
386
-			return [];
387
-		}
388
-
389
-		return $storage->getDirectDownload($internalPath);
390
-	}
391
-
392
-	/**
393
-	 * @param resource $data
394
-	 * @return null|string
395
-	 * @throws Exception
396
-	 * @throws BadRequest
397
-	 * @throws NotImplemented
398
-	 * @throws ServiceUnavailable
399
-	 */
400
-	private function createFileChunked($data) {
401
-		list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($this->path);
402
-
403
-		$info = \OC_FileChunking::decodeName($name);
404
-		if (empty($info)) {
405
-			throw new NotImplemented('Invalid chunk name');
406
-		}
407
-
408
-		$chunk_handler = new \OC_FileChunking($info);
409
-		$bytesWritten = $chunk_handler->store($info['index'], $data);
410
-
411
-		//detect aborted upload
412
-		if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
413
-			if (isset($_SERVER['CONTENT_LENGTH'])) {
414
-				$expected = $_SERVER['CONTENT_LENGTH'];
415
-				if ($bytesWritten != $expected) {
416
-					$chunk_handler->remove($info['index']);
417
-					throw new BadRequest(
418
-						'expected filesize ' . $expected . ' got ' . $bytesWritten);
419
-				}
420
-			}
421
-		}
422
-
423
-		if ($chunk_handler->isComplete()) {
424
-			list($storage,) = $this->fileView->resolvePath($path);
425
-			$needsPartFile = $this->needsPartFile($storage);
426
-			$partFile = null;
427
-
428
-			$targetPath = $path . '/' . $info['name'];
429
-			/** @var \OC\Files\Storage\Storage $targetStorage */
430
-			list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
431
-
432
-			$exists = $this->fileView->file_exists($targetPath);
433
-
434
-			try {
435
-				$this->fileView->lockFile($targetPath, ILockingProvider::LOCK_SHARED);
436
-
437
-				$this->emitPreHooks($exists, $targetPath);
438
-				$this->fileView->changeLock($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
439
-				/** @var \OC\Files\Storage\Storage $targetStorage */
440
-				list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
441
-
442
-				if ($needsPartFile) {
443
-					// we first assembly the target file as a part file
444
-					$partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part';
445
-					/** @var \OC\Files\Storage\Storage $targetStorage */
446
-					list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile);
447
-
448
-
449
-					$chunk_handler->file_assemble($partStorage, $partInternalPath);
450
-
451
-					if (!self::isChecksumValid($partStorage, $partInternalPath)) {
452
-						throw new BadRequest('The computed checksum does not match the one received from the client.');
453
-					}
454
-
455
-					// here is the final atomic rename
456
-					$renameOkay = $targetStorage->moveFromStorage($partStorage, $partInternalPath, $targetInternalPath);
457
-					$fileExists = $targetStorage->file_exists($targetInternalPath);
458
-					if ($renameOkay === false || $fileExists === false) {
459
-						\OCP\Util::writeLog('webdav', '\OC\Files\Filesystem::rename() failed', \OCP\Util::ERROR);
460
-						// only delete if an error occurred and the target file was already created
461
-						if ($fileExists) {
462
-							// set to null to avoid double-deletion when handling exception
463
-							// stray part file
464
-							$partFile = null;
465
-							$targetStorage->unlink($targetInternalPath);
466
-						}
467
-						$this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
468
-						throw new Exception('Could not rename part file assembled from chunks');
469
-					}
470
-				} else {
471
-					// assemble directly into the final file
472
-					$chunk_handler->file_assemble($targetStorage, $targetInternalPath);
473
-				}
474
-
475
-				// allow sync clients to send the mtime along in a header
476
-				$request = \OC::$server->getRequest();
477
-				if (isset($request->server['HTTP_X_OC_MTIME'])) {
478
-					if ($targetStorage->touch($targetInternalPath, $request->server['HTTP_X_OC_MTIME'])) {
479
-						header('X-OC-MTime: accepted');
480
-					}
481
-				}
482
-
483
-				// since we skipped the view we need to scan and emit the hooks ourselves
484
-				$targetStorage->getUpdater()->update($targetInternalPath);
485
-
486
-				$this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
487
-
488
-				$this->emitPostHooks($exists, $targetPath);
489
-
490
-				// FIXME: should call refreshInfo but can't because $this->path is not the of the final file
491
-				$info = $this->fileView->getFileInfo($targetPath);
492
-
493
-
494
-				if (isset($partStorage) && isset($partInternalPath)) {
495
-					$checksums = $partStorage->getMetaData($partInternalPath)['checksum'];
496
-				} else {
497
-					$checksums = $targetStorage->getMetaData($targetInternalPath)['checksum'];
498
-				}
499
-
500
-				$this->fileView->putFileInfo(
501
-					$targetPath,
502
-					['checksum' => $checksums]
503
-				);
504
-
505
-				$this->refreshInfo();
506
-
507
-				$this->fileView->unlockFile($targetPath, ILockingProvider::LOCK_SHARED);
508
-
509
-				return $info->getEtag();
510
-			} catch (\Exception $e) {
511
-				if ($partFile !== null) {
512
-					$targetStorage->unlink($targetInternalPath);
513
-				}
514
-				$this->convertToSabreException($e);
515
-			}
516
-		}
517
-
518
-		return null;
519
-	}
520
-
521
-	/**
522
-	 * will return true if checksum was not provided in request
523
-	 *
524
-	 * @param Storage $storage
525
-	 * @param $path
526
-	 * @return bool
527
-	 */
528
-	private static function isChecksumValid(Storage $storage, $path) {
529
-		$meta = $storage->getMetaData($path);
530
-		$request = \OC::$server->getRequest();
531
-
532
-		if (!isset($request->server['HTTP_OC_CHECKSUM']) || !isset($meta['checksum'])) {
533
-			// No comparison possible, skip the check
534
-			return true;
535
-		}
536
-
537
-		$expectedChecksum = trim($request->server['HTTP_OC_CHECKSUM']);
538
-		$computedChecksums = $meta['checksum'];
539
-
540
-		return strpos($computedChecksums, $expectedChecksum) !== false;
541
-
542
-	}
543
-
544
-	/**
545
-	 * Returns whether a part file is needed for the given storage
546
-	 * or whether the file can be assembled/uploaded directly on the
547
-	 * target storage.
548
-	 *
549
-	 * @param \OCP\Files\Storage $storage
550
-	 * @return bool true if the storage needs part file handling
551
-	 */
552
-	private function needsPartFile($storage) {
553
-		// TODO: in the future use ChunkHandler provided by storage
554
-		return !$storage->instanceOfStorage('OCA\Files_Sharing\External\Storage') &&
555
-			!$storage->instanceOfStorage('OC\Files\Storage\OwnCloud') &&
556
-			$storage->needsPartFile();
557
-	}
558
-
559
-	/**
560
-	 * Convert the given exception to a SabreException instance
561
-	 *
562
-	 * @param \Exception $e
563
-	 *
564
-	 * @throws \Sabre\DAV\Exception
565
-	 */
566
-	private function convertToSabreException(\Exception $e) {
567
-		if ($e instanceof \Sabre\DAV\Exception) {
568
-			throw $e;
569
-		}
570
-		if ($e instanceof NotPermittedException) {
571
-			// a more general case - due to whatever reason the content could not be written
572
-			throw new Forbidden($e->getMessage(), 0, $e);
573
-		}
574
-		if ($e instanceof ForbiddenException) {
575
-			// the path for the file was forbidden
576
-			throw new DAVForbiddenException($e->getMessage(), $e->getRetry(), $e);
577
-		}
578
-		if ($e instanceof EntityTooLargeException) {
579
-			// the file is too big to be stored
580
-			throw new EntityTooLarge($e->getMessage(), 0, $e);
581
-		}
582
-		if ($e instanceof InvalidContentException) {
583
-			// the file content is not permitted
584
-			throw new UnsupportedMediaType($e->getMessage(), 0, $e);
585
-		}
586
-		if ($e instanceof InvalidPathException) {
587
-			// the path for the file was not valid
588
-			// TODO: find proper http status code for this case
589
-			throw new Forbidden($e->getMessage(), 0, $e);
590
-		}
591
-		if ($e instanceof LockedException || $e instanceof LockNotAcquiredException) {
592
-			// the file is currently being written to by another process
593
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
594
-		}
595
-		if ($e instanceof GenericEncryptionException) {
596
-			// returning 503 will allow retry of the operation at a later point in time
597
-			throw new ServiceUnavailable('Encryption not ready: ' . $e->getMessage(), 0, $e);
598
-		}
599
-		if ($e instanceof StorageNotAvailableException) {
600
-			throw new ServiceUnavailable('Failed to write file contents: ' . $e->getMessage(), 0, $e);
601
-		}
602
-
603
-		throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e);
604
-	}
605
-
606
-
607
-	/**
608
-	 * Set $algo to get a specific checksum, leave null to get all checksums
609
-	 * (space seperated)
610
-	 * @param null $algo
611
-	 * @return string
612
-	 */
613
-	public function getChecksum($algo = null) {
614
-		$allChecksums = $this->info->getChecksum();
615
-
616
-		if (!$algo) {
617
-			return $allChecksums;
618
-		}
619
-
620
-		$checksums = explode(' ', $allChecksums);
621
-		$algoPrefix = strtoupper($algo) . ':';
622
-
623
-		foreach ($checksums as $checksum) {
624
-			// starts with $algoPrefix
625
-			if (substr($checksum, 0, strlen($algoPrefix)) === $algoPrefix) {
626
-				return $checksum;
627
-			}
628
-		}
629
-
630
-		return '';
631
-	}
224
+            if ($view) {
225
+                $this->emitPostHooks($exists);
226
+            }
227
+
228
+            $this->refreshInfo();
229
+
230
+            $meta = $partStorage->getMetaData($internalPartPath);
231
+
232
+            if (isset($meta['checksum'])) {
233
+                $this->fileView->putFileInfo(
234
+                    $this->path,
235
+                    ['checksum' => $meta['checksum']]
236
+                );
237
+            }
238
+
239
+            $this->refreshInfo();
240
+
241
+        } catch (StorageNotAvailableException $e) {
242
+            throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
243
+        }
244
+
245
+        return '"' . $this->info->getEtag() . '"';
246
+    }
247
+
248
+    private function getPartFileBasePath($path) {
249
+        $partFileInStorage = \OC::$server->getConfig()->getSystemValue('part_file_in_storage', true);
250
+        if ($partFileInStorage) {
251
+            return $path;
252
+        } else {
253
+            return md5($path); // will place it in the root of the view with a unique name
254
+        }
255
+    }
256
+
257
+    /**
258
+     * @param string $path
259
+     */
260
+    private function emitPreHooks($exists, $path = null) {
261
+        if (is_null($path)) {
262
+            $path = $this->path;
263
+        }
264
+        $hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
265
+        $run = true;
266
+
267
+        if (!$exists) {
268
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_create, array(
269
+                \OC\Files\Filesystem::signal_param_path => $hookPath,
270
+                \OC\Files\Filesystem::signal_param_run => &$run,
271
+            ));
272
+        } else {
273
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_update, array(
274
+                \OC\Files\Filesystem::signal_param_path => $hookPath,
275
+                \OC\Files\Filesystem::signal_param_run => &$run,
276
+            ));
277
+        }
278
+        \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_write, array(
279
+            \OC\Files\Filesystem::signal_param_path => $hookPath,
280
+            \OC\Files\Filesystem::signal_param_run => &$run,
281
+        ));
282
+        return $run;
283
+    }
284
+
285
+    /**
286
+     * @param string $path
287
+     */
288
+    private function emitPostHooks($exists, $path = null) {
289
+        if (is_null($path)) {
290
+            $path = $this->path;
291
+        }
292
+        $hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
293
+        if (!$exists) {
294
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_create, array(
295
+                \OC\Files\Filesystem::signal_param_path => $hookPath
296
+            ));
297
+        } else {
298
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_update, array(
299
+                \OC\Files\Filesystem::signal_param_path => $hookPath
300
+            ));
301
+        }
302
+        \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_write, array(
303
+            \OC\Files\Filesystem::signal_param_path => $hookPath
304
+        ));
305
+    }
306
+
307
+    /**
308
+     * Returns the data
309
+     *
310
+     * @return resource
311
+     * @throws Forbidden
312
+     * @throws ServiceUnavailable
313
+     */
314
+    public function get() {
315
+        //throw exception if encryption is disabled but files are still encrypted
316
+        try {
317
+            $res = $this->fileView->fopen(ltrim($this->path, '/'), 'rb');
318
+            if ($res === false) {
319
+                throw new ServiceUnavailable("Could not open file");
320
+            }
321
+            return $res;
322
+        } catch (GenericEncryptionException $e) {
323
+            // returning 503 will allow retry of the operation at a later point in time
324
+            throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage());
325
+        } catch (StorageNotAvailableException $e) {
326
+            throw new ServiceUnavailable("Failed to open file: " . $e->getMessage());
327
+        } catch (ForbiddenException $ex) {
328
+            throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
329
+        } catch (LockedException $e) {
330
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
331
+        }
332
+    }
333
+
334
+    /**
335
+     * Delete the current file
336
+     *
337
+     * @throws Forbidden
338
+     * @throws ServiceUnavailable
339
+     */
340
+    public function delete() {
341
+        if (!$this->info->isDeletable()) {
342
+            throw new Forbidden();
343
+        }
344
+
345
+        try {
346
+            if (!$this->fileView->unlink($this->path)) {
347
+                // assume it wasn't possible to delete due to permissions
348
+                throw new Forbidden();
349
+            }
350
+        } catch (StorageNotAvailableException $e) {
351
+            throw new ServiceUnavailable("Failed to unlink: " . $e->getMessage());
352
+        } catch (ForbiddenException $ex) {
353
+            throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
354
+        } catch (LockedException $e) {
355
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
356
+        }
357
+    }
358
+
359
+    /**
360
+     * Returns the mime-type for a file
361
+     *
362
+     * If null is returned, we'll assume application/octet-stream
363
+     *
364
+     * @return string
365
+     */
366
+    public function getContentType() {
367
+        $mimeType = $this->info->getMimetype();
368
+
369
+        // PROPFIND needs to return the correct mime type, for consistency with the web UI
370
+        if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
371
+            return $mimeType;
372
+        }
373
+        return \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType);
374
+    }
375
+
376
+    /**
377
+     * @return array|false
378
+     */
379
+    public function getDirectDownload() {
380
+        if (\OCP\App::isEnabled('encryption')) {
381
+            return [];
382
+        }
383
+        /** @var \OCP\Files\Storage $storage */
384
+        list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
385
+        if (is_null($storage)) {
386
+            return [];
387
+        }
388
+
389
+        return $storage->getDirectDownload($internalPath);
390
+    }
391
+
392
+    /**
393
+     * @param resource $data
394
+     * @return null|string
395
+     * @throws Exception
396
+     * @throws BadRequest
397
+     * @throws NotImplemented
398
+     * @throws ServiceUnavailable
399
+     */
400
+    private function createFileChunked($data) {
401
+        list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($this->path);
402
+
403
+        $info = \OC_FileChunking::decodeName($name);
404
+        if (empty($info)) {
405
+            throw new NotImplemented('Invalid chunk name');
406
+        }
407
+
408
+        $chunk_handler = new \OC_FileChunking($info);
409
+        $bytesWritten = $chunk_handler->store($info['index'], $data);
410
+
411
+        //detect aborted upload
412
+        if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
413
+            if (isset($_SERVER['CONTENT_LENGTH'])) {
414
+                $expected = $_SERVER['CONTENT_LENGTH'];
415
+                if ($bytesWritten != $expected) {
416
+                    $chunk_handler->remove($info['index']);
417
+                    throw new BadRequest(
418
+                        'expected filesize ' . $expected . ' got ' . $bytesWritten);
419
+                }
420
+            }
421
+        }
422
+
423
+        if ($chunk_handler->isComplete()) {
424
+            list($storage,) = $this->fileView->resolvePath($path);
425
+            $needsPartFile = $this->needsPartFile($storage);
426
+            $partFile = null;
427
+
428
+            $targetPath = $path . '/' . $info['name'];
429
+            /** @var \OC\Files\Storage\Storage $targetStorage */
430
+            list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
431
+
432
+            $exists = $this->fileView->file_exists($targetPath);
433
+
434
+            try {
435
+                $this->fileView->lockFile($targetPath, ILockingProvider::LOCK_SHARED);
436
+
437
+                $this->emitPreHooks($exists, $targetPath);
438
+                $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
439
+                /** @var \OC\Files\Storage\Storage $targetStorage */
440
+                list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
441
+
442
+                if ($needsPartFile) {
443
+                    // we first assembly the target file as a part file
444
+                    $partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part';
445
+                    /** @var \OC\Files\Storage\Storage $targetStorage */
446
+                    list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile);
447
+
448
+
449
+                    $chunk_handler->file_assemble($partStorage, $partInternalPath);
450
+
451
+                    if (!self::isChecksumValid($partStorage, $partInternalPath)) {
452
+                        throw new BadRequest('The computed checksum does not match the one received from the client.');
453
+                    }
454
+
455
+                    // here is the final atomic rename
456
+                    $renameOkay = $targetStorage->moveFromStorage($partStorage, $partInternalPath, $targetInternalPath);
457
+                    $fileExists = $targetStorage->file_exists($targetInternalPath);
458
+                    if ($renameOkay === false || $fileExists === false) {
459
+                        \OCP\Util::writeLog('webdav', '\OC\Files\Filesystem::rename() failed', \OCP\Util::ERROR);
460
+                        // only delete if an error occurred and the target file was already created
461
+                        if ($fileExists) {
462
+                            // set to null to avoid double-deletion when handling exception
463
+                            // stray part file
464
+                            $partFile = null;
465
+                            $targetStorage->unlink($targetInternalPath);
466
+                        }
467
+                        $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
468
+                        throw new Exception('Could not rename part file assembled from chunks');
469
+                    }
470
+                } else {
471
+                    // assemble directly into the final file
472
+                    $chunk_handler->file_assemble($targetStorage, $targetInternalPath);
473
+                }
474
+
475
+                // allow sync clients to send the mtime along in a header
476
+                $request = \OC::$server->getRequest();
477
+                if (isset($request->server['HTTP_X_OC_MTIME'])) {
478
+                    if ($targetStorage->touch($targetInternalPath, $request->server['HTTP_X_OC_MTIME'])) {
479
+                        header('X-OC-MTime: accepted');
480
+                    }
481
+                }
482
+
483
+                // since we skipped the view we need to scan and emit the hooks ourselves
484
+                $targetStorage->getUpdater()->update($targetInternalPath);
485
+
486
+                $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
487
+
488
+                $this->emitPostHooks($exists, $targetPath);
489
+
490
+                // FIXME: should call refreshInfo but can't because $this->path is not the of the final file
491
+                $info = $this->fileView->getFileInfo($targetPath);
492
+
493
+
494
+                if (isset($partStorage) && isset($partInternalPath)) {
495
+                    $checksums = $partStorage->getMetaData($partInternalPath)['checksum'];
496
+                } else {
497
+                    $checksums = $targetStorage->getMetaData($targetInternalPath)['checksum'];
498
+                }
499
+
500
+                $this->fileView->putFileInfo(
501
+                    $targetPath,
502
+                    ['checksum' => $checksums]
503
+                );
504
+
505
+                $this->refreshInfo();
506
+
507
+                $this->fileView->unlockFile($targetPath, ILockingProvider::LOCK_SHARED);
508
+
509
+                return $info->getEtag();
510
+            } catch (\Exception $e) {
511
+                if ($partFile !== null) {
512
+                    $targetStorage->unlink($targetInternalPath);
513
+                }
514
+                $this->convertToSabreException($e);
515
+            }
516
+        }
517
+
518
+        return null;
519
+    }
520
+
521
+    /**
522
+     * will return true if checksum was not provided in request
523
+     *
524
+     * @param Storage $storage
525
+     * @param $path
526
+     * @return bool
527
+     */
528
+    private static function isChecksumValid(Storage $storage, $path) {
529
+        $meta = $storage->getMetaData($path);
530
+        $request = \OC::$server->getRequest();
531
+
532
+        if (!isset($request->server['HTTP_OC_CHECKSUM']) || !isset($meta['checksum'])) {
533
+            // No comparison possible, skip the check
534
+            return true;
535
+        }
536
+
537
+        $expectedChecksum = trim($request->server['HTTP_OC_CHECKSUM']);
538
+        $computedChecksums = $meta['checksum'];
539
+
540
+        return strpos($computedChecksums, $expectedChecksum) !== false;
541
+
542
+    }
543
+
544
+    /**
545
+     * Returns whether a part file is needed for the given storage
546
+     * or whether the file can be assembled/uploaded directly on the
547
+     * target storage.
548
+     *
549
+     * @param \OCP\Files\Storage $storage
550
+     * @return bool true if the storage needs part file handling
551
+     */
552
+    private function needsPartFile($storage) {
553
+        // TODO: in the future use ChunkHandler provided by storage
554
+        return !$storage->instanceOfStorage('OCA\Files_Sharing\External\Storage') &&
555
+            !$storage->instanceOfStorage('OC\Files\Storage\OwnCloud') &&
556
+            $storage->needsPartFile();
557
+    }
558
+
559
+    /**
560
+     * Convert the given exception to a SabreException instance
561
+     *
562
+     * @param \Exception $e
563
+     *
564
+     * @throws \Sabre\DAV\Exception
565
+     */
566
+    private function convertToSabreException(\Exception $e) {
567
+        if ($e instanceof \Sabre\DAV\Exception) {
568
+            throw $e;
569
+        }
570
+        if ($e instanceof NotPermittedException) {
571
+            // a more general case - due to whatever reason the content could not be written
572
+            throw new Forbidden($e->getMessage(), 0, $e);
573
+        }
574
+        if ($e instanceof ForbiddenException) {
575
+            // the path for the file was forbidden
576
+            throw new DAVForbiddenException($e->getMessage(), $e->getRetry(), $e);
577
+        }
578
+        if ($e instanceof EntityTooLargeException) {
579
+            // the file is too big to be stored
580
+            throw new EntityTooLarge($e->getMessage(), 0, $e);
581
+        }
582
+        if ($e instanceof InvalidContentException) {
583
+            // the file content is not permitted
584
+            throw new UnsupportedMediaType($e->getMessage(), 0, $e);
585
+        }
586
+        if ($e instanceof InvalidPathException) {
587
+            // the path for the file was not valid
588
+            // TODO: find proper http status code for this case
589
+            throw new Forbidden($e->getMessage(), 0, $e);
590
+        }
591
+        if ($e instanceof LockedException || $e instanceof LockNotAcquiredException) {
592
+            // the file is currently being written to by another process
593
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
594
+        }
595
+        if ($e instanceof GenericEncryptionException) {
596
+            // returning 503 will allow retry of the operation at a later point in time
597
+            throw new ServiceUnavailable('Encryption not ready: ' . $e->getMessage(), 0, $e);
598
+        }
599
+        if ($e instanceof StorageNotAvailableException) {
600
+            throw new ServiceUnavailable('Failed to write file contents: ' . $e->getMessage(), 0, $e);
601
+        }
602
+
603
+        throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e);
604
+    }
605
+
606
+
607
+    /**
608
+     * Set $algo to get a specific checksum, leave null to get all checksums
609
+     * (space seperated)
610
+     * @param null $algo
611
+     * @return string
612
+     */
613
+    public function getChecksum($algo = null) {
614
+        $allChecksums = $this->info->getChecksum();
615
+
616
+        if (!$algo) {
617
+            return $allChecksums;
618
+        }
619
+
620
+        $checksums = explode(' ', $allChecksums);
621
+        $algoPrefix = strtoupper($algo) . ':';
622
+
623
+        foreach ($checksums as $checksum) {
624
+            // starts with $algoPrefix
625
+            if (substr($checksum, 0, strlen($algoPrefix)) === $algoPrefix) {
626
+                return $checksum;
627
+            }
628
+        }
629
+
630
+        return '';
631
+    }
632 632
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -93,7 +93,7 @@  discard block
 block discarded – undo
93 93
 				throw new Forbidden();
94 94
 			}
95 95
 		} catch (StorageNotAvailableException $e) {
96
-			throw new ServiceUnavailable("File is not updatable: " . $e->getMessage());
96
+			throw new ServiceUnavailable("File is not updatable: ".$e->getMessage());
97 97
 		}
98 98
 
99 99
 		// verify path of the target
@@ -113,7 +113,7 @@  discard block
 block discarded – undo
113 113
 
114 114
 		if ($needsPartFile) {
115 115
 			// mark file as partial while uploading (ignored by the scanner)
116
-			$partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part';
116
+			$partFilePath = $this->getPartFileBasePath($this->path).'.ocTransferId'.rand().'.part';
117 117
 		} else {
118 118
 			// upload file directly as the final path
119 119
 			$partFilePath = $this->path;
@@ -143,7 +143,7 @@  discard block
 block discarded – undo
143 143
 				if (isset($_SERVER['CONTENT_LENGTH'])) {
144 144
 					$expected = $_SERVER['CONTENT_LENGTH'];
145 145
 				}
146
-				throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )');
146
+				throw new Exception('Error while copying file to target location (copied bytes: '.$count.', expected filesize: '.$expected.' )');
147 147
 			}
148 148
 
149 149
 			// if content length is sent by client:
@@ -152,7 +152,7 @@  discard block
 block discarded – undo
152 152
 			if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
153 153
 				$expected = $_SERVER['CONTENT_LENGTH'];
154 154
 				if ($count != $expected) {
155
-					throw new BadRequest('expected filesize ' . $expected . ' got ' . $count);
155
+					throw new BadRequest('expected filesize '.$expected.' got '.$count);
156 156
 				}
157 157
 			}
158 158
 
@@ -239,10 +239,10 @@  discard block
 block discarded – undo
239 239
 			$this->refreshInfo();
240 240
 
241 241
 		} catch (StorageNotAvailableException $e) {
242
-			throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
242
+			throw new ServiceUnavailable("Failed to check file size: ".$e->getMessage());
243 243
 		}
244 244
 
245
-		return '"' . $this->info->getEtag() . '"';
245
+		return '"'.$this->info->getEtag().'"';
246 246
 	}
247 247
 
248 248
 	private function getPartFileBasePath($path) {
@@ -321,9 +321,9 @@  discard block
 block discarded – undo
321 321
 			return $res;
322 322
 		} catch (GenericEncryptionException $e) {
323 323
 			// returning 503 will allow retry of the operation at a later point in time
324
-			throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage());
324
+			throw new ServiceUnavailable("Encryption not ready: ".$e->getMessage());
325 325
 		} catch (StorageNotAvailableException $e) {
326
-			throw new ServiceUnavailable("Failed to open file: " . $e->getMessage());
326
+			throw new ServiceUnavailable("Failed to open file: ".$e->getMessage());
327 327
 		} catch (ForbiddenException $ex) {
328 328
 			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
329 329
 		} catch (LockedException $e) {
@@ -348,7 +348,7 @@  discard block
 block discarded – undo
348 348
 				throw new Forbidden();
349 349
 			}
350 350
 		} catch (StorageNotAvailableException $e) {
351
-			throw new ServiceUnavailable("Failed to unlink: " . $e->getMessage());
351
+			throw new ServiceUnavailable("Failed to unlink: ".$e->getMessage());
352 352
 		} catch (ForbiddenException $ex) {
353 353
 			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
354 354
 		} catch (LockedException $e) {
@@ -415,7 +415,7 @@  discard block
 block discarded – undo
415 415
 				if ($bytesWritten != $expected) {
416 416
 					$chunk_handler->remove($info['index']);
417 417
 					throw new BadRequest(
418
-						'expected filesize ' . $expected . ' got ' . $bytesWritten);
418
+						'expected filesize '.$expected.' got '.$bytesWritten);
419 419
 				}
420 420
 			}
421 421
 		}
@@ -425,7 +425,7 @@  discard block
 block discarded – undo
425 425
 			$needsPartFile = $this->needsPartFile($storage);
426 426
 			$partFile = null;
427 427
 
428
-			$targetPath = $path . '/' . $info['name'];
428
+			$targetPath = $path.'/'.$info['name'];
429 429
 			/** @var \OC\Files\Storage\Storage $targetStorage */
430 430
 			list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
431 431
 
@@ -441,7 +441,7 @@  discard block
 block discarded – undo
441 441
 
442 442
 				if ($needsPartFile) {
443 443
 					// we first assembly the target file as a part file
444
-					$partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part';
444
+					$partFile = $this->getPartFileBasePath($path.'/'.$info['name']).'.ocTransferId'.$info['transferid'].'.part';
445 445
 					/** @var \OC\Files\Storage\Storage $targetStorage */
446 446
 					list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile);
447 447
 
@@ -594,10 +594,10 @@  discard block
 block discarded – undo
594 594
 		}
595 595
 		if ($e instanceof GenericEncryptionException) {
596 596
 			// returning 503 will allow retry of the operation at a later point in time
597
-			throw new ServiceUnavailable('Encryption not ready: ' . $e->getMessage(), 0, $e);
597
+			throw new ServiceUnavailable('Encryption not ready: '.$e->getMessage(), 0, $e);
598 598
 		}
599 599
 		if ($e instanceof StorageNotAvailableException) {
600
-			throw new ServiceUnavailable('Failed to write file contents: ' . $e->getMessage(), 0, $e);
600
+			throw new ServiceUnavailable('Failed to write file contents: '.$e->getMessage(), 0, $e);
601 601
 		}
602 602
 
603 603
 		throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e);
@@ -618,7 +618,7 @@  discard block
 block discarded – undo
618 618
 		}
619 619
 
620 620
 		$checksums = explode(' ', $allChecksums);
621
-		$algoPrefix = strtoupper($algo) . ':';
621
+		$algoPrefix = strtoupper($algo).':';
622 622
 
623 623
 		foreach ($checksums as $checksum) {
624 624
 			// starts with $algoPrefix
Please login to merge, or discard this patch.
lib/private/Files/Stream/Checksum.php 2 patches
Doc Comments   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -64,8 +64,8 @@
 block discarded – undo
64 64
 
65 65
 
66 66
 	/**
67
-	 * @param $source
68
-	 * @param $path
67
+	 * @param resource $source
68
+	 * @param string $path
69 69
 	 * @return resource
70 70
 	 */
71 71
 	public static function wrap($source, $path) {
Please login to merge, or discard this patch.
Indentation   +161 added lines, -161 removed lines patch added patch discarded remove patch
@@ -35,165 +35,165 @@
 block discarded – undo
35 35
  */
36 36
 class Checksum extends Wrapper {
37 37
 
38
-	/**
39
-	 * To stepwise compute a hash on a continuous stream
40
-	 * of data a "context" is required which stores the intermediate
41
-	 * hash result while the stream has not finished.
42
-	 *
43
-	 * After the stream ends the hashing contexts needs to be finalized
44
-	 * to compute the final checksum.
45
-	 *
46
-	 * @var  resource[]
47
-	 */
48
- 	private $hashingContexts;
49
-
50
-	/** @var CappedMemoryCache Key is path, value is array of checksums */
51
-	private static $checksums;
52
-
53
-
54
-	public function __construct(array $algos = ['sha1', 'md5', 'adler32']) {
55
-
56
-		foreach ($algos as $algo) {
57
-			$this->hashingContexts[$algo] = hash_init($algo);
58
-		}
59
-
60
-		if (!self::$checksums) {
61
-			self::$checksums = new CappedMemoryCache();
62
-		}
63
-	}
64
-
65
-
66
-	/**
67
-	 * @param $source
68
-	 * @param $path
69
-	 * @return resource
70
-	 */
71
-	public static function wrap($source, $path) {
72
-		$context = stream_context_create([
73
-			'occhecksum' => [
74
-				'source' => $source,
75
-				'path' => $path
76
-			]
77
-		]);
78
-
79
-		return Wrapper::wrapSource(
80
-			$source, $context, 'occhecksum', self::class
81
-		);
82
-	}
83
-
84
-
85
-	/**
86
-	 * @param string $path
87
-	 * @param array $options
88
-	 * @return bool
89
-	 */
90
-	public function dir_opendir($path, $options) {
91
-		return true;
92
-	}
93
-
94
-	/**
95
-	 * @param string $path
96
-	 * @param string $mode
97
-	 * @param int $options
98
-	 * @param string $opened_path
99
-	 * @return bool
100
-	 */
101
-	public function stream_open($path, $mode, $options, &$opened_path) {
102
-		$context = parent::loadContext('occhecksum');
103
-		$this->setSourceStream($context['source']);
104
-
105
-		return true;
106
-	}
107
-
108
-	/**
109
-	 * @param int $count
110
-	 * @return string
111
-	 */
112
-	public function stream_read($count) {
113
-		$data = parent::stream_read($count);
114
-		$this->updateHashingContexts($data);
115
-
116
-		return $data;
117
-	}
118
-
119
-	/**
120
-	 * @param string $data
121
-	 * @return int
122
-	 */
123
-	public function stream_write($data) {
124
-		$this->updateHashingContexts($data);
125
-
126
-		return parent::stream_write($data);
127
-	}
128
-
129
-	private function updateHashingContexts($data) {
130
-		foreach ($this->hashingContexts as $ctx) {
131
-			hash_update($ctx, $data);
132
-		}
133
-	}
134
-
135
-	/**
136
-	 * @return bool
137
-	 */
138
-	public function stream_close() {
139
-		$currentPath = $this->getPathFromStreamContext();
140
-		self::$checksums[$currentPath] = $this->finalizeHashingContexts();
141
-
142
-		return parent::stream_close();
143
-	}
144
-
145
-	/**
146
-	 * @return array
147
-	 */
148
-	private function finalizeHashingContexts() {
149
-		$hashes = [];
150
-
151
-		foreach ($this->hashingContexts as $algo => $ctx) {
152
-			$hashes[$algo] = hash_final($ctx);
153
-		}
154
-
155
-		return $hashes;
156
-	}
157
-
158
-	public function dir_closedir() {
159
-		if (!isset($this->source)) {
160
-			return false;
161
-		}
162
-		return parent::dir_closedir();
163
-	}
164
-
165
-	/**
166
-	 * @return mixed
167
-	 * @return string
168
-	 */
169
-	private function getPathFromStreamContext() {
170
-		$ctx = stream_context_get_options($this->context);
171
-
172
-		return $ctx['occhecksum']['path'];
173
-	}
174
-
175
-	/**
176
-	 * @param $path
177
-	 * @return array
178
-	 */
179
-	public static function getChecksums($path) {
180
-		if (!isset(self::$checksums[$path])) {
181
-			return [];
182
-		}
183
-
184
-		return self::$checksums[$path];
185
-	}
186
-
187
-	/**
188
-	 * For debugging
189
-	 *
190
-	 * @return CappedMemoryCache
191
-	 */
192
-	public static function getChecksumsForAllPaths() {
193
-		if (!self::$checksums) {
194
-			self::$checksums = new CappedMemoryCache();
195
-		}
196
-
197
-		return self::$checksums;
198
-	}
38
+    /**
39
+     * To stepwise compute a hash on a continuous stream
40
+     * of data a "context" is required which stores the intermediate
41
+     * hash result while the stream has not finished.
42
+     *
43
+     * After the stream ends the hashing contexts needs to be finalized
44
+     * to compute the final checksum.
45
+     *
46
+     * @var  resource[]
47
+     */
48
+        private $hashingContexts;
49
+
50
+    /** @var CappedMemoryCache Key is path, value is array of checksums */
51
+    private static $checksums;
52
+
53
+
54
+    public function __construct(array $algos = ['sha1', 'md5', 'adler32']) {
55
+
56
+        foreach ($algos as $algo) {
57
+            $this->hashingContexts[$algo] = hash_init($algo);
58
+        }
59
+
60
+        if (!self::$checksums) {
61
+            self::$checksums = new CappedMemoryCache();
62
+        }
63
+    }
64
+
65
+
66
+    /**
67
+     * @param $source
68
+     * @param $path
69
+     * @return resource
70
+     */
71
+    public static function wrap($source, $path) {
72
+        $context = stream_context_create([
73
+            'occhecksum' => [
74
+                'source' => $source,
75
+                'path' => $path
76
+            ]
77
+        ]);
78
+
79
+        return Wrapper::wrapSource(
80
+            $source, $context, 'occhecksum', self::class
81
+        );
82
+    }
83
+
84
+
85
+    /**
86
+     * @param string $path
87
+     * @param array $options
88
+     * @return bool
89
+     */
90
+    public function dir_opendir($path, $options) {
91
+        return true;
92
+    }
93
+
94
+    /**
95
+     * @param string $path
96
+     * @param string $mode
97
+     * @param int $options
98
+     * @param string $opened_path
99
+     * @return bool
100
+     */
101
+    public function stream_open($path, $mode, $options, &$opened_path) {
102
+        $context = parent::loadContext('occhecksum');
103
+        $this->setSourceStream($context['source']);
104
+
105
+        return true;
106
+    }
107
+
108
+    /**
109
+     * @param int $count
110
+     * @return string
111
+     */
112
+    public function stream_read($count) {
113
+        $data = parent::stream_read($count);
114
+        $this->updateHashingContexts($data);
115
+
116
+        return $data;
117
+    }
118
+
119
+    /**
120
+     * @param string $data
121
+     * @return int
122
+     */
123
+    public function stream_write($data) {
124
+        $this->updateHashingContexts($data);
125
+
126
+        return parent::stream_write($data);
127
+    }
128
+
129
+    private function updateHashingContexts($data) {
130
+        foreach ($this->hashingContexts as $ctx) {
131
+            hash_update($ctx, $data);
132
+        }
133
+    }
134
+
135
+    /**
136
+     * @return bool
137
+     */
138
+    public function stream_close() {
139
+        $currentPath = $this->getPathFromStreamContext();
140
+        self::$checksums[$currentPath] = $this->finalizeHashingContexts();
141
+
142
+        return parent::stream_close();
143
+    }
144
+
145
+    /**
146
+     * @return array
147
+     */
148
+    private function finalizeHashingContexts() {
149
+        $hashes = [];
150
+
151
+        foreach ($this->hashingContexts as $algo => $ctx) {
152
+            $hashes[$algo] = hash_final($ctx);
153
+        }
154
+
155
+        return $hashes;
156
+    }
157
+
158
+    public function dir_closedir() {
159
+        if (!isset($this->source)) {
160
+            return false;
161
+        }
162
+        return parent::dir_closedir();
163
+    }
164
+
165
+    /**
166
+     * @return mixed
167
+     * @return string
168
+     */
169
+    private function getPathFromStreamContext() {
170
+        $ctx = stream_context_get_options($this->context);
171
+
172
+        return $ctx['occhecksum']['path'];
173
+    }
174
+
175
+    /**
176
+     * @param $path
177
+     * @return array
178
+     */
179
+    public static function getChecksums($path) {
180
+        if (!isset(self::$checksums[$path])) {
181
+            return [];
182
+        }
183
+
184
+        return self::$checksums[$path];
185
+    }
186
+
187
+    /**
188
+     * For debugging
189
+     *
190
+     * @return CappedMemoryCache
191
+     */
192
+    public static function getChecksumsForAllPaths() {
193
+        if (!self::$checksums) {
194
+            self::$checksums = new CappedMemoryCache();
195
+        }
196
+
197
+        return self::$checksums;
198
+    }
199 199
 }
Please login to merge, or discard this patch.
apps/files/lib/Capabilities.php 1 patch
Indentation   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -34,33 +34,33 @@
 block discarded – undo
34 34
  * @package OCA\Files
35 35
  */
36 36
 class Capabilities implements ICapability {
37
-	/** @var IConfig */
38
-	protected $config;
37
+    /** @var IConfig */
38
+    protected $config;
39 39
 
40
-	/**
41
-	 * Capabilities constructor.
42
-	 *
43
-	 * @param IConfig $config
44
-	 */
45
-	public function __construct(IConfig $config) {
46
-		$this->config = $config;
47
-	}
40
+    /**
41
+     * Capabilities constructor.
42
+     *
43
+     * @param IConfig $config
44
+     */
45
+    public function __construct(IConfig $config) {
46
+        $this->config = $config;
47
+    }
48 48
 
49
-	/**
50
-	 * Return this classes capabilities
51
-	 *
52
-	 * @return array
53
-	 */
54
-	public function getCapabilities() {
55
-		return [
56
-			'checksums' => [
57
-				'supportedTypes' => ['SHA1'],
58
-				'preferredUploadType' => 'SHA1'
59
-			],
60
-			'files' => [
61
-				'bigfilechunking' => true,
62
-				'blacklisted_files' => $this->config->getSystemValue('blacklisted_files', ['.htaccess']),
63
-			],
64
-		];
65
-	}
49
+    /**
50
+     * Return this classes capabilities
51
+     *
52
+     * @return array
53
+     */
54
+    public function getCapabilities() {
55
+        return [
56
+            'checksums' => [
57
+                'supportedTypes' => ['SHA1'],
58
+                'preferredUploadType' => 'SHA1'
59
+            ],
60
+            'files' => [
61
+                'bigfilechunking' => true,
62
+                'blacklisted_files' => $this->config->getSystemValue('blacklisted_files', ['.htaccess']),
63
+            ],
64
+        ];
65
+    }
66 66
 }
Please login to merge, or discard this patch.
lib/private/legacy/util.php 2 patches
Indentation   +1391 added lines, -1391 removed lines patch added patch discarded remove patch
@@ -61,1399 +61,1399 @@
 block discarded – undo
61 61
 use OCP\IUser;
62 62
 
63 63
 class OC_Util {
64
-	public static $scripts = array();
65
-	public static $styles = array();
66
-	public static $headers = array();
67
-	private static $rootMounted = false;
68
-	private static $fsSetup = false;
69
-
70
-	/** @var array Local cache of version.php */
71
-	private static $versionCache = null;
72
-
73
-	protected static function getAppManager() {
74
-		return \OC::$server->getAppManager();
75
-	}
76
-
77
-	private static function initLocalStorageRootFS() {
78
-		// mount local file backend as root
79
-		$configDataDirectory = \OC::$server->getSystemConfig()->getValue("datadirectory", OC::$SERVERROOT . "/data");
80
-		//first set up the local "root" storage
81
-		\OC\Files\Filesystem::initMountManager();
82
-		if (!self::$rootMounted) {
83
-			\OC\Files\Filesystem::mount('\OC\Files\Storage\Local', array('datadir' => $configDataDirectory), '/');
84
-			self::$rootMounted = true;
85
-		}
86
-	}
87
-
88
-	/**
89
-	 * mounting an object storage as the root fs will in essence remove the
90
-	 * necessity of a data folder being present.
91
-	 * TODO make home storage aware of this and use the object storage instead of local disk access
92
-	 *
93
-	 * @param array $config containing 'class' and optional 'arguments'
94
-	 */
95
-	private static function initObjectStoreRootFS($config) {
96
-		// check misconfiguration
97
-		if (empty($config['class'])) {
98
-			\OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR);
99
-		}
100
-		if (!isset($config['arguments'])) {
101
-			$config['arguments'] = array();
102
-		}
103
-
104
-		// instantiate object store implementation
105
-		$name = $config['class'];
106
-		if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
107
-			$segments = explode('\\', $name);
108
-			OC_App::loadApp(strtolower($segments[1]));
109
-		}
110
-		$config['arguments']['objectstore'] = new $config['class']($config['arguments']);
111
-		// mount with plain / root object store implementation
112
-		$config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
113
-
114
-		// mount object storage as root
115
-		\OC\Files\Filesystem::initMountManager();
116
-		if (!self::$rootMounted) {
117
-			\OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/');
118
-			self::$rootMounted = true;
119
-		}
120
-	}
121
-
122
-	/**
123
-	 * Can be set up
124
-	 *
125
-	 * @param string $user
126
-	 * @return boolean
127
-	 * @description configure the initial filesystem based on the configuration
128
-	 */
129
-	public static function setupFS($user = '') {
130
-		//setting up the filesystem twice can only lead to trouble
131
-		if (self::$fsSetup) {
132
-			return false;
133
-		}
134
-
135
-		\OC::$server->getEventLogger()->start('setup_fs', 'Setup filesystem');
136
-
137
-		// If we are not forced to load a specific user we load the one that is logged in
138
-		if ($user === null) {
139
-			$user = '';
140
-		} else if ($user == "" && \OC::$server->getUserSession()->isLoggedIn()) {
141
-			$user = OC_User::getUser();
142
-		}
143
-
144
-		// load all filesystem apps before, so no setup-hook gets lost
145
-		OC_App::loadApps(array('filesystem'));
146
-
147
-		// the filesystem will finish when $user is not empty,
148
-		// mark fs setup here to avoid doing the setup from loading
149
-		// OC_Filesystem
150
-		if ($user != '') {
151
-			self::$fsSetup = true;
152
-		}
153
-
154
-		\OC\Files\Filesystem::initMountManager();
155
-
156
-		\OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(false);
157
-		\OC\Files\Filesystem::addStorageWrapper('mount_options', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
158
-			if ($storage->instanceOfStorage('\OC\Files\Storage\Common')) {
159
-				/** @var \OC\Files\Storage\Common $storage */
160
-				$storage->setMountOptions($mount->getOptions());
161
-			}
162
-			return $storage;
163
-		});
164
-
165
-		\OC\Files\Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
166
-			if (!$mount->getOption('enable_sharing', true)) {
167
-				return new \OC\Files\Storage\Wrapper\PermissionsMask([
168
-					'storage' => $storage,
169
-					'mask' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_SHARE
170
-				]);
171
-			}
172
-			return $storage;
173
-		});
174
-
175
-		// install storage availability wrapper, before most other wrappers
176
-		\OC\Files\Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, $storage) {
177
-			if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
178
-				return new \OC\Files\Storage\Wrapper\Availability(['storage' => $storage]);
179
-			}
180
-			return $storage;
181
-		});
182
-
183
-		// install storage checksum wrapper
184
-		\OC\Files\Filesystem::addStorageWrapper('oc_checksum', function ($mountPoint, \OCP\Files\Storage\IStorage $storage) {
185
-			if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
186
-				return new \OC\Files\Storage\Wrapper\Checksum(['storage' => $storage]);
187
-			}
188
-
189
-			return $storage;
190
-
191
-		}, 1);
192
-
193
-
194
-		\OC\Files\Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
195
-			if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
196
-				return new \OC\Files\Storage\Wrapper\Encoding(['storage' => $storage]);
197
-			}
198
-			return $storage;
199
-		});
200
-
201
-		\OC\Files\Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
202
-			// set up quota for home storages, even for other users
203
-			// which can happen when using sharing
204
-
205
-			/**
206
-			 * @var \OC\Files\Storage\Storage $storage
207
-			 */
208
-			if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
209
-				|| $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
210
-			) {
211
-				/** @var \OC\Files\Storage\Home $storage */
212
-				if (is_object($storage->getUser())) {
213
-					$user = $storage->getUser()->getUID();
214
-					$quota = OC_Util::getUserQuota($user);
215
-					if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
216
-						return new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => $quota, 'root' => 'files'));
217
-					}
218
-				}
219
-			}
220
-
221
-			return $storage;
222
-		});
223
-
224
-		OC_Hook::emit('OC_Filesystem', 'preSetup', array('user' => $user));
225
-		\OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(true);
226
-
227
-		//check if we are using an object storage
228
-		$objectStore = \OC::$server->getSystemConfig()->getValue('objectstore', null);
229
-		if (isset($objectStore)) {
230
-			self::initObjectStoreRootFS($objectStore);
231
-		} else {
232
-			self::initLocalStorageRootFS();
233
-		}
234
-
235
-		if ($user != '' && !OCP\User::userExists($user)) {
236
-			\OC::$server->getEventLogger()->end('setup_fs');
237
-			return false;
238
-		}
239
-
240
-		//if we aren't logged in, there is no use to set up the filesystem
241
-		if ($user != "") {
242
-
243
-			$userDir = '/' . $user . '/files';
244
-
245
-			//jail the user into his "home" directory
246
-			\OC\Files\Filesystem::init($user, $userDir);
247
-
248
-			OC_Hook::emit('OC_Filesystem', 'setup', array('user' => $user, 'user_dir' => $userDir));
249
-		}
250
-		\OC::$server->getEventLogger()->end('setup_fs');
251
-		return true;
252
-	}
253
-
254
-	/**
255
-	 * check if a password is required for each public link
256
-	 *
257
-	 * @return boolean
258
-	 */
259
-	public static function isPublicLinkPasswordRequired() {
260
-		$appConfig = \OC::$server->getAppConfig();
261
-		$enforcePassword = $appConfig->getValue('core', 'shareapi_enforce_links_password', 'no');
262
-		return ($enforcePassword === 'yes') ? true : false;
263
-	}
264
-
265
-	/**
266
-	 * check if sharing is disabled for the current user
267
-	 * @param IConfig $config
268
-	 * @param IGroupManager $groupManager
269
-	 * @param IUser|null $user
270
-	 * @return bool
271
-	 */
272
-	public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
273
-		if ($config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
274
-			$groupsList = $config->getAppValue('core', 'shareapi_exclude_groups_list', '');
275
-			$excludedGroups = json_decode($groupsList);
276
-			if (is_null($excludedGroups)) {
277
-				$excludedGroups = explode(',', $groupsList);
278
-				$newValue = json_encode($excludedGroups);
279
-				$config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
280
-			}
281
-			$usersGroups = $groupManager->getUserGroupIds($user);
282
-			if (!empty($usersGroups)) {
283
-				$remainingGroups = array_diff($usersGroups, $excludedGroups);
284
-				// if the user is only in groups which are disabled for sharing then
285
-				// sharing is also disabled for the user
286
-				if (empty($remainingGroups)) {
287
-					return true;
288
-				}
289
-			}
290
-		}
291
-		return false;
292
-	}
293
-
294
-	/**
295
-	 * check if share API enforces a default expire date
296
-	 *
297
-	 * @return boolean
298
-	 */
299
-	public static function isDefaultExpireDateEnforced() {
300
-		$isDefaultExpireDateEnabled = \OCP\Config::getAppValue('core', 'shareapi_default_expire_date', 'no');
301
-		$enforceDefaultExpireDate = false;
302
-		if ($isDefaultExpireDateEnabled === 'yes') {
303
-			$value = \OCP\Config::getAppValue('core', 'shareapi_enforce_expire_date', 'no');
304
-			$enforceDefaultExpireDate = ($value === 'yes') ? true : false;
305
-		}
306
-
307
-		return $enforceDefaultExpireDate;
308
-	}
309
-
310
-	/**
311
-	 * Get the quota of a user
312
-	 *
313
-	 * @param string $userId
314
-	 * @return int Quota bytes
315
-	 */
316
-	public static function getUserQuota($userId) {
317
-		$user = \OC::$server->getUserManager()->get($userId);
318
-		if (is_null($user)) {
319
-			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
320
-		}
321
-		$userQuota = $user->getQuota();
322
-		if($userQuota === 'none') {
323
-			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
324
-		}
325
-		return OC_Helper::computerFileSize($userQuota);
326
-	}
327
-
328
-	/**
329
-	 * copies the skeleton to the users /files
330
-	 *
331
-	 * @param String $userId
332
-	 * @param \OCP\Files\Folder $userDirectory
333
-	 * @throws \RuntimeException
334
-	 */
335
-	public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
336
-
337
-		$skeletonDirectory = \OC::$server->getConfig()->getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
338
-		$instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', '');
339
-
340
-		if ($instanceId === null) {
341
-			throw new \RuntimeException('no instance id!');
342
-		}
343
-		$appdata = 'appdata_' . $instanceId;
344
-		if ($userId === $appdata) {
345
-			throw new \RuntimeException('username is reserved name: ' . $appdata);
346
-		}
347
-
348
-		if (!empty($skeletonDirectory)) {
349
-			\OCP\Util::writeLog(
350
-				'files_skeleton',
351
-				'copying skeleton for '.$userId.' from '.$skeletonDirectory.' to '.$userDirectory->getFullPath('/'),
352
-				\OCP\Util::DEBUG
353
-			);
354
-			self::copyr($skeletonDirectory, $userDirectory);
355
-			// update the file cache
356
-			$userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
357
-		}
358
-	}
359
-
360
-	/**
361
-	 * copies a directory recursively by using streams
362
-	 *
363
-	 * @param string $source
364
-	 * @param \OCP\Files\Folder $target
365
-	 * @return void
366
-	 */
367
-	public static function copyr($source, \OCP\Files\Folder $target) {
368
-		$logger = \OC::$server->getLogger();
369
-
370
-		// Verify if folder exists
371
-		$dir = opendir($source);
372
-		if($dir === false) {
373
-			$logger->error(sprintf('Could not opendir "%s"', $source), ['app' => 'core']);
374
-			return;
375
-		}
376
-
377
-		// Copy the files
378
-		while (false !== ($file = readdir($dir))) {
379
-			if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
380
-				if (is_dir($source . '/' . $file)) {
381
-					$child = $target->newFolder($file);
382
-					self::copyr($source . '/' . $file, $child);
383
-				} else {
384
-					$child = $target->newFile($file);
385
-					$sourceStream = fopen($source . '/' . $file, 'r');
386
-					if($sourceStream === false) {
387
-						$logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
388
-						closedir($dir);
389
-						return;
390
-					}
391
-					stream_copy_to_stream($sourceStream, $child->fopen('w'));
392
-				}
393
-			}
394
-		}
395
-		closedir($dir);
396
-	}
397
-
398
-	/**
399
-	 * @return void
400
-	 */
401
-	public static function tearDownFS() {
402
-		\OC\Files\Filesystem::tearDown();
403
-		\OC::$server->getRootFolder()->clearCache();
404
-		self::$fsSetup = false;
405
-		self::$rootMounted = false;
406
-	}
407
-
408
-	/**
409
-	 * get the current installed version of ownCloud
410
-	 *
411
-	 * @return array
412
-	 */
413
-	public static function getVersion() {
414
-		OC_Util::loadVersion();
415
-		return self::$versionCache['OC_Version'];
416
-	}
417
-
418
-	/**
419
-	 * get the current installed version string of ownCloud
420
-	 *
421
-	 * @return string
422
-	 */
423
-	public static function getVersionString() {
424
-		OC_Util::loadVersion();
425
-		return self::$versionCache['OC_VersionString'];
426
-	}
427
-
428
-	/**
429
-	 * @deprecated the value is of no use anymore
430
-	 * @return string
431
-	 */
432
-	public static function getEditionString() {
433
-		return '';
434
-	}
435
-
436
-	/**
437
-	 * @description get the update channel of the current installed of ownCloud.
438
-	 * @return string
439
-	 */
440
-	public static function getChannel() {
441
-		OC_Util::loadVersion();
442
-		return \OC::$server->getConfig()->getSystemValue('updater.release.channel', self::$versionCache['OC_Channel']);
443
-	}
444
-
445
-	/**
446
-	 * @description get the build number of the current installed of ownCloud.
447
-	 * @return string
448
-	 */
449
-	public static function getBuild() {
450
-		OC_Util::loadVersion();
451
-		return self::$versionCache['OC_Build'];
452
-	}
453
-
454
-	/**
455
-	 * @description load the version.php into the session as cache
456
-	 */
457
-	private static function loadVersion() {
458
-		if (self::$versionCache !== null) {
459
-			return;
460
-		}
461
-
462
-		$timestamp = filemtime(OC::$SERVERROOT . '/version.php');
463
-		require OC::$SERVERROOT . '/version.php';
464
-		/** @var $timestamp int */
465
-		self::$versionCache['OC_Version_Timestamp'] = $timestamp;
466
-		/** @var $OC_Version string */
467
-		self::$versionCache['OC_Version'] = $OC_Version;
468
-		/** @var $OC_VersionString string */
469
-		self::$versionCache['OC_VersionString'] = $OC_VersionString;
470
-		/** @var $OC_Build string */
471
-		self::$versionCache['OC_Build'] = $OC_Build;
472
-
473
-		/** @var $OC_Channel string */
474
-		self::$versionCache['OC_Channel'] = $OC_Channel;
475
-	}
476
-
477
-	/**
478
-	 * generates a path for JS/CSS files. If no application is provided it will create the path for core.
479
-	 *
480
-	 * @param string $application application to get the files from
481
-	 * @param string $directory directory within this application (css, js, vendor, etc)
482
-	 * @param string $file the file inside of the above folder
483
-	 * @return string the path
484
-	 */
485
-	private static function generatePath($application, $directory, $file) {
486
-		if (is_null($file)) {
487
-			$file = $application;
488
-			$application = "";
489
-		}
490
-		if (!empty($application)) {
491
-			return "$application/$directory/$file";
492
-		} else {
493
-			return "$directory/$file";
494
-		}
495
-	}
496
-
497
-	/**
498
-	 * add a javascript file
499
-	 *
500
-	 * @param string $application application id
501
-	 * @param string|null $file filename
502
-	 * @param bool $prepend prepend the Script to the beginning of the list
503
-	 * @return void
504
-	 */
505
-	public static function addScript($application, $file = null, $prepend = false) {
506
-		$path = OC_Util::generatePath($application, 'js', $file);
507
-
508
-		// core js files need separate handling
509
-		if ($application !== 'core' && $file !== null) {
510
-			self::addTranslations ( $application );
511
-		}
512
-		self::addExternalResource($application, $prepend, $path, "script");
513
-	}
514
-
515
-	/**
516
-	 * add a javascript file from the vendor sub folder
517
-	 *
518
-	 * @param string $application application id
519
-	 * @param string|null $file filename
520
-	 * @param bool $prepend prepend the Script to the beginning of the list
521
-	 * @return void
522
-	 */
523
-	public static function addVendorScript($application, $file = null, $prepend = false) {
524
-		$path = OC_Util::generatePath($application, 'vendor', $file);
525
-		self::addExternalResource($application, $prepend, $path, "script");
526
-	}
527
-
528
-	/**
529
-	 * add a translation JS file
530
-	 *
531
-	 * @param string $application application id
532
-	 * @param string $languageCode language code, defaults to the current language
533
-	 * @param bool $prepend prepend the Script to the beginning of the list
534
-	 */
535
-	public static function addTranslations($application, $languageCode = null, $prepend = false) {
536
-		if (is_null($languageCode)) {
537
-			$languageCode = \OC::$server->getL10NFactory()->findLanguage($application);
538
-		}
539
-		if (!empty($application)) {
540
-			$path = "$application/l10n/$languageCode";
541
-		} else {
542
-			$path = "l10n/$languageCode";
543
-		}
544
-		self::addExternalResource($application, $prepend, $path, "script");
545
-	}
546
-
547
-	/**
548
-	 * add a css file
549
-	 *
550
-	 * @param string $application application id
551
-	 * @param string|null $file filename
552
-	 * @param bool $prepend prepend the Style to the beginning of the list
553
-	 * @return void
554
-	 */
555
-	public static function addStyle($application, $file = null, $prepend = false) {
556
-		$path = OC_Util::generatePath($application, 'css', $file);
557
-		self::addExternalResource($application, $prepend, $path, "style");
558
-	}
559
-
560
-	/**
561
-	 * add a css file from the vendor sub folder
562
-	 *
563
-	 * @param string $application application id
564
-	 * @param string|null $file filename
565
-	 * @param bool $prepend prepend the Style to the beginning of the list
566
-	 * @return void
567
-	 */
568
-	public static function addVendorStyle($application, $file = null, $prepend = false) {
569
-		$path = OC_Util::generatePath($application, 'vendor', $file);
570
-		self::addExternalResource($application, $prepend, $path, "style");
571
-	}
572
-
573
-	/**
574
-	 * add an external resource css/js file
575
-	 *
576
-	 * @param string $application application id
577
-	 * @param bool $prepend prepend the file to the beginning of the list
578
-	 * @param string $path
579
-	 * @param string $type (script or style)
580
-	 * @return void
581
-	 */
582
-	private static function addExternalResource($application, $prepend, $path, $type = "script") {
583
-
584
-		if ($type === "style") {
585
-			if (!in_array($path, self::$styles)) {
586
-				if ($prepend === true) {
587
-					array_unshift ( self::$styles, $path );
588
-				} else {
589
-					self::$styles[] = $path;
590
-				}
591
-			}
592
-		} elseif ($type === "script") {
593
-			if (!in_array($path, self::$scripts)) {
594
-				if ($prepend === true) {
595
-					array_unshift ( self::$scripts, $path );
596
-				} else {
597
-					self::$scripts [] = $path;
598
-				}
599
-			}
600
-		}
601
-	}
602
-
603
-	/**
604
-	 * Add a custom element to the header
605
-	 * If $text is null then the element will be written as empty element.
606
-	 * So use "" to get a closing tag.
607
-	 * @param string $tag tag name of the element
608
-	 * @param array $attributes array of attributes for the element
609
-	 * @param string $text the text content for the element
610
-	 */
611
-	public static function addHeader($tag, $attributes, $text=null) {
612
-		self::$headers[] = array(
613
-			'tag' => $tag,
614
-			'attributes' => $attributes,
615
-			'text' => $text
616
-		);
617
-	}
618
-
619
-	/**
620
-	 * formats a timestamp in the "right" way
621
-	 *
622
-	 * @param int $timestamp
623
-	 * @param bool $dateOnly option to omit time from the result
624
-	 * @param DateTimeZone|string $timeZone where the given timestamp shall be converted to
625
-	 * @return string timestamp
626
-	 *
627
-	 * @deprecated Use \OC::$server->query('DateTimeFormatter') instead
628
-	 */
629
-	public static function formatDate($timestamp, $dateOnly = false, $timeZone = null) {
630
-		if ($timeZone !== null && !$timeZone instanceof \DateTimeZone) {
631
-			$timeZone = new \DateTimeZone($timeZone);
632
-		}
633
-
634
-		/** @var \OC\DateTimeFormatter $formatter */
635
-		$formatter = \OC::$server->query('DateTimeFormatter');
636
-		if ($dateOnly) {
637
-			return $formatter->formatDate($timestamp, 'long', $timeZone);
638
-		}
639
-		return $formatter->formatDateTime($timestamp, 'long', 'long', $timeZone);
640
-	}
641
-
642
-	/**
643
-	 * check if the current server configuration is suitable for ownCloud
644
-	 *
645
-	 * @param \OC\SystemConfig $config
646
-	 * @return array arrays with error messages and hints
647
-	 */
648
-	public static function checkServer(\OC\SystemConfig $config) {
649
-		$l = \OC::$server->getL10N('lib');
650
-		$errors = array();
651
-		$CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT . '/data');
652
-
653
-		if (!self::needUpgrade($config) && $config->getValue('installed', false)) {
654
-			// this check needs to be done every time
655
-			$errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY);
656
-		}
657
-
658
-		// Assume that if checkServer() succeeded before in this session, then all is fine.
659
-		if (\OC::$server->getSession()->exists('checkServer_succeeded') && \OC::$server->getSession()->get('checkServer_succeeded')) {
660
-			return $errors;
661
-		}
662
-
663
-		$webServerRestart = false;
664
-		$setup = new \OC\Setup($config, \OC::$server->getIniWrapper(), \OC::$server->getL10N('lib'),
665
-			\OC::$server->query(\OCP\Defaults::class), \OC::$server->getLogger(), \OC::$server->getSecureRandom());
666
-
667
-		$urlGenerator = \OC::$server->getURLGenerator();
668
-
669
-		$availableDatabases = $setup->getSupportedDatabases();
670
-		if (empty($availableDatabases)) {
671
-			$errors[] = array(
672
-				'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'),
673
-				'hint' => '' //TODO: sane hint
674
-			);
675
-			$webServerRestart = true;
676
-		}
677
-
678
-		// Check if config folder is writable.
679
-		if(!OC_Helper::isReadOnlyConfigEnabled()) {
680
-			if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
681
-				$errors[] = array(
682
-					'error' => $l->t('Cannot write into "config" directory'),
683
-					'hint' => $l->t('This can usually be fixed by '
684
-						. '%sgiving the webserver write access to the config directory%s.',
685
-						array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>'))
686
-				);
687
-			}
688
-		}
689
-
690
-		// Check if there is a writable install folder.
691
-		if ($config->getValue('appstoreenabled', true)) {
692
-			if (OC_App::getInstallPath() === null
693
-				|| !is_writable(OC_App::getInstallPath())
694
-				|| !is_readable(OC_App::getInstallPath())
695
-			) {
696
-				$errors[] = array(
697
-					'error' => $l->t('Cannot write into "apps" directory'),
698
-					'hint' => $l->t('This can usually be fixed by '
699
-						. '%sgiving the webserver write access to the apps directory%s'
700
-						. ' or disabling the appstore in the config file.',
701
-						array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>'))
702
-				);
703
-			}
704
-		}
705
-		// Create root dir.
706
-		if ($config->getValue('installed', false)) {
707
-			if (!is_dir($CONFIG_DATADIRECTORY)) {
708
-				$success = @mkdir($CONFIG_DATADIRECTORY);
709
-				if ($success) {
710
-					$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
711
-				} else {
712
-					$errors[] = [
713
-						'error' => $l->t('Cannot create "data" directory'),
714
-						'hint' => $l->t('This can usually be fixed by '
715
-							. '<a href="%s" target="_blank" rel="noreferrer">giving the webserver write access to the root directory</a>.',
716
-							[$urlGenerator->linkToDocs('admin-dir_permissions')])
717
-					];
718
-				}
719
-			} else if (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
720
-				//common hint for all file permissions error messages
721
-				$permissionsHint = $l->t('Permissions can usually be fixed by '
722
-					. '%sgiving the webserver write access to the root directory%s.',
723
-					['<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>']);
724
-				$errors[] = [
725
-					'error' => 'Your data directory is not writable',
726
-					'hint' => $permissionsHint
727
-				];
728
-			} else {
729
-				$errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
730
-			}
731
-		}
732
-
733
-		if (!OC_Util::isSetLocaleWorking()) {
734
-			$errors[] = array(
735
-				'error' => $l->t('Setting locale to %s failed',
736
-					array('en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
737
-						. 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8')),
738
-				'hint' => $l->t('Please install one of these locales on your system and restart your webserver.')
739
-			);
740
-		}
741
-
742
-		// Contains the dependencies that should be checked against
743
-		// classes = class_exists
744
-		// functions = function_exists
745
-		// defined = defined
746
-		// ini = ini_get
747
-		// If the dependency is not found the missing module name is shown to the EndUser
748
-		// When adding new checks always verify that they pass on Travis as well
749
-		// for ini settings, see https://github.com/owncloud/administration/blob/master/travis-ci/custom.ini
750
-		$dependencies = array(
751
-			'classes' => array(
752
-				'ZipArchive' => 'zip',
753
-				'DOMDocument' => 'dom',
754
-				'XMLWriter' => 'XMLWriter',
755
-				'XMLReader' => 'XMLReader',
756
-			),
757
-			'functions' => [
758
-				'xml_parser_create' => 'libxml',
759
-				'mb_strcut' => 'mb multibyte',
760
-				'ctype_digit' => 'ctype',
761
-				'json_encode' => 'JSON',
762
-				'gd_info' => 'GD',
763
-				'gzencode' => 'zlib',
764
-				'iconv' => 'iconv',
765
-				'simplexml_load_string' => 'SimpleXML',
766
-				'hash' => 'HASH Message Digest Framework',
767
-				'curl_init' => 'cURL',
768
-				'openssl_verify' => 'OpenSSL',
769
-			],
770
-			'defined' => array(
771
-				'PDO::ATTR_DRIVER_NAME' => 'PDO'
772
-			),
773
-			'ini' => [
774
-				'default_charset' => 'UTF-8',
775
-			],
776
-		);
777
-		$missingDependencies = array();
778
-		$invalidIniSettings = [];
779
-		$moduleHint = $l->t('Please ask your server administrator to install the module.');
780
-
781
-		/**
782
-		 * FIXME: The dependency check does not work properly on HHVM on the moment
783
-		 *        and prevents installation. Once HHVM is more compatible with our
784
-		 *        approach to check for these values we should re-enable those
785
-		 *        checks.
786
-		 */
787
-		$iniWrapper = \OC::$server->getIniWrapper();
788
-		if (!self::runningOnHhvm()) {
789
-			foreach ($dependencies['classes'] as $class => $module) {
790
-				if (!class_exists($class)) {
791
-					$missingDependencies[] = $module;
792
-				}
793
-			}
794
-			foreach ($dependencies['functions'] as $function => $module) {
795
-				if (!function_exists($function)) {
796
-					$missingDependencies[] = $module;
797
-				}
798
-			}
799
-			foreach ($dependencies['defined'] as $defined => $module) {
800
-				if (!defined($defined)) {
801
-					$missingDependencies[] = $module;
802
-				}
803
-			}
804
-			foreach ($dependencies['ini'] as $setting => $expected) {
805
-				if (is_bool($expected)) {
806
-					if ($iniWrapper->getBool($setting) !== $expected) {
807
-						$invalidIniSettings[] = [$setting, $expected];
808
-					}
809
-				}
810
-				if (is_int($expected)) {
811
-					if ($iniWrapper->getNumeric($setting) !== $expected) {
812
-						$invalidIniSettings[] = [$setting, $expected];
813
-					}
814
-				}
815
-				if (is_string($expected)) {
816
-					if (strtolower($iniWrapper->getString($setting)) !== strtolower($expected)) {
817
-						$invalidIniSettings[] = [$setting, $expected];
818
-					}
819
-				}
820
-			}
821
-		}
822
-
823
-		foreach($missingDependencies as $missingDependency) {
824
-			$errors[] = array(
825
-				'error' => $l->t('PHP module %s not installed.', array($missingDependency)),
826
-				'hint' => $moduleHint
827
-			);
828
-			$webServerRestart = true;
829
-		}
830
-		foreach($invalidIniSettings as $setting) {
831
-			if(is_bool($setting[1])) {
832
-				$setting[1] = ($setting[1]) ? 'on' : 'off';
833
-			}
834
-			$errors[] = [
835
-				'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
836
-				'hint' =>  $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
837
-			];
838
-			$webServerRestart = true;
839
-		}
840
-
841
-		/**
842
-		 * The mbstring.func_overload check can only be performed if the mbstring
843
-		 * module is installed as it will return null if the checking setting is
844
-		 * not available and thus a check on the boolean value fails.
845
-		 *
846
-		 * TODO: Should probably be implemented in the above generic dependency
847
-		 *       check somehow in the long-term.
848
-		 */
849
-		if($iniWrapper->getBool('mbstring.func_overload') !== null &&
850
-			$iniWrapper->getBool('mbstring.func_overload') === true) {
851
-			$errors[] = array(
852
-				'error' => $l->t('mbstring.func_overload is set to "%s" instead of the expected value "0"', [$iniWrapper->getString('mbstring.func_overload')]),
853
-				'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini')
854
-			);
855
-		}
856
-
857
-		if(function_exists('xml_parser_create') &&
858
-			LIBXML_LOADED_VERSION < 20700 ) {
859
-			$version = LIBXML_LOADED_VERSION;
860
-			$major = floor($version/10000);
861
-			$version -= ($major * 10000);
862
-			$minor = floor($version/100);
863
-			$version -= ($minor * 100);
864
-			$patch = $version;
865
-			$errors[] = array(
866
-				'error' => $l->t('libxml2 2.7.0 is at least required. Currently %s is installed.', [$major . '.' . $minor . '.' . $patch]),
867
-				'hint' => $l->t('To fix this issue update your libxml2 version and restart your web server.')
868
-			);
869
-		}
870
-
871
-		if (!self::isAnnotationsWorking()) {
872
-			$errors[] = array(
873
-				'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
874
-				'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
875
-			);
876
-		}
877
-
878
-		if (!\OC::$CLI && $webServerRestart) {
879
-			$errors[] = array(
880
-				'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
881
-				'hint' => $l->t('Please ask your server administrator to restart the web server.')
882
-			);
883
-		}
884
-
885
-		$errors = array_merge($errors, self::checkDatabaseVersion());
886
-
887
-		// Cache the result of this function
888
-		\OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
889
-
890
-		return $errors;
891
-	}
892
-
893
-	/**
894
-	 * Check the database version
895
-	 *
896
-	 * @return array errors array
897
-	 */
898
-	public static function checkDatabaseVersion() {
899
-		$l = \OC::$server->getL10N('lib');
900
-		$errors = array();
901
-		$dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
902
-		if ($dbType === 'pgsql') {
903
-			// check PostgreSQL version
904
-			try {
905
-				$result = \OC_DB::executeAudited('SHOW SERVER_VERSION');
906
-				$data = $result->fetchRow();
907
-				if (isset($data['server_version'])) {
908
-					$version = $data['server_version'];
909
-					if (version_compare($version, '9.0.0', '<')) {
910
-						$errors[] = array(
911
-							'error' => $l->t('PostgreSQL >= 9 required'),
912
-							'hint' => $l->t('Please upgrade your database version')
913
-						);
914
-					}
915
-				}
916
-			} catch (\Doctrine\DBAL\DBALException $e) {
917
-				$logger = \OC::$server->getLogger();
918
-				$logger->warning('Error occurred while checking PostgreSQL version, assuming >= 9');
919
-				$logger->logException($e);
920
-			}
921
-		}
922
-		return $errors;
923
-	}
924
-
925
-	/**
926
-	 * Check for correct file permissions of data directory
927
-	 *
928
-	 * @param string $dataDirectory
929
-	 * @return array arrays with error messages and hints
930
-	 */
931
-	public static function checkDataDirectoryPermissions($dataDirectory) {
932
-		$l = \OC::$server->getL10N('lib');
933
-		$errors = array();
934
-		$permissionsModHint = $l->t('Please change the permissions to 0770 so that the directory'
935
-			. ' cannot be listed by other users.');
936
-		$perms = substr(decoct(@fileperms($dataDirectory)), -3);
937
-		if (substr($perms, -1) !== '0') {
938
-			chmod($dataDirectory, 0770);
939
-			clearstatcache();
940
-			$perms = substr(decoct(@fileperms($dataDirectory)), -3);
941
-			if ($perms[2] !== '0') {
942
-				$errors[] = [
943
-					'error' => $l->t('Your data directory is readable by other users'),
944
-					'hint' => $permissionsModHint
945
-				];
946
-			}
947
-		}
948
-		return $errors;
949
-	}
950
-
951
-	/**
952
-	 * Check that the data directory exists and is valid by
953
-	 * checking the existence of the ".ocdata" file.
954
-	 *
955
-	 * @param string $dataDirectory data directory path
956
-	 * @return array errors found
957
-	 */
958
-	public static function checkDataDirectoryValidity($dataDirectory) {
959
-		$l = \OC::$server->getL10N('lib');
960
-		$errors = [];
961
-		if ($dataDirectory[0] !== '/') {
962
-			$errors[] = [
963
-				'error' => $l->t('Your data directory must be an absolute path'),
964
-				'hint' => $l->t('Check the value of "datadirectory" in your configuration')
965
-			];
966
-		}
967
-		if (!file_exists($dataDirectory . '/.ocdata')) {
968
-			$errors[] = [
969
-				'error' => $l->t('Your data directory is invalid'),
970
-				'hint' => $l->t('Please check that the data directory contains a file' .
971
-					' ".ocdata" in its root.')
972
-			];
973
-		}
974
-		return $errors;
975
-	}
976
-
977
-	/**
978
-	 * Check if the user is logged in, redirects to home if not. With
979
-	 * redirect URL parameter to the request URI.
980
-	 *
981
-	 * @return void
982
-	 */
983
-	public static function checkLoggedIn() {
984
-		// Check if we are a user
985
-		if (!\OC::$server->getUserSession()->isLoggedIn()) {
986
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
987
-						'core.login.showLoginForm',
988
-						[
989
-							'redirect_url' => \OC::$server->getRequest()->getRequestUri(),
990
-						]
991
-					)
992
-			);
993
-			exit();
994
-		}
995
-		// Redirect to 2FA challenge selection if 2FA challenge was not solved yet
996
-		if (\OC::$server->getTwoFactorAuthManager()->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
997
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
998
-			exit();
999
-		}
1000
-	}
1001
-
1002
-	/**
1003
-	 * Check if the user is a admin, redirects to home if not
1004
-	 *
1005
-	 * @return void
1006
-	 */
1007
-	public static function checkAdminUser() {
1008
-		OC_Util::checkLoggedIn();
1009
-		if (!OC_User::isAdminUser(OC_User::getUser())) {
1010
-			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
1011
-			exit();
1012
-		}
1013
-	}
1014
-
1015
-	/**
1016
-	 * Check if the user is a subadmin, redirects to home if not
1017
-	 *
1018
-	 * @return null|boolean $groups where the current user is subadmin
1019
-	 */
1020
-	public static function checkSubAdminUser() {
1021
-		OC_Util::checkLoggedIn();
1022
-		$userObject = \OC::$server->getUserSession()->getUser();
1023
-		$isSubAdmin = false;
1024
-		if($userObject !== null) {
1025
-			$isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
1026
-		}
1027
-
1028
-		if (!$isSubAdmin) {
1029
-			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
1030
-			exit();
1031
-		}
1032
-		return true;
1033
-	}
1034
-
1035
-	/**
1036
-	 * Returns the URL of the default page
1037
-	 * based on the system configuration and
1038
-	 * the apps visible for the current user
1039
-	 *
1040
-	 * @return string URL
1041
-	 */
1042
-	public static function getDefaultPageUrl() {
1043
-		$urlGenerator = \OC::$server->getURLGenerator();
1044
-		// Deny the redirect if the URL contains a @
1045
-		// This prevents unvalidated redirects like ?redirect_url=:[email protected]
1046
-		if (isset($_REQUEST['redirect_url']) && strpos($_REQUEST['redirect_url'], '@') === false) {
1047
-			$location = $urlGenerator->getAbsoluteURL(urldecode($_REQUEST['redirect_url']));
1048
-		} else {
1049
-			$defaultPage = \OC::$server->getAppConfig()->getValue('core', 'defaultpage');
1050
-			if ($defaultPage) {
1051
-				$location = $urlGenerator->getAbsoluteURL($defaultPage);
1052
-			} else {
1053
-				$appId = 'files';
1054
-				$defaultApps = explode(',', \OCP\Config::getSystemValue('defaultapp', 'files'));
1055
-				// find the first app that is enabled for the current user
1056
-				foreach ($defaultApps as $defaultApp) {
1057
-					$defaultApp = OC_App::cleanAppId(strip_tags($defaultApp));
1058
-					if (static::getAppManager()->isEnabledForUser($defaultApp)) {
1059
-						$appId = $defaultApp;
1060
-						break;
1061
-					}
1062
-				}
1063
-
1064
-				if(\OC::$server->getConfig()->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true') {
1065
-					$location = $urlGenerator->getAbsoluteURL('/apps/' . $appId . '/');
1066
-				} else {
1067
-					$location = $urlGenerator->getAbsoluteURL('/index.php/apps/' . $appId . '/');
1068
-				}
1069
-			}
1070
-		}
1071
-		return $location;
1072
-	}
1073
-
1074
-	/**
1075
-	 * Redirect to the user default page
1076
-	 *
1077
-	 * @return void
1078
-	 */
1079
-	public static function redirectToDefaultPage() {
1080
-		$location = self::getDefaultPageUrl();
1081
-		header('Location: ' . $location);
1082
-		exit();
1083
-	}
1084
-
1085
-	/**
1086
-	 * get an id unique for this instance
1087
-	 *
1088
-	 * @return string
1089
-	 */
1090
-	public static function getInstanceId() {
1091
-		$id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
1092
-		if (is_null($id)) {
1093
-			// We need to guarantee at least one letter in instanceid so it can be used as the session_name
1094
-			$id = 'oc' . \OC::$server->getSecureRandom()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
1095
-			\OC::$server->getSystemConfig()->setValue('instanceid', $id);
1096
-		}
1097
-		return $id;
1098
-	}
1099
-
1100
-	/**
1101
-	 * Public function to sanitize HTML
1102
-	 *
1103
-	 * This function is used to sanitize HTML and should be applied on any
1104
-	 * string or array of strings before displaying it on a web page.
1105
-	 *
1106
-	 * @param string|array $value
1107
-	 * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter.
1108
-	 */
1109
-	public static function sanitizeHTML($value) {
1110
-		if (is_array($value)) {
1111
-			$value = array_map(function($value) {
1112
-				return self::sanitizeHTML($value);
1113
-			}, $value);
1114
-		} else {
1115
-			// Specify encoding for PHP<5.4
1116
-			$value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
1117
-		}
1118
-		return $value;
1119
-	}
1120
-
1121
-	/**
1122
-	 * Public function to encode url parameters
1123
-	 *
1124
-	 * This function is used to encode path to file before output.
1125
-	 * Encoding is done according to RFC 3986 with one exception:
1126
-	 * Character '/' is preserved as is.
1127
-	 *
1128
-	 * @param string $component part of URI to encode
1129
-	 * @return string
1130
-	 */
1131
-	public static function encodePath($component) {
1132
-		$encoded = rawurlencode($component);
1133
-		$encoded = str_replace('%2F', '/', $encoded);
1134
-		return $encoded;
1135
-	}
1136
-
1137
-
1138
-	public function createHtaccessTestFile(\OCP\IConfig $config) {
1139
-		// php dev server does not support htaccess
1140
-		if (php_sapi_name() === 'cli-server') {
1141
-			return false;
1142
-		}
1143
-
1144
-		// testdata
1145
-		$fileName = '/htaccesstest.txt';
1146
-		$testContent = 'This is used for testing whether htaccess is properly enabled to disallow access from the outside. This file can be safely removed.';
1147
-
1148
-		// creating a test file
1149
-		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1150
-
1151
-		if (file_exists($testFile)) {// already running this test, possible recursive call
1152
-			return false;
1153
-		}
1154
-
1155
-		$fp = @fopen($testFile, 'w');
1156
-		if (!$fp) {
1157
-			throw new OC\HintException('Can\'t create test file to check for working .htaccess file.',
1158
-				'Make sure it is possible for the webserver to write to ' . $testFile);
1159
-		}
1160
-		fwrite($fp, $testContent);
1161
-		fclose($fp);
1162
-
1163
-		return $testContent;
1164
-	}
1165
-
1166
-	/**
1167
-	 * Check if the .htaccess file is working
1168
-	 * @param \OCP\IConfig $config
1169
-	 * @return bool
1170
-	 * @throws Exception
1171
-	 * @throws \OC\HintException If the test file can't get written.
1172
-	 */
1173
-	public function isHtaccessWorking(\OCP\IConfig $config) {
1174
-
1175
-		if (\OC::$CLI || !$config->getSystemValue('check_for_working_htaccess', true)) {
1176
-			return true;
1177
-		}
1178
-
1179
-		$testContent = $this->createHtaccessTestFile($config);
1180
-		if ($testContent === false) {
1181
-			return false;
1182
-		}
1183
-
1184
-		$fileName = '/htaccesstest.txt';
1185
-		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1186
-
1187
-		// accessing the file via http
1188
-		$url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
1189
-		try {
1190
-			$content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1191
-		} catch (\Exception $e) {
1192
-			$content = false;
1193
-		}
1194
-
1195
-		// cleanup
1196
-		@unlink($testFile);
1197
-
1198
-		/*
64
+    public static $scripts = array();
65
+    public static $styles = array();
66
+    public static $headers = array();
67
+    private static $rootMounted = false;
68
+    private static $fsSetup = false;
69
+
70
+    /** @var array Local cache of version.php */
71
+    private static $versionCache = null;
72
+
73
+    protected static function getAppManager() {
74
+        return \OC::$server->getAppManager();
75
+    }
76
+
77
+    private static function initLocalStorageRootFS() {
78
+        // mount local file backend as root
79
+        $configDataDirectory = \OC::$server->getSystemConfig()->getValue("datadirectory", OC::$SERVERROOT . "/data");
80
+        //first set up the local "root" storage
81
+        \OC\Files\Filesystem::initMountManager();
82
+        if (!self::$rootMounted) {
83
+            \OC\Files\Filesystem::mount('\OC\Files\Storage\Local', array('datadir' => $configDataDirectory), '/');
84
+            self::$rootMounted = true;
85
+        }
86
+    }
87
+
88
+    /**
89
+     * mounting an object storage as the root fs will in essence remove the
90
+     * necessity of a data folder being present.
91
+     * TODO make home storage aware of this and use the object storage instead of local disk access
92
+     *
93
+     * @param array $config containing 'class' and optional 'arguments'
94
+     */
95
+    private static function initObjectStoreRootFS($config) {
96
+        // check misconfiguration
97
+        if (empty($config['class'])) {
98
+            \OCP\Util::writeLog('files', 'No class given for objectstore', \OCP\Util::ERROR);
99
+        }
100
+        if (!isset($config['arguments'])) {
101
+            $config['arguments'] = array();
102
+        }
103
+
104
+        // instantiate object store implementation
105
+        $name = $config['class'];
106
+        if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
107
+            $segments = explode('\\', $name);
108
+            OC_App::loadApp(strtolower($segments[1]));
109
+        }
110
+        $config['arguments']['objectstore'] = new $config['class']($config['arguments']);
111
+        // mount with plain / root object store implementation
112
+        $config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
113
+
114
+        // mount object storage as root
115
+        \OC\Files\Filesystem::initMountManager();
116
+        if (!self::$rootMounted) {
117
+            \OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/');
118
+            self::$rootMounted = true;
119
+        }
120
+    }
121
+
122
+    /**
123
+     * Can be set up
124
+     *
125
+     * @param string $user
126
+     * @return boolean
127
+     * @description configure the initial filesystem based on the configuration
128
+     */
129
+    public static function setupFS($user = '') {
130
+        //setting up the filesystem twice can only lead to trouble
131
+        if (self::$fsSetup) {
132
+            return false;
133
+        }
134
+
135
+        \OC::$server->getEventLogger()->start('setup_fs', 'Setup filesystem');
136
+
137
+        // If we are not forced to load a specific user we load the one that is logged in
138
+        if ($user === null) {
139
+            $user = '';
140
+        } else if ($user == "" && \OC::$server->getUserSession()->isLoggedIn()) {
141
+            $user = OC_User::getUser();
142
+        }
143
+
144
+        // load all filesystem apps before, so no setup-hook gets lost
145
+        OC_App::loadApps(array('filesystem'));
146
+
147
+        // the filesystem will finish when $user is not empty,
148
+        // mark fs setup here to avoid doing the setup from loading
149
+        // OC_Filesystem
150
+        if ($user != '') {
151
+            self::$fsSetup = true;
152
+        }
153
+
154
+        \OC\Files\Filesystem::initMountManager();
155
+
156
+        \OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(false);
157
+        \OC\Files\Filesystem::addStorageWrapper('mount_options', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
158
+            if ($storage->instanceOfStorage('\OC\Files\Storage\Common')) {
159
+                /** @var \OC\Files\Storage\Common $storage */
160
+                $storage->setMountOptions($mount->getOptions());
161
+            }
162
+            return $storage;
163
+        });
164
+
165
+        \OC\Files\Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
166
+            if (!$mount->getOption('enable_sharing', true)) {
167
+                return new \OC\Files\Storage\Wrapper\PermissionsMask([
168
+                    'storage' => $storage,
169
+                    'mask' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_SHARE
170
+                ]);
171
+            }
172
+            return $storage;
173
+        });
174
+
175
+        // install storage availability wrapper, before most other wrappers
176
+        \OC\Files\Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, $storage) {
177
+            if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
178
+                return new \OC\Files\Storage\Wrapper\Availability(['storage' => $storage]);
179
+            }
180
+            return $storage;
181
+        });
182
+
183
+        // install storage checksum wrapper
184
+        \OC\Files\Filesystem::addStorageWrapper('oc_checksum', function ($mountPoint, \OCP\Files\Storage\IStorage $storage) {
185
+            if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
186
+                return new \OC\Files\Storage\Wrapper\Checksum(['storage' => $storage]);
187
+            }
188
+
189
+            return $storage;
190
+
191
+        }, 1);
192
+
193
+
194
+        \OC\Files\Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
195
+            if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
196
+                return new \OC\Files\Storage\Wrapper\Encoding(['storage' => $storage]);
197
+            }
198
+            return $storage;
199
+        });
200
+
201
+        \OC\Files\Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
202
+            // set up quota for home storages, even for other users
203
+            // which can happen when using sharing
204
+
205
+            /**
206
+             * @var \OC\Files\Storage\Storage $storage
207
+             */
208
+            if ($storage->instanceOfStorage('\OC\Files\Storage\Home')
209
+                || $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage')
210
+            ) {
211
+                /** @var \OC\Files\Storage\Home $storage */
212
+                if (is_object($storage->getUser())) {
213
+                    $user = $storage->getUser()->getUID();
214
+                    $quota = OC_Util::getUserQuota($user);
215
+                    if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
216
+                        return new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => $quota, 'root' => 'files'));
217
+                    }
218
+                }
219
+            }
220
+
221
+            return $storage;
222
+        });
223
+
224
+        OC_Hook::emit('OC_Filesystem', 'preSetup', array('user' => $user));
225
+        \OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(true);
226
+
227
+        //check if we are using an object storage
228
+        $objectStore = \OC::$server->getSystemConfig()->getValue('objectstore', null);
229
+        if (isset($objectStore)) {
230
+            self::initObjectStoreRootFS($objectStore);
231
+        } else {
232
+            self::initLocalStorageRootFS();
233
+        }
234
+
235
+        if ($user != '' && !OCP\User::userExists($user)) {
236
+            \OC::$server->getEventLogger()->end('setup_fs');
237
+            return false;
238
+        }
239
+
240
+        //if we aren't logged in, there is no use to set up the filesystem
241
+        if ($user != "") {
242
+
243
+            $userDir = '/' . $user . '/files';
244
+
245
+            //jail the user into his "home" directory
246
+            \OC\Files\Filesystem::init($user, $userDir);
247
+
248
+            OC_Hook::emit('OC_Filesystem', 'setup', array('user' => $user, 'user_dir' => $userDir));
249
+        }
250
+        \OC::$server->getEventLogger()->end('setup_fs');
251
+        return true;
252
+    }
253
+
254
+    /**
255
+     * check if a password is required for each public link
256
+     *
257
+     * @return boolean
258
+     */
259
+    public static function isPublicLinkPasswordRequired() {
260
+        $appConfig = \OC::$server->getAppConfig();
261
+        $enforcePassword = $appConfig->getValue('core', 'shareapi_enforce_links_password', 'no');
262
+        return ($enforcePassword === 'yes') ? true : false;
263
+    }
264
+
265
+    /**
266
+     * check if sharing is disabled for the current user
267
+     * @param IConfig $config
268
+     * @param IGroupManager $groupManager
269
+     * @param IUser|null $user
270
+     * @return bool
271
+     */
272
+    public static function isSharingDisabledForUser(IConfig $config, IGroupManager $groupManager, $user) {
273
+        if ($config->getAppValue('core', 'shareapi_exclude_groups', 'no') === 'yes') {
274
+            $groupsList = $config->getAppValue('core', 'shareapi_exclude_groups_list', '');
275
+            $excludedGroups = json_decode($groupsList);
276
+            if (is_null($excludedGroups)) {
277
+                $excludedGroups = explode(',', $groupsList);
278
+                $newValue = json_encode($excludedGroups);
279
+                $config->setAppValue('core', 'shareapi_exclude_groups_list', $newValue);
280
+            }
281
+            $usersGroups = $groupManager->getUserGroupIds($user);
282
+            if (!empty($usersGroups)) {
283
+                $remainingGroups = array_diff($usersGroups, $excludedGroups);
284
+                // if the user is only in groups which are disabled for sharing then
285
+                // sharing is also disabled for the user
286
+                if (empty($remainingGroups)) {
287
+                    return true;
288
+                }
289
+            }
290
+        }
291
+        return false;
292
+    }
293
+
294
+    /**
295
+     * check if share API enforces a default expire date
296
+     *
297
+     * @return boolean
298
+     */
299
+    public static function isDefaultExpireDateEnforced() {
300
+        $isDefaultExpireDateEnabled = \OCP\Config::getAppValue('core', 'shareapi_default_expire_date', 'no');
301
+        $enforceDefaultExpireDate = false;
302
+        if ($isDefaultExpireDateEnabled === 'yes') {
303
+            $value = \OCP\Config::getAppValue('core', 'shareapi_enforce_expire_date', 'no');
304
+            $enforceDefaultExpireDate = ($value === 'yes') ? true : false;
305
+        }
306
+
307
+        return $enforceDefaultExpireDate;
308
+    }
309
+
310
+    /**
311
+     * Get the quota of a user
312
+     *
313
+     * @param string $userId
314
+     * @return int Quota bytes
315
+     */
316
+    public static function getUserQuota($userId) {
317
+        $user = \OC::$server->getUserManager()->get($userId);
318
+        if (is_null($user)) {
319
+            return \OCP\Files\FileInfo::SPACE_UNLIMITED;
320
+        }
321
+        $userQuota = $user->getQuota();
322
+        if($userQuota === 'none') {
323
+            return \OCP\Files\FileInfo::SPACE_UNLIMITED;
324
+        }
325
+        return OC_Helper::computerFileSize($userQuota);
326
+    }
327
+
328
+    /**
329
+     * copies the skeleton to the users /files
330
+     *
331
+     * @param String $userId
332
+     * @param \OCP\Files\Folder $userDirectory
333
+     * @throws \RuntimeException
334
+     */
335
+    public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
336
+
337
+        $skeletonDirectory = \OC::$server->getConfig()->getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
338
+        $instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', '');
339
+
340
+        if ($instanceId === null) {
341
+            throw new \RuntimeException('no instance id!');
342
+        }
343
+        $appdata = 'appdata_' . $instanceId;
344
+        if ($userId === $appdata) {
345
+            throw new \RuntimeException('username is reserved name: ' . $appdata);
346
+        }
347
+
348
+        if (!empty($skeletonDirectory)) {
349
+            \OCP\Util::writeLog(
350
+                'files_skeleton',
351
+                'copying skeleton for '.$userId.' from '.$skeletonDirectory.' to '.$userDirectory->getFullPath('/'),
352
+                \OCP\Util::DEBUG
353
+            );
354
+            self::copyr($skeletonDirectory, $userDirectory);
355
+            // update the file cache
356
+            $userDirectory->getStorage()->getScanner()->scan('', \OC\Files\Cache\Scanner::SCAN_RECURSIVE);
357
+        }
358
+    }
359
+
360
+    /**
361
+     * copies a directory recursively by using streams
362
+     *
363
+     * @param string $source
364
+     * @param \OCP\Files\Folder $target
365
+     * @return void
366
+     */
367
+    public static function copyr($source, \OCP\Files\Folder $target) {
368
+        $logger = \OC::$server->getLogger();
369
+
370
+        // Verify if folder exists
371
+        $dir = opendir($source);
372
+        if($dir === false) {
373
+            $logger->error(sprintf('Could not opendir "%s"', $source), ['app' => 'core']);
374
+            return;
375
+        }
376
+
377
+        // Copy the files
378
+        while (false !== ($file = readdir($dir))) {
379
+            if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
380
+                if (is_dir($source . '/' . $file)) {
381
+                    $child = $target->newFolder($file);
382
+                    self::copyr($source . '/' . $file, $child);
383
+                } else {
384
+                    $child = $target->newFile($file);
385
+                    $sourceStream = fopen($source . '/' . $file, 'r');
386
+                    if($sourceStream === false) {
387
+                        $logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
388
+                        closedir($dir);
389
+                        return;
390
+                    }
391
+                    stream_copy_to_stream($sourceStream, $child->fopen('w'));
392
+                }
393
+            }
394
+        }
395
+        closedir($dir);
396
+    }
397
+
398
+    /**
399
+     * @return void
400
+     */
401
+    public static function tearDownFS() {
402
+        \OC\Files\Filesystem::tearDown();
403
+        \OC::$server->getRootFolder()->clearCache();
404
+        self::$fsSetup = false;
405
+        self::$rootMounted = false;
406
+    }
407
+
408
+    /**
409
+     * get the current installed version of ownCloud
410
+     *
411
+     * @return array
412
+     */
413
+    public static function getVersion() {
414
+        OC_Util::loadVersion();
415
+        return self::$versionCache['OC_Version'];
416
+    }
417
+
418
+    /**
419
+     * get the current installed version string of ownCloud
420
+     *
421
+     * @return string
422
+     */
423
+    public static function getVersionString() {
424
+        OC_Util::loadVersion();
425
+        return self::$versionCache['OC_VersionString'];
426
+    }
427
+
428
+    /**
429
+     * @deprecated the value is of no use anymore
430
+     * @return string
431
+     */
432
+    public static function getEditionString() {
433
+        return '';
434
+    }
435
+
436
+    /**
437
+     * @description get the update channel of the current installed of ownCloud.
438
+     * @return string
439
+     */
440
+    public static function getChannel() {
441
+        OC_Util::loadVersion();
442
+        return \OC::$server->getConfig()->getSystemValue('updater.release.channel', self::$versionCache['OC_Channel']);
443
+    }
444
+
445
+    /**
446
+     * @description get the build number of the current installed of ownCloud.
447
+     * @return string
448
+     */
449
+    public static function getBuild() {
450
+        OC_Util::loadVersion();
451
+        return self::$versionCache['OC_Build'];
452
+    }
453
+
454
+    /**
455
+     * @description load the version.php into the session as cache
456
+     */
457
+    private static function loadVersion() {
458
+        if (self::$versionCache !== null) {
459
+            return;
460
+        }
461
+
462
+        $timestamp = filemtime(OC::$SERVERROOT . '/version.php');
463
+        require OC::$SERVERROOT . '/version.php';
464
+        /** @var $timestamp int */
465
+        self::$versionCache['OC_Version_Timestamp'] = $timestamp;
466
+        /** @var $OC_Version string */
467
+        self::$versionCache['OC_Version'] = $OC_Version;
468
+        /** @var $OC_VersionString string */
469
+        self::$versionCache['OC_VersionString'] = $OC_VersionString;
470
+        /** @var $OC_Build string */
471
+        self::$versionCache['OC_Build'] = $OC_Build;
472
+
473
+        /** @var $OC_Channel string */
474
+        self::$versionCache['OC_Channel'] = $OC_Channel;
475
+    }
476
+
477
+    /**
478
+     * generates a path for JS/CSS files. If no application is provided it will create the path for core.
479
+     *
480
+     * @param string $application application to get the files from
481
+     * @param string $directory directory within this application (css, js, vendor, etc)
482
+     * @param string $file the file inside of the above folder
483
+     * @return string the path
484
+     */
485
+    private static function generatePath($application, $directory, $file) {
486
+        if (is_null($file)) {
487
+            $file = $application;
488
+            $application = "";
489
+        }
490
+        if (!empty($application)) {
491
+            return "$application/$directory/$file";
492
+        } else {
493
+            return "$directory/$file";
494
+        }
495
+    }
496
+
497
+    /**
498
+     * add a javascript file
499
+     *
500
+     * @param string $application application id
501
+     * @param string|null $file filename
502
+     * @param bool $prepend prepend the Script to the beginning of the list
503
+     * @return void
504
+     */
505
+    public static function addScript($application, $file = null, $prepend = false) {
506
+        $path = OC_Util::generatePath($application, 'js', $file);
507
+
508
+        // core js files need separate handling
509
+        if ($application !== 'core' && $file !== null) {
510
+            self::addTranslations ( $application );
511
+        }
512
+        self::addExternalResource($application, $prepend, $path, "script");
513
+    }
514
+
515
+    /**
516
+     * add a javascript file from the vendor sub folder
517
+     *
518
+     * @param string $application application id
519
+     * @param string|null $file filename
520
+     * @param bool $prepend prepend the Script to the beginning of the list
521
+     * @return void
522
+     */
523
+    public static function addVendorScript($application, $file = null, $prepend = false) {
524
+        $path = OC_Util::generatePath($application, 'vendor', $file);
525
+        self::addExternalResource($application, $prepend, $path, "script");
526
+    }
527
+
528
+    /**
529
+     * add a translation JS file
530
+     *
531
+     * @param string $application application id
532
+     * @param string $languageCode language code, defaults to the current language
533
+     * @param bool $prepend prepend the Script to the beginning of the list
534
+     */
535
+    public static function addTranslations($application, $languageCode = null, $prepend = false) {
536
+        if (is_null($languageCode)) {
537
+            $languageCode = \OC::$server->getL10NFactory()->findLanguage($application);
538
+        }
539
+        if (!empty($application)) {
540
+            $path = "$application/l10n/$languageCode";
541
+        } else {
542
+            $path = "l10n/$languageCode";
543
+        }
544
+        self::addExternalResource($application, $prepend, $path, "script");
545
+    }
546
+
547
+    /**
548
+     * add a css file
549
+     *
550
+     * @param string $application application id
551
+     * @param string|null $file filename
552
+     * @param bool $prepend prepend the Style to the beginning of the list
553
+     * @return void
554
+     */
555
+    public static function addStyle($application, $file = null, $prepend = false) {
556
+        $path = OC_Util::generatePath($application, 'css', $file);
557
+        self::addExternalResource($application, $prepend, $path, "style");
558
+    }
559
+
560
+    /**
561
+     * add a css file from the vendor sub folder
562
+     *
563
+     * @param string $application application id
564
+     * @param string|null $file filename
565
+     * @param bool $prepend prepend the Style to the beginning of the list
566
+     * @return void
567
+     */
568
+    public static function addVendorStyle($application, $file = null, $prepend = false) {
569
+        $path = OC_Util::generatePath($application, 'vendor', $file);
570
+        self::addExternalResource($application, $prepend, $path, "style");
571
+    }
572
+
573
+    /**
574
+     * add an external resource css/js file
575
+     *
576
+     * @param string $application application id
577
+     * @param bool $prepend prepend the file to the beginning of the list
578
+     * @param string $path
579
+     * @param string $type (script or style)
580
+     * @return void
581
+     */
582
+    private static function addExternalResource($application, $prepend, $path, $type = "script") {
583
+
584
+        if ($type === "style") {
585
+            if (!in_array($path, self::$styles)) {
586
+                if ($prepend === true) {
587
+                    array_unshift ( self::$styles, $path );
588
+                } else {
589
+                    self::$styles[] = $path;
590
+                }
591
+            }
592
+        } elseif ($type === "script") {
593
+            if (!in_array($path, self::$scripts)) {
594
+                if ($prepend === true) {
595
+                    array_unshift ( self::$scripts, $path );
596
+                } else {
597
+                    self::$scripts [] = $path;
598
+                }
599
+            }
600
+        }
601
+    }
602
+
603
+    /**
604
+     * Add a custom element to the header
605
+     * If $text is null then the element will be written as empty element.
606
+     * So use "" to get a closing tag.
607
+     * @param string $tag tag name of the element
608
+     * @param array $attributes array of attributes for the element
609
+     * @param string $text the text content for the element
610
+     */
611
+    public static function addHeader($tag, $attributes, $text=null) {
612
+        self::$headers[] = array(
613
+            'tag' => $tag,
614
+            'attributes' => $attributes,
615
+            'text' => $text
616
+        );
617
+    }
618
+
619
+    /**
620
+     * formats a timestamp in the "right" way
621
+     *
622
+     * @param int $timestamp
623
+     * @param bool $dateOnly option to omit time from the result
624
+     * @param DateTimeZone|string $timeZone where the given timestamp shall be converted to
625
+     * @return string timestamp
626
+     *
627
+     * @deprecated Use \OC::$server->query('DateTimeFormatter') instead
628
+     */
629
+    public static function formatDate($timestamp, $dateOnly = false, $timeZone = null) {
630
+        if ($timeZone !== null && !$timeZone instanceof \DateTimeZone) {
631
+            $timeZone = new \DateTimeZone($timeZone);
632
+        }
633
+
634
+        /** @var \OC\DateTimeFormatter $formatter */
635
+        $formatter = \OC::$server->query('DateTimeFormatter');
636
+        if ($dateOnly) {
637
+            return $formatter->formatDate($timestamp, 'long', $timeZone);
638
+        }
639
+        return $formatter->formatDateTime($timestamp, 'long', 'long', $timeZone);
640
+    }
641
+
642
+    /**
643
+     * check if the current server configuration is suitable for ownCloud
644
+     *
645
+     * @param \OC\SystemConfig $config
646
+     * @return array arrays with error messages and hints
647
+     */
648
+    public static function checkServer(\OC\SystemConfig $config) {
649
+        $l = \OC::$server->getL10N('lib');
650
+        $errors = array();
651
+        $CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT . '/data');
652
+
653
+        if (!self::needUpgrade($config) && $config->getValue('installed', false)) {
654
+            // this check needs to be done every time
655
+            $errors = self::checkDataDirectoryValidity($CONFIG_DATADIRECTORY);
656
+        }
657
+
658
+        // Assume that if checkServer() succeeded before in this session, then all is fine.
659
+        if (\OC::$server->getSession()->exists('checkServer_succeeded') && \OC::$server->getSession()->get('checkServer_succeeded')) {
660
+            return $errors;
661
+        }
662
+
663
+        $webServerRestart = false;
664
+        $setup = new \OC\Setup($config, \OC::$server->getIniWrapper(), \OC::$server->getL10N('lib'),
665
+            \OC::$server->query(\OCP\Defaults::class), \OC::$server->getLogger(), \OC::$server->getSecureRandom());
666
+
667
+        $urlGenerator = \OC::$server->getURLGenerator();
668
+
669
+        $availableDatabases = $setup->getSupportedDatabases();
670
+        if (empty($availableDatabases)) {
671
+            $errors[] = array(
672
+                'error' => $l->t('No database drivers (sqlite, mysql, or postgresql) installed.'),
673
+                'hint' => '' //TODO: sane hint
674
+            );
675
+            $webServerRestart = true;
676
+        }
677
+
678
+        // Check if config folder is writable.
679
+        if(!OC_Helper::isReadOnlyConfigEnabled()) {
680
+            if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
681
+                $errors[] = array(
682
+                    'error' => $l->t('Cannot write into "config" directory'),
683
+                    'hint' => $l->t('This can usually be fixed by '
684
+                        . '%sgiving the webserver write access to the config directory%s.',
685
+                        array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>'))
686
+                );
687
+            }
688
+        }
689
+
690
+        // Check if there is a writable install folder.
691
+        if ($config->getValue('appstoreenabled', true)) {
692
+            if (OC_App::getInstallPath() === null
693
+                || !is_writable(OC_App::getInstallPath())
694
+                || !is_readable(OC_App::getInstallPath())
695
+            ) {
696
+                $errors[] = array(
697
+                    'error' => $l->t('Cannot write into "apps" directory'),
698
+                    'hint' => $l->t('This can usually be fixed by '
699
+                        . '%sgiving the webserver write access to the apps directory%s'
700
+                        . ' or disabling the appstore in the config file.',
701
+                        array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>'))
702
+                );
703
+            }
704
+        }
705
+        // Create root dir.
706
+        if ($config->getValue('installed', false)) {
707
+            if (!is_dir($CONFIG_DATADIRECTORY)) {
708
+                $success = @mkdir($CONFIG_DATADIRECTORY);
709
+                if ($success) {
710
+                    $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
711
+                } else {
712
+                    $errors[] = [
713
+                        'error' => $l->t('Cannot create "data" directory'),
714
+                        'hint' => $l->t('This can usually be fixed by '
715
+                            . '<a href="%s" target="_blank" rel="noreferrer">giving the webserver write access to the root directory</a>.',
716
+                            [$urlGenerator->linkToDocs('admin-dir_permissions')])
717
+                    ];
718
+                }
719
+            } else if (!is_writable($CONFIG_DATADIRECTORY) or !is_readable($CONFIG_DATADIRECTORY)) {
720
+                //common hint for all file permissions error messages
721
+                $permissionsHint = $l->t('Permissions can usually be fixed by '
722
+                    . '%sgiving the webserver write access to the root directory%s.',
723
+                    ['<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>']);
724
+                $errors[] = [
725
+                    'error' => 'Your data directory is not writable',
726
+                    'hint' => $permissionsHint
727
+                ];
728
+            } else {
729
+                $errors = array_merge($errors, self::checkDataDirectoryPermissions($CONFIG_DATADIRECTORY));
730
+            }
731
+        }
732
+
733
+        if (!OC_Util::isSetLocaleWorking()) {
734
+            $errors[] = array(
735
+                'error' => $l->t('Setting locale to %s failed',
736
+                    array('en_US.UTF-8/fr_FR.UTF-8/es_ES.UTF-8/de_DE.UTF-8/ru_RU.UTF-8/'
737
+                        . 'pt_BR.UTF-8/it_IT.UTF-8/ja_JP.UTF-8/zh_CN.UTF-8')),
738
+                'hint' => $l->t('Please install one of these locales on your system and restart your webserver.')
739
+            );
740
+        }
741
+
742
+        // Contains the dependencies that should be checked against
743
+        // classes = class_exists
744
+        // functions = function_exists
745
+        // defined = defined
746
+        // ini = ini_get
747
+        // If the dependency is not found the missing module name is shown to the EndUser
748
+        // When adding new checks always verify that they pass on Travis as well
749
+        // for ini settings, see https://github.com/owncloud/administration/blob/master/travis-ci/custom.ini
750
+        $dependencies = array(
751
+            'classes' => array(
752
+                'ZipArchive' => 'zip',
753
+                'DOMDocument' => 'dom',
754
+                'XMLWriter' => 'XMLWriter',
755
+                'XMLReader' => 'XMLReader',
756
+            ),
757
+            'functions' => [
758
+                'xml_parser_create' => 'libxml',
759
+                'mb_strcut' => 'mb multibyte',
760
+                'ctype_digit' => 'ctype',
761
+                'json_encode' => 'JSON',
762
+                'gd_info' => 'GD',
763
+                'gzencode' => 'zlib',
764
+                'iconv' => 'iconv',
765
+                'simplexml_load_string' => 'SimpleXML',
766
+                'hash' => 'HASH Message Digest Framework',
767
+                'curl_init' => 'cURL',
768
+                'openssl_verify' => 'OpenSSL',
769
+            ],
770
+            'defined' => array(
771
+                'PDO::ATTR_DRIVER_NAME' => 'PDO'
772
+            ),
773
+            'ini' => [
774
+                'default_charset' => 'UTF-8',
775
+            ],
776
+        );
777
+        $missingDependencies = array();
778
+        $invalidIniSettings = [];
779
+        $moduleHint = $l->t('Please ask your server administrator to install the module.');
780
+
781
+        /**
782
+         * FIXME: The dependency check does not work properly on HHVM on the moment
783
+         *        and prevents installation. Once HHVM is more compatible with our
784
+         *        approach to check for these values we should re-enable those
785
+         *        checks.
786
+         */
787
+        $iniWrapper = \OC::$server->getIniWrapper();
788
+        if (!self::runningOnHhvm()) {
789
+            foreach ($dependencies['classes'] as $class => $module) {
790
+                if (!class_exists($class)) {
791
+                    $missingDependencies[] = $module;
792
+                }
793
+            }
794
+            foreach ($dependencies['functions'] as $function => $module) {
795
+                if (!function_exists($function)) {
796
+                    $missingDependencies[] = $module;
797
+                }
798
+            }
799
+            foreach ($dependencies['defined'] as $defined => $module) {
800
+                if (!defined($defined)) {
801
+                    $missingDependencies[] = $module;
802
+                }
803
+            }
804
+            foreach ($dependencies['ini'] as $setting => $expected) {
805
+                if (is_bool($expected)) {
806
+                    if ($iniWrapper->getBool($setting) !== $expected) {
807
+                        $invalidIniSettings[] = [$setting, $expected];
808
+                    }
809
+                }
810
+                if (is_int($expected)) {
811
+                    if ($iniWrapper->getNumeric($setting) !== $expected) {
812
+                        $invalidIniSettings[] = [$setting, $expected];
813
+                    }
814
+                }
815
+                if (is_string($expected)) {
816
+                    if (strtolower($iniWrapper->getString($setting)) !== strtolower($expected)) {
817
+                        $invalidIniSettings[] = [$setting, $expected];
818
+                    }
819
+                }
820
+            }
821
+        }
822
+
823
+        foreach($missingDependencies as $missingDependency) {
824
+            $errors[] = array(
825
+                'error' => $l->t('PHP module %s not installed.', array($missingDependency)),
826
+                'hint' => $moduleHint
827
+            );
828
+            $webServerRestart = true;
829
+        }
830
+        foreach($invalidIniSettings as $setting) {
831
+            if(is_bool($setting[1])) {
832
+                $setting[1] = ($setting[1]) ? 'on' : 'off';
833
+            }
834
+            $errors[] = [
835
+                'error' => $l->t('PHP setting "%s" is not set to "%s".', [$setting[0], var_export($setting[1], true)]),
836
+                'hint' =>  $l->t('Adjusting this setting in php.ini will make Nextcloud run again')
837
+            ];
838
+            $webServerRestart = true;
839
+        }
840
+
841
+        /**
842
+         * The mbstring.func_overload check can only be performed if the mbstring
843
+         * module is installed as it will return null if the checking setting is
844
+         * not available and thus a check on the boolean value fails.
845
+         *
846
+         * TODO: Should probably be implemented in the above generic dependency
847
+         *       check somehow in the long-term.
848
+         */
849
+        if($iniWrapper->getBool('mbstring.func_overload') !== null &&
850
+            $iniWrapper->getBool('mbstring.func_overload') === true) {
851
+            $errors[] = array(
852
+                'error' => $l->t('mbstring.func_overload is set to "%s" instead of the expected value "0"', [$iniWrapper->getString('mbstring.func_overload')]),
853
+                'hint' => $l->t('To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini')
854
+            );
855
+        }
856
+
857
+        if(function_exists('xml_parser_create') &&
858
+            LIBXML_LOADED_VERSION < 20700 ) {
859
+            $version = LIBXML_LOADED_VERSION;
860
+            $major = floor($version/10000);
861
+            $version -= ($major * 10000);
862
+            $minor = floor($version/100);
863
+            $version -= ($minor * 100);
864
+            $patch = $version;
865
+            $errors[] = array(
866
+                'error' => $l->t('libxml2 2.7.0 is at least required. Currently %s is installed.', [$major . '.' . $minor . '.' . $patch]),
867
+                'hint' => $l->t('To fix this issue update your libxml2 version and restart your web server.')
868
+            );
869
+        }
870
+
871
+        if (!self::isAnnotationsWorking()) {
872
+            $errors[] = array(
873
+                'error' => $l->t('PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible.'),
874
+                'hint' => $l->t('This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator.')
875
+            );
876
+        }
877
+
878
+        if (!\OC::$CLI && $webServerRestart) {
879
+            $errors[] = array(
880
+                'error' => $l->t('PHP modules have been installed, but they are still listed as missing?'),
881
+                'hint' => $l->t('Please ask your server administrator to restart the web server.')
882
+            );
883
+        }
884
+
885
+        $errors = array_merge($errors, self::checkDatabaseVersion());
886
+
887
+        // Cache the result of this function
888
+        \OC::$server->getSession()->set('checkServer_succeeded', count($errors) == 0);
889
+
890
+        return $errors;
891
+    }
892
+
893
+    /**
894
+     * Check the database version
895
+     *
896
+     * @return array errors array
897
+     */
898
+    public static function checkDatabaseVersion() {
899
+        $l = \OC::$server->getL10N('lib');
900
+        $errors = array();
901
+        $dbType = \OC::$server->getSystemConfig()->getValue('dbtype', 'sqlite');
902
+        if ($dbType === 'pgsql') {
903
+            // check PostgreSQL version
904
+            try {
905
+                $result = \OC_DB::executeAudited('SHOW SERVER_VERSION');
906
+                $data = $result->fetchRow();
907
+                if (isset($data['server_version'])) {
908
+                    $version = $data['server_version'];
909
+                    if (version_compare($version, '9.0.0', '<')) {
910
+                        $errors[] = array(
911
+                            'error' => $l->t('PostgreSQL >= 9 required'),
912
+                            'hint' => $l->t('Please upgrade your database version')
913
+                        );
914
+                    }
915
+                }
916
+            } catch (\Doctrine\DBAL\DBALException $e) {
917
+                $logger = \OC::$server->getLogger();
918
+                $logger->warning('Error occurred while checking PostgreSQL version, assuming >= 9');
919
+                $logger->logException($e);
920
+            }
921
+        }
922
+        return $errors;
923
+    }
924
+
925
+    /**
926
+     * Check for correct file permissions of data directory
927
+     *
928
+     * @param string $dataDirectory
929
+     * @return array arrays with error messages and hints
930
+     */
931
+    public static function checkDataDirectoryPermissions($dataDirectory) {
932
+        $l = \OC::$server->getL10N('lib');
933
+        $errors = array();
934
+        $permissionsModHint = $l->t('Please change the permissions to 0770 so that the directory'
935
+            . ' cannot be listed by other users.');
936
+        $perms = substr(decoct(@fileperms($dataDirectory)), -3);
937
+        if (substr($perms, -1) !== '0') {
938
+            chmod($dataDirectory, 0770);
939
+            clearstatcache();
940
+            $perms = substr(decoct(@fileperms($dataDirectory)), -3);
941
+            if ($perms[2] !== '0') {
942
+                $errors[] = [
943
+                    'error' => $l->t('Your data directory is readable by other users'),
944
+                    'hint' => $permissionsModHint
945
+                ];
946
+            }
947
+        }
948
+        return $errors;
949
+    }
950
+
951
+    /**
952
+     * Check that the data directory exists and is valid by
953
+     * checking the existence of the ".ocdata" file.
954
+     *
955
+     * @param string $dataDirectory data directory path
956
+     * @return array errors found
957
+     */
958
+    public static function checkDataDirectoryValidity($dataDirectory) {
959
+        $l = \OC::$server->getL10N('lib');
960
+        $errors = [];
961
+        if ($dataDirectory[0] !== '/') {
962
+            $errors[] = [
963
+                'error' => $l->t('Your data directory must be an absolute path'),
964
+                'hint' => $l->t('Check the value of "datadirectory" in your configuration')
965
+            ];
966
+        }
967
+        if (!file_exists($dataDirectory . '/.ocdata')) {
968
+            $errors[] = [
969
+                'error' => $l->t('Your data directory is invalid'),
970
+                'hint' => $l->t('Please check that the data directory contains a file' .
971
+                    ' ".ocdata" in its root.')
972
+            ];
973
+        }
974
+        return $errors;
975
+    }
976
+
977
+    /**
978
+     * Check if the user is logged in, redirects to home if not. With
979
+     * redirect URL parameter to the request URI.
980
+     *
981
+     * @return void
982
+     */
983
+    public static function checkLoggedIn() {
984
+        // Check if we are a user
985
+        if (!\OC::$server->getUserSession()->isLoggedIn()) {
986
+            header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
987
+                        'core.login.showLoginForm',
988
+                        [
989
+                            'redirect_url' => \OC::$server->getRequest()->getRequestUri(),
990
+                        ]
991
+                    )
992
+            );
993
+            exit();
994
+        }
995
+        // Redirect to 2FA challenge selection if 2FA challenge was not solved yet
996
+        if (\OC::$server->getTwoFactorAuthManager()->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
997
+            header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
998
+            exit();
999
+        }
1000
+    }
1001
+
1002
+    /**
1003
+     * Check if the user is a admin, redirects to home if not
1004
+     *
1005
+     * @return void
1006
+     */
1007
+    public static function checkAdminUser() {
1008
+        OC_Util::checkLoggedIn();
1009
+        if (!OC_User::isAdminUser(OC_User::getUser())) {
1010
+            header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
1011
+            exit();
1012
+        }
1013
+    }
1014
+
1015
+    /**
1016
+     * Check if the user is a subadmin, redirects to home if not
1017
+     *
1018
+     * @return null|boolean $groups where the current user is subadmin
1019
+     */
1020
+    public static function checkSubAdminUser() {
1021
+        OC_Util::checkLoggedIn();
1022
+        $userObject = \OC::$server->getUserSession()->getUser();
1023
+        $isSubAdmin = false;
1024
+        if($userObject !== null) {
1025
+            $isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
1026
+        }
1027
+
1028
+        if (!$isSubAdmin) {
1029
+            header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
1030
+            exit();
1031
+        }
1032
+        return true;
1033
+    }
1034
+
1035
+    /**
1036
+     * Returns the URL of the default page
1037
+     * based on the system configuration and
1038
+     * the apps visible for the current user
1039
+     *
1040
+     * @return string URL
1041
+     */
1042
+    public static function getDefaultPageUrl() {
1043
+        $urlGenerator = \OC::$server->getURLGenerator();
1044
+        // Deny the redirect if the URL contains a @
1045
+        // This prevents unvalidated redirects like ?redirect_url=:[email protected]
1046
+        if (isset($_REQUEST['redirect_url']) && strpos($_REQUEST['redirect_url'], '@') === false) {
1047
+            $location = $urlGenerator->getAbsoluteURL(urldecode($_REQUEST['redirect_url']));
1048
+        } else {
1049
+            $defaultPage = \OC::$server->getAppConfig()->getValue('core', 'defaultpage');
1050
+            if ($defaultPage) {
1051
+                $location = $urlGenerator->getAbsoluteURL($defaultPage);
1052
+            } else {
1053
+                $appId = 'files';
1054
+                $defaultApps = explode(',', \OCP\Config::getSystemValue('defaultapp', 'files'));
1055
+                // find the first app that is enabled for the current user
1056
+                foreach ($defaultApps as $defaultApp) {
1057
+                    $defaultApp = OC_App::cleanAppId(strip_tags($defaultApp));
1058
+                    if (static::getAppManager()->isEnabledForUser($defaultApp)) {
1059
+                        $appId = $defaultApp;
1060
+                        break;
1061
+                    }
1062
+                }
1063
+
1064
+                if(\OC::$server->getConfig()->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true') {
1065
+                    $location = $urlGenerator->getAbsoluteURL('/apps/' . $appId . '/');
1066
+                } else {
1067
+                    $location = $urlGenerator->getAbsoluteURL('/index.php/apps/' . $appId . '/');
1068
+                }
1069
+            }
1070
+        }
1071
+        return $location;
1072
+    }
1073
+
1074
+    /**
1075
+     * Redirect to the user default page
1076
+     *
1077
+     * @return void
1078
+     */
1079
+    public static function redirectToDefaultPage() {
1080
+        $location = self::getDefaultPageUrl();
1081
+        header('Location: ' . $location);
1082
+        exit();
1083
+    }
1084
+
1085
+    /**
1086
+     * get an id unique for this instance
1087
+     *
1088
+     * @return string
1089
+     */
1090
+    public static function getInstanceId() {
1091
+        $id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
1092
+        if (is_null($id)) {
1093
+            // We need to guarantee at least one letter in instanceid so it can be used as the session_name
1094
+            $id = 'oc' . \OC::$server->getSecureRandom()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
1095
+            \OC::$server->getSystemConfig()->setValue('instanceid', $id);
1096
+        }
1097
+        return $id;
1098
+    }
1099
+
1100
+    /**
1101
+     * Public function to sanitize HTML
1102
+     *
1103
+     * This function is used to sanitize HTML and should be applied on any
1104
+     * string or array of strings before displaying it on a web page.
1105
+     *
1106
+     * @param string|array $value
1107
+     * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter.
1108
+     */
1109
+    public static function sanitizeHTML($value) {
1110
+        if (is_array($value)) {
1111
+            $value = array_map(function($value) {
1112
+                return self::sanitizeHTML($value);
1113
+            }, $value);
1114
+        } else {
1115
+            // Specify encoding for PHP<5.4
1116
+            $value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
1117
+        }
1118
+        return $value;
1119
+    }
1120
+
1121
+    /**
1122
+     * Public function to encode url parameters
1123
+     *
1124
+     * This function is used to encode path to file before output.
1125
+     * Encoding is done according to RFC 3986 with one exception:
1126
+     * Character '/' is preserved as is.
1127
+     *
1128
+     * @param string $component part of URI to encode
1129
+     * @return string
1130
+     */
1131
+    public static function encodePath($component) {
1132
+        $encoded = rawurlencode($component);
1133
+        $encoded = str_replace('%2F', '/', $encoded);
1134
+        return $encoded;
1135
+    }
1136
+
1137
+
1138
+    public function createHtaccessTestFile(\OCP\IConfig $config) {
1139
+        // php dev server does not support htaccess
1140
+        if (php_sapi_name() === 'cli-server') {
1141
+            return false;
1142
+        }
1143
+
1144
+        // testdata
1145
+        $fileName = '/htaccesstest.txt';
1146
+        $testContent = 'This is used for testing whether htaccess is properly enabled to disallow access from the outside. This file can be safely removed.';
1147
+
1148
+        // creating a test file
1149
+        $testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1150
+
1151
+        if (file_exists($testFile)) {// already running this test, possible recursive call
1152
+            return false;
1153
+        }
1154
+
1155
+        $fp = @fopen($testFile, 'w');
1156
+        if (!$fp) {
1157
+            throw new OC\HintException('Can\'t create test file to check for working .htaccess file.',
1158
+                'Make sure it is possible for the webserver to write to ' . $testFile);
1159
+        }
1160
+        fwrite($fp, $testContent);
1161
+        fclose($fp);
1162
+
1163
+        return $testContent;
1164
+    }
1165
+
1166
+    /**
1167
+     * Check if the .htaccess file is working
1168
+     * @param \OCP\IConfig $config
1169
+     * @return bool
1170
+     * @throws Exception
1171
+     * @throws \OC\HintException If the test file can't get written.
1172
+     */
1173
+    public function isHtaccessWorking(\OCP\IConfig $config) {
1174
+
1175
+        if (\OC::$CLI || !$config->getSystemValue('check_for_working_htaccess', true)) {
1176
+            return true;
1177
+        }
1178
+
1179
+        $testContent = $this->createHtaccessTestFile($config);
1180
+        if ($testContent === false) {
1181
+            return false;
1182
+        }
1183
+
1184
+        $fileName = '/htaccesstest.txt';
1185
+        $testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1186
+
1187
+        // accessing the file via http
1188
+        $url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
1189
+        try {
1190
+            $content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1191
+        } catch (\Exception $e) {
1192
+            $content = false;
1193
+        }
1194
+
1195
+        // cleanup
1196
+        @unlink($testFile);
1197
+
1198
+        /*
1199 1199
 		 * If the content is not equal to test content our .htaccess
1200 1200
 		 * is working as required
1201 1201
 		 */
1202
-		return $content !== $testContent;
1203
-	}
1204
-
1205
-	/**
1206
-	 * Check if the setlocal call does not work. This can happen if the right
1207
-	 * local packages are not available on the server.
1208
-	 *
1209
-	 * @return bool
1210
-	 */
1211
-	public static function isSetLocaleWorking() {
1212
-		\Patchwork\Utf8\Bootup::initLocale();
1213
-		if ('' === basename('§')) {
1214
-			return false;
1215
-		}
1216
-		return true;
1217
-	}
1218
-
1219
-	/**
1220
-	 * Check if it's possible to get the inline annotations
1221
-	 *
1222
-	 * @return bool
1223
-	 */
1224
-	public static function isAnnotationsWorking() {
1225
-		$reflection = new \ReflectionMethod(__METHOD__);
1226
-		$docs = $reflection->getDocComment();
1227
-
1228
-		return (is_string($docs) && strlen($docs) > 50);
1229
-	}
1230
-
1231
-	/**
1232
-	 * Check if the PHP module fileinfo is loaded.
1233
-	 *
1234
-	 * @return bool
1235
-	 */
1236
-	public static function fileInfoLoaded() {
1237
-		return function_exists('finfo_open');
1238
-	}
1239
-
1240
-	/**
1241
-	 * clear all levels of output buffering
1242
-	 *
1243
-	 * @return void
1244
-	 */
1245
-	public static function obEnd() {
1246
-		while (ob_get_level()) {
1247
-			ob_end_clean();
1248
-		}
1249
-	}
1250
-
1251
-	/**
1252
-	 * Checks whether the server is running on Mac OS X
1253
-	 *
1254
-	 * @return bool true if running on Mac OS X, false otherwise
1255
-	 */
1256
-	public static function runningOnMac() {
1257
-		return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
1258
-	}
1259
-
1260
-	/**
1261
-	 * Checks whether server is running on HHVM
1262
-	 *
1263
-	 * @return bool True if running on HHVM, false otherwise
1264
-	 */
1265
-	public static function runningOnHhvm() {
1266
-		return defined('HHVM_VERSION');
1267
-	}
1268
-
1269
-	/**
1270
-	 * Handles the case that there may not be a theme, then check if a "default"
1271
-	 * theme exists and take that one
1272
-	 *
1273
-	 * @return string the theme
1274
-	 */
1275
-	public static function getTheme() {
1276
-		$theme = \OC::$server->getSystemConfig()->getValue("theme", '');
1277
-
1278
-		if ($theme === '') {
1279
-			if (is_dir(OC::$SERVERROOT . '/themes/default')) {
1280
-				$theme = 'default';
1281
-			}
1282
-		}
1283
-
1284
-		return $theme;
1285
-	}
1286
-
1287
-	/**
1288
-	 * Clear a single file from the opcode cache
1289
-	 * This is useful for writing to the config file
1290
-	 * in case the opcode cache does not re-validate files
1291
-	 * Returns true if successful, false if unsuccessful:
1292
-	 * caller should fall back on clearing the entire cache
1293
-	 * with clearOpcodeCache() if unsuccessful
1294
-	 *
1295
-	 * @param string $path the path of the file to clear from the cache
1296
-	 * @return bool true if underlying function returns true, otherwise false
1297
-	 */
1298
-	public static function deleteFromOpcodeCache($path) {
1299
-		$ret = false;
1300
-		if ($path) {
1301
-			// APC >= 3.1.1
1302
-			if (function_exists('apc_delete_file')) {
1303
-				$ret = @apc_delete_file($path);
1304
-			}
1305
-			// Zend OpCache >= 7.0.0, PHP >= 5.5.0
1306
-			if (function_exists('opcache_invalidate')) {
1307
-				$ret = opcache_invalidate($path);
1308
-			}
1309
-		}
1310
-		return $ret;
1311
-	}
1312
-
1313
-	/**
1314
-	 * Clear the opcode cache if one exists
1315
-	 * This is necessary for writing to the config file
1316
-	 * in case the opcode cache does not re-validate files
1317
-	 *
1318
-	 * @return void
1319
-	 */
1320
-	public static function clearOpcodeCache() {
1321
-		// APC
1322
-		if (function_exists('apc_clear_cache')) {
1323
-			apc_clear_cache();
1324
-		}
1325
-		// Zend Opcache
1326
-		if (function_exists('accelerator_reset')) {
1327
-			accelerator_reset();
1328
-		}
1329
-		// XCache
1330
-		if (function_exists('xcache_clear_cache')) {
1331
-			if (\OC::$server->getIniWrapper()->getBool('xcache.admin.enable_auth')) {
1332
-				\OCP\Util::writeLog('core', 'XCache opcode cache will not be cleared because "xcache.admin.enable_auth" is enabled.', \OCP\Util::WARN);
1333
-			} else {
1334
-				@xcache_clear_cache(XC_TYPE_PHP, 0);
1335
-			}
1336
-		}
1337
-		// Opcache (PHP >= 5.5)
1338
-		if (function_exists('opcache_reset')) {
1339
-			opcache_reset();
1340
-		}
1341
-	}
1342
-
1343
-	/**
1344
-	 * Normalize a unicode string
1345
-	 *
1346
-	 * @param string $value a not normalized string
1347
-	 * @return bool|string
1348
-	 */
1349
-	public static function normalizeUnicode($value) {
1350
-		if(Normalizer::isNormalized($value)) {
1351
-			return $value;
1352
-		}
1353
-
1354
-		$normalizedValue = Normalizer::normalize($value);
1355
-		if ($normalizedValue === null || $normalizedValue === false) {
1356
-			\OC::$server->getLogger()->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
1357
-			return $value;
1358
-		}
1359
-
1360
-		return $normalizedValue;
1361
-	}
1362
-
1363
-	/**
1364
-	 * @param boolean|string $file
1365
-	 * @return string
1366
-	 */
1367
-	public static function basename($file) {
1368
-		$file = rtrim($file, '/');
1369
-		$t = explode('/', $file);
1370
-		return array_pop($t);
1371
-	}
1372
-
1373
-	/**
1374
-	 * A human readable string is generated based on version and build number
1375
-	 *
1376
-	 * @return string
1377
-	 */
1378
-	public static function getHumanVersion() {
1379
-		$version = OC_Util::getVersionString();
1380
-		$build = OC_Util::getBuild();
1381
-		if (!empty($build) and OC_Util::getChannel() === 'daily') {
1382
-			$version .= ' Build:' . $build;
1383
-		}
1384
-		return $version;
1385
-	}
1386
-
1387
-	/**
1388
-	 * Returns whether the given file name is valid
1389
-	 *
1390
-	 * @param string $file file name to check
1391
-	 * @return bool true if the file name is valid, false otherwise
1392
-	 * @deprecated use \OC\Files\View::verifyPath()
1393
-	 */
1394
-	public static function isValidFileName($file) {
1395
-		$trimmed = trim($file);
1396
-		if ($trimmed === '') {
1397
-			return false;
1398
-		}
1399
-		if (\OC\Files\Filesystem::isIgnoredDir($trimmed)) {
1400
-			return false;
1401
-		}
1402
-		foreach (str_split($trimmed) as $char) {
1403
-			if (strpos(\OCP\Constants::FILENAME_INVALID_CHARS, $char) !== false) {
1404
-				return false;
1405
-			}
1406
-		}
1407
-		return true;
1408
-	}
1409
-
1410
-	/**
1411
-	 * Check whether the instance needs to perform an upgrade,
1412
-	 * either when the core version is higher or any app requires
1413
-	 * an upgrade.
1414
-	 *
1415
-	 * @param \OC\SystemConfig $config
1416
-	 * @return bool whether the core or any app needs an upgrade
1417
-	 * @throws \OC\HintException When the upgrade from the given version is not allowed
1418
-	 */
1419
-	public static function needUpgrade(\OC\SystemConfig $config) {
1420
-		if ($config->getValue('installed', false)) {
1421
-			$installedVersion = $config->getValue('version', '0.0.0');
1422
-			$currentVersion = implode('.', \OCP\Util::getVersion());
1423
-			$versionDiff = version_compare($currentVersion, $installedVersion);
1424
-			if ($versionDiff > 0) {
1425
-				return true;
1426
-			} else if ($config->getValue('debug', false) && $versionDiff < 0) {
1427
-				// downgrade with debug
1428
-				$installedMajor = explode('.', $installedVersion);
1429
-				$installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
1430
-				$currentMajor = explode('.', $currentVersion);
1431
-				$currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
1432
-				if ($installedMajor === $currentMajor) {
1433
-					// Same major, allow downgrade for developers
1434
-					return true;
1435
-				} else {
1436
-					// downgrade attempt, throw exception
1437
-					throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1438
-				}
1439
-			} else if ($versionDiff < 0) {
1440
-				// downgrade attempt, throw exception
1441
-				throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1442
-			}
1443
-
1444
-			// also check for upgrades for apps (independently from the user)
1445
-			$apps = \OC_App::getEnabledApps(false, true);
1446
-			$shouldUpgrade = false;
1447
-			foreach ($apps as $app) {
1448
-				if (\OC_App::shouldUpgrade($app)) {
1449
-					$shouldUpgrade = true;
1450
-					break;
1451
-				}
1452
-			}
1453
-			return $shouldUpgrade;
1454
-		} else {
1455
-			return false;
1456
-		}
1457
-	}
1202
+        return $content !== $testContent;
1203
+    }
1204
+
1205
+    /**
1206
+     * Check if the setlocal call does not work. This can happen if the right
1207
+     * local packages are not available on the server.
1208
+     *
1209
+     * @return bool
1210
+     */
1211
+    public static function isSetLocaleWorking() {
1212
+        \Patchwork\Utf8\Bootup::initLocale();
1213
+        if ('' === basename('§')) {
1214
+            return false;
1215
+        }
1216
+        return true;
1217
+    }
1218
+
1219
+    /**
1220
+     * Check if it's possible to get the inline annotations
1221
+     *
1222
+     * @return bool
1223
+     */
1224
+    public static function isAnnotationsWorking() {
1225
+        $reflection = new \ReflectionMethod(__METHOD__);
1226
+        $docs = $reflection->getDocComment();
1227
+
1228
+        return (is_string($docs) && strlen($docs) > 50);
1229
+    }
1230
+
1231
+    /**
1232
+     * Check if the PHP module fileinfo is loaded.
1233
+     *
1234
+     * @return bool
1235
+     */
1236
+    public static function fileInfoLoaded() {
1237
+        return function_exists('finfo_open');
1238
+    }
1239
+
1240
+    /**
1241
+     * clear all levels of output buffering
1242
+     *
1243
+     * @return void
1244
+     */
1245
+    public static function obEnd() {
1246
+        while (ob_get_level()) {
1247
+            ob_end_clean();
1248
+        }
1249
+    }
1250
+
1251
+    /**
1252
+     * Checks whether the server is running on Mac OS X
1253
+     *
1254
+     * @return bool true if running on Mac OS X, false otherwise
1255
+     */
1256
+    public static function runningOnMac() {
1257
+        return (strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN');
1258
+    }
1259
+
1260
+    /**
1261
+     * Checks whether server is running on HHVM
1262
+     *
1263
+     * @return bool True if running on HHVM, false otherwise
1264
+     */
1265
+    public static function runningOnHhvm() {
1266
+        return defined('HHVM_VERSION');
1267
+    }
1268
+
1269
+    /**
1270
+     * Handles the case that there may not be a theme, then check if a "default"
1271
+     * theme exists and take that one
1272
+     *
1273
+     * @return string the theme
1274
+     */
1275
+    public static function getTheme() {
1276
+        $theme = \OC::$server->getSystemConfig()->getValue("theme", '');
1277
+
1278
+        if ($theme === '') {
1279
+            if (is_dir(OC::$SERVERROOT . '/themes/default')) {
1280
+                $theme = 'default';
1281
+            }
1282
+        }
1283
+
1284
+        return $theme;
1285
+    }
1286
+
1287
+    /**
1288
+     * Clear a single file from the opcode cache
1289
+     * This is useful for writing to the config file
1290
+     * in case the opcode cache does not re-validate files
1291
+     * Returns true if successful, false if unsuccessful:
1292
+     * caller should fall back on clearing the entire cache
1293
+     * with clearOpcodeCache() if unsuccessful
1294
+     *
1295
+     * @param string $path the path of the file to clear from the cache
1296
+     * @return bool true if underlying function returns true, otherwise false
1297
+     */
1298
+    public static function deleteFromOpcodeCache($path) {
1299
+        $ret = false;
1300
+        if ($path) {
1301
+            // APC >= 3.1.1
1302
+            if (function_exists('apc_delete_file')) {
1303
+                $ret = @apc_delete_file($path);
1304
+            }
1305
+            // Zend OpCache >= 7.0.0, PHP >= 5.5.0
1306
+            if (function_exists('opcache_invalidate')) {
1307
+                $ret = opcache_invalidate($path);
1308
+            }
1309
+        }
1310
+        return $ret;
1311
+    }
1312
+
1313
+    /**
1314
+     * Clear the opcode cache if one exists
1315
+     * This is necessary for writing to the config file
1316
+     * in case the opcode cache does not re-validate files
1317
+     *
1318
+     * @return void
1319
+     */
1320
+    public static function clearOpcodeCache() {
1321
+        // APC
1322
+        if (function_exists('apc_clear_cache')) {
1323
+            apc_clear_cache();
1324
+        }
1325
+        // Zend Opcache
1326
+        if (function_exists('accelerator_reset')) {
1327
+            accelerator_reset();
1328
+        }
1329
+        // XCache
1330
+        if (function_exists('xcache_clear_cache')) {
1331
+            if (\OC::$server->getIniWrapper()->getBool('xcache.admin.enable_auth')) {
1332
+                \OCP\Util::writeLog('core', 'XCache opcode cache will not be cleared because "xcache.admin.enable_auth" is enabled.', \OCP\Util::WARN);
1333
+            } else {
1334
+                @xcache_clear_cache(XC_TYPE_PHP, 0);
1335
+            }
1336
+        }
1337
+        // Opcache (PHP >= 5.5)
1338
+        if (function_exists('opcache_reset')) {
1339
+            opcache_reset();
1340
+        }
1341
+    }
1342
+
1343
+    /**
1344
+     * Normalize a unicode string
1345
+     *
1346
+     * @param string $value a not normalized string
1347
+     * @return bool|string
1348
+     */
1349
+    public static function normalizeUnicode($value) {
1350
+        if(Normalizer::isNormalized($value)) {
1351
+            return $value;
1352
+        }
1353
+
1354
+        $normalizedValue = Normalizer::normalize($value);
1355
+        if ($normalizedValue === null || $normalizedValue === false) {
1356
+            \OC::$server->getLogger()->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
1357
+            return $value;
1358
+        }
1359
+
1360
+        return $normalizedValue;
1361
+    }
1362
+
1363
+    /**
1364
+     * @param boolean|string $file
1365
+     * @return string
1366
+     */
1367
+    public static function basename($file) {
1368
+        $file = rtrim($file, '/');
1369
+        $t = explode('/', $file);
1370
+        return array_pop($t);
1371
+    }
1372
+
1373
+    /**
1374
+     * A human readable string is generated based on version and build number
1375
+     *
1376
+     * @return string
1377
+     */
1378
+    public static function getHumanVersion() {
1379
+        $version = OC_Util::getVersionString();
1380
+        $build = OC_Util::getBuild();
1381
+        if (!empty($build) and OC_Util::getChannel() === 'daily') {
1382
+            $version .= ' Build:' . $build;
1383
+        }
1384
+        return $version;
1385
+    }
1386
+
1387
+    /**
1388
+     * Returns whether the given file name is valid
1389
+     *
1390
+     * @param string $file file name to check
1391
+     * @return bool true if the file name is valid, false otherwise
1392
+     * @deprecated use \OC\Files\View::verifyPath()
1393
+     */
1394
+    public static function isValidFileName($file) {
1395
+        $trimmed = trim($file);
1396
+        if ($trimmed === '') {
1397
+            return false;
1398
+        }
1399
+        if (\OC\Files\Filesystem::isIgnoredDir($trimmed)) {
1400
+            return false;
1401
+        }
1402
+        foreach (str_split($trimmed) as $char) {
1403
+            if (strpos(\OCP\Constants::FILENAME_INVALID_CHARS, $char) !== false) {
1404
+                return false;
1405
+            }
1406
+        }
1407
+        return true;
1408
+    }
1409
+
1410
+    /**
1411
+     * Check whether the instance needs to perform an upgrade,
1412
+     * either when the core version is higher or any app requires
1413
+     * an upgrade.
1414
+     *
1415
+     * @param \OC\SystemConfig $config
1416
+     * @return bool whether the core or any app needs an upgrade
1417
+     * @throws \OC\HintException When the upgrade from the given version is not allowed
1418
+     */
1419
+    public static function needUpgrade(\OC\SystemConfig $config) {
1420
+        if ($config->getValue('installed', false)) {
1421
+            $installedVersion = $config->getValue('version', '0.0.0');
1422
+            $currentVersion = implode('.', \OCP\Util::getVersion());
1423
+            $versionDiff = version_compare($currentVersion, $installedVersion);
1424
+            if ($versionDiff > 0) {
1425
+                return true;
1426
+            } else if ($config->getValue('debug', false) && $versionDiff < 0) {
1427
+                // downgrade with debug
1428
+                $installedMajor = explode('.', $installedVersion);
1429
+                $installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
1430
+                $currentMajor = explode('.', $currentVersion);
1431
+                $currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
1432
+                if ($installedMajor === $currentMajor) {
1433
+                    // Same major, allow downgrade for developers
1434
+                    return true;
1435
+                } else {
1436
+                    // downgrade attempt, throw exception
1437
+                    throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1438
+                }
1439
+            } else if ($versionDiff < 0) {
1440
+                // downgrade attempt, throw exception
1441
+                throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1442
+            }
1443
+
1444
+            // also check for upgrades for apps (independently from the user)
1445
+            $apps = \OC_App::getEnabledApps(false, true);
1446
+            $shouldUpgrade = false;
1447
+            foreach ($apps as $app) {
1448
+                if (\OC_App::shouldUpgrade($app)) {
1449
+                    $shouldUpgrade = true;
1450
+                    break;
1451
+                }
1452
+            }
1453
+            return $shouldUpgrade;
1454
+        } else {
1455
+            return false;
1456
+        }
1457
+    }
1458 1458
 
1459 1459
 }
Please login to merge, or discard this patch.
Spacing   +63 added lines, -63 removed lines patch added patch discarded remove patch
@@ -76,7 +76,7 @@  discard block
 block discarded – undo
76 76
 
77 77
 	private static function initLocalStorageRootFS() {
78 78
 		// mount local file backend as root
79
-		$configDataDirectory = \OC::$server->getSystemConfig()->getValue("datadirectory", OC::$SERVERROOT . "/data");
79
+		$configDataDirectory = \OC::$server->getSystemConfig()->getValue("datadirectory", OC::$SERVERROOT."/data");
80 80
 		//first set up the local "root" storage
81 81
 		\OC\Files\Filesystem::initMountManager();
82 82
 		if (!self::$rootMounted) {
@@ -154,7 +154,7 @@  discard block
 block discarded – undo
154 154
 		\OC\Files\Filesystem::initMountManager();
155 155
 
156 156
 		\OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(false);
157
-		\OC\Files\Filesystem::addStorageWrapper('mount_options', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
157
+		\OC\Files\Filesystem::addStorageWrapper('mount_options', function($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
158 158
 			if ($storage->instanceOfStorage('\OC\Files\Storage\Common')) {
159 159
 				/** @var \OC\Files\Storage\Common $storage */
160 160
 				$storage->setMountOptions($mount->getOptions());
@@ -162,7 +162,7 @@  discard block
 block discarded – undo
162 162
 			return $storage;
163 163
 		});
164 164
 
165
-		\OC\Files\Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
165
+		\OC\Files\Filesystem::addStorageWrapper('enable_sharing', function($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
166 166
 			if (!$mount->getOption('enable_sharing', true)) {
167 167
 				return new \OC\Files\Storage\Wrapper\PermissionsMask([
168 168
 					'storage' => $storage,
@@ -173,7 +173,7 @@  discard block
 block discarded – undo
173 173
 		});
174 174
 
175 175
 		// install storage availability wrapper, before most other wrappers
176
-		\OC\Files\Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, $storage) {
176
+		\OC\Files\Filesystem::addStorageWrapper('oc_availability', function($mountPoint, $storage) {
177 177
 			if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
178 178
 				return new \OC\Files\Storage\Wrapper\Availability(['storage' => $storage]);
179 179
 			}
@@ -181,7 +181,7 @@  discard block
 block discarded – undo
181 181
 		});
182 182
 
183 183
 		// install storage checksum wrapper
184
-		\OC\Files\Filesystem::addStorageWrapper('oc_checksum', function ($mountPoint, \OCP\Files\Storage\IStorage $storage) {
184
+		\OC\Files\Filesystem::addStorageWrapper('oc_checksum', function($mountPoint, \OCP\Files\Storage\IStorage $storage) {
185 185
 			if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
186 186
 				return new \OC\Files\Storage\Wrapper\Checksum(['storage' => $storage]);
187 187
 			}
@@ -191,14 +191,14 @@  discard block
 block discarded – undo
191 191
 		}, 1);
192 192
 
193 193
 
194
-		\OC\Files\Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
194
+		\OC\Files\Filesystem::addStorageWrapper('oc_encoding', function($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) {
195 195
 			if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
196 196
 				return new \OC\Files\Storage\Wrapper\Encoding(['storage' => $storage]);
197 197
 			}
198 198
 			return $storage;
199 199
 		});
200 200
 
201
-		\OC\Files\Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
201
+		\OC\Files\Filesystem::addStorageWrapper('oc_quota', function($mountPoint, $storage) {
202 202
 			// set up quota for home storages, even for other users
203 203
 			// which can happen when using sharing
204 204
 
@@ -240,7 +240,7 @@  discard block
 block discarded – undo
240 240
 		//if we aren't logged in, there is no use to set up the filesystem
241 241
 		if ($user != "") {
242 242
 
243
-			$userDir = '/' . $user . '/files';
243
+			$userDir = '/'.$user.'/files';
244 244
 
245 245
 			//jail the user into his "home" directory
246 246
 			\OC\Files\Filesystem::init($user, $userDir);
@@ -319,7 +319,7 @@  discard block
 block discarded – undo
319 319
 			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
320 320
 		}
321 321
 		$userQuota = $user->getQuota();
322
-		if($userQuota === 'none') {
322
+		if ($userQuota === 'none') {
323 323
 			return \OCP\Files\FileInfo::SPACE_UNLIMITED;
324 324
 		}
325 325
 		return OC_Helper::computerFileSize($userQuota);
@@ -334,15 +334,15 @@  discard block
 block discarded – undo
334 334
 	 */
335 335
 	public static function copySkeleton($userId, \OCP\Files\Folder $userDirectory) {
336 336
 
337
-		$skeletonDirectory = \OC::$server->getConfig()->getSystemValue('skeletondirectory', \OC::$SERVERROOT . '/core/skeleton');
337
+		$skeletonDirectory = \OC::$server->getConfig()->getSystemValue('skeletondirectory', \OC::$SERVERROOT.'/core/skeleton');
338 338
 		$instanceId = \OC::$server->getConfig()->getSystemValue('instanceid', '');
339 339
 
340 340
 		if ($instanceId === null) {
341 341
 			throw new \RuntimeException('no instance id!');
342 342
 		}
343
-		$appdata = 'appdata_' . $instanceId;
343
+		$appdata = 'appdata_'.$instanceId;
344 344
 		if ($userId === $appdata) {
345
-			throw new \RuntimeException('username is reserved name: ' . $appdata);
345
+			throw new \RuntimeException('username is reserved name: '.$appdata);
346 346
 		}
347 347
 
348 348
 		if (!empty($skeletonDirectory)) {
@@ -369,7 +369,7 @@  discard block
 block discarded – undo
369 369
 
370 370
 		// Verify if folder exists
371 371
 		$dir = opendir($source);
372
-		if($dir === false) {
372
+		if ($dir === false) {
373 373
 			$logger->error(sprintf('Could not opendir "%s"', $source), ['app' => 'core']);
374 374
 			return;
375 375
 		}
@@ -377,14 +377,14 @@  discard block
 block discarded – undo
377 377
 		// Copy the files
378 378
 		while (false !== ($file = readdir($dir))) {
379 379
 			if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
380
-				if (is_dir($source . '/' . $file)) {
380
+				if (is_dir($source.'/'.$file)) {
381 381
 					$child = $target->newFolder($file);
382
-					self::copyr($source . '/' . $file, $child);
382
+					self::copyr($source.'/'.$file, $child);
383 383
 				} else {
384 384
 					$child = $target->newFile($file);
385
-					$sourceStream = fopen($source . '/' . $file, 'r');
386
-					if($sourceStream === false) {
387
-						$logger->error(sprintf('Could not fopen "%s"', $source . '/' . $file), ['app' => 'core']);
385
+					$sourceStream = fopen($source.'/'.$file, 'r');
386
+					if ($sourceStream === false) {
387
+						$logger->error(sprintf('Could not fopen "%s"', $source.'/'.$file), ['app' => 'core']);
388 388
 						closedir($dir);
389 389
 						return;
390 390
 					}
@@ -459,8 +459,8 @@  discard block
 block discarded – undo
459 459
 			return;
460 460
 		}
461 461
 
462
-		$timestamp = filemtime(OC::$SERVERROOT . '/version.php');
463
-		require OC::$SERVERROOT . '/version.php';
462
+		$timestamp = filemtime(OC::$SERVERROOT.'/version.php');
463
+		require OC::$SERVERROOT.'/version.php';
464 464
 		/** @var $timestamp int */
465 465
 		self::$versionCache['OC_Version_Timestamp'] = $timestamp;
466 466
 		/** @var $OC_Version string */
@@ -507,7 +507,7 @@  discard block
 block discarded – undo
507 507
 
508 508
 		// core js files need separate handling
509 509
 		if ($application !== 'core' && $file !== null) {
510
-			self::addTranslations ( $application );
510
+			self::addTranslations($application);
511 511
 		}
512 512
 		self::addExternalResource($application, $prepend, $path, "script");
513 513
 	}
@@ -584,7 +584,7 @@  discard block
 block discarded – undo
584 584
 		if ($type === "style") {
585 585
 			if (!in_array($path, self::$styles)) {
586 586
 				if ($prepend === true) {
587
-					array_unshift ( self::$styles, $path );
587
+					array_unshift(self::$styles, $path);
588 588
 				} else {
589 589
 					self::$styles[] = $path;
590 590
 				}
@@ -592,7 +592,7 @@  discard block
 block discarded – undo
592 592
 		} elseif ($type === "script") {
593 593
 			if (!in_array($path, self::$scripts)) {
594 594
 				if ($prepend === true) {
595
-					array_unshift ( self::$scripts, $path );
595
+					array_unshift(self::$scripts, $path);
596 596
 				} else {
597 597
 					self::$scripts [] = $path;
598 598
 				}
@@ -608,7 +608,7 @@  discard block
 block discarded – undo
608 608
 	 * @param array $attributes array of attributes for the element
609 609
 	 * @param string $text the text content for the element
610 610
 	 */
611
-	public static function addHeader($tag, $attributes, $text=null) {
611
+	public static function addHeader($tag, $attributes, $text = null) {
612 612
 		self::$headers[] = array(
613 613
 			'tag' => $tag,
614 614
 			'attributes' => $attributes,
@@ -648,7 +648,7 @@  discard block
 block discarded – undo
648 648
 	public static function checkServer(\OC\SystemConfig $config) {
649 649
 		$l = \OC::$server->getL10N('lib');
650 650
 		$errors = array();
651
-		$CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT . '/data');
651
+		$CONFIG_DATADIRECTORY = $config->getValue('datadirectory', OC::$SERVERROOT.'/data');
652 652
 
653 653
 		if (!self::needUpgrade($config) && $config->getValue('installed', false)) {
654 654
 			// this check needs to be done every time
@@ -676,13 +676,13 @@  discard block
 block discarded – undo
676 676
 		}
677 677
 
678 678
 		// Check if config folder is writable.
679
-		if(!OC_Helper::isReadOnlyConfigEnabled()) {
679
+		if (!OC_Helper::isReadOnlyConfigEnabled()) {
680 680
 			if (!is_writable(OC::$configDir) or !is_readable(OC::$configDir)) {
681 681
 				$errors[] = array(
682 682
 					'error' => $l->t('Cannot write into "config" directory'),
683 683
 					'hint' => $l->t('This can usually be fixed by '
684 684
 						. '%sgiving the webserver write access to the config directory%s.',
685
-						array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>'))
685
+						array('<a href="'.$urlGenerator->linkToDocs('admin-dir_permissions').'" target="_blank" rel="noreferrer">', '</a>'))
686 686
 				);
687 687
 			}
688 688
 		}
@@ -698,7 +698,7 @@  discard block
 block discarded – undo
698 698
 					'hint' => $l->t('This can usually be fixed by '
699 699
 						. '%sgiving the webserver write access to the apps directory%s'
700 700
 						. ' or disabling the appstore in the config file.',
701
-						array('<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>'))
701
+						array('<a href="'.$urlGenerator->linkToDocs('admin-dir_permissions').'" target="_blank" rel="noreferrer">', '</a>'))
702 702
 				);
703 703
 			}
704 704
 		}
@@ -720,7 +720,7 @@  discard block
 block discarded – undo
720 720
 				//common hint for all file permissions error messages
721 721
 				$permissionsHint = $l->t('Permissions can usually be fixed by '
722 722
 					. '%sgiving the webserver write access to the root directory%s.',
723
-					['<a href="' . $urlGenerator->linkToDocs('admin-dir_permissions') . '" target="_blank" rel="noreferrer">', '</a>']);
723
+					['<a href="'.$urlGenerator->linkToDocs('admin-dir_permissions').'" target="_blank" rel="noreferrer">', '</a>']);
724 724
 				$errors[] = [
725 725
 					'error' => 'Your data directory is not writable',
726 726
 					'hint' => $permissionsHint
@@ -820,15 +820,15 @@  discard block
 block discarded – undo
820 820
 			}
821 821
 		}
822 822
 
823
-		foreach($missingDependencies as $missingDependency) {
823
+		foreach ($missingDependencies as $missingDependency) {
824 824
 			$errors[] = array(
825 825
 				'error' => $l->t('PHP module %s not installed.', array($missingDependency)),
826 826
 				'hint' => $moduleHint
827 827
 			);
828 828
 			$webServerRestart = true;
829 829
 		}
830
-		foreach($invalidIniSettings as $setting) {
831
-			if(is_bool($setting[1])) {
830
+		foreach ($invalidIniSettings as $setting) {
831
+			if (is_bool($setting[1])) {
832 832
 				$setting[1] = ($setting[1]) ? 'on' : 'off';
833 833
 			}
834 834
 			$errors[] = [
@@ -846,7 +846,7 @@  discard block
 block discarded – undo
846 846
 		 * TODO: Should probably be implemented in the above generic dependency
847 847
 		 *       check somehow in the long-term.
848 848
 		 */
849
-		if($iniWrapper->getBool('mbstring.func_overload') !== null &&
849
+		if ($iniWrapper->getBool('mbstring.func_overload') !== null &&
850 850
 			$iniWrapper->getBool('mbstring.func_overload') === true) {
851 851
 			$errors[] = array(
852 852
 				'error' => $l->t('mbstring.func_overload is set to "%s" instead of the expected value "0"', [$iniWrapper->getString('mbstring.func_overload')]),
@@ -854,16 +854,16 @@  discard block
 block discarded – undo
854 854
 			);
855 855
 		}
856 856
 
857
-		if(function_exists('xml_parser_create') &&
858
-			LIBXML_LOADED_VERSION < 20700 ) {
857
+		if (function_exists('xml_parser_create') &&
858
+			LIBXML_LOADED_VERSION < 20700) {
859 859
 			$version = LIBXML_LOADED_VERSION;
860
-			$major = floor($version/10000);
860
+			$major = floor($version / 10000);
861 861
 			$version -= ($major * 10000);
862
-			$minor = floor($version/100);
862
+			$minor = floor($version / 100);
863 863
 			$version -= ($minor * 100);
864 864
 			$patch = $version;
865 865
 			$errors[] = array(
866
-				'error' => $l->t('libxml2 2.7.0 is at least required. Currently %s is installed.', [$major . '.' . $minor . '.' . $patch]),
866
+				'error' => $l->t('libxml2 2.7.0 is at least required. Currently %s is installed.', [$major.'.'.$minor.'.'.$patch]),
867 867
 				'hint' => $l->t('To fix this issue update your libxml2 version and restart your web server.')
868 868
 			);
869 869
 		}
@@ -964,10 +964,10 @@  discard block
 block discarded – undo
964 964
 				'hint' => $l->t('Check the value of "datadirectory" in your configuration')
965 965
 			];
966 966
 		}
967
-		if (!file_exists($dataDirectory . '/.ocdata')) {
967
+		if (!file_exists($dataDirectory.'/.ocdata')) {
968 968
 			$errors[] = [
969 969
 				'error' => $l->t('Your data directory is invalid'),
970
-				'hint' => $l->t('Please check that the data directory contains a file' .
970
+				'hint' => $l->t('Please check that the data directory contains a file'.
971 971
 					' ".ocdata" in its root.')
972 972
 			];
973 973
 		}
@@ -983,7 +983,7 @@  discard block
 block discarded – undo
983 983
 	public static function checkLoggedIn() {
984 984
 		// Check if we are a user
985 985
 		if (!\OC::$server->getUserSession()->isLoggedIn()) {
986
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute(
986
+			header('Location: '.\OC::$server->getURLGenerator()->linkToRoute(
987 987
 						'core.login.showLoginForm',
988 988
 						[
989 989
 							'redirect_url' => \OC::$server->getRequest()->getRequestUri(),
@@ -994,7 +994,7 @@  discard block
 block discarded – undo
994 994
 		}
995 995
 		// Redirect to 2FA challenge selection if 2FA challenge was not solved yet
996 996
 		if (\OC::$server->getTwoFactorAuthManager()->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
997
-			header('Location: ' . \OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
997
+			header('Location: '.\OC::$server->getURLGenerator()->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
998 998
 			exit();
999 999
 		}
1000 1000
 	}
@@ -1007,7 +1007,7 @@  discard block
 block discarded – undo
1007 1007
 	public static function checkAdminUser() {
1008 1008
 		OC_Util::checkLoggedIn();
1009 1009
 		if (!OC_User::isAdminUser(OC_User::getUser())) {
1010
-			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
1010
+			header('Location: '.\OCP\Util::linkToAbsolute('', 'index.php'));
1011 1011
 			exit();
1012 1012
 		}
1013 1013
 	}
@@ -1021,12 +1021,12 @@  discard block
 block discarded – undo
1021 1021
 		OC_Util::checkLoggedIn();
1022 1022
 		$userObject = \OC::$server->getUserSession()->getUser();
1023 1023
 		$isSubAdmin = false;
1024
-		if($userObject !== null) {
1024
+		if ($userObject !== null) {
1025 1025
 			$isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
1026 1026
 		}
1027 1027
 
1028 1028
 		if (!$isSubAdmin) {
1029
-			header('Location: ' . \OCP\Util::linkToAbsolute('', 'index.php'));
1029
+			header('Location: '.\OCP\Util::linkToAbsolute('', 'index.php'));
1030 1030
 			exit();
1031 1031
 		}
1032 1032
 		return true;
@@ -1061,10 +1061,10 @@  discard block
 block discarded – undo
1061 1061
 					}
1062 1062
 				}
1063 1063
 
1064
-				if(\OC::$server->getConfig()->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true') {
1065
-					$location = $urlGenerator->getAbsoluteURL('/apps/' . $appId . '/');
1064
+				if (\OC::$server->getConfig()->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true') {
1065
+					$location = $urlGenerator->getAbsoluteURL('/apps/'.$appId.'/');
1066 1066
 				} else {
1067
-					$location = $urlGenerator->getAbsoluteURL('/index.php/apps/' . $appId . '/');
1067
+					$location = $urlGenerator->getAbsoluteURL('/index.php/apps/'.$appId.'/');
1068 1068
 				}
1069 1069
 			}
1070 1070
 		}
@@ -1078,7 +1078,7 @@  discard block
 block discarded – undo
1078 1078
 	 */
1079 1079
 	public static function redirectToDefaultPage() {
1080 1080
 		$location = self::getDefaultPageUrl();
1081
-		header('Location: ' . $location);
1081
+		header('Location: '.$location);
1082 1082
 		exit();
1083 1083
 	}
1084 1084
 
@@ -1091,7 +1091,7 @@  discard block
 block discarded – undo
1091 1091
 		$id = \OC::$server->getSystemConfig()->getValue('instanceid', null);
1092 1092
 		if (is_null($id)) {
1093 1093
 			// We need to guarantee at least one letter in instanceid so it can be used as the session_name
1094
-			$id = 'oc' . \OC::$server->getSecureRandom()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
1094
+			$id = 'oc'.\OC::$server->getSecureRandom()->generate(10, \OCP\Security\ISecureRandom::CHAR_LOWER.\OCP\Security\ISecureRandom::CHAR_DIGITS);
1095 1095
 			\OC::$server->getSystemConfig()->setValue('instanceid', $id);
1096 1096
 		}
1097 1097
 		return $id;
@@ -1113,7 +1113,7 @@  discard block
 block discarded – undo
1113 1113
 			}, $value);
1114 1114
 		} else {
1115 1115
 			// Specify encoding for PHP<5.4
1116
-			$value = htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
1116
+			$value = htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
1117 1117
 		}
1118 1118
 		return $value;
1119 1119
 	}
@@ -1146,7 +1146,7 @@  discard block
 block discarded – undo
1146 1146
 		$testContent = 'This is used for testing whether htaccess is properly enabled to disallow access from the outside. This file can be safely removed.';
1147 1147
 
1148 1148
 		// creating a test file
1149
-		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1149
+		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT.'/data').'/'.$fileName;
1150 1150
 
1151 1151
 		if (file_exists($testFile)) {// already running this test, possible recursive call
1152 1152
 			return false;
@@ -1155,7 +1155,7 @@  discard block
 block discarded – undo
1155 1155
 		$fp = @fopen($testFile, 'w');
1156 1156
 		if (!$fp) {
1157 1157
 			throw new OC\HintException('Can\'t create test file to check for working .htaccess file.',
1158
-				'Make sure it is possible for the webserver to write to ' . $testFile);
1158
+				'Make sure it is possible for the webserver to write to '.$testFile);
1159 1159
 		}
1160 1160
 		fwrite($fp, $testContent);
1161 1161
 		fclose($fp);
@@ -1182,10 +1182,10 @@  discard block
 block discarded – undo
1182 1182
 		}
1183 1183
 
1184 1184
 		$fileName = '/htaccesstest.txt';
1185
-		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data') . '/' . $fileName;
1185
+		$testFile = $config->getSystemValue('datadirectory', OC::$SERVERROOT.'/data').'/'.$fileName;
1186 1186
 
1187 1187
 		// accessing the file via http
1188
-		$url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT . '/data' . $fileName);
1188
+		$url = \OC::$server->getURLGenerator()->getAbsoluteURL(OC::$WEBROOT.'/data'.$fileName);
1189 1189
 		try {
1190 1190
 			$content = \OC::$server->getHTTPClientService()->newClient()->get($url)->getBody();
1191 1191
 		} catch (\Exception $e) {
@@ -1276,7 +1276,7 @@  discard block
 block discarded – undo
1276 1276
 		$theme = \OC::$server->getSystemConfig()->getValue("theme", '');
1277 1277
 
1278 1278
 		if ($theme === '') {
1279
-			if (is_dir(OC::$SERVERROOT . '/themes/default')) {
1279
+			if (is_dir(OC::$SERVERROOT.'/themes/default')) {
1280 1280
 				$theme = 'default';
1281 1281
 			}
1282 1282
 		}
@@ -1347,13 +1347,13 @@  discard block
 block discarded – undo
1347 1347
 	 * @return bool|string
1348 1348
 	 */
1349 1349
 	public static function normalizeUnicode($value) {
1350
-		if(Normalizer::isNormalized($value)) {
1350
+		if (Normalizer::isNormalized($value)) {
1351 1351
 			return $value;
1352 1352
 		}
1353 1353
 
1354 1354
 		$normalizedValue = Normalizer::normalize($value);
1355 1355
 		if ($normalizedValue === null || $normalizedValue === false) {
1356
-			\OC::$server->getLogger()->warning('normalizing failed for "' . $value . '"', ['app' => 'core']);
1356
+			\OC::$server->getLogger()->warning('normalizing failed for "'.$value.'"', ['app' => 'core']);
1357 1357
 			return $value;
1358 1358
 		}
1359 1359
 
@@ -1379,7 +1379,7 @@  discard block
 block discarded – undo
1379 1379
 		$version = OC_Util::getVersionString();
1380 1380
 		$build = OC_Util::getBuild();
1381 1381
 		if (!empty($build) and OC_Util::getChannel() === 'daily') {
1382
-			$version .= ' Build:' . $build;
1382
+			$version .= ' Build:'.$build;
1383 1383
 		}
1384 1384
 		return $version;
1385 1385
 	}
@@ -1426,19 +1426,19 @@  discard block
 block discarded – undo
1426 1426
 			} else if ($config->getValue('debug', false) && $versionDiff < 0) {
1427 1427
 				// downgrade with debug
1428 1428
 				$installedMajor = explode('.', $installedVersion);
1429
-				$installedMajor = $installedMajor[0] . '.' . $installedMajor[1];
1429
+				$installedMajor = $installedMajor[0].'.'.$installedMajor[1];
1430 1430
 				$currentMajor = explode('.', $currentVersion);
1431
-				$currentMajor = $currentMajor[0] . '.' . $currentMajor[1];
1431
+				$currentMajor = $currentMajor[0].'.'.$currentMajor[1];
1432 1432
 				if ($installedMajor === $currentMajor) {
1433 1433
 					// Same major, allow downgrade for developers
1434 1434
 					return true;
1435 1435
 				} else {
1436 1436
 					// downgrade attempt, throw exception
1437
-					throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1437
+					throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from '.$installedVersion.' to '.$currentVersion.')');
1438 1438
 				}
1439 1439
 			} else if ($versionDiff < 0) {
1440 1440
 				// downgrade attempt, throw exception
1441
-				throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from ' . $installedVersion . ' to ' . $currentVersion . ')');
1441
+				throw new \OC\HintException('Downgrading is not supported and is likely to cause unpredictable issues (from '.$installedVersion.' to '.$currentVersion.')');
1442 1442
 			}
1443 1443
 
1444 1444
 			// also check for upgrades for apps (independently from the user)
Please login to merge, or discard this patch.
lib/private/Files/Storage/Wrapper/Checksum.php 1 patch
Indentation   +136 added lines, -136 removed lines patch added patch discarded remove patch
@@ -41,140 +41,140 @@
 block discarded – undo
41 41
 class Checksum extends Wrapper {
42 42
 
43 43
 
44
-	const NOT_REQUIRED = 0;
45
-	/** Calculate checksum on write (to be stored in oc_filecache) */
46
-	const PATH_NEW_OR_UPDATED = 1;
47
-	/** File needs to be checksummed on first read because it is already in cache but has no checksum */
48
-	const PATH_IN_CACHE_WITHOUT_CHECKSUM = 2;
49
-
50
-	/** @var array */
51
-	private $pathsInCacheWithoutChecksum = [];
52
-
53
-	/**
54
-	 * @param string $path
55
-	 * @param string $mode
56
-	 * @return false|resource
57
-	 */
58
-	public function fopen($path, $mode) {
59
-		$stream = $this->getWrapperStorage()->fopen($path, $mode);
60
-		if (!is_resource($stream)) {
61
-			// don't wrap on error
62
-			return $stream;
63
-		}
64
-
65
-		$requirement = $this->getChecksumRequirement($path, $mode);
66
-
67
-		if ($requirement === self::PATH_NEW_OR_UPDATED) {
68
-			return \OC\Files\Stream\Checksum::wrap($stream, $path);
69
-		}
70
-
71
-		// If file is without checksum we save the path and create
72
-		// a callback because we can only calculate the checksum
73
-		// after the client has read the entire filestream once.
74
-		// the checksum is then saved to oc_filecache for subsequent
75
-		// retrieval (see onClose())
76
-		if ($requirement == self::PATH_IN_CACHE_WITHOUT_CHECKSUM) {
77
-			$checksumStream = \OC\Files\Stream\Checksum::wrap($stream, $path);
78
-			return CallbackWrapper::wrap(
79
-				$checksumStream,
80
-				null,
81
-				null,
82
-				[$this, 'onClose']
83
-			);
84
-		}
85
-
86
-		return $stream;
87
-	}
88
-
89
-	/**
90
-	 * @param $mode
91
-	 * @param $path
92
-	 * @return int
93
-	 */
94
-	private function getChecksumRequirement($path, $mode) {
95
-		$isNormalFile = true;
96
-		if ($this->instanceOfStorage(IHomeStorage::class)) {
97
-			// home storage stores files in "files"
98
-			$isNormalFile = substr($path, 0, 6) === 'files/';
99
-		}
100
-		$fileIsWritten = $mode !== 'r' && $mode !== 'rb';
101
-
102
-		if ($isNormalFile && $fileIsWritten) {
103
-			return self::PATH_NEW_OR_UPDATED;
104
-		}
105
-
106
-		// file could be in cache but without checksum for example
107
-		// if mounted from ext. storage
108
-		$cache = $this->getCache($path);
109
-
110
-		$cacheEntry = $cache->get($path);
111
-
112
-		// Cache entry is sometimes an array (partial) when encryption is enabled without id so
113
-		// we ignore it.
114
-		if ($cacheEntry && empty($cacheEntry['checksum']) && is_object($cacheEntry)) {
115
-			$this->pathsInCacheWithoutChecksum[$cacheEntry->getId()] = $path;
116
-			return self::PATH_IN_CACHE_WITHOUT_CHECKSUM;
117
-		}
118
-
119
-		return self::NOT_REQUIRED;
120
-	}
121
-
122
-	/**
123
-	 * Callback registered in fopen
124
-	 */
125
-	public function onClose() {
126
-		$cache = $this->getCache();
127
-		foreach ($this->pathsInCacheWithoutChecksum as $cacheId => $path) {
128
-			$cache->update(
129
-				$cacheId,
130
-				['checksum' => self::getChecksumsInDbFormat($path)]
131
-			);
132
-		}
133
-
134
-		$this->pathsInCacheWithoutChecksum = [];
135
-	}
136
-
137
-	/**
138
-	 * @param $path
139
-	 * Format like "SHA1:abc MD5:def ADLER32:ghi"
140
-	 * @return string
141
-	 */
142
-	private static function getChecksumsInDbFormat($path) {
143
-		$checksumString = '';
144
-		foreach (ChecksumStream::getChecksums($path) as $algo => $checksum) {
145
-			$checksumString .= sprintf('%s:%s ', strtoupper($algo), $checksum);
146
-		}
147
-
148
-		return rtrim($checksumString);
149
-	}
150
-
151
-	/**
152
-	 * @param string $path
153
-	 * @param string $data
154
-	 * @return bool
155
-	 */
156
-	public function file_put_contents($path, $data) {
157
-		$memoryStream = fopen('php://memory', 'r+');
158
-		$checksumStream = \OC\Files\Stream\Checksum::wrap($memoryStream, $path);
159
-
160
-		fwrite($checksumStream, $data);
161
-		fclose($checksumStream);
162
-
163
-		return $this->getWrapperStorage()->file_put_contents($path, $data);
164
-	}
165
-
166
-	/**
167
-	 * @param string $path
168
-	 * @return array
169
-	 */
170
-	public function getMetaData($path) {
171
-		$parentMetaData = $this->getWrapperStorage()->getMetaData($path);
172
-		$parentMetaData['checksum'] = self::getChecksumsInDbFormat($path);
173
-
174
-		if (!isset($parentMetaData['mimetype'])) {
175
-			$parentMetaData['mimetype'] = 'application/octet-stream';
176
-		}
177
-
178
-		return $parentMetaData;
179
-	}
44
+    const NOT_REQUIRED = 0;
45
+    /** Calculate checksum on write (to be stored in oc_filecache) */
46
+    const PATH_NEW_OR_UPDATED = 1;
47
+    /** File needs to be checksummed on first read because it is already in cache but has no checksum */
48
+    const PATH_IN_CACHE_WITHOUT_CHECKSUM = 2;
49
+
50
+    /** @var array */
51
+    private $pathsInCacheWithoutChecksum = [];
52
+
53
+    /**
54
+     * @param string $path
55
+     * @param string $mode
56
+     * @return false|resource
57
+     */
58
+    public function fopen($path, $mode) {
59
+        $stream = $this->getWrapperStorage()->fopen($path, $mode);
60
+        if (!is_resource($stream)) {
61
+            // don't wrap on error
62
+            return $stream;
63
+        }
64
+
65
+        $requirement = $this->getChecksumRequirement($path, $mode);
66
+
67
+        if ($requirement === self::PATH_NEW_OR_UPDATED) {
68
+            return \OC\Files\Stream\Checksum::wrap($stream, $path);
69
+        }
70
+
71
+        // If file is without checksum we save the path and create
72
+        // a callback because we can only calculate the checksum
73
+        // after the client has read the entire filestream once.
74
+        // the checksum is then saved to oc_filecache for subsequent
75
+        // retrieval (see onClose())
76
+        if ($requirement == self::PATH_IN_CACHE_WITHOUT_CHECKSUM) {
77
+            $checksumStream = \OC\Files\Stream\Checksum::wrap($stream, $path);
78
+            return CallbackWrapper::wrap(
79
+                $checksumStream,
80
+                null,
81
+                null,
82
+                [$this, 'onClose']
83
+            );
84
+        }
85
+
86
+        return $stream;
87
+    }
88
+
89
+    /**
90
+     * @param $mode
91
+     * @param $path
92
+     * @return int
93
+     */
94
+    private function getChecksumRequirement($path, $mode) {
95
+        $isNormalFile = true;
96
+        if ($this->instanceOfStorage(IHomeStorage::class)) {
97
+            // home storage stores files in "files"
98
+            $isNormalFile = substr($path, 0, 6) === 'files/';
99
+        }
100
+        $fileIsWritten = $mode !== 'r' && $mode !== 'rb';
101
+
102
+        if ($isNormalFile && $fileIsWritten) {
103
+            return self::PATH_NEW_OR_UPDATED;
104
+        }
105
+
106
+        // file could be in cache but without checksum for example
107
+        // if mounted from ext. storage
108
+        $cache = $this->getCache($path);
109
+
110
+        $cacheEntry = $cache->get($path);
111
+
112
+        // Cache entry is sometimes an array (partial) when encryption is enabled without id so
113
+        // we ignore it.
114
+        if ($cacheEntry && empty($cacheEntry['checksum']) && is_object($cacheEntry)) {
115
+            $this->pathsInCacheWithoutChecksum[$cacheEntry->getId()] = $path;
116
+            return self::PATH_IN_CACHE_WITHOUT_CHECKSUM;
117
+        }
118
+
119
+        return self::NOT_REQUIRED;
120
+    }
121
+
122
+    /**
123
+     * Callback registered in fopen
124
+     */
125
+    public function onClose() {
126
+        $cache = $this->getCache();
127
+        foreach ($this->pathsInCacheWithoutChecksum as $cacheId => $path) {
128
+            $cache->update(
129
+                $cacheId,
130
+                ['checksum' => self::getChecksumsInDbFormat($path)]
131
+            );
132
+        }
133
+
134
+        $this->pathsInCacheWithoutChecksum = [];
135
+    }
136
+
137
+    /**
138
+     * @param $path
139
+     * Format like "SHA1:abc MD5:def ADLER32:ghi"
140
+     * @return string
141
+     */
142
+    private static function getChecksumsInDbFormat($path) {
143
+        $checksumString = '';
144
+        foreach (ChecksumStream::getChecksums($path) as $algo => $checksum) {
145
+            $checksumString .= sprintf('%s:%s ', strtoupper($algo), $checksum);
146
+        }
147
+
148
+        return rtrim($checksumString);
149
+    }
150
+
151
+    /**
152
+     * @param string $path
153
+     * @param string $data
154
+     * @return bool
155
+     */
156
+    public function file_put_contents($path, $data) {
157
+        $memoryStream = fopen('php://memory', 'r+');
158
+        $checksumStream = \OC\Files\Stream\Checksum::wrap($memoryStream, $path);
159
+
160
+        fwrite($checksumStream, $data);
161
+        fclose($checksumStream);
162
+
163
+        return $this->getWrapperStorage()->file_put_contents($path, $data);
164
+    }
165
+
166
+    /**
167
+     * @param string $path
168
+     * @return array
169
+     */
170
+    public function getMetaData($path) {
171
+        $parentMetaData = $this->getWrapperStorage()->getMetaData($path);
172
+        $parentMetaData['checksum'] = self::getChecksumsInDbFormat($path);
173
+
174
+        if (!isset($parentMetaData['mimetype'])) {
175
+            $parentMetaData['mimetype'] = 'application/octet-stream';
176
+        }
177
+
178
+        return $parentMetaData;
179
+    }
180 180
 }
Please login to merge, or discard this patch.
apps/dav/lib/Connector/Sabre/FilesPlugin.php 1 patch
Indentation   +388 added lines, -388 removed lines patch added patch discarded remove patch
@@ -48,392 +48,392 @@
 block discarded – undo
48 48
 
49 49
 class FilesPlugin extends ServerPlugin {
50 50
 
51
-	// namespace
52
-	const NS_OWNCLOUD = 'http://owncloud.org/ns';
53
-	const NS_NEXTCLOUD = 'http://nextcloud.org/ns';
54
-	const FILEID_PROPERTYNAME = '{http://owncloud.org/ns}id';
55
-	const INTERNAL_FILEID_PROPERTYNAME = '{http://owncloud.org/ns}fileid';
56
-	const PERMISSIONS_PROPERTYNAME = '{http://owncloud.org/ns}permissions';
57
-	const SHARE_PERMISSIONS_PROPERTYNAME = '{http://open-collaboration-services.org/ns}share-permissions';
58
-	const DOWNLOADURL_PROPERTYNAME = '{http://owncloud.org/ns}downloadURL';
59
-	const SIZE_PROPERTYNAME = '{http://owncloud.org/ns}size';
60
-	const GETETAG_PROPERTYNAME = '{DAV:}getetag';
61
-	const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified';
62
-	const OWNER_ID_PROPERTYNAME = '{http://owncloud.org/ns}owner-id';
63
-	const OWNER_DISPLAY_NAME_PROPERTYNAME = '{http://owncloud.org/ns}owner-display-name';
64
-	const CHECKSUMS_PROPERTYNAME = '{http://owncloud.org/ns}checksums';
65
-	const DATA_FINGERPRINT_PROPERTYNAME = '{http://owncloud.org/ns}data-fingerprint';
66
-	const HAS_PREVIEW_PROPERTYNAME = '{http://nextcloud.org/ns}has-preview';
67
-
68
-	/**
69
-	 * Reference to main server object
70
-	 *
71
-	 * @var \Sabre\DAV\Server
72
-	 */
73
-	private $server;
74
-
75
-	/**
76
-	 * @var Tree
77
-	 */
78
-	private $tree;
79
-
80
-	/**
81
-	 * Whether this is public webdav.
82
-	 * If true, some returned information will be stripped off.
83
-	 *
84
-	 * @var bool
85
-	 */
86
-	private $isPublic;
87
-
88
-	/**
89
-	 * @var View
90
-	 */
91
-	private $fileView;
92
-
93
-	/**
94
-	 * @var bool
95
-	 */
96
-	private $downloadAttachment;
97
-
98
-	/**
99
-	 * @var IConfig
100
-	 */
101
-	private $config;
102
-
103
-	/**
104
-	 * @var IRequest
105
-	 */
106
-	private $request;
107
-
108
-	/**
109
-	 * @var IPreview
110
-	 */
111
-	private $previewManager;
112
-
113
-	/**
114
-	 * @param Tree $tree
115
-	 * @param IConfig $config
116
-	 * @param IRequest $request
117
-	 * @param IPreview $previewManager
118
-	 * @param bool $isPublic
119
-	 * @param bool $downloadAttachment
120
-	 */
121
-	public function __construct(Tree $tree,
122
-								IConfig $config,
123
-								IRequest $request,
124
-								IPreview $previewManager,
125
-								$isPublic = false,
126
-								$downloadAttachment = true) {
127
-		$this->tree = $tree;
128
-		$this->config = $config;
129
-		$this->request = $request;
130
-		$this->isPublic = $isPublic;
131
-		$this->downloadAttachment = $downloadAttachment;
132
-		$this->previewManager = $previewManager;
133
-	}
134
-
135
-	/**
136
-	 * This initializes the plugin.
137
-	 *
138
-	 * This function is called by \Sabre\DAV\Server, after
139
-	 * addPlugin is called.
140
-	 *
141
-	 * This method should set up the required event subscriptions.
142
-	 *
143
-	 * @param \Sabre\DAV\Server $server
144
-	 * @return void
145
-	 */
146
-	public function initialize(\Sabre\DAV\Server $server) {
147
-
148
-		$server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
149
-		$server->xml->namespaceMap[self::NS_NEXTCLOUD] = 'nc';
150
-		$server->protectedProperties[] = self::FILEID_PROPERTYNAME;
151
-		$server->protectedProperties[] = self::INTERNAL_FILEID_PROPERTYNAME;
152
-		$server->protectedProperties[] = self::PERMISSIONS_PROPERTYNAME;
153
-		$server->protectedProperties[] = self::SHARE_PERMISSIONS_PROPERTYNAME;
154
-		$server->protectedProperties[] = self::SIZE_PROPERTYNAME;
155
-		$server->protectedProperties[] = self::DOWNLOADURL_PROPERTYNAME;
156
-		$server->protectedProperties[] = self::OWNER_ID_PROPERTYNAME;
157
-		$server->protectedProperties[] = self::OWNER_DISPLAY_NAME_PROPERTYNAME;
158
-		$server->protectedProperties[] = self::CHECKSUMS_PROPERTYNAME;
159
-		$server->protectedProperties[] = self::DATA_FINGERPRINT_PROPERTYNAME;
160
-		$server->protectedProperties[] = self::HAS_PREVIEW_PROPERTYNAME;
161
-
162
-		// normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH
163
-		$allowedProperties = ['{DAV:}getetag'];
164
-		$server->protectedProperties = array_diff($server->protectedProperties, $allowedProperties);
165
-
166
-		$this->server = $server;
167
-		$this->server->on('propFind', array($this, 'handleGetProperties'));
168
-		$this->server->on('propPatch', array($this, 'handleUpdateProperties'));
169
-		$this->server->on('afterBind', array($this, 'sendFileIdHeader'));
170
-		$this->server->on('afterWriteContent', array($this, 'sendFileIdHeader'));
171
-		$this->server->on('afterMethod:GET', [$this,'httpGet']);
172
-		$this->server->on('afterMethod:GET', array($this, 'handleDownloadToken'));
173
-		$this->server->on('afterResponse', function($request, ResponseInterface $response) {
174
-			$body = $response->getBody();
175
-			if (is_resource($body)) {
176
-				fclose($body);
177
-			}
178
-		});
179
-		$this->server->on('beforeMove', [$this, 'checkMove']);
180
-	}
181
-
182
-	/**
183
-	 * Plugin that checks if a move can actually be performed.
184
-	 *
185
-	 * @param string $source source path
186
-	 * @param string $destination destination path
187
-	 * @throws Forbidden
188
-	 * @throws NotFound
189
-	 */
190
-	function checkMove($source, $destination) {
191
-		$sourceNode = $this->tree->getNodeForPath($source);
192
-		if (!$sourceNode instanceof Node) {
193
-			return;
194
-		}
195
-		list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($source);
196
-		list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination);
197
-
198
-		if ($sourceDir !== $destinationDir) {
199
-			$sourceNodeFileInfo = $sourceNode->getFileInfo();
200
-			if (is_null($sourceNodeFileInfo)) {
201
-				throw new NotFound($source . ' does not exist');
202
-			}
203
-
204
-			if (!$sourceNodeFileInfo->isDeletable()) {
205
-				throw new Forbidden($source . " cannot be deleted");
206
-			}
207
-		}
208
-	}
209
-
210
-	/**
211
-	 * This sets a cookie to be able to recognize the start of the download
212
-	 * the content must not be longer than 32 characters and must only contain
213
-	 * alphanumeric characters
214
-	 *
215
-	 * @param RequestInterface $request
216
-	 * @param ResponseInterface $response
217
-	 */
218
-	function handleDownloadToken(RequestInterface $request, ResponseInterface $response) {
219
-		$queryParams = $request->getQueryParameters();
220
-
221
-		/**
222
-		 * this sets a cookie to be able to recognize the start of the download
223
-		 * the content must not be longer than 32 characters and must only contain
224
-		 * alphanumeric characters
225
-		 */
226
-		if (isset($queryParams['downloadStartSecret'])) {
227
-			$token = $queryParams['downloadStartSecret'];
228
-			if (!isset($token[32])
229
-				&& preg_match('!^[a-zA-Z0-9]+$!', $token) === 1) {
230
-				// FIXME: use $response->setHeader() instead
231
-				setcookie('ocDownloadStarted', $token, time() + 20, '/');
232
-			}
233
-		}
234
-	}
235
-
236
-	/**
237
-	 * Add headers to file download
238
-	 *
239
-	 * @param RequestInterface $request
240
-	 * @param ResponseInterface $response
241
-	 */
242
-	function httpGet(RequestInterface $request, ResponseInterface $response) {
243
-		// Only handle valid files
244
-		$node = $this->tree->getNodeForPath($request->getPath());
245
-		if (!($node instanceof IFile)) return;
246
-
247
-		// adds a 'Content-Disposition: attachment' header in case no disposition
248
-		// header has been set before
249
-		if ($this->downloadAttachment &&
250
-			$response->getHeader('Content-Disposition') === null) {
251
-			$filename = $node->getName();
252
-			if ($this->request->isUserAgent(
253
-				[
254
-					\OC\AppFramework\Http\Request::USER_AGENT_IE,
255
-					\OC\AppFramework\Http\Request::USER_AGENT_ANDROID_MOBILE_CHROME,
256
-					\OC\AppFramework\Http\Request::USER_AGENT_FREEBOX,
257
-				])) {
258
-				$response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"');
259
-			} else {
260
-				$response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\'' . rawurlencode($filename)
261
-													 . '; filename="' . rawurlencode($filename) . '"');
262
-			}
263
-		}
264
-
265
-		if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
266
-			//Add OC-Checksum header
267
-			/** @var $node File */
268
-			$checksum = $node->getChecksum('sha1');
269
-			if ($checksum !== null && $checksum !== '') {
270
-				$response->addHeader('OC-Checksum', $checksum);
271
-			}
272
-		}
273
-	}
274
-
275
-	/**
276
-	 * Adds all ownCloud-specific properties
277
-	 *
278
-	 * @param PropFind $propFind
279
-	 * @param \Sabre\DAV\INode $node
280
-	 * @return void
281
-	 */
282
-	public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) {
283
-
284
-		$httpRequest = $this->server->httpRequest;
285
-
286
-		if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
287
-
288
-			$propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) {
289
-				return $node->getFileId();
290
-			});
291
-
292
-			$propFind->handle(self::INTERNAL_FILEID_PROPERTYNAME, function() use ($node) {
293
-				return $node->getInternalFileId();
294
-			});
295
-
296
-			$propFind->handle(self::PERMISSIONS_PROPERTYNAME, function() use ($node) {
297
-				$perms = $node->getDavPermissions();
298
-				if ($this->isPublic) {
299
-					// remove mount information
300
-					$perms = str_replace(['S', 'M'], '', $perms);
301
-				}
302
-				return $perms;
303
-			});
304
-
305
-			$propFind->handle(self::SHARE_PERMISSIONS_PROPERTYNAME, function() use ($node, $httpRequest) {
306
-				return $node->getSharePermissions(
307
-					$httpRequest->getRawServerValue('PHP_AUTH_USER')
308
-				);
309
-			});
310
-
311
-			$propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) {
312
-				return $node->getETag();
313
-			});
314
-
315
-			$propFind->handle(self::OWNER_ID_PROPERTYNAME, function() use ($node) {
316
-				$owner = $node->getOwner();
317
-				if (!$owner) {
318
-					return null;
319
-				} else {
320
-					return $owner->getUID();
321
-				}
322
-			});
323
-			$propFind->handle(self::OWNER_DISPLAY_NAME_PROPERTYNAME, function() use ($node) {
324
-				$owner = $node->getOwner();
325
-				if (!$owner) {
326
-					return null;
327
-				} else {
328
-					return $owner->getDisplayName();
329
-				}
330
-			});
331
-
332
-			$propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function () use ($node) {
333
-				return json_encode($this->previewManager->isAvailable($node->getFileInfo()));
334
-			});
335
-			$propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
336
-				return $node->getSize();
337
-			});
338
-		}
339
-
340
-		if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
341
-			$propFind->handle(self::DATA_FINGERPRINT_PROPERTYNAME, function() use ($node) {
342
-				return $this->config->getSystemValue('data-fingerprint', '');
343
-			});
344
-		}
345
-
346
-		if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
347
-			$propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) {
348
-				/** @var $node \OCA\DAV\Connector\Sabre\File */
349
-				try {
350
-					$directDownloadUrl = $node->getDirectDownload();
351
-					if (isset($directDownloadUrl['url'])) {
352
-						return $directDownloadUrl['url'];
353
-					}
354
-				} catch (StorageNotAvailableException $e) {
355
-					return false;
356
-				} catch (ForbiddenException $e) {
357
-					return false;
358
-				}
359
-				return false;
360
-			});
361
-
362
-			$propFind->handle(self::CHECKSUMS_PROPERTYNAME, function() use ($node) {
363
-				$checksum = $node->getChecksum();
364
-				if ($checksum === NULL || $checksum === '') {
365
-					return null;
366
-				}
367
-
368
-				return new ChecksumList($checksum);
369
-			});
370
-
371
-		}
372
-
373
-		if ($node instanceof \OCA\DAV\Connector\Sabre\Directory) {
374
-			$propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
375
-				return $node->getSize();
376
-			});
377
-		}
378
-	}
379
-
380
-	/**
381
-	 * Update ownCloud-specific properties
382
-	 *
383
-	 * @param string $path
384
-	 * @param PropPatch $propPatch
385
-	 *
386
-	 * @return void
387
-	 */
388
-	public function handleUpdateProperties($path, PropPatch $propPatch) {
389
-		$node = $this->tree->getNodeForPath($path);
390
-		if (!($node instanceof \OCA\DAV\Connector\Sabre\Node)) {
391
-			return;
392
-		}
393
-
394
-		$propPatch->handle(self::LASTMODIFIED_PROPERTYNAME, function($time) use ($node) {
395
-			if (empty($time)) {
396
-				return false;
397
-			}
398
-			$node->touch($time);
399
-			return true;
400
-		});
401
-		$propPatch->handle(self::GETETAG_PROPERTYNAME, function($etag) use ($node) {
402
-			if (empty($etag)) {
403
-				return false;
404
-			}
405
-			if ($node->setEtag($etag) !== -1) {
406
-				return true;
407
-			}
408
-			return false;
409
-		});
410
-	}
411
-
412
-	/**
413
-	 * @param string $filePath
414
-	 * @param \Sabre\DAV\INode $node
415
-	 * @throws \Sabre\DAV\Exception\BadRequest
416
-	 */
417
-	public function sendFileIdHeader($filePath, \Sabre\DAV\INode $node = null) {
418
-		// chunked upload handling
419
-		if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
420
-			list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath);
421
-			$info = \OC_FileChunking::decodeName($name);
422
-			if (!empty($info)) {
423
-				$filePath = $path . '/' . $info['name'];
424
-			}
425
-		}
426
-
427
-		// we get the node for the given $filePath here because in case of afterCreateFile $node is the parent folder
428
-		if (!$this->server->tree->nodeExists($filePath)) {
429
-			return;
430
-		}
431
-		$node = $this->server->tree->getNodeForPath($filePath);
432
-		if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
433
-			$fileId = $node->getFileId();
434
-			if (!is_null($fileId)) {
435
-				$this->server->httpResponse->setHeader('OC-FileId', $fileId);
436
-			}
437
-		}
438
-	}
51
+    // namespace
52
+    const NS_OWNCLOUD = 'http://owncloud.org/ns';
53
+    const NS_NEXTCLOUD = 'http://nextcloud.org/ns';
54
+    const FILEID_PROPERTYNAME = '{http://owncloud.org/ns}id';
55
+    const INTERNAL_FILEID_PROPERTYNAME = '{http://owncloud.org/ns}fileid';
56
+    const PERMISSIONS_PROPERTYNAME = '{http://owncloud.org/ns}permissions';
57
+    const SHARE_PERMISSIONS_PROPERTYNAME = '{http://open-collaboration-services.org/ns}share-permissions';
58
+    const DOWNLOADURL_PROPERTYNAME = '{http://owncloud.org/ns}downloadURL';
59
+    const SIZE_PROPERTYNAME = '{http://owncloud.org/ns}size';
60
+    const GETETAG_PROPERTYNAME = '{DAV:}getetag';
61
+    const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified';
62
+    const OWNER_ID_PROPERTYNAME = '{http://owncloud.org/ns}owner-id';
63
+    const OWNER_DISPLAY_NAME_PROPERTYNAME = '{http://owncloud.org/ns}owner-display-name';
64
+    const CHECKSUMS_PROPERTYNAME = '{http://owncloud.org/ns}checksums';
65
+    const DATA_FINGERPRINT_PROPERTYNAME = '{http://owncloud.org/ns}data-fingerprint';
66
+    const HAS_PREVIEW_PROPERTYNAME = '{http://nextcloud.org/ns}has-preview';
67
+
68
+    /**
69
+     * Reference to main server object
70
+     *
71
+     * @var \Sabre\DAV\Server
72
+     */
73
+    private $server;
74
+
75
+    /**
76
+     * @var Tree
77
+     */
78
+    private $tree;
79
+
80
+    /**
81
+     * Whether this is public webdav.
82
+     * If true, some returned information will be stripped off.
83
+     *
84
+     * @var bool
85
+     */
86
+    private $isPublic;
87
+
88
+    /**
89
+     * @var View
90
+     */
91
+    private $fileView;
92
+
93
+    /**
94
+     * @var bool
95
+     */
96
+    private $downloadAttachment;
97
+
98
+    /**
99
+     * @var IConfig
100
+     */
101
+    private $config;
102
+
103
+    /**
104
+     * @var IRequest
105
+     */
106
+    private $request;
107
+
108
+    /**
109
+     * @var IPreview
110
+     */
111
+    private $previewManager;
112
+
113
+    /**
114
+     * @param Tree $tree
115
+     * @param IConfig $config
116
+     * @param IRequest $request
117
+     * @param IPreview $previewManager
118
+     * @param bool $isPublic
119
+     * @param bool $downloadAttachment
120
+     */
121
+    public function __construct(Tree $tree,
122
+                                IConfig $config,
123
+                                IRequest $request,
124
+                                IPreview $previewManager,
125
+                                $isPublic = false,
126
+                                $downloadAttachment = true) {
127
+        $this->tree = $tree;
128
+        $this->config = $config;
129
+        $this->request = $request;
130
+        $this->isPublic = $isPublic;
131
+        $this->downloadAttachment = $downloadAttachment;
132
+        $this->previewManager = $previewManager;
133
+    }
134
+
135
+    /**
136
+     * This initializes the plugin.
137
+     *
138
+     * This function is called by \Sabre\DAV\Server, after
139
+     * addPlugin is called.
140
+     *
141
+     * This method should set up the required event subscriptions.
142
+     *
143
+     * @param \Sabre\DAV\Server $server
144
+     * @return void
145
+     */
146
+    public function initialize(\Sabre\DAV\Server $server) {
147
+
148
+        $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';
149
+        $server->xml->namespaceMap[self::NS_NEXTCLOUD] = 'nc';
150
+        $server->protectedProperties[] = self::FILEID_PROPERTYNAME;
151
+        $server->protectedProperties[] = self::INTERNAL_FILEID_PROPERTYNAME;
152
+        $server->protectedProperties[] = self::PERMISSIONS_PROPERTYNAME;
153
+        $server->protectedProperties[] = self::SHARE_PERMISSIONS_PROPERTYNAME;
154
+        $server->protectedProperties[] = self::SIZE_PROPERTYNAME;
155
+        $server->protectedProperties[] = self::DOWNLOADURL_PROPERTYNAME;
156
+        $server->protectedProperties[] = self::OWNER_ID_PROPERTYNAME;
157
+        $server->protectedProperties[] = self::OWNER_DISPLAY_NAME_PROPERTYNAME;
158
+        $server->protectedProperties[] = self::CHECKSUMS_PROPERTYNAME;
159
+        $server->protectedProperties[] = self::DATA_FINGERPRINT_PROPERTYNAME;
160
+        $server->protectedProperties[] = self::HAS_PREVIEW_PROPERTYNAME;
161
+
162
+        // normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH
163
+        $allowedProperties = ['{DAV:}getetag'];
164
+        $server->protectedProperties = array_diff($server->protectedProperties, $allowedProperties);
165
+
166
+        $this->server = $server;
167
+        $this->server->on('propFind', array($this, 'handleGetProperties'));
168
+        $this->server->on('propPatch', array($this, 'handleUpdateProperties'));
169
+        $this->server->on('afterBind', array($this, 'sendFileIdHeader'));
170
+        $this->server->on('afterWriteContent', array($this, 'sendFileIdHeader'));
171
+        $this->server->on('afterMethod:GET', [$this,'httpGet']);
172
+        $this->server->on('afterMethod:GET', array($this, 'handleDownloadToken'));
173
+        $this->server->on('afterResponse', function($request, ResponseInterface $response) {
174
+            $body = $response->getBody();
175
+            if (is_resource($body)) {
176
+                fclose($body);
177
+            }
178
+        });
179
+        $this->server->on('beforeMove', [$this, 'checkMove']);
180
+    }
181
+
182
+    /**
183
+     * Plugin that checks if a move can actually be performed.
184
+     *
185
+     * @param string $source source path
186
+     * @param string $destination destination path
187
+     * @throws Forbidden
188
+     * @throws NotFound
189
+     */
190
+    function checkMove($source, $destination) {
191
+        $sourceNode = $this->tree->getNodeForPath($source);
192
+        if (!$sourceNode instanceof Node) {
193
+            return;
194
+        }
195
+        list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($source);
196
+        list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination);
197
+
198
+        if ($sourceDir !== $destinationDir) {
199
+            $sourceNodeFileInfo = $sourceNode->getFileInfo();
200
+            if (is_null($sourceNodeFileInfo)) {
201
+                throw new NotFound($source . ' does not exist');
202
+            }
203
+
204
+            if (!$sourceNodeFileInfo->isDeletable()) {
205
+                throw new Forbidden($source . " cannot be deleted");
206
+            }
207
+        }
208
+    }
209
+
210
+    /**
211
+     * This sets a cookie to be able to recognize the start of the download
212
+     * the content must not be longer than 32 characters and must only contain
213
+     * alphanumeric characters
214
+     *
215
+     * @param RequestInterface $request
216
+     * @param ResponseInterface $response
217
+     */
218
+    function handleDownloadToken(RequestInterface $request, ResponseInterface $response) {
219
+        $queryParams = $request->getQueryParameters();
220
+
221
+        /**
222
+         * this sets a cookie to be able to recognize the start of the download
223
+         * the content must not be longer than 32 characters and must only contain
224
+         * alphanumeric characters
225
+         */
226
+        if (isset($queryParams['downloadStartSecret'])) {
227
+            $token = $queryParams['downloadStartSecret'];
228
+            if (!isset($token[32])
229
+                && preg_match('!^[a-zA-Z0-9]+$!', $token) === 1) {
230
+                // FIXME: use $response->setHeader() instead
231
+                setcookie('ocDownloadStarted', $token, time() + 20, '/');
232
+            }
233
+        }
234
+    }
235
+
236
+    /**
237
+     * Add headers to file download
238
+     *
239
+     * @param RequestInterface $request
240
+     * @param ResponseInterface $response
241
+     */
242
+    function httpGet(RequestInterface $request, ResponseInterface $response) {
243
+        // Only handle valid files
244
+        $node = $this->tree->getNodeForPath($request->getPath());
245
+        if (!($node instanceof IFile)) return;
246
+
247
+        // adds a 'Content-Disposition: attachment' header in case no disposition
248
+        // header has been set before
249
+        if ($this->downloadAttachment &&
250
+            $response->getHeader('Content-Disposition') === null) {
251
+            $filename = $node->getName();
252
+            if ($this->request->isUserAgent(
253
+                [
254
+                    \OC\AppFramework\Http\Request::USER_AGENT_IE,
255
+                    \OC\AppFramework\Http\Request::USER_AGENT_ANDROID_MOBILE_CHROME,
256
+                    \OC\AppFramework\Http\Request::USER_AGENT_FREEBOX,
257
+                ])) {
258
+                $response->addHeader('Content-Disposition', 'attachment; filename="' . rawurlencode($filename) . '"');
259
+            } else {
260
+                $response->addHeader('Content-Disposition', 'attachment; filename*=UTF-8\'\'' . rawurlencode($filename)
261
+                                                        . '; filename="' . rawurlencode($filename) . '"');
262
+            }
263
+        }
264
+
265
+        if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
266
+            //Add OC-Checksum header
267
+            /** @var $node File */
268
+            $checksum = $node->getChecksum('sha1');
269
+            if ($checksum !== null && $checksum !== '') {
270
+                $response->addHeader('OC-Checksum', $checksum);
271
+            }
272
+        }
273
+    }
274
+
275
+    /**
276
+     * Adds all ownCloud-specific properties
277
+     *
278
+     * @param PropFind $propFind
279
+     * @param \Sabre\DAV\INode $node
280
+     * @return void
281
+     */
282
+    public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) {
283
+
284
+        $httpRequest = $this->server->httpRequest;
285
+
286
+        if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
287
+
288
+            $propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) {
289
+                return $node->getFileId();
290
+            });
291
+
292
+            $propFind->handle(self::INTERNAL_FILEID_PROPERTYNAME, function() use ($node) {
293
+                return $node->getInternalFileId();
294
+            });
295
+
296
+            $propFind->handle(self::PERMISSIONS_PROPERTYNAME, function() use ($node) {
297
+                $perms = $node->getDavPermissions();
298
+                if ($this->isPublic) {
299
+                    // remove mount information
300
+                    $perms = str_replace(['S', 'M'], '', $perms);
301
+                }
302
+                return $perms;
303
+            });
304
+
305
+            $propFind->handle(self::SHARE_PERMISSIONS_PROPERTYNAME, function() use ($node, $httpRequest) {
306
+                return $node->getSharePermissions(
307
+                    $httpRequest->getRawServerValue('PHP_AUTH_USER')
308
+                );
309
+            });
310
+
311
+            $propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) {
312
+                return $node->getETag();
313
+            });
314
+
315
+            $propFind->handle(self::OWNER_ID_PROPERTYNAME, function() use ($node) {
316
+                $owner = $node->getOwner();
317
+                if (!$owner) {
318
+                    return null;
319
+                } else {
320
+                    return $owner->getUID();
321
+                }
322
+            });
323
+            $propFind->handle(self::OWNER_DISPLAY_NAME_PROPERTYNAME, function() use ($node) {
324
+                $owner = $node->getOwner();
325
+                if (!$owner) {
326
+                    return null;
327
+                } else {
328
+                    return $owner->getDisplayName();
329
+                }
330
+            });
331
+
332
+            $propFind->handle(self::HAS_PREVIEW_PROPERTYNAME, function () use ($node) {
333
+                return json_encode($this->previewManager->isAvailable($node->getFileInfo()));
334
+            });
335
+            $propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
336
+                return $node->getSize();
337
+            });
338
+        }
339
+
340
+        if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
341
+            $propFind->handle(self::DATA_FINGERPRINT_PROPERTYNAME, function() use ($node) {
342
+                return $this->config->getSystemValue('data-fingerprint', '');
343
+            });
344
+        }
345
+
346
+        if ($node instanceof \OCA\DAV\Connector\Sabre\File) {
347
+            $propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) {
348
+                /** @var $node \OCA\DAV\Connector\Sabre\File */
349
+                try {
350
+                    $directDownloadUrl = $node->getDirectDownload();
351
+                    if (isset($directDownloadUrl['url'])) {
352
+                        return $directDownloadUrl['url'];
353
+                    }
354
+                } catch (StorageNotAvailableException $e) {
355
+                    return false;
356
+                } catch (ForbiddenException $e) {
357
+                    return false;
358
+                }
359
+                return false;
360
+            });
361
+
362
+            $propFind->handle(self::CHECKSUMS_PROPERTYNAME, function() use ($node) {
363
+                $checksum = $node->getChecksum();
364
+                if ($checksum === NULL || $checksum === '') {
365
+                    return null;
366
+                }
367
+
368
+                return new ChecksumList($checksum);
369
+            });
370
+
371
+        }
372
+
373
+        if ($node instanceof \OCA\DAV\Connector\Sabre\Directory) {
374
+            $propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
375
+                return $node->getSize();
376
+            });
377
+        }
378
+    }
379
+
380
+    /**
381
+     * Update ownCloud-specific properties
382
+     *
383
+     * @param string $path
384
+     * @param PropPatch $propPatch
385
+     *
386
+     * @return void
387
+     */
388
+    public function handleUpdateProperties($path, PropPatch $propPatch) {
389
+        $node = $this->tree->getNodeForPath($path);
390
+        if (!($node instanceof \OCA\DAV\Connector\Sabre\Node)) {
391
+            return;
392
+        }
393
+
394
+        $propPatch->handle(self::LASTMODIFIED_PROPERTYNAME, function($time) use ($node) {
395
+            if (empty($time)) {
396
+                return false;
397
+            }
398
+            $node->touch($time);
399
+            return true;
400
+        });
401
+        $propPatch->handle(self::GETETAG_PROPERTYNAME, function($etag) use ($node) {
402
+            if (empty($etag)) {
403
+                return false;
404
+            }
405
+            if ($node->setEtag($etag) !== -1) {
406
+                return true;
407
+            }
408
+            return false;
409
+        });
410
+    }
411
+
412
+    /**
413
+     * @param string $filePath
414
+     * @param \Sabre\DAV\INode $node
415
+     * @throws \Sabre\DAV\Exception\BadRequest
416
+     */
417
+    public function sendFileIdHeader($filePath, \Sabre\DAV\INode $node = null) {
418
+        // chunked upload handling
419
+        if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
420
+            list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath);
421
+            $info = \OC_FileChunking::decodeName($name);
422
+            if (!empty($info)) {
423
+                $filePath = $path . '/' . $info['name'];
424
+            }
425
+        }
426
+
427
+        // we get the node for the given $filePath here because in case of afterCreateFile $node is the parent folder
428
+        if (!$this->server->tree->nodeExists($filePath)) {
429
+            return;
430
+        }
431
+        $node = $this->server->tree->getNodeForPath($filePath);
432
+        if ($node instanceof \OCA\DAV\Connector\Sabre\Node) {
433
+            $fileId = $node->getFileId();
434
+            if (!is_null($fileId)) {
435
+                $this->server->httpResponse->setHeader('OC-FileId', $fileId);
436
+            }
437
+        }
438
+    }
439 439
 }
Please login to merge, or discard this patch.