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