Skip to content

Commit

Permalink
store chunk in multiple subfolder
Browse files Browse the repository at this point in the history
  • Loading branch information
ArtificialOwl committed Oct 1, 2021
1 parent 426a976 commit a451033
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 24 deletions.
4 changes: 2 additions & 2 deletions lib/Command/PointRestore.php
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ public function restorePointComplete(RestoringPoint $point): void {

foreach ($data->getChunks() as $chunk) {
$this->output->write(
' > Chunk: ' . $chunk->getFilename() . ' (' . $chunk->getCount() . ' files) '
' > Chunk: ' . $chunk->getPath() . $chunk->getFilename() . ' (' . $chunk->getCount() . ' files) '
);

try {
Expand Down Expand Up @@ -366,7 +366,7 @@ private function restoreUniqueFile(
$this->output->write(
' > restoring ' . $file->getName() . ' (' . $this->humanReadable($file->getFilesize())
. ') from <info>'
. $chunk->getName() . '</info>'
. $chunk->getPath() . $chunk->getName() . '</info>'
);

// TODO: display $root and add a confirmation step
Expand Down
46 changes: 46 additions & 0 deletions lib/Exceptions/RestoringPointNotInitiatedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);


/**
* Nextcloud - Backup
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2021, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/


namespace OCA\Backup\Exceptions;


use Exception;


/**
* Class RestoringPointNotInitiatedException
*
* @package OCA\Backup\Exceptions
*/
class RestoringPointNotInitiatedException extends Exception {

}

38 changes: 33 additions & 5 deletions lib/Model/RestoringChunk.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ class RestoringChunk implements JsonSerializable, IDeserializable {


/** @var string */
private $name;
private $name = '';

/** @var string */
private $path = '';

/** @var string */
private $content = '';
Expand Down Expand Up @@ -83,11 +86,15 @@ class RestoringChunk implements JsonSerializable, IDeserializable {
*/
public function __construct(string $name = '', bool $staticName = false) {
$this->staticName = $staticName;
if ($name === '') {
return;
}

if (!$staticName) {
if ($name !== '') {
$name .= '-';
}
$name .= $this->uuid();
$name .= '-';
$uuid = $this->uuid();
$this->path = $name . substr($uuid, 0, 1) . '/' . substr($uuid, 0, 2) . '/';
$name .= $uuid;
}

$this->name = $name;
Expand Down Expand Up @@ -132,6 +139,25 @@ public function isStaticName(): bool {
}


/**
* @return string
*/
public function getPath(): string {
return $this->path;
}

/**
* @param string $path
*
* @return $this
*/
public function setPath(string $path): self {
$this->path = $path;

return $this;
}


/**
* @return string
*/
Expand Down Expand Up @@ -261,6 +287,7 @@ public function getContent(): string {
*/
public function import(array $data): IDeserializable {
$this->setName($this->get('name', $data))
->setPath($this->get('path', $data))
// ->setFiles($this->getArray('files', $data, []))
->setCount($this->getInt('count', $data))
->setSize($this->getInt('size', $data))
Expand Down Expand Up @@ -288,6 +315,7 @@ public function getResume(): array {
public function jsonSerialize(): array {
$arr = [
'name' => $this->getName(),
'path' => $this->getPath(),
'count' => $this->getCount(),
'size' => $this->getSize(),
'staticName' => $this->isStaticName(),
Expand Down
30 changes: 30 additions & 0 deletions lib/Model/RestoringPoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
use JsonSerializable;
use OCA\Backup\Exceptions\RestoringDataNotFoundException;
use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\Files\SimpleFS\ISimpleRoot;


/**
Expand Down Expand Up @@ -79,6 +80,9 @@ class RestoringPoint implements IDeserializable, INC23QueryRow, ISignedModel, Js
/** @var ISimpleFolder */
private $baseFolder = null;

/** @var ISimpleRoot */
private $baseRoot = null;

/** @var RestoringData[] */
private $restoringData = [];

Expand Down Expand Up @@ -238,6 +242,32 @@ public function getBaseFolder(): ISimpleFolder {
}


/**
* @return bool
*/
public function hasRootFolder(): bool {
return !is_null($this->rootFolder);
}

/**
* @param ISimpleRoot $root
*
* @return RestoringPoint
*/
public function setRootFolder(ISimpleRoot $root): self {
$this->rootFolder = $root;

return $this;
}

/**
* @return ISimpleRoot
*/
public function getRootFolder(): ISimpleRoot {
return $this->rootFolder;
}


/**
* @return RestoringData[]
*/
Expand Down
61 changes: 45 additions & 16 deletions lib/Service/ChunkService.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,15 @@
use OCA\Backup\Exceptions\RestoreChunkException;
use OCA\Backup\Exceptions\RestoringChunkNotFoundException;
use OCA\Backup\Exceptions\RestoringDataNotFoundException;
use OCA\Backup\Exceptions\RestoringPointNotInitiatedException;
use OCA\Backup\Model\ArchiveFile;
use OCA\Backup\Model\RestoringChunk;
use OCA\Backup\Model\RestoringData;
use OCA\Backup\Model\RestoringPoint;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use OCP\Files\SimpleFS\ISimpleFile;
use OCP\Files\SimpleFS\ISimpleFolder;
use ZipArchive;
use ZipStreamer\COMPR;
use ZipStreamer\ZipStreamer;
Expand Down Expand Up @@ -190,17 +192,14 @@ public function restoreChunk(
* @throws ArchiveNotFoundException
* @throws NotFoundException
* @throws NotPermittedException
* @throws RestoringPointNotInitiatedException
*/
public function openZipArchive(
RestoringPoint $point,
RestoringChunk $chunk,
bool $stream = false
): ZipArchive {
if (!$point->hasBaseFolder()) {
throw new ArchiveCreateException('Backup has no Base Folder');
}

$folder = $point->getBaseFolder();
$folder = $this->getChunkFolder($point, $chunk);
$file = $folder->getFile($chunk->getFilename());

$tmp = tmpfile();
Expand Down Expand Up @@ -387,14 +386,16 @@ public function createSingleFileChunk(
* @param string $path
*
* @throws ArchiveCreateException
* @throws NotPermittedException
* @throws RestoringPointNotInitiatedException
*/
private function createSingleFileZip(
RestoringPoint $point,
RestoringChunk $chunk,
string $filename,
string $path
): void {
$zip = $this->generateZip($point, $chunk->getFilename());
$zip = $this->generateZip($point, $chunk);
$read = fopen($path, 'r');
$zip->addFileFromStream($read, $filename);
$zip->finalize();
Expand All @@ -416,7 +417,7 @@ private function generateChunk(
): RestoringChunk {
$chunk = new RestoringChunk($data->getName());

$zip = $this->generateZip($point, $chunk->getfilename());
$zip = $this->generateZip($point, $chunk);
$zipSize = 0;
while (($filename = array_shift($files)) !== null) {
$fileSize = filesize($data->getAbsolutePath() . $filename);
Expand Down Expand Up @@ -447,19 +448,18 @@ private function generateChunk(

/**
* @param RestoringPoint $point
* @param string $filename
* @param RestoringChunk $chunk
*
* @return ZipStreamer
* @throws ArchiveCreateException
* @throws NotPermittedException
* @throws RestoringPointNotInitiatedException
*/
public function generateZip(RestoringPoint $point, string $filename): ZipStreamer {
if (!$point->hasBaseFolder()) {
throw new ArchiveCreateException('Backup has no Base Folder');
}
public function generateZip(RestoringPoint $point, RestoringChunk $chunk): ZipStreamer {
$folder = $this->getChunkFolder($point, $chunk);

$folder = $point->getBaseFolder();
try {
$file = $folder->newFile($filename);
$file = $folder->newFile($chunk->getFilename());
$zip = new ZipStreamer(
[
'outstream' => $file->write(),
Expand Down Expand Up @@ -517,12 +517,14 @@ public function getChecksum(RestoringPoint $point, RestoringChunk $chunk): strin
}
$stream = fopen('./' . $chunk->getFilename(), 'r');
} else {
$folder = $point->getBaseFolder();
$folder = $this->getChunkFolder($point, $chunk);
$file = $folder->getFile($chunk->getFilename());
$stream = $file->read();
}
} catch (Exception $e) {
throw new ArchiveNotFoundException('Chunk ' . $chunk->getFilename() . ' not found');
throw new ArchiveNotFoundException(
'Chunk ' . $chunk->getPath() . $chunk->getFilename() . ' not found'
);
}

if (is_bool($stream)) {
Expand Down Expand Up @@ -910,4 +912,31 @@ function (ArchiveFile $file) use ($filename): ?ArchiveFile {
return $file;
}


/**
* @param RestoringPoint $point
* @param RestoringChunk $chunk
*
* @return ISimpleFolder
* @throws NotPermittedException
* @throws RestoringPointNotInitiatedException
*/
private function getChunkFolder(RestoringPoint $point, RestoringChunk $chunk): ISimpleFolder {
if (!$point->hasBaseFolder() || !$point->hasRootFolder()) {
throw new RestoringPointNotInitiatedException('Restoring Point is not initiated');
}

$folder = $point->getBaseFolder();
if ($chunk->getPath() !== '') {
$root = $point->getRootFolder();
try {
$folder = $root->getFolder('/' . $folder->getName() . '/' . $chunk->getPath());
} catch (NotFoundException $e) {
$folder = $root->newFolder('/' . $folder->getName() . '/' . $chunk->getPath());
}
}

return $folder;
}

}
2 changes: 1 addition & 1 deletion lib/Service/PointService.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
use OCP\Files\IAppData;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use OCP\Files\SimpleFS\ISimpleFile;
use OCP\Util;
use Throwable;

Expand Down Expand Up @@ -564,6 +563,7 @@ public function initBaseFolder(RestoringPoint $point): void {
$folder = $this->appData->getFolder('/' . $point->getId());
}

$point->setRootFolder($this->appData);
$point->setBaseFolder($folder);
}

Expand Down

0 comments on commit a451033

Please sign in to comment.