Skip to content

Commit

Permalink
Handle missing disk versions
Browse files Browse the repository at this point in the history
Signed-off-by: Louis Chemineau <louis@chmn.me>
  • Loading branch information
artonge committed Jan 16, 2024
1 parent d7ee3e9 commit e82162b
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 19 deletions.
11 changes: 10 additions & 1 deletion lib/Versions/GroupVersionsExpireManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@

namespace OCA\GroupFolders\Versions;

use OC\Files\FileInfo;
use OC\Files\View;
use OC\Hooks\BasicEmitter;
use OC\User\User;
use OCA\GroupFolders\Folder\FolderManager;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\FileInfo;
use OCP\IUser;

class GroupVersionsExpireManager extends BasicEmitter {
private $folderManager;
Expand Down Expand Up @@ -66,9 +67,17 @@ public function expireAll(): void {
public function expireFolder(array $folder): void {
$view = new View('/__groupfolders/versions/' . $folder['id']);
$files = $this->versionsBackend->getAllVersionedFiles($folder);
/** @var IUser */
$dummyUser = new User('', null, $this->dispatcher);
foreach ($files as $fileId => $file) {
if ($file instanceof FileInfo) {
// Some versions could have been lost during move operations across storage.
// When this is the case, the fileinfo's path will not contains the name.
// When this is the case, we unlink the version's folder for the fileid, and continue to the next file.
if (!str_ends_with($file->getPath(), $file->getName())) {
$view->unlink('/' . $fileId);
continue;
}
$versions = $this->versionsBackend->getVersionsForFile($dummyUser, $file);
$expireVersions = $this->expireManager->getExpiredVersion($versions, $this->timeFactory->getTime(), false);
foreach ($expireVersions as $version) {
Expand Down
63 changes: 45 additions & 18 deletions lib/Versions/VersionsBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,15 @@ public function getVersionsForFile(IUser $user, FileInfo $file): array {

try {
$folderId = $mount->getFolderId();
/** @var Folder $versionsFolder */
$versionsFolder = $this->getVersionsFolder($mount->getFolderId())->get((string)$file->getId());

try {
$groupfoldersVersionsFolder = $this->getVersionsFolder($mount->getFolderId());
/** @var Folder $versionsFolder */
$versionsFolder = $groupfoldersVersionsFolder->get((string)$file->getId());
} catch (NotFoundException $e) {
// The folder for the file's versions might not exists if no versions has been create yet.
$versionsFolder = $groupfoldersVersionsFolder->newFolder((string)$file->getId());
}

$versions = $this->getVersionsForFileFromDB($file, $user, $folderId);

Expand Down Expand Up @@ -131,23 +138,43 @@ private function getVersionsForFileFromDB(FileInfo $fileInfo, IUser $user, int $
$folder = $this->appFolder->get((string)$folderId);
$file = $folder->get($fileInfo->getInternalPath());

return array_map(
fn (GroupVersionEntity $versionEntity) => new GroupVersion(
$versionEntity->getTimestamp(),
$versionEntity->getTimestamp(),
$file->getName(),
$versionEntity->getSize(),
$this->mimeTypeLoader->getMimetypeById($versionEntity->getMimetype()),
$mountPoint->getInternalPath($file->getPath()),
$file,
$this,
$user,
$versionEntity->getLabel(),
$file->getMtime() === $versionEntity->getTimestamp() ? $file : $versionsFolder->get((string)$versionEntity->getTimestamp()),
$folderId,
),
$this->groupVersionsMapper->findAllVersionsForFileId($file->getId())
$versionEntities = $this->groupVersionsMapper->findAllVersionsForFileId($fileInfo->getId());
$mappedVersions = array_map(
function (GroupVersionEntity $versionEntity) use ($versionsFolder, $mountPoint, $file, $fileInfo, $user, $folderId) {
if ($fileInfo->getMtime() === $versionEntity->getTimestamp()) {
$versionFile = $file;
} else {
try {
$versionFile = $versionsFolder->get((string)$versionEntity->getTimestamp());
} catch (NotFoundException $e) {
// The version does not exists on disk anymore, so we can delete its entity in the DB.
// The reality is that the disk version might have been lost during a move operation between storages,
// and its not possible to recover it, so removing the entity makes sense.
// TODO: same logic in main version backend?
$this->groupVersionsMapper->delete($versionEntity);
return null;
}
}

return new GroupVersion(
$versionEntity->getTimestamp(),
$versionEntity->getTimestamp(),
$fileInfo->getName(),
$versionEntity->getSize(),
$this->mimeTypeLoader->getMimetypeById($versionEntity->getMimetype()),
$mountPoint->getInternalPath($fileInfo->getPath()),
$fileInfo,
$this,
$user,
$versionEntity->getLabel(),
$versionFile,
$folderId,
);
},
$versionEntities,
);
// Filter out null values.
return array_filter($mappedVersions);
}

/**
Expand Down

0 comments on commit e82162b

Please sign in to comment.