archive: add lock to folder creation
Close #122 Close #681 Signed-off-by: Varun Patil <radialapps@gmail.com>pull/900/head
parent
782b2c9243
commit
5e4b963379
|
@ -28,6 +28,7 @@ use OCA\Memories\Util;
|
||||||
use OCP\AppFramework\Http;
|
use OCP\AppFramework\Http;
|
||||||
use OCP\AppFramework\Http\JSONResponse;
|
use OCP\AppFramework\Http\JSONResponse;
|
||||||
use OCP\Files\Folder;
|
use OCP\Files\Folder;
|
||||||
|
use OCP\Lock\ILockingProvider;
|
||||||
|
|
||||||
class ArchiveController extends GenericApiController
|
class ArchiveController extends GenericApiController
|
||||||
{
|
{
|
||||||
|
@ -152,19 +153,7 @@ class ArchiveController extends GenericApiController
|
||||||
// Create folder tree
|
// Create folder tree
|
||||||
$folder = $parent;
|
$folder = $parent;
|
||||||
foreach ($destinationFolders as $folderName) {
|
foreach ($destinationFolders as $folderName) {
|
||||||
try {
|
$folder = $this->getOrCreateFolder($folder, $folderName);
|
||||||
$existingFolder = $folder->get($folderName.'/');
|
|
||||||
if (!$existingFolder instanceof Folder) {
|
|
||||||
throw Exceptions::NotFound('Not a folder: '.$existingFolder->getPath());
|
|
||||||
}
|
|
||||||
$folder = $existingFolder;
|
|
||||||
} catch (\OCP\Files\NotFoundException $e) {
|
|
||||||
try {
|
|
||||||
$folder = $folder->newFolder($folderName);
|
|
||||||
} catch (\OCP\Files\NotPermittedException $e) {
|
|
||||||
throw Exceptions::ForbiddenFileUpdate($folder->getPath().' [create]');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move file to archive folder
|
// Move file to archive folder
|
||||||
|
@ -173,4 +162,65 @@ class ArchiveController extends GenericApiController
|
||||||
return new JSONResponse([], Http::STATUS_OK);
|
return new JSONResponse([], Http::STATUS_OK);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create a folder in the given parent folder.
|
||||||
|
*
|
||||||
|
* @param Folder $parent Parent folder
|
||||||
|
* @param string $name Folder name
|
||||||
|
* @param int $tries Number of tries to create the folder
|
||||||
|
*
|
||||||
|
* @throws \OCA\Memories\HttpResponseException
|
||||||
|
*/
|
||||||
|
private function getOrCreateFolder(Folder $parent, string $name, int $tries = 3): Folder
|
||||||
|
{
|
||||||
|
// Path of the folder we want to create (for error messages)
|
||||||
|
$finalPath = $parent->getPath().'/'.$name;
|
||||||
|
|
||||||
|
// Attempt to create the folder
|
||||||
|
if (!$parent->nodeExists($name)) {
|
||||||
|
$lockingProvider = \OC::$server->get(ILockingProvider::class);
|
||||||
|
$lockKey = "memories/create/{$finalPath}";
|
||||||
|
$lockType = ILockingProvider::LOCK_EXCLUSIVE;
|
||||||
|
$locked = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Attempt to acquire exclusive lock
|
||||||
|
$lockingProvider->acquireLock($lockKey, $lockType);
|
||||||
|
$locked = true;
|
||||||
|
} catch (\OCP\Lock\LockedException) {
|
||||||
|
// Someone else is creating, wait and try to get the folder
|
||||||
|
usleep(1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($locked) {
|
||||||
|
// Green light to create the folder
|
||||||
|
try {
|
||||||
|
return $parent->newFolder($name);
|
||||||
|
} catch (\OCP\Files\NotPermittedException $e) {
|
||||||
|
// Cannot create folder, throw error
|
||||||
|
throw Exceptions::ForbiddenFileUpdate("{$finalPath} [create]");
|
||||||
|
} catch (\OCP\Lock\LockedException $e) {
|
||||||
|
// This is the Files lock ... well
|
||||||
|
throw Exceptions::ForbiddenFileUpdate("{$finalPath} [locked]");
|
||||||
|
} finally {
|
||||||
|
// Release our lock
|
||||||
|
$lockingProvider->releaseLock($lockKey, $lockType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second check if the folder exists
|
||||||
|
if (!$parent->nodeExists($name)) {
|
||||||
|
throw Exceptions::NotFound("Folder not found: {$finalPath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to get the folder that should already exist
|
||||||
|
$existing = $parent->get($name);
|
||||||
|
if (!$existing instanceof Folder) {
|
||||||
|
throw Exceptions::NotFound("Not a folder: {$existing->getPath()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $existing;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue