Skip to content

Commit 68e2a44

Browse files
committed
Handle quota properly and add part handling to storage
Signed-off-by: Julius Härtl <[email protected]>
1 parent a6010b6 commit 68e2a44

12 files changed

Lines changed: 113 additions & 17 deletions

File tree

apps/dav/lib/DAV/CustomPropertiesBackend.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public function propPatch($path, PropPatch $propPatch) {
180180
*/
181181
public function delete($path) {
182182
$this->customPropertiesService->delete($this->user->getUID(), $path);
183-
unset($this->cache[$path]);
183+
unset($this->userCache[$path]);
184184
}
185185

186186
/**

apps/dav/lib/Upload/ChunkingV2Plugin.php

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
use OC\Files\View;
3030
use OCA\DAV\Connector\Sabre\Directory;
3131
use OCA\DAV\Connector\Sabre\FilesPlugin;
32+
use OCP\Files\ObjectStore\IObjectStoreMultiPartUpload;
3233
use OCP\Files\Storage\IChunkedFileWrite;
34+
use OCP\Files\Storage\IProcessingCallbackStorage;
3335
use OCP\Files\Storage\IStorage;
3436
use OCP\Files\StorageInvalidException;
3537
use Sabre\DAV\Exception\BadRequest;
@@ -118,6 +120,10 @@ public function beforeMkcol(RequestInterface $request, ResponseInterface $respon
118120

119121
public function beforePut(RequestInterface $request, ResponseInterface $response): bool {
120122
$this->uploadFolder = $this->server->tree->getNodeForPath(dirname($request->getPath()));
123+
if (!$this->uploadFolder instanceof UploadFolder) {
124+
return true;
125+
}
126+
121127
try {
122128
$this->checkPrerequisites();
123129
$storage = $this->getStorage();
@@ -143,7 +149,7 @@ public function beforePut(RequestInterface $request, ResponseInterface $response
143149

144150
$additionalSize = (int)$request->getHeader('Content-Length');
145151
if ($this->uploadFolder->childExists(self::TEMP_TARGET)) {
146-
// FIXME Quota checking will not work for existing files that way
152+
/** @var UploadFile $tempTargetFile */
147153
$tempTargetFile = $this->uploadFolder->getChild(self::TEMP_TARGET);
148154
$tempTargetCache = $storage->getCache()->get($tempTargetFile->getInternalPath());
149155

@@ -159,7 +165,6 @@ public function beforePut(RequestInterface $request, ResponseInterface $response
159165

160166
$stream = $request->getBodyAsStream();
161167
$storage->putChunkedFilePart($targetFile->getInternalPath(), $uploadId, (string)$partId, $stream, $additionalSize);
162-
// FIXME add return value to putChunkedFilePart to validate against size
163168

164169
$storage->getCache()->update($cacheEntry->getId(), ['size' => $cacheEntry->getSize() + $additionalSize]);
165170
if ($tempTargetFile) {
@@ -211,6 +216,22 @@ public function beforeMove($sourcePath, $destination): bool {
211216

212217
$rootView = new View();
213218
if ($storage->instanceOfStorage(ObjectStoreStorage::class)) {
219+
/** @var ObjectStoreStorage $storage */
220+
$objectStore = $storage->getObjectStore();
221+
if ($objectStore instanceof IObjectStoreMultiPartUpload) {
222+
$parts = $objectStore->getMultipartUploads($storage->getURN($targetFile->getId()), $uploadId);
223+
$size = 0;
224+
foreach ($parts as $part) {
225+
$size += $part['Size'];
226+
}
227+
$free = $storage->free_space($destinationParent->getInternalPath());
228+
if ($free >= 0 && ($size > $free)) {
229+
throw new InsufficientStorage("Insufficient space in $targetPath");
230+
}
231+
}
232+
}
233+
if ($storage->instanceOfStorage(IProcessingCallbackStorage::class)) {
234+
/** @var IProcessingCallbackStorage $storage */
214235
$lastTick = time();
215236
$storage->processingCallback('writeChunkedFile', function () use ($lastTick) {
216237
if ($lastTick < time()) {
@@ -245,7 +266,7 @@ public function beforeMove($sourcePath, $destination): bool {
245266
['200' => [
246267
FilesPlugin::SIZE_PROPERTYNAME => $rootView->filesize($destinationInView)
247268
]],
248-
$destinationExists ? 204 : 201
269+
$destinationExists ? '204' : '201'
249270
);
250271
echo $this->server->xml->write(
251272
'{DAV:}multistatus',

apps/dav/lib/Upload/UploadFile.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ public function get() {
4545
return $this->file->get();
4646
}
4747

48+
public function getId() {
49+
return $this->file->getId();
50+
}
51+
4852
public function getContentType() {
4953
return $this->file->getContentType();
5054
}

apps/dav/tests/unit/CapabilitiesTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public function testGetCapabilities() {
3434
$capabilities = new Capabilities();
3535
$expected = [
3636
'dav' => [
37-
'chunking' => '1.0',
37+
'chunking' => '2.0',
3838
],
3939
];
4040
$this->assertSame($expected, $capabilities->getCapabilities());

build/psalm-baseline.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,12 @@
10141014
<code>null</code>
10151015
</NullArgument>
10161016
</file>
1017+
<file src="apps/dav/lib/Upload/ChunkingV2Plugin.php">
1018+
<UndefinedFunction occurrences="2">
1019+
<code>Uri\split($destination)</code>
1020+
<code>Uri\split($targetPath)</code>
1021+
</UndefinedFunction>
1022+
</file>
10171023
<file src="apps/dav/lib/Upload/UploadHome.php">
10181024
<UndefinedFunction occurrences="1">
10191025
<code>\Sabre\Uri\split($this-&gt;principalInfo['uri'])</code>

lib/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@
322322
'OCP\\Files\\Storage\\IDisableEncryptionStorage' => $baseDir . '/lib/public/Files/Storage/IDisableEncryptionStorage.php',
323323
'OCP\\Files\\Storage\\ILockingStorage' => $baseDir . '/lib/public/Files/Storage/ILockingStorage.php',
324324
'OCP\\Files\\Storage\\INotifyStorage' => $baseDir . '/lib/public/Files/Storage/INotifyStorage.php',
325+
'OCP\\Files\\Storage\\IProcessingCallbackStorage' => $baseDir . '/lib/public/Files/Storage/IProcessingCallbackStorage.php',
325326
'OCP\\Files\\Storage\\IStorage' => $baseDir . '/lib/public/Files/Storage/IStorage.php',
326327
'OCP\\Files\\Storage\\IStorageFactory' => $baseDir . '/lib/public/Files/Storage/IStorageFactory.php',
327328
'OCP\\Files\\Storage\\IWriteStreamStorage' => $baseDir . '/lib/public/Files/Storage/IWriteStreamStorage.php',

lib/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
351351
'OCP\\Files\\Storage\\IDisableEncryptionStorage' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/IDisableEncryptionStorage.php',
352352
'OCP\\Files\\Storage\\ILockingStorage' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/ILockingStorage.php',
353353
'OCP\\Files\\Storage\\INotifyStorage' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/INotifyStorage.php',
354+
'OCP\\Files\\Storage\\IProcessingCallbackStorage' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/IProcessingCallbackStorage.php',
354355
'OCP\\Files\\Storage\\IStorage' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/IStorage.php',
355356
'OCP\\Files\\Storage\\IStorageFactory' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/IStorageFactory.php',
356357
'OCP\\Files\\Storage\\IWriteStreamStorage' => __DIR__ . '/../../..' . '/lib/public/Files/Storage/IWriteStreamStorage.php',

lib/private/Files/ObjectStore/ObjectStoreStorage.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,11 @@
4646
use OCP\Files\ObjectStore\IObjectStore;
4747
use OCP\Files\ObjectStore\IObjectStoreMultiPartUpload;
4848
use OCP\Files\Storage\IChunkedFileWrite;
49+
use OCP\Files\Storage\IProcessingCallbackStorage;
4950
use OCP\Files\Storage\IStorage;
5051
use OCP\ICache;
5152

52-
class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFileWrite {
53+
class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFileWrite, IProcessingCallbackStorage {
5354
use CopyDirectory;
5455

5556
/**
@@ -654,7 +655,7 @@ public function putChunkedFilePart(string $targetPath, string $writeToken, strin
654655
$this->uploadCache->set($this->getUploadCacheKey($urn, $uploadId, 'parts'), $parts);
655656
}
656657

657-
public function processingCallback(string $method, callable $callback) {
658+
public function processingCallback(string $method, callable $callback): void {
658659
if (in_array($method, ['writeChunkedFile'])) {
659660
if (!isset($this->processingCallbacks[$method])) {
660661
$this->processingCallbacks[$method] = [];

lib/private/Files/ObjectStore/S3.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ public function uploadMultipartPart(string $urn, string $uploadId, int $partId,
6767
]);
6868
}
6969

70+
public function getMultipartUploads(string $urn, string $uploadId): array {
71+
$parts = $this->getConnection()->listParts([
72+
'Bucket' => $this->bucket,
73+
'Key' => $urn,
74+
'UploadId' => $uploadId
75+
]);
76+
return array_map(function ($part) {
77+
return $part;
78+
}, $parts->get('Parts'));
79+
}
80+
7081
public function completeMultipartUpload(string $urn, string $uploadId, array $result, callable $processingCallback = null): int {
7182
$this->getConnection()->completeMultipartUpload([
7283
'Bucket' => $this->bucket,

lib/public/Files/ObjectStore/IObjectStoreMultiPartUpload.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,26 +29,31 @@
2929
use Aws\Result;
3030

3131
/**
32-
* @since 22.0.0
32+
* @since 23.0.0
3333
*/
3434
interface IObjectStoreMultiPartUpload {
3535
/**
36-
* @since 22.0.0
36+
* @since 23.0.0
3737
*/
3838
public function initiateMultipartUpload(string $urn): string;
3939

4040
/**
41-
* @since 22.0.0
41+
* @since 23.0.0
4242
*/
4343
public function uploadMultipartPart(string $urn, string $uploadId, int $partId, $stream, $size): Result;
4444

4545
/**
46-
* @since 22.0.0
46+
* @since 23.0.0
4747
*/
4848
public function completeMultipartUpload(string $urn, string $uploadId, array $result): int;
4949

5050
/**
51-
* @since 22.0.0
51+
* @since 23.0.0
5252
*/
5353
public function abortMultipartUpload(string $urn, string $uploadId): void;
54+
55+
/**
56+
* @since 23.0.0
57+
*/
58+
public function getMultipartUploads(string $urn, string $uploadId): array;
5459
}

0 commit comments

Comments
 (0)