Passed
Push — master ( 36b7fc...79ec7b )
by Morris
30:25 queued 13:08
created
apps/dav/lib/Connector/Sabre/File.php 2 patches
Indentation   +563 added lines, -563 removed lines patch added patch discarded remove patch
@@ -68,567 +68,567 @@
 block discarded – undo
68 68
 
69 69
 class File extends Node implements IFile {
70 70
 
71
-	protected $request;
72
-
73
-	/**
74
-	 * Sets up the node, expects a full path name
75
-	 *
76
-	 * @param \OC\Files\View $view
77
-	 * @param \OCP\Files\FileInfo $info
78
-	 * @param \OCP\Share\IManager $shareManager
79
-	 * @param \OC\AppFramework\Http\Request $request
80
-	 */
81
-	public function __construct(View $view, FileInfo $info, IManager $shareManager = null, Request $request = null) {
82
-		parent::__construct($view, $info, $shareManager);
83
-
84
-		if (isset($request)) {
85
-			$this->request = $request;
86
-		} else {
87
-			$this->request = \OC::$server->getRequest();
88
-		}
89
-	}
90
-
91
-	/**
92
-	 * Updates the data
93
-	 *
94
-	 * The data argument is a readable stream resource.
95
-	 *
96
-	 * After a successful put operation, you may choose to return an ETag. The
97
-	 * etag must always be surrounded by double-quotes. These quotes must
98
-	 * appear in the actual string you're returning.
99
-	 *
100
-	 * Clients may use the ETag from a PUT request to later on make sure that
101
-	 * when they update the file, the contents haven't changed in the mean
102
-	 * time.
103
-	 *
104
-	 * If you don't plan to store the file byte-by-byte, and you return a
105
-	 * different object on a subsequent GET you are strongly recommended to not
106
-	 * return an ETag, and just return null.
107
-	 *
108
-	 * @param resource $data
109
-	 *
110
-	 * @throws Forbidden
111
-	 * @throws UnsupportedMediaType
112
-	 * @throws BadRequest
113
-	 * @throws Exception
114
-	 * @throws EntityTooLarge
115
-	 * @throws ServiceUnavailable
116
-	 * @throws FileLocked
117
-	 * @return string|null
118
-	 */
119
-	public function put($data) {
120
-		try {
121
-			$exists = $this->fileView->file_exists($this->path);
122
-			if ($this->info && $exists && !$this->info->isUpdateable()) {
123
-				throw new Forbidden();
124
-			}
125
-		} catch (StorageNotAvailableException $e) {
126
-			throw new ServiceUnavailable("File is not updatable: " . $e->getMessage());
127
-		}
128
-
129
-		// verify path of the target
130
-		$this->verifyPath();
131
-
132
-		// chunked handling
133
-		if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
134
-			try {
135
-				return $this->createFileChunked($data);
136
-			} catch (\Exception $e) {
137
-				$this->convertToSabreException($e);
138
-			}
139
-		}
140
-
141
-		/** @var Storage $partStorage */
142
-		list($partStorage) = $this->fileView->resolvePath($this->path);
143
-		$needsPartFile = $partStorage->needsPartFile() && (strlen($this->path) > 1);
144
-
145
-		$view = \OC\Files\Filesystem::getView();
146
-
147
-		if ($needsPartFile) {
148
-			// mark file as partial while uploading (ignored by the scanner)
149
-			$partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part';
150
-		} else {
151
-			// upload file directly as the final path
152
-			$partFilePath = $this->path;
153
-
154
-			if ($view && !$this->emitPreHooks($exists)) {
155
-				throw new Exception('Could not write to final file, canceled by hook');
156
-			}
157
-		}
158
-
159
-		// the part file and target file might be on a different storage in case of a single file storage (e.g. single file share)
160
-		/** @var \OC\Files\Storage\Storage $partStorage */
161
-		list($partStorage, $internalPartPath) = $this->fileView->resolvePath($partFilePath);
162
-		/** @var \OC\Files\Storage\Storage $storage */
163
-		list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
164
-		try {
165
-			if (!$needsPartFile) {
166
-				$this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
167
-			}
168
-
169
-			if ($partStorage->instanceOfStorage(Storage\IWriteStreamStorage::class)) {
170
-
171
-				if (!is_resource($data)) {
172
-					$data = fopen('php://temp', 'r+');
173
-					fwrite($data, 'foobar');
174
-					rewind($data);
175
-				}
176
-
177
-				$isEOF = false;
178
-				$wrappedData = CallbackWrapper::wrap($data, null, null, null, null, function($stream) use (&$isEOF) {
179
-					$isEOF = feof($stream);
180
-				});
181
-
182
-				$count = $partStorage->writeStream($internalPartPath, $wrappedData);
183
-				$result = $count > 0;
184
-
185
-				if ($result === false) {
186
-					$result = $isEOF;
187
-					if (is_resource($wrappedData)) {
188
-						$result = feof($wrappedData);
189
-					}
190
-				}
191
-
192
-			} else {
193
-				$target = $partStorage->fopen($internalPartPath, 'wb');
194
-				if ($target === false) {
195
-					\OC::$server->getLogger()->error('\OC\Files\Filesystem::fopen() failed', ['app' => 'webdav']);
196
-					// because we have no clue about the cause we can only throw back a 500/Internal Server Error
197
-					throw new Exception('Could not write file contents');
198
-				}
199
-				list($count, $result) = \OC_Helper::streamCopy($data, $target);
200
-				fclose($target);
201
-			}
202
-
203
-			if ($result === false) {
204
-				$expected = -1;
205
-				if (isset($_SERVER['CONTENT_LENGTH'])) {
206
-					$expected = $_SERVER['CONTENT_LENGTH'];
207
-				}
208
-				if ($expected !== "0") {
209
-					throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )');
210
-				}
211
-			}
212
-
213
-			// if content length is sent by client:
214
-			// double check if the file was fully received
215
-			// compare expected and actual size
216
-			if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
217
-				$expected = (int)$_SERVER['CONTENT_LENGTH'];
218
-				if ($count !== $expected) {
219
-					throw new BadRequest('expected filesize ' . $expected . ' got ' . $count);
220
-				}
221
-			}
222
-
223
-		} catch (\Exception $e) {
224
-			\OC::$server->getLogger()->logException($e);
225
-			if ($needsPartFile) {
226
-				$partStorage->unlink($internalPartPath);
227
-			}
228
-			$this->convertToSabreException($e);
229
-		}
230
-
231
-		try {
232
-			if ($needsPartFile) {
233
-				if ($view && !$this->emitPreHooks($exists)) {
234
-					$partStorage->unlink($internalPartPath);
235
-					throw new Exception('Could not rename part file to final file, canceled by hook');
236
-				}
237
-				try {
238
-					$this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
239
-				} catch (LockedException $e) {
240
-					if ($needsPartFile) {
241
-						$partStorage->unlink($internalPartPath);
242
-					}
243
-					throw new FileLocked($e->getMessage(), $e->getCode(), $e);
244
-				}
245
-
246
-				// rename to correct path
247
-				try {
248
-					$renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath);
249
-					$fileExists = $storage->file_exists($internalPath);
250
-					if ($renameOkay === false || $fileExists === false) {
251
-						\OC::$server->getLogger()->error('renaming part file to final file failed $renameOkay: ' . ($renameOkay ? 'true' : 'false') . ', $fileExists: ' . ($fileExists ? 'true' : 'false') . ')', ['app' => 'webdav']);
252
-						throw new Exception('Could not rename part file to final file');
253
-					}
254
-				} catch (ForbiddenException $ex) {
255
-					throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
256
-				} catch (\Exception $e) {
257
-					$partStorage->unlink($internalPartPath);
258
-					$this->convertToSabreException($e);
259
-				}
260
-			}
261
-
262
-			// since we skipped the view we need to scan and emit the hooks ourselves
263
-			$storage->getUpdater()->update($internalPath);
264
-
265
-			try {
266
-				$this->changeLock(ILockingProvider::LOCK_SHARED);
267
-			} catch (LockedException $e) {
268
-				throw new FileLocked($e->getMessage(), $e->getCode(), $e);
269
-			}
270
-
271
-			// allow sync clients to send the mtime along in a header
272
-			if (isset($this->request->server['HTTP_X_OC_MTIME'])) {
273
-				$mtime = $this->sanitizeMtime($this->request->server['HTTP_X_OC_MTIME']);
274
-				if ($this->fileView->touch($this->path, $mtime)) {
275
-					$this->header('X-OC-MTime: accepted');
276
-				}
277
-			}
278
-
279
-			if ($view) {
280
-				$this->emitPostHooks($exists);
281
-			}
282
-
283
-			$this->refreshInfo();
284
-
285
-			if (isset($this->request->server['HTTP_OC_CHECKSUM'])) {
286
-				$checksum = trim($this->request->server['HTTP_OC_CHECKSUM']);
287
-				$this->fileView->putFileInfo($this->path, ['checksum' => $checksum]);
288
-				$this->refreshInfo();
289
-			} else if ($this->getChecksum() !== null && $this->getChecksum() !== '') {
290
-				$this->fileView->putFileInfo($this->path, ['checksum' => '']);
291
-				$this->refreshInfo();
292
-			}
293
-
294
-		} catch (StorageNotAvailableException $e) {
295
-			throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
296
-		}
297
-
298
-		return '"' . $this->info->getEtag() . '"';
299
-	}
300
-
301
-	private function getPartFileBasePath($path) {
302
-		$partFileInStorage = \OC::$server->getConfig()->getSystemValue('part_file_in_storage', true);
303
-		if ($partFileInStorage) {
304
-			return $path;
305
-		} else {
306
-			return md5($path); // will place it in the root of the view with a unique name
307
-		}
308
-	}
309
-
310
-	/**
311
-	 * @param string $path
312
-	 */
313
-	private function emitPreHooks($exists, $path = null) {
314
-		if (is_null($path)) {
315
-			$path = $this->path;
316
-		}
317
-		$hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
318
-		$run = true;
319
-
320
-		if (!$exists) {
321
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_create, array(
322
-				\OC\Files\Filesystem::signal_param_path => $hookPath,
323
-				\OC\Files\Filesystem::signal_param_run => &$run,
324
-			));
325
-		} else {
326
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_update, array(
327
-				\OC\Files\Filesystem::signal_param_path => $hookPath,
328
-				\OC\Files\Filesystem::signal_param_run => &$run,
329
-			));
330
-		}
331
-		\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_write, array(
332
-			\OC\Files\Filesystem::signal_param_path => $hookPath,
333
-			\OC\Files\Filesystem::signal_param_run => &$run,
334
-		));
335
-		return $run;
336
-	}
337
-
338
-	/**
339
-	 * @param string $path
340
-	 */
341
-	private function emitPostHooks($exists, $path = null) {
342
-		if (is_null($path)) {
343
-			$path = $this->path;
344
-		}
345
-		$hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
346
-		if (!$exists) {
347
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_create, array(
348
-				\OC\Files\Filesystem::signal_param_path => $hookPath
349
-			));
350
-		} else {
351
-			\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_update, array(
352
-				\OC\Files\Filesystem::signal_param_path => $hookPath
353
-			));
354
-		}
355
-		\OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_write, array(
356
-			\OC\Files\Filesystem::signal_param_path => $hookPath
357
-		));
358
-	}
359
-
360
-	/**
361
-	 * Returns the data
362
-	 *
363
-	 * @return resource
364
-	 * @throws Forbidden
365
-	 * @throws ServiceUnavailable
366
-	 */
367
-	public function get() {
368
-		//throw exception if encryption is disabled but files are still encrypted
369
-		try {
370
-			if (!$this->info->isReadable()) {
371
-				// do a if the file did not exist
372
-				throw new NotFound();
373
-			}
374
-			try {
375
-				$res = $this->fileView->fopen(ltrim($this->path, '/'), 'rb');
376
-			} catch (\Exception $e) {
377
-				$this->convertToSabreException($e);
378
-			}
379
-			if ($res === false) {
380
-				throw new ServiceUnavailable("Could not open file");
381
-			}
382
-			return $res;
383
-		} catch (GenericEncryptionException $e) {
384
-			// returning 503 will allow retry of the operation at a later point in time
385
-			throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage());
386
-		} catch (StorageNotAvailableException $e) {
387
-			throw new ServiceUnavailable("Failed to open file: " . $e->getMessage());
388
-		} catch (ForbiddenException $ex) {
389
-			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
390
-		} catch (LockedException $e) {
391
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
392
-		}
393
-	}
394
-
395
-	/**
396
-	 * Delete the current file
397
-	 *
398
-	 * @throws Forbidden
399
-	 * @throws ServiceUnavailable
400
-	 */
401
-	public function delete() {
402
-		if (!$this->info->isDeletable()) {
403
-			throw new Forbidden();
404
-		}
405
-
406
-		try {
407
-			if (!$this->fileView->unlink($this->path)) {
408
-				// assume it wasn't possible to delete due to permissions
409
-				throw new Forbidden();
410
-			}
411
-		} catch (StorageNotAvailableException $e) {
412
-			throw new ServiceUnavailable("Failed to unlink: " . $e->getMessage());
413
-		} catch (ForbiddenException $ex) {
414
-			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
415
-		} catch (LockedException $e) {
416
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
417
-		}
418
-	}
419
-
420
-	/**
421
-	 * Returns the mime-type for a file
422
-	 *
423
-	 * If null is returned, we'll assume application/octet-stream
424
-	 *
425
-	 * @return string
426
-	 */
427
-	public function getContentType() {
428
-		$mimeType = $this->info->getMimetype();
429
-
430
-		// PROPFIND needs to return the correct mime type, for consistency with the web UI
431
-		if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
432
-			return $mimeType;
433
-		}
434
-		return \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType);
435
-	}
436
-
437
-	/**
438
-	 * @return array|false
439
-	 */
440
-	public function getDirectDownload() {
441
-		if (\OCP\App::isEnabled('encryption')) {
442
-			return [];
443
-		}
444
-		/** @var \OCP\Files\Storage $storage */
445
-		list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
446
-		if (is_null($storage)) {
447
-			return [];
448
-		}
449
-
450
-		return $storage->getDirectDownload($internalPath);
451
-	}
452
-
453
-	/**
454
-	 * @param resource $data
455
-	 * @return null|string
456
-	 * @throws Exception
457
-	 * @throws BadRequest
458
-	 * @throws NotImplemented
459
-	 * @throws ServiceUnavailable
460
-	 */
461
-	private function createFileChunked($data) {
462
-		list($path, $name) = \Sabre\Uri\split($this->path);
463
-
464
-		$info = \OC_FileChunking::decodeName($name);
465
-		if (empty($info)) {
466
-			throw new NotImplemented('Invalid chunk name');
467
-		}
468
-
469
-		$chunk_handler = new \OC_FileChunking($info);
470
-		$bytesWritten = $chunk_handler->store($info['index'], $data);
471
-
472
-		//detect aborted upload
473
-		if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
474
-			if (isset($_SERVER['CONTENT_LENGTH'])) {
475
-				$expected = (int)$_SERVER['CONTENT_LENGTH'];
476
-				if ($bytesWritten !== $expected) {
477
-					$chunk_handler->remove($info['index']);
478
-					throw new BadRequest(
479
-						'expected filesize ' . $expected . ' got ' . $bytesWritten);
480
-				}
481
-			}
482
-		}
483
-
484
-		if ($chunk_handler->isComplete()) {
485
-			/** @var Storage $storage */
486
-			list($storage,) = $this->fileView->resolvePath($path);
487
-			$needsPartFile = $storage->needsPartFile();
488
-			$partFile = null;
489
-
490
-			$targetPath = $path . '/' . $info['name'];
491
-			/** @var \OC\Files\Storage\Storage $targetStorage */
492
-			list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
493
-
494
-			$exists = $this->fileView->file_exists($targetPath);
495
-
496
-			try {
497
-				$this->fileView->lockFile($targetPath, ILockingProvider::LOCK_SHARED);
498
-
499
-				$this->emitPreHooks($exists, $targetPath);
500
-				$this->fileView->changeLock($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
501
-				/** @var \OC\Files\Storage\Storage $targetStorage */
502
-				list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
503
-
504
-				if ($needsPartFile) {
505
-					// we first assembly the target file as a part file
506
-					$partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part';
507
-					/** @var \OC\Files\Storage\Storage $targetStorage */
508
-					list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile);
509
-
510
-
511
-					$chunk_handler->file_assemble($partStorage, $partInternalPath);
512
-
513
-					// here is the final atomic rename
514
-					$renameOkay = $targetStorage->moveFromStorage($partStorage, $partInternalPath, $targetInternalPath);
515
-					$fileExists = $targetStorage->file_exists($targetInternalPath);
516
-					if ($renameOkay === false || $fileExists === false) {
517
-						\OC::$server->getLogger()->error('\OC\Files\Filesystem::rename() failed', ['app' => 'webdav']);
518
-						// only delete if an error occurred and the target file was already created
519
-						if ($fileExists) {
520
-							// set to null to avoid double-deletion when handling exception
521
-							// stray part file
522
-							$partFile = null;
523
-							$targetStorage->unlink($targetInternalPath);
524
-						}
525
-						$this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
526
-						throw new Exception('Could not rename part file assembled from chunks');
527
-					}
528
-				} else {
529
-					// assemble directly into the final file
530
-					$chunk_handler->file_assemble($targetStorage, $targetInternalPath);
531
-				}
532
-
533
-				// allow sync clients to send the mtime along in a header
534
-				if (isset($this->request->server['HTTP_X_OC_MTIME'])) {
535
-					$mtime = $this->sanitizeMtime($this->request->server['HTTP_X_OC_MTIME']);
536
-					if ($targetStorage->touch($targetInternalPath, $mtime)) {
537
-						$this->header('X-OC-MTime: accepted');
538
-					}
539
-				}
540
-
541
-				// since we skipped the view we need to scan and emit the hooks ourselves
542
-				$targetStorage->getUpdater()->update($targetInternalPath);
543
-
544
-				$this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
545
-
546
-				$this->emitPostHooks($exists, $targetPath);
547
-
548
-				// FIXME: should call refreshInfo but can't because $this->path is not the of the final file
549
-				$info = $this->fileView->getFileInfo($targetPath);
550
-
551
-				if (isset($this->request->server['HTTP_OC_CHECKSUM'])) {
552
-					$checksum = trim($this->request->server['HTTP_OC_CHECKSUM']);
553
-					$this->fileView->putFileInfo($targetPath, ['checksum' => $checksum]);
554
-				} else if ($info->getChecksum() !== null && $info->getChecksum() !== '') {
555
-					$this->fileView->putFileInfo($this->path, ['checksum' => '']);
556
-				}
557
-
558
-				$this->fileView->unlockFile($targetPath, ILockingProvider::LOCK_SHARED);
559
-
560
-				return $info->getEtag();
561
-			} catch (\Exception $e) {
562
-				if ($partFile !== null) {
563
-					$targetStorage->unlink($targetInternalPath);
564
-				}
565
-				$this->convertToSabreException($e);
566
-			}
567
-		}
568
-
569
-		return null;
570
-	}
571
-
572
-	/**
573
-	 * Convert the given exception to a SabreException instance
574
-	 *
575
-	 * @param \Exception $e
576
-	 *
577
-	 * @throws \Sabre\DAV\Exception
578
-	 */
579
-	private function convertToSabreException(\Exception $e) {
580
-		if ($e instanceof \Sabre\DAV\Exception) {
581
-			throw $e;
582
-		}
583
-		if ($e instanceof NotPermittedException) {
584
-			// a more general case - due to whatever reason the content could not be written
585
-			throw new Forbidden($e->getMessage(), 0, $e);
586
-		}
587
-		if ($e instanceof ForbiddenException) {
588
-			// the path for the file was forbidden
589
-			throw new DAVForbiddenException($e->getMessage(), $e->getRetry(), $e);
590
-		}
591
-		if ($e instanceof EntityTooLargeException) {
592
-			// the file is too big to be stored
593
-			throw new EntityTooLarge($e->getMessage(), 0, $e);
594
-		}
595
-		if ($e instanceof InvalidContentException) {
596
-			// the file content is not permitted
597
-			throw new UnsupportedMediaType($e->getMessage(), 0, $e);
598
-		}
599
-		if ($e instanceof InvalidPathException) {
600
-			// the path for the file was not valid
601
-			// TODO: find proper http status code for this case
602
-			throw new Forbidden($e->getMessage(), 0, $e);
603
-		}
604
-		if ($e instanceof LockedException || $e instanceof LockNotAcquiredException) {
605
-			// the file is currently being written to by another process
606
-			throw new FileLocked($e->getMessage(), $e->getCode(), $e);
607
-		}
608
-		if ($e instanceof GenericEncryptionException) {
609
-			// returning 503 will allow retry of the operation at a later point in time
610
-			throw new ServiceUnavailable('Encryption not ready: ' . $e->getMessage(), 0, $e);
611
-		}
612
-		if ($e instanceof StorageNotAvailableException) {
613
-			throw new ServiceUnavailable('Failed to write file contents: ' . $e->getMessage(), 0, $e);
614
-		}
615
-		if ($e instanceof NotFoundException) {
616
-			throw new NotFound('File not found: ' . $e->getMessage(), 0, $e);
617
-		}
618
-
619
-		throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e);
620
-	}
621
-
622
-	/**
623
-	 * Get the checksum for this file
624
-	 *
625
-	 * @return string
626
-	 */
627
-	public function getChecksum() {
628
-		return $this->info->getChecksum();
629
-	}
630
-
631
-	protected function header($string) {
632
-		\header($string);
633
-	}
71
+    protected $request;
72
+
73
+    /**
74
+     * Sets up the node, expects a full path name
75
+     *
76
+     * @param \OC\Files\View $view
77
+     * @param \OCP\Files\FileInfo $info
78
+     * @param \OCP\Share\IManager $shareManager
79
+     * @param \OC\AppFramework\Http\Request $request
80
+     */
81
+    public function __construct(View $view, FileInfo $info, IManager $shareManager = null, Request $request = null) {
82
+        parent::__construct($view, $info, $shareManager);
83
+
84
+        if (isset($request)) {
85
+            $this->request = $request;
86
+        } else {
87
+            $this->request = \OC::$server->getRequest();
88
+        }
89
+    }
90
+
91
+    /**
92
+     * Updates the data
93
+     *
94
+     * The data argument is a readable stream resource.
95
+     *
96
+     * After a successful put operation, you may choose to return an ETag. The
97
+     * etag must always be surrounded by double-quotes. These quotes must
98
+     * appear in the actual string you're returning.
99
+     *
100
+     * Clients may use the ETag from a PUT request to later on make sure that
101
+     * when they update the file, the contents haven't changed in the mean
102
+     * time.
103
+     *
104
+     * If you don't plan to store the file byte-by-byte, and you return a
105
+     * different object on a subsequent GET you are strongly recommended to not
106
+     * return an ETag, and just return null.
107
+     *
108
+     * @param resource $data
109
+     *
110
+     * @throws Forbidden
111
+     * @throws UnsupportedMediaType
112
+     * @throws BadRequest
113
+     * @throws Exception
114
+     * @throws EntityTooLarge
115
+     * @throws ServiceUnavailable
116
+     * @throws FileLocked
117
+     * @return string|null
118
+     */
119
+    public function put($data) {
120
+        try {
121
+            $exists = $this->fileView->file_exists($this->path);
122
+            if ($this->info && $exists && !$this->info->isUpdateable()) {
123
+                throw new Forbidden();
124
+            }
125
+        } catch (StorageNotAvailableException $e) {
126
+            throw new ServiceUnavailable("File is not updatable: " . $e->getMessage());
127
+        }
128
+
129
+        // verify path of the target
130
+        $this->verifyPath();
131
+
132
+        // chunked handling
133
+        if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
134
+            try {
135
+                return $this->createFileChunked($data);
136
+            } catch (\Exception $e) {
137
+                $this->convertToSabreException($e);
138
+            }
139
+        }
140
+
141
+        /** @var Storage $partStorage */
142
+        list($partStorage) = $this->fileView->resolvePath($this->path);
143
+        $needsPartFile = $partStorage->needsPartFile() && (strlen($this->path) > 1);
144
+
145
+        $view = \OC\Files\Filesystem::getView();
146
+
147
+        if ($needsPartFile) {
148
+            // mark file as partial while uploading (ignored by the scanner)
149
+            $partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part';
150
+        } else {
151
+            // upload file directly as the final path
152
+            $partFilePath = $this->path;
153
+
154
+            if ($view && !$this->emitPreHooks($exists)) {
155
+                throw new Exception('Could not write to final file, canceled by hook');
156
+            }
157
+        }
158
+
159
+        // the part file and target file might be on a different storage in case of a single file storage (e.g. single file share)
160
+        /** @var \OC\Files\Storage\Storage $partStorage */
161
+        list($partStorage, $internalPartPath) = $this->fileView->resolvePath($partFilePath);
162
+        /** @var \OC\Files\Storage\Storage $storage */
163
+        list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
164
+        try {
165
+            if (!$needsPartFile) {
166
+                $this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
167
+            }
168
+
169
+            if ($partStorage->instanceOfStorage(Storage\IWriteStreamStorage::class)) {
170
+
171
+                if (!is_resource($data)) {
172
+                    $data = fopen('php://temp', 'r+');
173
+                    fwrite($data, 'foobar');
174
+                    rewind($data);
175
+                }
176
+
177
+                $isEOF = false;
178
+                $wrappedData = CallbackWrapper::wrap($data, null, null, null, null, function($stream) use (&$isEOF) {
179
+                    $isEOF = feof($stream);
180
+                });
181
+
182
+                $count = $partStorage->writeStream($internalPartPath, $wrappedData);
183
+                $result = $count > 0;
184
+
185
+                if ($result === false) {
186
+                    $result = $isEOF;
187
+                    if (is_resource($wrappedData)) {
188
+                        $result = feof($wrappedData);
189
+                    }
190
+                }
191
+
192
+            } else {
193
+                $target = $partStorage->fopen($internalPartPath, 'wb');
194
+                if ($target === false) {
195
+                    \OC::$server->getLogger()->error('\OC\Files\Filesystem::fopen() failed', ['app' => 'webdav']);
196
+                    // because we have no clue about the cause we can only throw back a 500/Internal Server Error
197
+                    throw new Exception('Could not write file contents');
198
+                }
199
+                list($count, $result) = \OC_Helper::streamCopy($data, $target);
200
+                fclose($target);
201
+            }
202
+
203
+            if ($result === false) {
204
+                $expected = -1;
205
+                if (isset($_SERVER['CONTENT_LENGTH'])) {
206
+                    $expected = $_SERVER['CONTENT_LENGTH'];
207
+                }
208
+                if ($expected !== "0") {
209
+                    throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )');
210
+                }
211
+            }
212
+
213
+            // if content length is sent by client:
214
+            // double check if the file was fully received
215
+            // compare expected and actual size
216
+            if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
217
+                $expected = (int)$_SERVER['CONTENT_LENGTH'];
218
+                if ($count !== $expected) {
219
+                    throw new BadRequest('expected filesize ' . $expected . ' got ' . $count);
220
+                }
221
+            }
222
+
223
+        } catch (\Exception $e) {
224
+            \OC::$server->getLogger()->logException($e);
225
+            if ($needsPartFile) {
226
+                $partStorage->unlink($internalPartPath);
227
+            }
228
+            $this->convertToSabreException($e);
229
+        }
230
+
231
+        try {
232
+            if ($needsPartFile) {
233
+                if ($view && !$this->emitPreHooks($exists)) {
234
+                    $partStorage->unlink($internalPartPath);
235
+                    throw new Exception('Could not rename part file to final file, canceled by hook');
236
+                }
237
+                try {
238
+                    $this->changeLock(ILockingProvider::LOCK_EXCLUSIVE);
239
+                } catch (LockedException $e) {
240
+                    if ($needsPartFile) {
241
+                        $partStorage->unlink($internalPartPath);
242
+                    }
243
+                    throw new FileLocked($e->getMessage(), $e->getCode(), $e);
244
+                }
245
+
246
+                // rename to correct path
247
+                try {
248
+                    $renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath);
249
+                    $fileExists = $storage->file_exists($internalPath);
250
+                    if ($renameOkay === false || $fileExists === false) {
251
+                        \OC::$server->getLogger()->error('renaming part file to final file failed $renameOkay: ' . ($renameOkay ? 'true' : 'false') . ', $fileExists: ' . ($fileExists ? 'true' : 'false') . ')', ['app' => 'webdav']);
252
+                        throw new Exception('Could not rename part file to final file');
253
+                    }
254
+                } catch (ForbiddenException $ex) {
255
+                    throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
256
+                } catch (\Exception $e) {
257
+                    $partStorage->unlink($internalPartPath);
258
+                    $this->convertToSabreException($e);
259
+                }
260
+            }
261
+
262
+            // since we skipped the view we need to scan and emit the hooks ourselves
263
+            $storage->getUpdater()->update($internalPath);
264
+
265
+            try {
266
+                $this->changeLock(ILockingProvider::LOCK_SHARED);
267
+            } catch (LockedException $e) {
268
+                throw new FileLocked($e->getMessage(), $e->getCode(), $e);
269
+            }
270
+
271
+            // allow sync clients to send the mtime along in a header
272
+            if (isset($this->request->server['HTTP_X_OC_MTIME'])) {
273
+                $mtime = $this->sanitizeMtime($this->request->server['HTTP_X_OC_MTIME']);
274
+                if ($this->fileView->touch($this->path, $mtime)) {
275
+                    $this->header('X-OC-MTime: accepted');
276
+                }
277
+            }
278
+
279
+            if ($view) {
280
+                $this->emitPostHooks($exists);
281
+            }
282
+
283
+            $this->refreshInfo();
284
+
285
+            if (isset($this->request->server['HTTP_OC_CHECKSUM'])) {
286
+                $checksum = trim($this->request->server['HTTP_OC_CHECKSUM']);
287
+                $this->fileView->putFileInfo($this->path, ['checksum' => $checksum]);
288
+                $this->refreshInfo();
289
+            } else if ($this->getChecksum() !== null && $this->getChecksum() !== '') {
290
+                $this->fileView->putFileInfo($this->path, ['checksum' => '']);
291
+                $this->refreshInfo();
292
+            }
293
+
294
+        } catch (StorageNotAvailableException $e) {
295
+            throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
296
+        }
297
+
298
+        return '"' . $this->info->getEtag() . '"';
299
+    }
300
+
301
+    private function getPartFileBasePath($path) {
302
+        $partFileInStorage = \OC::$server->getConfig()->getSystemValue('part_file_in_storage', true);
303
+        if ($partFileInStorage) {
304
+            return $path;
305
+        } else {
306
+            return md5($path); // will place it in the root of the view with a unique name
307
+        }
308
+    }
309
+
310
+    /**
311
+     * @param string $path
312
+     */
313
+    private function emitPreHooks($exists, $path = null) {
314
+        if (is_null($path)) {
315
+            $path = $this->path;
316
+        }
317
+        $hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
318
+        $run = true;
319
+
320
+        if (!$exists) {
321
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_create, array(
322
+                \OC\Files\Filesystem::signal_param_path => $hookPath,
323
+                \OC\Files\Filesystem::signal_param_run => &$run,
324
+            ));
325
+        } else {
326
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_update, array(
327
+                \OC\Files\Filesystem::signal_param_path => $hookPath,
328
+                \OC\Files\Filesystem::signal_param_run => &$run,
329
+            ));
330
+        }
331
+        \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_write, array(
332
+            \OC\Files\Filesystem::signal_param_path => $hookPath,
333
+            \OC\Files\Filesystem::signal_param_run => &$run,
334
+        ));
335
+        return $run;
336
+    }
337
+
338
+    /**
339
+     * @param string $path
340
+     */
341
+    private function emitPostHooks($exists, $path = null) {
342
+        if (is_null($path)) {
343
+            $path = $this->path;
344
+        }
345
+        $hookPath = Filesystem::getView()->getRelativePath($this->fileView->getAbsolutePath($path));
346
+        if (!$exists) {
347
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_create, array(
348
+                \OC\Files\Filesystem::signal_param_path => $hookPath
349
+            ));
350
+        } else {
351
+            \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_update, array(
352
+                \OC\Files\Filesystem::signal_param_path => $hookPath
353
+            ));
354
+        }
355
+        \OC_Hook::emit(\OC\Files\Filesystem::CLASSNAME, \OC\Files\Filesystem::signal_post_write, array(
356
+            \OC\Files\Filesystem::signal_param_path => $hookPath
357
+        ));
358
+    }
359
+
360
+    /**
361
+     * Returns the data
362
+     *
363
+     * @return resource
364
+     * @throws Forbidden
365
+     * @throws ServiceUnavailable
366
+     */
367
+    public function get() {
368
+        //throw exception if encryption is disabled but files are still encrypted
369
+        try {
370
+            if (!$this->info->isReadable()) {
371
+                // do a if the file did not exist
372
+                throw new NotFound();
373
+            }
374
+            try {
375
+                $res = $this->fileView->fopen(ltrim($this->path, '/'), 'rb');
376
+            } catch (\Exception $e) {
377
+                $this->convertToSabreException($e);
378
+            }
379
+            if ($res === false) {
380
+                throw new ServiceUnavailable("Could not open file");
381
+            }
382
+            return $res;
383
+        } catch (GenericEncryptionException $e) {
384
+            // returning 503 will allow retry of the operation at a later point in time
385
+            throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage());
386
+        } catch (StorageNotAvailableException $e) {
387
+            throw new ServiceUnavailable("Failed to open file: " . $e->getMessage());
388
+        } catch (ForbiddenException $ex) {
389
+            throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
390
+        } catch (LockedException $e) {
391
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
392
+        }
393
+    }
394
+
395
+    /**
396
+     * Delete the current file
397
+     *
398
+     * @throws Forbidden
399
+     * @throws ServiceUnavailable
400
+     */
401
+    public function delete() {
402
+        if (!$this->info->isDeletable()) {
403
+            throw new Forbidden();
404
+        }
405
+
406
+        try {
407
+            if (!$this->fileView->unlink($this->path)) {
408
+                // assume it wasn't possible to delete due to permissions
409
+                throw new Forbidden();
410
+            }
411
+        } catch (StorageNotAvailableException $e) {
412
+            throw new ServiceUnavailable("Failed to unlink: " . $e->getMessage());
413
+        } catch (ForbiddenException $ex) {
414
+            throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
415
+        } catch (LockedException $e) {
416
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
417
+        }
418
+    }
419
+
420
+    /**
421
+     * Returns the mime-type for a file
422
+     *
423
+     * If null is returned, we'll assume application/octet-stream
424
+     *
425
+     * @return string
426
+     */
427
+    public function getContentType() {
428
+        $mimeType = $this->info->getMimetype();
429
+
430
+        // PROPFIND needs to return the correct mime type, for consistency with the web UI
431
+        if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PROPFIND') {
432
+            return $mimeType;
433
+        }
434
+        return \OC::$server->getMimeTypeDetector()->getSecureMimeType($mimeType);
435
+    }
436
+
437
+    /**
438
+     * @return array|false
439
+     */
440
+    public function getDirectDownload() {
441
+        if (\OCP\App::isEnabled('encryption')) {
442
+            return [];
443
+        }
444
+        /** @var \OCP\Files\Storage $storage */
445
+        list($storage, $internalPath) = $this->fileView->resolvePath($this->path);
446
+        if (is_null($storage)) {
447
+            return [];
448
+        }
449
+
450
+        return $storage->getDirectDownload($internalPath);
451
+    }
452
+
453
+    /**
454
+     * @param resource $data
455
+     * @return null|string
456
+     * @throws Exception
457
+     * @throws BadRequest
458
+     * @throws NotImplemented
459
+     * @throws ServiceUnavailable
460
+     */
461
+    private function createFileChunked($data) {
462
+        list($path, $name) = \Sabre\Uri\split($this->path);
463
+
464
+        $info = \OC_FileChunking::decodeName($name);
465
+        if (empty($info)) {
466
+            throw new NotImplemented('Invalid chunk name');
467
+        }
468
+
469
+        $chunk_handler = new \OC_FileChunking($info);
470
+        $bytesWritten = $chunk_handler->store($info['index'], $data);
471
+
472
+        //detect aborted upload
473
+        if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
474
+            if (isset($_SERVER['CONTENT_LENGTH'])) {
475
+                $expected = (int)$_SERVER['CONTENT_LENGTH'];
476
+                if ($bytesWritten !== $expected) {
477
+                    $chunk_handler->remove($info['index']);
478
+                    throw new BadRequest(
479
+                        'expected filesize ' . $expected . ' got ' . $bytesWritten);
480
+                }
481
+            }
482
+        }
483
+
484
+        if ($chunk_handler->isComplete()) {
485
+            /** @var Storage $storage */
486
+            list($storage,) = $this->fileView->resolvePath($path);
487
+            $needsPartFile = $storage->needsPartFile();
488
+            $partFile = null;
489
+
490
+            $targetPath = $path . '/' . $info['name'];
491
+            /** @var \OC\Files\Storage\Storage $targetStorage */
492
+            list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
493
+
494
+            $exists = $this->fileView->file_exists($targetPath);
495
+
496
+            try {
497
+                $this->fileView->lockFile($targetPath, ILockingProvider::LOCK_SHARED);
498
+
499
+                $this->emitPreHooks($exists, $targetPath);
500
+                $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_EXCLUSIVE);
501
+                /** @var \OC\Files\Storage\Storage $targetStorage */
502
+                list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
503
+
504
+                if ($needsPartFile) {
505
+                    // we first assembly the target file as a part file
506
+                    $partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part';
507
+                    /** @var \OC\Files\Storage\Storage $targetStorage */
508
+                    list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile);
509
+
510
+
511
+                    $chunk_handler->file_assemble($partStorage, $partInternalPath);
512
+
513
+                    // here is the final atomic rename
514
+                    $renameOkay = $targetStorage->moveFromStorage($partStorage, $partInternalPath, $targetInternalPath);
515
+                    $fileExists = $targetStorage->file_exists($targetInternalPath);
516
+                    if ($renameOkay === false || $fileExists === false) {
517
+                        \OC::$server->getLogger()->error('\OC\Files\Filesystem::rename() failed', ['app' => 'webdav']);
518
+                        // only delete if an error occurred and the target file was already created
519
+                        if ($fileExists) {
520
+                            // set to null to avoid double-deletion when handling exception
521
+                            // stray part file
522
+                            $partFile = null;
523
+                            $targetStorage->unlink($targetInternalPath);
524
+                        }
525
+                        $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
526
+                        throw new Exception('Could not rename part file assembled from chunks');
527
+                    }
528
+                } else {
529
+                    // assemble directly into the final file
530
+                    $chunk_handler->file_assemble($targetStorage, $targetInternalPath);
531
+                }
532
+
533
+                // allow sync clients to send the mtime along in a header
534
+                if (isset($this->request->server['HTTP_X_OC_MTIME'])) {
535
+                    $mtime = $this->sanitizeMtime($this->request->server['HTTP_X_OC_MTIME']);
536
+                    if ($targetStorage->touch($targetInternalPath, $mtime)) {
537
+                        $this->header('X-OC-MTime: accepted');
538
+                    }
539
+                }
540
+
541
+                // since we skipped the view we need to scan and emit the hooks ourselves
542
+                $targetStorage->getUpdater()->update($targetInternalPath);
543
+
544
+                $this->fileView->changeLock($targetPath, ILockingProvider::LOCK_SHARED);
545
+
546
+                $this->emitPostHooks($exists, $targetPath);
547
+
548
+                // FIXME: should call refreshInfo but can't because $this->path is not the of the final file
549
+                $info = $this->fileView->getFileInfo($targetPath);
550
+
551
+                if (isset($this->request->server['HTTP_OC_CHECKSUM'])) {
552
+                    $checksum = trim($this->request->server['HTTP_OC_CHECKSUM']);
553
+                    $this->fileView->putFileInfo($targetPath, ['checksum' => $checksum]);
554
+                } else if ($info->getChecksum() !== null && $info->getChecksum() !== '') {
555
+                    $this->fileView->putFileInfo($this->path, ['checksum' => '']);
556
+                }
557
+
558
+                $this->fileView->unlockFile($targetPath, ILockingProvider::LOCK_SHARED);
559
+
560
+                return $info->getEtag();
561
+            } catch (\Exception $e) {
562
+                if ($partFile !== null) {
563
+                    $targetStorage->unlink($targetInternalPath);
564
+                }
565
+                $this->convertToSabreException($e);
566
+            }
567
+        }
568
+
569
+        return null;
570
+    }
571
+
572
+    /**
573
+     * Convert the given exception to a SabreException instance
574
+     *
575
+     * @param \Exception $e
576
+     *
577
+     * @throws \Sabre\DAV\Exception
578
+     */
579
+    private function convertToSabreException(\Exception $e) {
580
+        if ($e instanceof \Sabre\DAV\Exception) {
581
+            throw $e;
582
+        }
583
+        if ($e instanceof NotPermittedException) {
584
+            // a more general case - due to whatever reason the content could not be written
585
+            throw new Forbidden($e->getMessage(), 0, $e);
586
+        }
587
+        if ($e instanceof ForbiddenException) {
588
+            // the path for the file was forbidden
589
+            throw new DAVForbiddenException($e->getMessage(), $e->getRetry(), $e);
590
+        }
591
+        if ($e instanceof EntityTooLargeException) {
592
+            // the file is too big to be stored
593
+            throw new EntityTooLarge($e->getMessage(), 0, $e);
594
+        }
595
+        if ($e instanceof InvalidContentException) {
596
+            // the file content is not permitted
597
+            throw new UnsupportedMediaType($e->getMessage(), 0, $e);
598
+        }
599
+        if ($e instanceof InvalidPathException) {
600
+            // the path for the file was not valid
601
+            // TODO: find proper http status code for this case
602
+            throw new Forbidden($e->getMessage(), 0, $e);
603
+        }
604
+        if ($e instanceof LockedException || $e instanceof LockNotAcquiredException) {
605
+            // the file is currently being written to by another process
606
+            throw new FileLocked($e->getMessage(), $e->getCode(), $e);
607
+        }
608
+        if ($e instanceof GenericEncryptionException) {
609
+            // returning 503 will allow retry of the operation at a later point in time
610
+            throw new ServiceUnavailable('Encryption not ready: ' . $e->getMessage(), 0, $e);
611
+        }
612
+        if ($e instanceof StorageNotAvailableException) {
613
+            throw new ServiceUnavailable('Failed to write file contents: ' . $e->getMessage(), 0, $e);
614
+        }
615
+        if ($e instanceof NotFoundException) {
616
+            throw new NotFound('File not found: ' . $e->getMessage(), 0, $e);
617
+        }
618
+
619
+        throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e);
620
+    }
621
+
622
+    /**
623
+     * Get the checksum for this file
624
+     *
625
+     * @return string
626
+     */
627
+    public function getChecksum() {
628
+        return $this->info->getChecksum();
629
+    }
630
+
631
+    protected function header($string) {
632
+        \header($string);
633
+    }
634 634
 }
