From a40d984b104aaa72bc41c17fa7b67cd280a9e544 Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 10 Mar 2026 10:04:33 -0400 Subject: [PATCH 1/2] docs(Storage): fix legacy docblock LocalTempFileTrait It was just a copy/paste of the one one Common and thus was not adding anything/inaccurate. Signed-off-by: Josh --- .../Files/Storage/LocalTempFileTrait.php | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/lib/private/Files/Storage/LocalTempFileTrait.php b/lib/private/Files/Storage/LocalTempFileTrait.php index 805a67084ccaa..3e29f78e81ec9 100644 --- a/lib/private/Files/Storage/LocalTempFileTrait.php +++ b/lib/private/Files/Storage/LocalTempFileTrait.php @@ -11,20 +11,26 @@ use OCP\Server; /** - * Storage backend class for providing common filesystem operation methods - * which are not storage-backend specific. + * Helper methods for temporary local file handling for storage paths. * - * \OC\Files\Storage\Common is never used directly; it is extended by all other - * storage backends, where its methods may be overridden, and additional - * (backend-specific) methods are defined. + * Intended for use by storage implementations such as \OC\Files\Storage\Common. * - * Some \OC\Files\Storage\Common methods call functions which are first defined - * in classes which extend it, e.g. $this->stat() . + * This trait caches per-path temporary local copies created from storage streams, + * so repeated local-file access can reuse the same temp file during the instance + * lifetime. */ trait LocalTempFileTrait { /** @var array */ protected array $cachedFiles = []; + /** + * Returns the temporary local file path associated with the specified storage file. + * + * Creates temp file on first use if necessary. Caches for repeated (instance-level) access. + * + * @param string $path Storage-internal path + * @return string|false Local temp file path, or false if the source cannot be opened/copied + */ protected function getCachedFile(string $path): string|false { if (!isset($this->cachedFiles[$path])) { $this->cachedFiles[$path] = $this->toTmpFile($path); @@ -32,10 +38,23 @@ protected function getCachedFile(string $path): string|false { return $this->cachedFiles[$path]; } + /** + * Invalidate the cached temp local file entry for the specified storage file. + * + * @param string $path Storage-internal path + */ protected function removeCachedFile(string $path): void { unset($this->cachedFiles[$path]); } + /** + * Copies a storage file stream into a temporary local file. + * + * The temporary local file keeps the same extension (if any) as the source file. + * + * @param string $path Storage-internal path + * @return string|false Local temp file path, or false on failure + */ protected function toTmpFile(string $path): string|false { //no longer in the storage api, still useful here $source = $this->fopen($path, 'r'); if (!$source) { From 20d4f40bc7dc56bdd2d23d4ea1488d654d5e4166 Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 10 Mar 2026 11:43:36 -0400 Subject: [PATCH 2/2] fix(storage): ensure LocalTempFileTrait::toTmpFile always closes streams A refactor for clarity and general robustness Signed-off-by: Josh --- .../Files/Storage/LocalTempFileTrait.php | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/private/Files/Storage/LocalTempFileTrait.php b/lib/private/Files/Storage/LocalTempFileTrait.php index 3e29f78e81ec9..4114081de3942 100644 --- a/lib/private/Files/Storage/LocalTempFileTrait.php +++ b/lib/private/Files/Storage/LocalTempFileTrait.php @@ -1,7 +1,7 @@ fopen($path, 'r'); if (!$source) { return false; } - if ($pos = strrpos($path, '.')) { - $extension = substr($path, $pos); - } else { - $extension = ''; - } + + $ext = pathinfo($path, PATHINFO_EXTENSION); + $extension = $ext !== '' ? '.' . $ext : ''; + $tmpFile = Server::get(ITempManager::class)->getTemporaryFile($extension); $target = fopen($tmpFile, 'w'); - $result = stream_copy_to_stream($source, $target); - fclose($target); - if ($result === false) { + if ($target === false) { + fclose($source); return false; } + try { + $result = stream_copy_to_stream($source, $target); + if ($result === false) { + return false; + } + } finally { + fclose($target); + fclose($source); + } + return $tmpFile; } }