From 78b3a418afe15540cbff56d7b57f26286564e753 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 6 Sep 2022 15:05:11 +0200 Subject: [PATCH] enable locking for upload chunks Signed-off-by: Robin Appelman --- apps/dav/lib/Connector/Sabre/Directory.php | 19 +++++++++++++++++-- lib/private/Files/View.php | 6 +++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/apps/dav/lib/Connector/Sabre/Directory.php b/apps/dav/lib/Connector/Sabre/Directory.php index b575a051b2a..fa87aa1dd21 100644 --- a/apps/dav/lib/Connector/Sabre/Directory.php +++ b/apps/dav/lib/Connector/Sabre/Directory.php @@ -144,9 +144,24 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node implements \Sabre\DAV\ICol } $node = new \OCA\DAV\Connector\Sabre\File($this->fileView, $info); - // only allow 1 process to upload a file at once but still allow reading the file while writing the part file + + /** @var LoggerInterface $logger */ + $logger = \OC::$server->get(LoggerInterface::class); + + // we get a shared lock on the file being uploaded and an exclusive lock on a virtual '.upload.part' file. + // + // The shared lock prevents writes or deletes during the upload while still allowing reading the file. + // The exclusive lock stops concurrent upload requests. + // + // Additionally, the shared lock will be changed into an exclusive one for the actual file write $node->acquireLock(ILockingProvider::LOCK_SHARED); - $this->fileView->lockFile($path . '.upload.part', ILockingProvider::LOCK_EXCLUSIVE); + try { + $logger->debug("Getting lock for upload: $path"); + $this->fileView->lockFile($path . '.upload.part', ILockingProvider::LOCK_EXCLUSIVE); + } catch (LockedException $e) { + $logger->error("Failed to acquire lock for upload: $path", ['exception' => $e]); + throw $e; + } $result = $node->put($data); diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php index e5394e72ffe..51eff754cb1 100644 --- a/lib/private/Files/View.php +++ b/lib/private/Files/View.php @@ -1957,7 +1957,7 @@ class View { } catch (LockedException $e) { // rethrow with the a human-readable path throw new LockedException( - $this->getPathRelativeToFiles($absolutePath), + $this->getRelativePath($absolutePath), $e, $e->getExistingLock() ); @@ -2000,7 +2000,7 @@ class View { try { // rethrow with the a human-readable path throw new LockedException( - $this->getPathRelativeToFiles($absolutePath), + $this->getRelativePath($absolutePath), $e, $e->getExistingLock() ); @@ -2115,7 +2115,7 @@ class View { $pathSegments = explode('/', $path); if (isset($pathSegments[2])) { // E.g.: /username/files/path-to-file - return ($pathSegments[2] === 'files') && (count($pathSegments) > 3); + return ($pathSegments[2] === 'files' || $pathSegments[2] === 'uploads') && (count($pathSegments) > 3); } return strpos($path, '/appdata_') !== 0;