Please login to merge, or discard this patch.
Spacing   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -123,7 +123,7 @@  discard block
 block discarded – undo
123 123
 				throw new Forbidden();
124 124
 			}
125 125
 		} catch (StorageNotAvailableException $e) {
126
-			throw new ServiceUnavailable("File is not updatable: " . $e->getMessage());
126
+			throw new ServiceUnavailable("File is not updatable: ".$e->getMessage());
127 127
 		}
128 128
 
129 129
 		// verify path of the target
@@ -146,7 +146,7 @@  discard block
 block discarded – undo
146 146
 
147 147
 		if ($needsPartFile) {
148 148
 			// mark file as partial while uploading (ignored by the scanner)
149
-			$partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part';
149
+			$partFilePath = $this->getPartFileBasePath($this->path).'.ocTransferId'.rand().'.part';
150 150
 		} else {
151 151
 			// upload file directly as the final path
152 152
 			$partFilePath = $this->path;
@@ -206,7 +206,7 @@  discard block
 block discarded – undo
206 206
 					$expected = $_SERVER['CONTENT_LENGTH'];
207 207
 				}
208 208
 				if ($expected !== "0") {
209
-					throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )');
209
+					throw new Exception('Error while copying file to target location (copied bytes: '.$count.', expected filesize: '.$expected.' )');
210 210
 				}
