diff --git a/lib/private/connector/sabre/file.php b/lib/private/connector/sabre/file.php index 76ebe3ed9f..cd05db8e12 100644 --- a/lib/private/connector/sabre/file.php +++ b/lib/private/connector/sabre/file.php @@ -74,8 +74,16 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\ return $this->createFileChunked($data); } - // mark file as partial while uploading (ignored by the scanner) - $partFilePath = $this->path . '.ocTransferId' . rand() . '.part'; + list($storage, $internalPath) = $this->fileView->resolvePath($this->path); + $needsPartFile = $this->needsPartFile($storage); + + if ($needsPartFile) { + // mark file as partial while uploading (ignored by the scanner) + $partFilePath = $this->path . '.ocTransferId' . rand() . '.part'; + } else { + // upload file directly as the final path + $partFilePath = $this->path; + } try { $putOkay = $this->fileView->file_put_contents($partFilePath, $data); @@ -123,19 +131,21 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\ } } - // rename to correct path - try { - $renameOkay = $this->fileView->rename($partFilePath, $this->path); - $fileExists = $this->fileView->file_exists($this->path); - if ($renameOkay === false || $fileExists === false) { - \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); - $this->fileView->unlink($partFilePath); - throw new \Sabre\DAV\Exception('Could not rename part file to final file'); + if ($needsPartFile) { + // rename to correct path + try { + $renameOkay = $this->fileView->rename($partFilePath, $this->path); + $fileExists = $this->fileView->file_exists($this->path); + if ($renameOkay === false || $fileExists === false) { + \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); + $this->fileView->unlink($partFilePath); + throw new \Sabre\DAV\Exception('Could not rename part file to final file'); + } + } + catch (\OCP\Files\LockNotAcquiredException $e) { + // the file is currently being written to by another process + throw new OC_Connector_Sabre_Exception_FileLocked($e->getMessage(), $e->getCode(), $e); } - } - catch (\OCP\Files\LockNotAcquiredException $e) { - // the file is currently being written to by another process - throw new OC_Connector_Sabre_Exception_FileLocked($e->getMessage(), $e->getCode(), $e); } // allow sync clients to send the mtime along in a header @@ -267,23 +277,31 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\ } if ($chunk_handler->isComplete()) { + list($storage, $internalPath) = $this->fileView->resolvePath($path); + $needsPartFile = $this->needsPartFile($storage); try { - // we first assembly the target file as a part file - $partFile = $path . '/' . $info['name'] . '.ocTransferId' . $info['transferid'] . '.part'; - $chunk_handler->file_assemble($partFile); + if ($needsPartFile) { + // we first assembly the target file as a part file + $partFile = $path . '/' . $info['name'] . '.ocTransferId' . $info['transferid'] . '.part'; + $chunk_handler->file_assemble($partFile); - // here is the final atomic rename - $targetPath = $path . '/' . $info['name']; - $renameOkay = $this->fileView->rename($partFile, $targetPath); - $fileExists = $this->fileView->file_exists($targetPath); - if ($renameOkay === false || $fileExists === false) { - \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); - // only delete if an error occurred and the target file was already created - if ($fileExists) { - $this->fileView->unlink($targetPath); + // here is the final atomic rename + $targetPath = $path . '/' . $info['name']; + $renameOkay = $this->fileView->rename($partFile, $targetPath); + $fileExists = $this->fileView->file_exists($targetPath); + if ($renameOkay === false || $fileExists === false) { + \OC_Log::write('webdav', '\OC\Files\Filesystem::rename() failed', \OC_Log::ERROR); + // only delete if an error occurred and the target file was already created + if ($fileExists) { + $this->fileView->unlink($targetPath); + } + throw new \Sabre\DAV\Exception('Could not rename part file assembled from chunks'); } - throw new \Sabre\DAV\Exception('Could not rename part file assembled from chunks'); + } else { + // assemble directly into the final file + $partFile = $path . '/' . $info['name']; + $chunk_handler->file_assemble($partFile); } // allow sync clients to send the mtime along in a header @@ -303,4 +321,19 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\ return null; } + + /** + * Returns whether a part file is needed for the given storage + * or whether the file can be assembled/uploaded directly on the + * target storage. + * + * @param \OCP\Files\Storage $storage storage to check + * @param bool true if the storage needs part file handling + */ + private function needsPartFile($storage) { + // TODO: in the future use ChunkHandler provided by storage + // and/or add method on Storage called "needsPartFile()" + return !$storage->instanceOfStorage('OCA\Files_Sharing\External\Storage') && + !$storage->instanceOfStorage('OC\Files\Storage\OwnCloud'); + } }