/** * @param resource $data * @return null|string */ private function createFileChunked($data) { list($path, $name) = \Sabre\DAV\URLUtil::splitPath($this->path); $info = OC_FileChunking::decodeName($name); if (empty($info)) { throw new \Sabre\DAV\Exception\NotImplemented(); } $chunk_handler = new OC_FileChunking($info); $bytesWritten = $chunk_handler->store($info['index'], $data); //detect aborted upload if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') { if (isset($_SERVER['CONTENT_LENGTH'])) { $expected = $_SERVER['CONTENT_LENGTH']; if ($bytesWritten != $expected) { $chunk_handler->remove($info['index']); throw new \Sabre\DAV\Exception\BadRequest('expected filesize ' . $expected . ' got ' . $bytesWritten); } } } if ($chunk_handler->isComplete()) { // 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); } throw new \Sabre\DAV\Exception('Could not rename part file assembled from chunks'); } // allow sync clients to send the mtime along in a header $mtime = OC_Request::hasModificationTime(); if ($mtime !== false) { if ($this->fileView->touch($targetPath, $mtime)) { header('X-OC-MTime: accepted'); } } $info = $this->fileView->getFileInfo($targetPath); return $info->getEtag(); } return null; }
/** * @param resource $data * @return null|string * @throws Exception * @throws BadRequest * @throws NotImplemented * @throws ServiceUnavailable */ private function createFileChunked($data) { list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($this->path); $info = \OC_FileChunking::decodeName($name); if (empty($info)) { throw new NotImplemented('Invalid chunk name'); } $chunk_handler = new \OC_FileChunking($info); $bytesWritten = $chunk_handler->store($info['index'], $data); //detect aborted upload if (isset ($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') { if (isset($_SERVER['CONTENT_LENGTH'])) { $expected = $_SERVER['CONTENT_LENGTH']; if ($bytesWritten != $expected) { $chunk_handler->remove($info['index']); throw new BadRequest( 'expected filesize ' . $expected . ' got ' . $bytesWritten); } } } if ($chunk_handler->isComplete()) { list($storage,) = $this->fileView->resolvePath($path); $needsPartFile = $this->needsPartFile($storage); $partFile = null; $targetPath = $path . '/' . $info['name']; /** @var \OC\Files\Storage\Storage $targetStorage */ list($targetStorage, $targetInternalPath) = $this->fileView->resolvePath($targetPath); $exists = $this->fileView->file_exists($targetPath); try { $this->emitPreHooks($exists, $targetPath); $this->changeLock(ILockingProvider::LOCK_EXCLUSIVE); if ($needsPartFile) { // we first assembly the target file as a part file $partFile = $this->getPartFileBasePath($path . '/' . $info['name']) . '.ocTransferId' . $info['transferid'] . '.part'; /** @var \OC\Files\Storage\Storage $targetStorage */ list($partStorage, $partInternalPath) = $this->fileView->resolvePath($partFile); $chunk_handler->file_assemble($partStorage, $partInternalPath, $this->fileView->getAbsolutePath($targetPath)); // here is the final atomic rename $renameOkay = $targetStorage->moveFromStorage($partStorage, $partInternalPath, $targetInternalPath); $fileExists = $this->fileView->file_exists($targetPath); if ($renameOkay === false || $fileExists === false) { \OCP\Util::writeLog('webdav', '\OC\Files\Filesystem::rename() failed', \OCP\Util::ERROR); // only delete if an error occurred and the target file was already created if ($fileExists) { // set to null to avoid double-deletion when handling exception // stray part file $partFile = null; $targetStorage->unlink($targetInternalPath); } $this->changeLock(ILockingProvider::LOCK_SHARED); throw new Exception('Could not rename part file assembled from chunks'); } } else { // assemble directly into the final file $chunk_handler->file_assemble($targetStorage, $targetInternalPath, $this->fileView->getAbsolutePath($targetPath)); } // allow sync clients to send the mtime along in a header $request = \OC::$server->getRequest(); if (isset($request->server['HTTP_X_OC_MTIME'])) { if ($targetStorage->touch($targetInternalPath, $request->server['HTTP_X_OC_MTIME'])) { header('X-OC-MTime: accepted'); } } // since we skipped the view we need to scan and emit the hooks ourselves $this->fileView->getUpdater()->update($targetPath); $this->changeLock(ILockingProvider::LOCK_SHARED); $this->emitPostHooks($exists, $targetPath); $info = $this->fileView->getFileInfo($targetPath); return $info->getEtag(); } catch (\Exception $e) { if ($partFile !== null) { $targetStorage->unlink($targetInternalPath); } $this->convertToSabreException($e); } } return null; }
/** * @param resource $data * @return null|string * @throws Exception * @throws BadRequest * @throws NotImplemented * @throws ServiceUnavailable */ private function createFileChunked($data) { list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($this->path); $info = \OC_FileChunking::decodeName($name); if (empty($info)) { throw new NotImplemented(); } $chunk_handler = new \OC_FileChunking($info); $bytesWritten = $chunk_handler->store($info['index'], $data); //detect aborted upload if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'PUT') { if (isset($_SERVER['CONTENT_LENGTH'])) { $expected = $_SERVER['CONTENT_LENGTH']; if ($bytesWritten != $expected) { $chunk_handler->remove($info['index']); throw new BadRequest('expected filesize ' . $expected . ' got ' . $bytesWritten); } } } if ($chunk_handler->isComplete()) { list($storage, ) = $this->fileView->resolvePath($path); $needsPartFile = $this->needsPartFile($storage); try { $targetPath = $path . '/' . $info['name']; 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 $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 Exception('Could not rename part file assembled from chunks'); } } else { // assemble directly into the final file $chunk_handler->file_assemble($targetPath); } // allow sync clients to send the mtime along in a header $request = \OC::$server->getRequest(); if (isset($request->server['HTTP_X_OC_MTIME'])) { if ($this->fileView->touch($targetPath, $request->server['HTTP_X_OC_MTIME'])) { header('X-OC-MTime: accepted'); } } $info = $this->fileView->getFileInfo($targetPath); return $info->getEtag(); } catch (StorageNotAvailableException $e) { throw new ServiceUnavailable("Failed to put file: " . $e->getMessage()); } } return null; }