211 211
 			}
212 212
 
@@ -214,9 +214,9 @@  discard block
 block discarded – undo
214 214
 			// double check if the file was fully received
215 215
 			// compare expected and actual size
216 216
 			if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
217
-				$expected = (int)$_SERVER['CONTENT_LENGTH'];
217
+				$expected = (int) $_SERVER['CONTENT_LENGTH'];
218 218
 				if ($count !== $expected) {
219
-					throw new BadRequest('expected filesize ' . $expected . ' got ' . $count);
219
+					throw new BadRequest('expected filesize '.$expected.' got '.$count);
220 220
 				}
221 221
 			}
222 222
 
@@ -248,7 +248,7 @@  discard block
 block discarded – undo
248 248
 					$renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath);
249 249
 					$fileExists = $storage->file_exists($internalPath);
250 250
 					if ($renameOkay === false || $fileExists === false) {
251
-						\OC::$server->getLogger()->error('renaming part file to final file failed $renameOkay: ' . ($renameOkay ? 'true' : 'false') . ', $fileExists: ' . ($fileExists ? 'true' : 'false') . ')', ['app' => 'webdav']);
251
+						\OC::$server->getLogger()->error('renaming part file to final file failed $renameOkay: '.($renameOkay ? 'true' : 'false').', $fileExists: '.($fileExists ? 'true' : 'false').')', ['app' => 'webdav']);
252 252
 						throw new Exception('Could not rename part file to final file');
253 253
 					}
254 254
 				} catch (ForbiddenException $ex) {
@@ -292,10 +292,10 @@  discard block
 block discarded – undo
292 292
 			}
293 293
 
294 294
 		} catch (StorageNotAvailableException $e) {
295
-			throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage());
295
+			throw new ServiceUnavailable("Failed to check file size: ".$e->getMessage());
296 296
 		}
297 297
 
298
-		return '"' . $this->info->getEtag() . '"';
298
+		return '"'.$this->info->getEtag().'"';
299 299
 	}
300 300
 
301 301
 	private function getPartFileBasePath($path) {
@@ -382,9 +382,9 @@  discard block
 block discarded – undo
382 382
 			return $res;
383 383
 		} catch (GenericEncryptionException $e) {
384 384
 			// returning 503 will allow retry of the operation at a later point in time
385
-			throw new ServiceUnavailable("Encryption not ready: " . $e->getMessage());
385
+			throw new ServiceUnavailable("Encryption not ready: ".$e->getMessage());
386 386
 		} catch (StorageNotAvailableException $e) {
387
-			throw new ServiceUnavailable("Failed to open file: " . $e->getMessage());
387
+			throw new ServiceUnavailable("Failed to open file: ".$e->getMessage());
388 388
 		} catch (ForbiddenException $ex) {
389 389
 			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
390 390
 		} catch (LockedException $e) {
@@ -409,7 +409,7 @@  discard block
 block discarded – undo
409 409
 				throw new Forbidden();
410 410
 			}
