Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stable10] Replace emittingCall with separate before and after events #30986

Merged
merged 1 commit into from
Apr 3, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
243 changes: 121 additions & 122 deletions apps/dav/lib/Connector/Sabre/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down