aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2025-05-16 00:07:33 +0200
committerFerdinand Thiessen <opensource@fthiessen.de>2025-05-16 13:03:05 +0200
commit01db539d0ae936abdc82723d458cf816dcb6aad8 (patch)
treed1bc7707264e91bd0c5f39c83262b00ce0b3c689
parent12fdcd0826d59a797d5e9e6aaea181dde240f503 (diff)
downloadnextcloud-server-01db539d0ae936abdc82723d458cf816dcb6aad8.tar.gz
nextcloud-server-01db539d0ae936abdc82723d458cf816dcb6aad8.zip
chore: move streamCopy implementation from `OC_Helper` to `OCP\Files`
The function was already there but called the legacy version. So moved the implementation and migrated all usages of it. Sadly the interface was slightly different so adjusted it to be compatible with both legacy and the OCP one. Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
-rw-r--r--apps/dav/lib/Connector/Sabre/File.php3
-rw-r--r--apps/files_versions/lib/Storage.php7
-rw-r--r--build/psalm-baseline.xml11
-rw-r--r--lib/private/Files/Storage/Common.php5
-rw-r--r--lib/private/Files/Storage/LocalTempFileTrait.php4
-rw-r--r--lib/private/Files/Storage/Wrapper/Encryption.php5
-rw-r--r--lib/private/Files/Storage/Wrapper/Jail.php3
-rw-r--r--lib/private/Files/Storage/Wrapper/Wrapper.php3
-rw-r--r--lib/private/Files/View.php3
-rw-r--r--lib/private/legacy/OC_Helper.php25
-rw-r--r--lib/public/Files.php38
11 files changed, 66 insertions, 41 deletions
diff --git a/apps/dav/lib/Connector/Sabre/File.php b/apps/dav/lib/Connector/Sabre/File.php
index 045b9d7e784..98e0f2e9e4b 100644
--- a/apps/dav/lib/Connector/Sabre/File.php
+++ b/apps/dav/lib/Connector/Sabre/File.php
@@ -19,6 +19,7 @@ use OCA\DAV\Connector\Sabre\Exception\Forbidden as DAVForbiddenException;
use OCA\DAV\Connector\Sabre\Exception\UnsupportedMediaType;
use OCP\App\IAppManager;
use OCP\Encryption\Exceptions\GenericEncryptionException;
+use OCP\Files;
use OCP\Files\EntityTooLargeException;
use OCP\Files\FileInfo;
use OCP\Files\ForbiddenException;
@@ -229,7 +230,7 @@ class File extends Node implements IFile {
// because we have no clue about the cause we can only throw back a 500/Internal Server Error
throw new Exception($this->l10n->t('Could not write file contents'));
}
- [$count, $result] = \OC_Helper::streamCopy($data, $target);
+ [$count, $result] = Files::streamCopy($data, $target, true);
fclose($target);
}
diff --git a/apps/files_versions/lib/Storage.php b/apps/files_versions/lib/Storage.php
index 19e7dd598ae..49d577ed94b 100644
--- a/apps/files_versions/lib/Storage.php
+++ b/apps/files_versions/lib/Storage.php
@@ -23,6 +23,7 @@ use OCA\Files_Versions\Versions\IVersionManager;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\Command\IBus;
use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Files;
use OCP\Files\FileInfo;
use OCP\Files\Folder;
use OCP\Files\IMimeTypeDetector;
@@ -416,10 +417,12 @@ class Storage {
try {
// TODO add a proper way of overwriting a file while maintaining file ids
- if ($storage1->instanceOfStorage('\OC\Files\ObjectStore\ObjectStoreStorage') || $storage2->instanceOfStorage('\OC\Files\ObjectStore\ObjectStoreStorage')) {
+ if ($storage1->instanceOfStorage(\OC\Files\ObjectStore\ObjectStoreStorage::class)
+ || $storage2->instanceOfStorage(\OC\Files\ObjectStore\ObjectStoreStorage::class)
+ ) {
$source = $storage1->fopen($internalPath1, 'r');
$target = $storage2->fopen($internalPath2, 'w');
- [, $result] = \OC_Helper::streamCopy($source, $target);
+ [, $result] = Files::streamCopy($source, $target, true);
fclose($source);
fclose($target);
diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml
index 8d409314d4d..4cb20e11af2 100644
--- a/build/psalm-baseline.xml
+++ b/build/psalm-baseline.xml
@@ -675,6 +675,12 @@
</ParamNameMismatch>
</file>
<file src="apps/dav/lib/Connector/Sabre/File.php">
+ <DeprecatedClass>
+ <code><![CDATA[Files::streamCopy($data, $target, true)]]></code>
+ </DeprecatedClass>
+ <DeprecatedMethod>
+ <code><![CDATA[Files::streamCopy($data, $target, true)]]></code>
+ </DeprecatedMethod>
<LessSpecificReturnStatement>
<code><![CDATA[$this->node]]></code>
</LessSpecificReturnStatement>
@@ -1965,14 +1971,13 @@
</file>
<file src="apps/files_versions/lib/Storage.php">
<DeprecatedClass>
+ <code><![CDATA[Files::streamCopy($source, $target, true)]]></code>
<code><![CDATA[\OC_Util::setupFS($uid)]]></code>
</DeprecatedClass>
<DeprecatedMethod>
+ <code><![CDATA[Files::streamCopy($source, $target, true)]]></code>
<code><![CDATA[dispatch]]></code>
</DeprecatedMethod>
- <RedundantCondition>
- <code><![CDATA[$storage1->instanceOfStorage('\OC\Files\ObjectStore\ObjectStoreStorage')]]></code>
- </RedundantCondition>
</file>
<file src="apps/oauth2/lib/Controller/OauthApiController.php">
<NoInterfaceProperties>
diff --git a/lib/private/Files/Storage/Common.php b/lib/private/Files/Storage/Common.php
index ca0e38774c8..b1e02cf2e6c 100644
--- a/lib/private/Files/Storage/Common.php
+++ b/lib/private/Files/Storage/Common.php
@@ -19,6 +19,7 @@ use OC\Files\ObjectStore\ObjectStoreStorage;
use OC\Files\Storage\Wrapper\Encryption;
use OC\Files\Storage\Wrapper\Jail;
use OC\Files\Storage\Wrapper\Wrapper;
+use OCP\Files;
use OCP\Files\Cache\ICache;
use OCP\Files\Cache\IPropagator;
use OCP\Files\Cache\IScanner;
@@ -205,7 +206,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
} else {
$sourceStream = $this->fopen($source, 'r');
$targetStream = $this->fopen($target, 'w');
- [, $result] = \OC_Helper::streamCopy($sourceStream, $targetStream);
+ [, $result] = Files::streamCopy($sourceStream, $targetStream, true);
if (!$result) {
Server::get(LoggerInterface::class)->warning("Failed to write data while copying $source to $target");
}
@@ -734,7 +735,7 @@ abstract class Common implements Storage, ILockingStorage, IWriteStreamStorage,
throw new GenericFileException("Failed to open $path for writing");
}
try {
- [$count, $result] = \OC_Helper::streamCopy($stream, $target);
+ [$count, $result] = Files::streamCopy($stream, $target, true);
if (!$result) {
throw new GenericFileException('Failed to copy stream');
}
diff --git a/lib/private/Files/Storage/LocalTempFileTrait.php b/lib/private/Files/Storage/LocalTempFileTrait.php
index c8e3588f2e8..fffc3e789f3 100644
--- a/lib/private/Files/Storage/LocalTempFileTrait.php
+++ b/lib/private/Files/Storage/LocalTempFileTrait.php
@@ -7,6 +7,8 @@
*/
namespace OC\Files\Storage;
+use OCP\Files;
+
/**
* Storage backend class for providing common filesystem operation methods
* which are not storage-backend specific.
@@ -45,7 +47,7 @@ trait LocalTempFileTrait {
}
$tmpFile = \OC::$server->getTempManager()->getTemporaryFile($extension);
$target = fopen($tmpFile, 'w');
- \OC_Helper::streamCopy($source, $target);
+ Files::streamCopy($source, $target);
fclose($target);
return $tmpFile;
}
diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php
index f4ab4754cff..4d38d2d37aa 100644
--- a/lib/private/Files/Storage/Wrapper/Encryption.php
+++ b/lib/private/Files/Storage/Wrapper/Encryption.php
@@ -21,6 +21,7 @@ use OCP\Encryption\Exceptions\InvalidHeaderException;
use OCP\Encryption\IFile;
use OCP\Encryption\IManager;
use OCP\Encryption\Keys\IStorage;
+use OCP\Files;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\Storage;
@@ -684,7 +685,7 @@ class Encryption extends Wrapper {
try {
$source = $sourceStorage->fopen($sourceInternalPath, 'r');
$target = $this->fopen($targetInternalPath, 'w');
- [, $result] = \OC_Helper::streamCopy($source, $target);
+ [, $result] = Files::streamCopy($source, $target, true);
} finally {
if (is_resource($source)) {
fclose($source);
@@ -893,7 +894,7 @@ class Encryption extends Wrapper {
public function writeStream(string $path, $stream, ?int $size = null): int {
// always fall back to fopen
$target = $this->fopen($path, 'w');
- [$count, $result] = \OC_Helper::streamCopy($stream, $target);
+ [$count, $result] = Files::streamCopy($stream, $target, true);
fclose($stream);
fclose($target);
diff --git a/lib/private/Files/Storage/Wrapper/Jail.php b/lib/private/Files/Storage/Wrapper/Jail.php
index c8db0e94e59..38b113cef88 100644
--- a/lib/private/Files/Storage/Wrapper/Jail.php
+++ b/lib/private/Files/Storage/Wrapper/Jail.php
@@ -11,6 +11,7 @@ use OC\Files\Cache\Wrapper\CacheJail;
use OC\Files\Cache\Wrapper\JailPropagator;
use OC\Files\Cache\Wrapper\JailWatcher;
use OC\Files\Filesystem;
+use OCP\Files;
use OCP\Files\Cache\ICache;
use OCP\Files\Cache\IPropagator;
use OCP\Files\Cache\IWatcher;
@@ -253,7 +254,7 @@ class Jail extends Wrapper {
return $storage->writeStream($this->getUnjailedPath($path), $stream, $size);
} else {
$target = $this->fopen($path, 'w');
- [$count, $result] = \OC_Helper::streamCopy($stream, $target);
+ $count = Files::streamCopy($stream, $target);
fclose($stream);
fclose($target);
return $count;
diff --git a/lib/private/Files/Storage/Wrapper/Wrapper.php b/lib/private/Files/Storage/Wrapper/Wrapper.php
index 6dea439fe25..7af11dd5ef7 100644
--- a/lib/private/Files/Storage/Wrapper/Wrapper.php
+++ b/lib/private/Files/Storage/Wrapper/Wrapper.php
@@ -9,6 +9,7 @@ namespace OC\Files\Storage\Wrapper;
use OC\Files\Storage\FailedStorage;
use OC\Files\Storage\Storage;
+use OCP\Files;
use OCP\Files\Cache\ICache;
use OCP\Files\Cache\IPropagator;
use OCP\Files\Cache\IScanner;
@@ -322,7 +323,7 @@ class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage, IWriteStrea
return $storage->writeStream($path, $stream, $size);
} else {
$target = $this->fopen($path, 'w');
- [$count, $result] = \OC_Helper::streamCopy($stream, $target);
+ $count = Files::streamCopy($stream, $target);
fclose($stream);
fclose($target);
return $count;
diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php
index e49043355e8..6832b4e1551 100644
--- a/lib/private/Files/View.php
+++ b/lib/private/Files/View.php
@@ -17,6 +17,7 @@ use OC\User\Manager as UserManager;
use OC\User\User;
use OCA\Files_Sharing\SharedMount;
use OCP\Constants;
+use OCP\Files;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\ConnectionLostException;
use OCP\Files\EmptyFileNameException;
@@ -629,7 +630,7 @@ class View {
[$storage, $internalPath] = $this->resolvePath($path);
$target = $storage->fopen($internalPath, 'w');
if ($target) {
- [, $result] = \OC_Helper::streamCopy($data, $target);
+ [, $result] = Files::streamCopy($data, $target, true);
fclose($target);
fclose($data);
diff --git a/lib/private/legacy/OC_Helper.php b/lib/private/legacy/OC_Helper.php
index 841433c6ea1..3717dc75cbc 100644
--- a/lib/private/legacy/OC_Helper.php
+++ b/lib/private/legacy/OC_Helper.php
@@ -158,31 +158,10 @@ class OC_Helper {
* @param resource $source
* @param resource $target
* @return array the number of bytes copied and result
+ * @deprecated 5.0.0 - Use \OCP\Files::streamCopy
*/
public static function streamCopy($source, $target) {
- if (!$source or !$target) {
- return [0, false];
- }
- $bufSize = 8192;
- $result = true;
- $count = 0;
- while (!feof($source)) {
- $buf = fread($source, $bufSize);
- $bytesWritten = fwrite($target, $buf);
- if ($bytesWritten !== false) {
- $count += $bytesWritten;
- }
- // note: strlen is expensive so only use it when necessary,
- // on the last block
- if ($bytesWritten === false
- || ($bytesWritten < $bufSize && $bytesWritten < strlen($buf))
- ) {
- // write error, could be disk full ?
- $result = false;
- break;
- }
- }
- return [$count, $result];
+ return \OCP\Files::streamCopy($source, $target, true);
}
/**
diff --git a/lib/public/Files.php b/lib/public/Files.php
index b12aa463f1a..3df3152b0ef 100644
--- a/lib/public/Files.php
+++ b/lib/public/Files.php
@@ -85,15 +85,45 @@ class Files {
/**
* Copy the contents of one stream to another
+ *
+ * @template T of null|true
* @param resource $source
* @param resource $target
- * @return int the number of bytes copied
+ * @param T $includeResult
+ * @return int|array
+ * @psalm-return (T is true ? array{0: int, 1: bool} : int)
* @since 5.0.0
+ * @since 32.0.0 added $includeResult parameter
* @deprecated 14.0.0
*/
- public static function streamCopy($source, $target) {
- [$count, ] = \OC_Helper::streamCopy($source, $target);
- return $count;
+ public static function streamCopy($source, $target, ?bool $includeResult = null) {
+ if (!$source or !$target) {
+ return $includeResult ? [0, false] : 0;
+ }
+
+ $bufSize = 8192;
+ $count = 0;
+ $result = true;
+ while (!feof($source)) {
+ $buf = fread($source, $bufSize);
+ if ($buf === false) {
+ $result = false;
+ break;
+ }
+
+ $bytesWritten = fwrite($target, $buf);
+ if ($bytesWritten !== false) {
+ $count += $bytesWritten;
+ }
+
+ if ($bytesWritten === false
+ || ($bytesWritten < $bufSize && $bytesWritten < strlen($buf))
+ ) {
+ $result = false;
+ break;
+ }
+ }
+ return $includeResult ? [$count, $result] : $count;
}
/**