411 411
 		} catch (StorageNotAvailableException $e) {
412
-			throw new ServiceUnavailable("Failed to unlink: " . $e->getMessage());
412
+			throw new ServiceUnavailable("Failed to unlink: ".$e->getMessage());
413 413
 		} catch (ForbiddenException $ex) {
414 414
 			throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry());
415 415
 		} catch (LockedException $e) {
@@ -472,11 +472,11 @@  discard block
 block discarded – undo
472 472
 		//detect aborted upload
473 473
 		if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') {
474 474
 			if (isset($_SERVER['CONTENT_LENGTH'])) {
475
-				$expected = (int)$_SERVER['CONTENT_LENGTH'];
475
+				$expected = (int) $_SERVER['CONTENT_LENGTH'];
476 476
 				if ($bytesWritten !== $expected) {
477 477
 					$chunk_handler->remove($info['index']);
478 478
 					throw new BadRequest(
479
-						'expected filesize ' . $expected . ' got ' . $bytesWritten);
479
+						'expected filesize '.$expected.' got '.$bytesWritten);
480 480
 				}
481 481
 			}
482 482
 		}
@@ -487,7 +487,7 @@  discard block
 block discarded – undo
487 487
 			$needsPartFile = $storage->needsPartFile();
488 488
 			$partFile = null;
