diff --git a/apps/dav/lib/Connector/Sabre/File.php b/apps/dav/lib/Connector/Sabre/File.php index d7e9afb4fdc2..65039bc42141 100644 --- a/apps/dav/lib/Connector/Sabre/File.php +++ b/apps/dav/lib/Connector/Sabre/File.php @@ -111,162 +111,161 @@ public function __construct($view, $info, $shareManager = null, Request $request */ public function put($data) { $path = $this->fileView->getAbsolutePath($this->path); - return $this->emittingCall(function () use (&$data) { - try { - $exists = $this->fileView->file_exists($this->path); - if ($this->info && $exists && !$this->info->isUpdateable()) { - throw new Forbidden(); - } - } catch (StorageNotAvailableException $e) { - throw new ServiceUnavailable("File is not updatable: " . $e->getMessage()); + $beforeEvent = new GenericEvent(null, ['path' => $path]); + \OC::$server->getEventDispatcher()->dispatch('file.beforecreate', $beforeEvent); + try { + $exists = $this->fileView->file_exists($this->path); + if ($this->info && $exists && !$this->info->isUpdateable()) { + throw new Forbidden(); } + } catch (StorageNotAvailableException $e) { + throw new ServiceUnavailable("File is not updatable: " . $e->getMessage()); + } - // verify path of the target - $this->verifyPath(); + // verify path of the target + $this->verifyPath(); - // chunked handling - if (\OC_FileChunking::isWebdavChunk()) { - try { - return $this->createFileChunked($data); - } catch (\Exception $e) { - $this->convertToSabreException($e); - } + // chunked handling + if (\OC_FileChunking::isWebdavChunk()) { + try { + return $this->createFileChunked($data); + } catch (\Exception $e) { + $this->convertToSabreException($e); } + } - list($partStorage) = $this->fileView->resolvePath($this->path); - $needsPartFile = $this->needsPartFile($partStorage) && (strlen($this->path) > 1); + list($partStorage) = $this->fileView->resolvePath($this->path); + $needsPartFile = $this->needsPartFile($partStorage) && (strlen($this->path) > 1); - if ($needsPartFile) { - // mark file as partial while uploading (ignored by the scanner) - $partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part'; - } else { - // upload file directly as the final path - $partFilePath = $this->path; + if ($needsPartFile) { + // mark file as partial while uploading (ignored by the scanner) + $partFilePath = $this->getPartFileBasePath($this->path) . '.ocTransferId' . rand() . '.part'; + } else { + // upload file directly as the final path + $partFilePath = $this->path; + } + + // the part file and target file might be on a different storage in case of a single file storage (e.g. single file share) + /** @var \OC\Files\Storage\Storage $partStorage */ + list($partStorage, $internalPartPath) = $this->fileView->resolvePath($partFilePath); + /** @var \OC\Files\Storage\Storage $storage */ + list($storage, $internalPath) = $this->fileView->resolvePath($this->path); + try { + $target = $partStorage->fopen($internalPartPath, 'wb'); + if ($target === false) { + \OCP\Util::writeLog('webdav', '\OC\Files\Filesystem::fopen() failed', \OCP\Util::ERROR); + // because we have no clue about the cause we can only throw back a 500/Internal Server Error + throw new Exception('Could not write file contents'); } + list($count, $result) = \OC_Helper::streamCopy($data, $target); + fclose($target); - // the part file and target file might be on a different storage in case of a single file storage (e.g. single file share) - /** @var \OC\Files\Storage\Storage $partStorage */ - list($partStorage, $internalPartPath) = $this->fileView->resolvePath($partFilePath); - /** @var \OC\Files\Storage\Storage $storage */ - list($storage, $internalPath) = $this->fileView->resolvePath($this->path); - try { - $target = $partStorage->fopen($internalPartPath, 'wb'); - if ($target === false) { - \OCP\Util::writeLog('webdav', '\OC\Files\Filesystem::fopen() failed', \OCP\Util::ERROR); - // because we have no clue about the cause we can only throw back a 500/Internal Server Error - throw new Exception('Could not write file contents'); - } - list($count, $result) = \OC_Helper::streamCopy($data, $target); - fclose($target); + if (!self::isChecksumValid($partStorage, $internalPartPath)) { + throw new BadRequest('The computed checksum does not match the one received from the client.'); + } - if (!self::isChecksumValid($partStorage, $internalPartPath)) { - throw new BadRequest('The computed checksum does not match the one received from the client.'); + if ($result === false) { + $expected = -1; + if (isset($_SERVER['CONTENT_LENGTH'])) { + $expected = $_SERVER['CONTENT_LENGTH']; } + throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )'); + } - if ($result === false) { - $expected = -1; - if (isset($_SERVER['CONTENT_LENGTH'])) { - $expected = $_SERVER['CONTENT_LENGTH']; - } - throw new Exception('Error while copying file to target location (copied bytes: ' . $count . ', expected filesize: ' . $expected . ' )'); + // if content length is sent by client: + // double check if the file was fully received + // compare expected and actual size + if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') { + $expected = $_SERVER['CONTENT_LENGTH']; + if ($count != $expected) { + throw new BadRequest('expected filesize ' . $expected . ' got ' . $count); } + } - // if content length is sent by client: - // double check if the file was fully received - // compare expected and actual size - if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['REQUEST_METHOD'] === 'PUT') { - $expected = $_SERVER['CONTENT_LENGTH']; - if ($count != $expected) { - throw new BadRequest('expected filesize ' . $expected . ' got ' . $count); - } - } + } catch (\Exception $e) { + if ($needsPartFile) { + $partStorage->unlink($internalPartPath); + } + $this->convertToSabreException($e); + } - } catch (\Exception $e) { - if ($needsPartFile) { - $partStorage->unlink($internalPartPath); - } - $this->convertToSabreException($e); + try { + $view = \OC\Files\Filesystem::getView(); + if ($view) { + $run = $this->emitPreHooks($exists); + } else { + $run = true; } try { - $view = \OC\Files\Filesystem::getView(); - if ($view) { - $run = $this->emitPreHooks($exists); - } else { - $run = true; + $this->changeLock(ILockingProvider::LOCK_EXCLUSIVE); + } catch (LockedException $e) { + if ($needsPartFile) { + $partStorage->unlink($internalPartPath); } + throw new FileLocked($e->getMessage(), $e->getCode(), $e); + } + if ($needsPartFile) { + // rename to correct path try { - $this->changeLock(ILockingProvider::LOCK_EXCLUSIVE); - } catch (LockedException $e) { - if ($needsPartFile) { - $partStorage->unlink($internalPartPath); + if ($run) { + $renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath); + $fileExists = $storage->file_exists($internalPath); } - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } - - if ($needsPartFile) { - // rename to correct path - try { - if ($run) { - $renameOkay = $storage->moveFromStorage($partStorage, $internalPartPath, $internalPath); - $fileExists = $storage->file_exists($internalPath); - } - if (!$run || $renameOkay === false || $fileExists === false) { - \OCP\Util::writeLog('webdav', 'renaming part file to final file failed', \OCP\Util::ERROR); - throw new Exception('Could not rename part file to final file'); - } - } catch (ForbiddenException $ex) { - throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry()); - } catch (\Exception $e) { - $partStorage->unlink($internalPartPath); - $this->convertToSabreException($e); + if (!$run || $renameOkay === false || $fileExists === false) { + \OCP\Util::writeLog('webdav', 'renaming part file to final file failed', \OCP\Util::ERROR); + throw new Exception('Could not rename part file to final file'); } + } catch (ForbiddenException $ex) { + throw new DAVForbiddenException($ex->getMessage(), $ex->getRetry()); + } catch (\Exception $e) { + $partStorage->unlink($internalPartPath); + $this->convertToSabreException($e); } + } - // since we skipped the view we need to scan and emit the hooks ourselves - $storage->getUpdater()->update($internalPath); + // since we skipped the view we need to scan and emit the hooks ourselves + $storage->getUpdater()->update($internalPath); - try { - $this->changeLock(ILockingProvider::LOCK_SHARED); - } catch (LockedException $e) { - throw new FileLocked($e->getMessage(), $e->getCode(), $e); - } + try { + $this->changeLock(ILockingProvider::LOCK_SHARED); + } catch (LockedException $e) { + throw new FileLocked($e->getMessage(), $e->getCode(), $e); + } - // allow sync clients to send the mtime along in a header - if (isset($this->request->server['HTTP_X_OC_MTIME'])) { - $mtime = $this->sanitizeMtime($this->request->server ['HTTP_X_OC_MTIME']); - if ($this->fileView->touch($this->path, $mtime)) { - $this->header('X-OC-MTime: accepted'); - } + // allow sync clients to send the mtime along in a header + if (isset($this->request->server['HTTP_X_OC_MTIME'])) { + $mtime = $this->sanitizeMtime($this->request->server ['HTTP_X_OC_MTIME']); + if ($this->fileView->touch($this->path, $mtime)) { + $this->header('X-OC-MTime: accepted'); } + } - if ($view) { - $this->emitPostHooks($exists); - } + if ($view) { + $this->emitPostHooks($exists); + } - $this->refreshInfo(); + $this->refreshInfo(); - $meta = $partStorage->getMetaData($internalPartPath); + $meta = $partStorage->getMetaData($internalPartPath); - if (isset($meta['checksum'])) { - $this->fileView->putFileInfo( - $this->path, - ['checksum' => $meta['checksum']] - ); - } + if (isset($meta['checksum'])) { + $this->fileView->putFileInfo( + $this->path, + ['checksum' => $meta['checksum']] + ); + } - $this->refreshInfo(); + $this->refreshInfo(); - } catch (StorageNotAvailableException $e) { - throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage()); - } + } catch (StorageNotAvailableException $e) { + throw new ServiceUnavailable("Failed to check file size: " . $e->getMessage()); + } - return '"' . $this->info->getEtag() . '"'; - },[ - 'before' => ['path' => $path], - 'after' => ['path' => $path], - ], 'file', 'create'); + $afterEvent = new GenericEvent(null, ['path' => $path]); + \OC::$server->getEventDispatcher()->dispatch('file.aftercreate', $afterEvent); + return '"' . $this->info->getEtag() . '"'; } private function getPartFileBasePath($path) {