diff options
author | Kate <26026535+provokateurin@users.noreply.github.com> | 2025-05-06 15:21:01 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-05-06 15:21:01 +0200 |
commit | 95923900709079a19f77f9c0bbaf48e07add3767 (patch) | |
tree | 34809d00c8052385ff12655d1bc73246fd23ea46 | |
parent | 24c6a1ff0bbab2d2c325bb30fed7df956d0470b1 (diff) | |
parent | 8aae332622587e7d3fc53c2a08be2f6fa61f9070 (diff) | |
download | nextcloud-server-95923900709079a19f77f9c0bbaf48e07add3767.tar.gz nextcloud-server-95923900709079a19f77f9c0bbaf48e07add3767.zip |
Merge pull request #51779 from nextcloud/object-store-filename
-rw-r--r-- | lib/private/Files/ObjectStore/ObjectStoreStorage.php | 18 | ||||
-rw-r--r-- | lib/private/Files/ObjectStore/S3.php | 12 | ||||
-rw-r--r-- | lib/private/Files/ObjectStore/S3ObjectTrait.php | 45 | ||||
-rw-r--r-- | lib/public/Files/ObjectStore/IObjectStoreMetaData.php | 11 |
4 files changed, 66 insertions, 20 deletions
diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php index 16ef4e7de63..ebe87399ab4 100644 --- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php @@ -22,6 +22,7 @@ use OCP\Files\FileInfo; use OCP\Files\GenericFileException; use OCP\Files\NotFoundException; use OCP\Files\ObjectStore\IObjectStore; +use OCP\Files\ObjectStore\IObjectStoreMetaData; use OCP\Files\ObjectStore\IObjectStoreMultiPartUpload; use OCP\Files\Storage\IChunkedFileWrite; use OCP\Files\Storage\IStorage; @@ -479,6 +480,11 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil $mimetypeDetector = \OC::$server->getMimeTypeDetector(); $mimetype = $mimetypeDetector->detectPath($path); + $metadata = [ + 'mimetype' => $mimetype, + 'original-storage' => $this->getId(), + 'original-path' => $path, + ]; $stat['mimetype'] = $mimetype; $stat['etag'] = $this->getETag($path); @@ -507,13 +513,21 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil ]); $size = $writtenSize; }); - $this->objectStore->writeObject($urn, $countStream, $mimetype); + if ($this->objectStore instanceof IObjectStoreMetaData) { + $this->objectStore->writeObjectWithMetaData($urn, $countStream, $metadata); + } else { + $this->objectStore->writeObject($urn, $countStream, $metadata['mimetype']); + } if (is_resource($countStream)) { fclose($countStream); } $stat['size'] = $size; } else { - $this->objectStore->writeObject($urn, $stream, $mimetype); + if ($this->objectStore instanceof IObjectStoreMetaData) { + $this->objectStore->writeObjectWithMetaData($urn, $stream, $metadata); + } else { + $this->objectStore->writeObject($urn, $stream, $metadata['mimetype']); + } if (is_resource($stream)) { fclose($stream); } diff --git a/lib/private/Files/ObjectStore/S3.php b/lib/private/Files/ObjectStore/S3.php index e970fb6ac14..23c061db174 100644 --- a/lib/private/Files/ObjectStore/S3.php +++ b/lib/private/Files/ObjectStore/S3.php @@ -95,6 +95,16 @@ class S3 implements IObjectStore, IObjectStoreMultiPartUpload, IObjectStoreMetaD ]); } + private function parseS3Metadata(array $metadata): array { + $result = []; + foreach ($metadata as $key => $value) { + if (str_starts_with($key, 'x-amz-meta-')) { + $result[substr($key, strlen('x-amz-meta-'))] = $value; + } + } + return $result; + } + public function getObjectMetaData(string $urn): array { $object = $this->getConnection()->headObject([ 'Bucket' => $this->bucket, @@ -104,7 +114,7 @@ class S3 implements IObjectStore, IObjectStoreMultiPartUpload, IObjectStoreMetaD 'mtime' => $object['LastModified'], 'etag' => trim($object['ETag'], '"'), 'size' => (int)($object['Size'] ?? $object['ContentLength']), - ]; + ] + $this->parseS3Metadata($object['Metadata'] ?? []); } public function listObjects(string $prefix = ''): \Iterator { diff --git a/lib/private/Files/ObjectStore/S3ObjectTrait.php b/lib/private/Files/ObjectStore/S3ObjectTrait.php index 9d7cfa644e6..61e8158b863 100644 --- a/lib/private/Files/ObjectStore/S3ObjectTrait.php +++ b/lib/private/Files/ObjectStore/S3ObjectTrait.php @@ -77,22 +77,32 @@ trait S3ObjectTrait { return $fh; } + private function buildS3Metadata(array $metadata): array { + $result = []; + foreach ($metadata as $key => $value) { + $result['x-amz-meta-' . $key] = $value; + } + return $result; + } /** * Single object put helper * * @param string $urn the unified resource name used to identify the object * @param StreamInterface $stream stream with the data to write - * @param string|null $mimetype the mimetype to set for the remove object @since 22.0.0 + * @param array $metaData the metadata to set for the object * @throws \Exception when something goes wrong, message will be logged */ - protected function writeSingle(string $urn, StreamInterface $stream, ?string $mimetype = null): void { + protected function writeSingle(string $urn, StreamInterface $stream, array $metaData): void { + $mimetype = $metaData['mimetype'] ?? null; + unset($metaData['mimetype']); $this->getConnection()->putObject([ 'Bucket' => $this->bucket, 'Key' => $urn, 'Body' => $stream, 'ACL' => 'private', 'ContentType' => $mimetype, + 'Metadata' => $this->buildS3Metadata($metaData), 'StorageClass' => $this->storageClass, ] + $this->getSSECParameters()); } @@ -103,10 +113,12 @@ trait S3ObjectTrait { * * @param string $urn the unified resource name used to identify the object * @param StreamInterface $stream stream with the data to write - * @param string|null $mimetype the mimetype to set for the remove object + * @param array $metaData the metadata to set for the object * @throws \Exception when something goes wrong, message will be logged */ - protected function writeMultiPart(string $urn, StreamInterface $stream, ?string $mimetype = null): void { + protected function writeMultiPart(string $urn, StreamInterface $stream, array $metaData): void { + $mimetype = $metaData['mimetype'] ?? null; + unset($metaData['mimetype']); $uploader = new MultipartUploader($this->getConnection(), $stream, [ 'bucket' => $this->bucket, 'concurrency' => $this->concurrency, @@ -114,6 +126,7 @@ trait S3ObjectTrait { 'part_size' => $this->uploadPartSize, 'params' => [ 'ContentType' => $mimetype, + 'Metadata' => $this->buildS3Metadata($metaData), 'StorageClass' => $this->storageClass, ] + $this->getSSECParameters(), ]); @@ -131,15 +144,15 @@ trait S3ObjectTrait { } } - - /** - * @param string $urn the unified resource name used to identify the object - * @param resource $stream stream with the data to write - * @param string|null $mimetype the mimetype to set for the remove object @since 22.0.0 - * @throws \Exception when something goes wrong, message will be logged - * @since 7.0.0 - */ public function writeObject($urn, $stream, ?string $mimetype = null) { + $metaData = []; + if ($mimetype) { + $metaData['mimetype'] = $mimetype; + } + $this->writeObjectWithMetaData($urn, $stream, $metaData); + } + + public function writeObjectWithMetaData(string $urn, $stream, array $metaData): void { $canSeek = fseek($stream, 0, SEEK_CUR) === 0; $psrStream = Utils::streamFor($stream); @@ -154,16 +167,16 @@ trait S3ObjectTrait { $buffer->seek(0); if ($buffer->getSize() < $this->putSizeLimit) { // buffer is fully seekable, so use it directly for the small upload - $this->writeSingle($urn, $buffer, $mimetype); + $this->writeSingle($urn, $buffer, $metaData); } else { $loadStream = new Psr7\AppendStream([$buffer, $psrStream]); - $this->writeMultiPart($urn, $loadStream, $mimetype); + $this->writeMultiPart($urn, $loadStream, $metaData); } } else { if ($size < $this->putSizeLimit) { - $this->writeSingle($urn, $psrStream, $mimetype); + $this->writeSingle($urn, $psrStream, $metaData); } else { - $this->writeMultiPart($urn, $psrStream, $mimetype); + $this->writeMultiPart($urn, $psrStream, $metaData); } } $psrStream->close(); diff --git a/lib/public/Files/ObjectStore/IObjectStoreMetaData.php b/lib/public/Files/ObjectStore/IObjectStoreMetaData.php index 8359e83f573..9683873be36 100644 --- a/lib/public/Files/ObjectStore/IObjectStoreMetaData.php +++ b/lib/public/Files/ObjectStore/IObjectStoreMetaData.php @@ -9,7 +9,7 @@ namespace OCP\Files\ObjectStore; /** * Interface IObjectStoreMetaData * - * @psalm-type ObjectMetaData = array{mtime?: \DateTime, etag?: string, size?: int, mimetype?: string, filename?: string} + * @psalm-type ObjectMetaData = array{mtime?: \DateTime, etag?: string, size?: int, mimetype?: string, filename?: string, original-path?: string, original-storage?: string} * * @since 32.0.0 */ @@ -35,4 +35,13 @@ interface IObjectStoreMetaData { * @since 32.0.0 */ public function listObjects(string $prefix = ''): \Iterator; + + /** + * @param string $urn the unified resource name used to identify the object + * @param resource $stream stream with the data to write + * @param ObjectMetaData $metaData the metadata to set for the object + * @throws \Exception when something goes wrong, message will be logged + * @since 32.0.0 + */ + public function writeObjectWithMetaData(string $urn, $stream, array $metaData): void; } |