From 20738d287e456ddb05a617f6b808f152cc3028a9 Mon Sep 17 00:00:00 2001
From: Vincent Petry <pvince81@owncloud.com>
Date: Mon, 23 Feb 2015 12:31:22 +0100
Subject: [PATCH] Properly detect streamCopy errors

Now checking whether the written bytes match the number of read bytes.
---
 lib/private/helper.php                    | 16 +++++++++++++---
 tests/lib/files/storage/wrapper/quota.php | 22 ++++++++++++++++++++++
 2 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/lib/private/helper.php b/lib/private/helper.php
index 04c063145b..f4992744ad 100644
--- a/lib/private/helper.php
+++ b/lib/private/helper.php
@@ -594,13 +594,23 @@ class OC_Helper {
 		if (!$source or !$target) {
 			return array(0, false);
 		}
+		$bufSize = 8192;
 		$result = true;
 		$count = 0;
 		while (!feof($source)) {
-			if (($c = fwrite($target, fread($source, 8192))) === false) {
+			$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;
-			} else {
-				$count += $c;
+				break;
 			}
 		}
 		return array($count, $result);
diff --git a/tests/lib/files/storage/wrapper/quota.php b/tests/lib/files/storage/wrapper/quota.php
index dc4de4697d..8ca8f308b7 100644
--- a/tests/lib/files/storage/wrapper/quota.php
+++ b/tests/lib/files/storage/wrapper/quota.php
@@ -99,6 +99,28 @@ class Quota extends \Test\Files\Storage\Storage {
 		$this->assertEquals('foobarqwe', $instance->file_get_contents('foo'));
 	}
 
+	public function testStreamCopyWithEnoughSpace() {
+		$instance = $this->getLimitedStorage(16);
+		$inputStream = fopen('data://text/plain,foobarqwerty', 'r');
+		$outputStream = $instance->fopen('foo', 'w+');
+		list($count, $result) = \OC_Helper::streamCopy($inputStream, $outputStream);
+		$this->assertEquals(12, $count);
+		$this->assertTrue($result);
+		fclose($inputStream);
+		fclose($outputStream);
+	}
+
+	public function testStreamCopyNotEnoughSpace() {
+		$instance = $this->getLimitedStorage(9);
+		$inputStream = fopen('data://text/plain,foobarqwerty', 'r');
+		$outputStream = $instance->fopen('foo', 'w+');
+		list($count, $result) = \OC_Helper::streamCopy($inputStream, $outputStream);
+		$this->assertEquals(9, $count);
+		$this->assertFalse($result);
+		fclose($inputStream);
+		fclose($outputStream);
+	}
+
 	public function testReturnFalseWhenFopenFailed() {
 		$failStorage = $this->getMock(
 			'\OC\Files\Storage\Local',
-- 
GitLab