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