489 489
 
490
-			$targetPath = $path . '/' . $info['name'];
490
+			$targetPath = $path.'/'.$info['name'];
491 491
 			/** @var \OC\Files\Storage\Storage $targetStorage */
492 492
 			list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath);
493 493
 
@@ -503,7 +503,7 @@  discard block
 block discarded – undo
503 503
 
504 504
 				if ($needsPartFile) {
505 505
 					// we first assembly the target file as a part file
506
-					$partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part';
506
+					$partFile = $this->getPartFileBasePath($path.'/'.$info['name']).'.ocTransferId'.$info['transferid'].'.part';
507 507
 					/** @var \OC\Files\Storage\Storage $targetStorage */
508 508
 					list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile);
509 509
 
@@ -607,13 +607,13 @@  discard block
 block discarded – undo
607 607
 		}
608 608
 		if ($e instanceof GenericEncryptionException) {
609 609
 			// returning 503 will allow retry of the operation at a later point in time
610
-			throw new ServiceUnavailable('Encryption not ready: ' . $e->getMessage(), 0, $e);
610
+			throw new ServiceUnavailable('Encryption not ready: '.$e->getMessage(), 0, $e);
611 611
 		}
612 612
 		if ($e instanceof StorageNotAvailableException) {
613
-			throw new ServiceUnavailable('Failed to write file contents: ' . $e->getMessage(), 0, $e);
613
+			throw new ServiceUnavailable('Failed to write file contents: '.$e->getMessage(), 0, $e);
614 614
 		}
615 615
 		if ($e instanceof NotFoundException) {
616
-			throw new NotFound('File not found: ' . $e->getMessage(), 0, $e);
616
+			throw new NotFound('File not found: '.$e->getMessage(), 0, $e);
617 617
 		}
618 618
 
619 619
 		throw new \Sabre\DAV\Exception($e->getMessage(), 0, $e);
Please login to merge, or discard this patch.