diff --git a/apps/files_sharing/lib/sharedstorage.php b/apps/files_sharing/lib/sharedstorage.php
index 257da89c84e52e3a68ae27d4282109301b461563..6141d832199f3272a3c20c8ed20c0dcc479cee60 100644
--- a/apps/files_sharing/lib/sharedstorage.php
+++ b/apps/files_sharing/lib/sharedstorage.php
@@ -43,7 +43,7 @@ class Shared extends \OC\Files\Storage\Common {
 	* @param string Shared target file path
 	* @return Returns array with the keys path, permissions, and owner or false if not found
 	*/
-	private function getFile($target) {
+	public function getFile($target) {
 		if (!isset($this->files[$target])) {
 			// Check for partial files
 			if (pathinfo($target, PATHINFO_EXTENSION) === 'part') {
@@ -66,7 +66,7 @@ class Shared extends \OC\Files\Storage\Common {
 	* @param string Shared target file path
 	* @return string source file path or false if not found
 	*/
-	private function getSourcePath($target) {
+	public function getSourcePath($target) {
 		$source = $this->getFile($target);
 		if ($source) {
 			if (!isset($source['fullPath'])) {
diff --git a/apps/files_sharing/lib/watcher.php b/apps/files_sharing/lib/watcher.php
index 6fdfc1db36d05295e525754415129102e47f2131..c40cf6911b8d37a0e7ea0bd662319428783e05d8 100644
--- a/apps/files_sharing/lib/watcher.php
+++ b/apps/files_sharing/lib/watcher.php
@@ -32,9 +32,32 @@ class Shared_Watcher extends Watcher {
 	 * @param string $path
 	 */
 	public function checkUpdate($path) {
-		if ($path != '') {
-			parent::checkUpdate($path);
+		if ($path != '' && parent::checkUpdate($path)) {
+			// since checkUpdate() has already updated the size of the subdirs,
+			// only apply the update to the owner's parent dirs
+
+			// find last parent before reaching the shared storage root,
+			// which is the actual shared dir from the owner
+			$sepPos = strpos($path, '/');
+			if ($sepPos > 0) {
+				$baseDir = substr($path, 0, $sepPos);
+			} else {
+				$baseDir = $path;
+			}
+
+			// find the path relative to the data dir
+			$file = $this->storage->getFile($baseDir);
+			$view = new \OC\Files\View('/' . $file['fileOwner']);
+
+			// find the owner's storage and path
+			list($storage, $internalPath) = $view->resolvePath($file['path']);
+
+			// update the parent dirs' sizes in the owner's cache
+			$storage->getCache()->correctFolderSize(dirname($internalPath));
+
+			return true;
 		}
+		return false;
 	}
 
 	/**
diff --git a/apps/files_sharing/tests/api.php b/apps/files_sharing/tests/api.php
index 44fc4d8b7b3e269d37bde694cb0bcc02f4065b27..1278e0c4d1fa2e00d14669be4551676c537edee0 100644
--- a/apps/files_sharing/tests/api.php
+++ b/apps/files_sharing/tests/api.php
@@ -20,90 +20,33 @@
  *
  */
 
-require_once __DIR__ . '/../../../lib/base.php';
+require_once __DIR__ . '/base.php';
 
 use OCA\Files\Share;
 
 /**
  * Class Test_Files_Sharing_Api
  */
-class Test_Files_Sharing_Api extends \PHPUnit_Framework_TestCase {
-
-	const TEST_FILES_SHARING_API_USER1 = "test-share-user1";
-	const TEST_FILES_SHARING_API_USER2 = "test-share-user2";
-	const TEST_FILES_SHARING_API_USER3 = "test-share-user3";
-
-	public $stateFilesEncryption;
-	public $filename;
-	public $data;
-	/**
-	 * @var OC_FilesystemView
-	 */
-	public $view;
-	public $folder;
-
-	public static function setUpBeforeClass() {
-		// reset backend
-		\OC_User::clearBackends();
-		\OC_User::useBackend('database');
-
-		// clear share hooks
-		\OC_Hook::clear('OCP\\Share');
-		\OC::registerShareHooks();
-		\OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup');
-
-		// create users
-		self::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1, true);
-		self::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2, true);
-		self::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER3, true);
-
-	}
+class Test_Files_Sharing_Api extends Test_Files_Sharing_Base {
 
 	function setUp() {
-
-		//login as user1
-		\Test_Files_Sharing_Api::loginHelper(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1);
-
-		$this->data = 'foobar';
-		$this->view = new \OC_FilesystemView('/' . \Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1 . '/files');
+		parent::setUp();
 
 		$this->folder = '/folder_share_api_test';
 
 		$this->filename = 'share-api-test.txt';
 
-		// remember files_encryption state
-		$this->stateFilesEncryption = \OC_App::isEnabled('files_encryption');
-
-		 //we don't want to tests with app files_encryption enabled
-		\OC_App::disable('files_encryption');
-
-
-		$this->assertTrue(!\OC_App::isEnabled('files_encryption'));
-
 		// save file with content
 		$this->view->file_put_contents($this->filename, $this->data);
 		$this->view->mkdir($this->folder);
 		$this->view->file_put_contents($this->folder.'/'.$this->filename, $this->data);
-
 	}
 
 	function tearDown() {
 		$this->view->unlink($this->filename);
 		$this->view->deleteAll($this->folder);
-		// reset app files_encryption
-		if ($this->stateFilesEncryption) {
-			\OC_App::enable('files_encryption');
-		} else {
-			\OC_App::disable('files_encryption');
-		}
-	}
-
-	public static function tearDownAfterClass() {
 
-		// cleanup users
-		\OC_User::deleteUser(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER1);
-		\OC_User::deleteUser(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER2);
-		\OC_User::deleteUser(\Test_Files_Sharing_Api::TEST_FILES_SHARING_API_USER3);
+		parent::tearDown();
 	}
 
 	/**
@@ -548,50 +491,4 @@ class Test_Files_Sharing_Api extends \PHPUnit_Framework_TestCase {
 		$this->assertTrue(empty($itemsAfterDelete));
 
 	}
-
-	/**
-	 * @param $user
-	 * @param bool $create
-	 * @param bool $password
-	 */
-	private static function loginHelper($user, $create = false, $password = false) {
-		if ($create) {
-			\OC_User::createUser($user, $user);
-		}
-
-		if ($password === false) {
-			$password = $user;
-		}
-
-		\OC_Util::tearDownFS();
-		\OC_User::setUserId('');
-		\OC\Files\Filesystem::tearDown();
-		\OC_Util::setupFS($user);
-		\OC_User::setUserId($user);
-
-		$params['uid'] = $user;
-		$params['password'] = $password;
-	}
-
-	/**
-	 * @brief get some information from a given share
-	 * @param int $shareID
-	 * @return array with: item_source, share_type, share_with, item_type, permissions
-	 */
-	private function getShareFromId($shareID) {
-		$sql = 'SELECT `item_source`, `share_type`, `share_with`, `item_type`, `permissions` FROM `*PREFIX*share` WHERE `id` = ?';
-		$args = array($shareID);
-		$query = \OCP\DB::prepare($sql);
-		$result = $query->execute($args);
-
-		$share = Null;
-
-		if ($result && $result->numRows() > 0) {
-				$share = $result->fetchRow();
-		}
-
-		return $share;
-
-	}
-
 }
diff --git a/apps/files_sharing/tests/base.php b/apps/files_sharing/tests/base.php
new file mode 100644
index 0000000000000000000000000000000000000000..689c80cb9e642763dcf543c3a2bfe529db306190
--- /dev/null
+++ b/apps/files_sharing/tests/base.php
@@ -0,0 +1,143 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Bjoern Schiessle
+ * @copyright 2013 Bjoern Schiessle <schiessle@owncloud.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+require_once __DIR__ . '/../../../lib/base.php';
+
+use OCA\Files\Share;
+
+/**
+ * Class Test_Files_Sharing_Base
+ *
+ * Base class for sharing tests.
+ */
+abstract class Test_Files_Sharing_Base extends \PHPUnit_Framework_TestCase {
+
+	const TEST_FILES_SHARING_API_USER1 = "test-share-user1";
+	const TEST_FILES_SHARING_API_USER2 = "test-share-user2";
+	const TEST_FILES_SHARING_API_USER3 = "test-share-user3";
+
+	public $stateFilesEncryption;
+	public $filename;
+	public $data;
+	/**
+	 * @var OC_FilesystemView
+	 */
+	public $view;
+	public $folder;
+
+	public static function setUpBeforeClass() {
+		// reset backend
+		\OC_User::clearBackends();
+		\OC_User::useBackend('database');
+
+		// clear share hooks
+		\OC_Hook::clear('OCP\\Share');
+		\OC::registerShareHooks();
+		\OCP\Util::connectHook('OC_Filesystem', 'setup', '\OC\Files\Storage\Shared', 'setup');
+
+		// create users
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER1, true);
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER2, true);
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER3, true);
+
+	}
+
+	function setUp() {
+
+		//login as user1
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+
+		$this->data = 'foobar';
+		$this->view = new \OC_FilesystemView('/' . self::TEST_FILES_SHARING_API_USER1 . '/files');
+		// remember files_encryption state
+		$this->stateFilesEncryption = \OC_App::isEnabled('files_encryption');
+
+		 //we don't want to tests with app files_encryption enabled
+		\OC_App::disable('files_encryption');
+
+
+		$this->assertTrue(!\OC_App::isEnabled('files_encryption'));
+	}
+
+	function tearDown() {
+		// reset app files_encryption
+		if ($this->stateFilesEncryption) {
+			\OC_App::enable('files_encryption');
+		} else {
+			\OC_App::disable('files_encryption');
+		}
+	}
+
+	public static function tearDownAfterClass() {
+
+		// cleanup users
+		\OC_User::deleteUser(self::TEST_FILES_SHARING_API_USER1);
+		\OC_User::deleteUser(self::TEST_FILES_SHARING_API_USER2);
+		\OC_User::deleteUser(self::TEST_FILES_SHARING_API_USER3);
+	}
+
+	/**
+	 * @param $user
+	 * @param bool $create
+	 * @param bool $password
+	 */
+	protected static function loginHelper($user, $create = false, $password = false) {
+		if ($create) {
+			\OC_User::createUser($user, $user);
+		}
+
+		if ($password === false) {
+			$password = $user;
+		}
+
+		\OC_Util::tearDownFS();
+		\OC_User::setUserId('');
+		\OC\Files\Filesystem::tearDown();
+		\OC_Util::setupFS($user);
+		\OC_User::setUserId($user);
+
+		$params['uid'] = $user;
+		$params['password'] = $password;
+	}
+
+	/**
+	 * @brief get some information from a given share
+	 * @param int $shareID
+	 * @return array with: item_source, share_type, share_with, item_type, permissions
+	 */
+	protected function getShareFromId($shareID) {
+		$sql = 'SELECT `item_source`, `share_type`, `share_with`, `item_type`, `permissions` FROM `*PREFIX*share` WHERE `id` = ?';
+		$args = array($shareID);
+		$query = \OCP\DB::prepare($sql);
+		$result = $query->execute($args);
+
+		$share = Null;
+
+		if ($result && $result->numRows() > 0) {
+				$share = $result->fetchRow();
+		}
+
+		return $share;
+
+	}
+
+}
diff --git a/apps/files_sharing/tests/watcher.php b/apps/files_sharing/tests/watcher.php
new file mode 100644
index 0000000000000000000000000000000000000000..1a9a54cbcf8a413891a1c0c7438d217414f87afb
--- /dev/null
+++ b/apps/files_sharing/tests/watcher.php
@@ -0,0 +1,161 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Vincent Petry
+ * @copyright 2013 Vincent Petry <pvince81@owncloud.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+require_once __DIR__ . '/base.php';
+
+class Test_Files_Sharing_Watcher extends Test_Files_Sharing_Base {
+
+	function setUp() {
+		parent::setUp();
+
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+
+		// prepare user1's dir structure
+		$textData = "dummy file data\n";
+		$this->view->mkdir('container');
+		$this->view->mkdir('container/shareddir');
+		$this->view->mkdir('container/shareddir/subdir');
+
+		list($this->ownerStorage, $internalPath) = $this->view->resolvePath('');
+		$this->ownerCache = $this->ownerStorage->getCache();
+		$this->ownerStorage->getScanner()->scan('');
+
+		// share "shareddir" with user2
+		$fileinfo = $this->view->getFileInfo('container/shareddir');
+		\OCP\Share::shareItem('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+			self::TEST_FILES_SHARING_API_USER2, 31);
+
+		// login as user2
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
+
+		// retrieve the shared storage
+		$secondView = new \OC\Files\View('/' . self::TEST_FILES_SHARING_API_USER2);
+		list($this->sharedStorage, $internalPath) = $secondView->resolvePath('files/Shared/shareddir');
+		$this->sharedCache = $this->sharedStorage->getCache();
+	}
+
+	function tearDown() {
+		$this->sharedCache->clear();
+
+		self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
+
+		$fileinfo = $this->view->getFileInfo('container/shareddir');
+		\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER,
+			self::TEST_FILES_SHARING_API_USER2);
+
+		$this->view->deleteAll('container');
+
+		$this->ownerCache->clear();
+
+		parent::tearDown();
+	}
+
+	/**
+	 * Tests that writing a file using the shared storage will propagate the file
+	 * size to the owner's parent folders.
+	 */
+	function testFolderSizePropagationToOwnerStorage() {
+		$initialSizes = self::getOwnerDirSizes('files/container/shareddir');
+
+		$textData = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+		$dataLen = strlen($textData);
+		$this->sharedCache->put('shareddir/bar.txt', array('storage_mtime' => 10));
+		$this->sharedStorage->file_put_contents('shareddir/bar.txt', $textData);
+		$this->sharedCache->put('shareddir', array('storage_mtime' => 10));
+
+		// run the propagation code
+		$result = $this->sharedStorage->getWatcher()->checkUpdate('shareddir');
+
+		$this->assertTrue($result);
+
+		// the owner's parent dirs must have increase size
+		$newSizes = self::getOwnerDirSizes('files/container/shareddir');
+		$this->assertEquals($initialSizes[''] + $dataLen, $newSizes['']);
+		$this->assertEquals($initialSizes['files'] + $dataLen, $newSizes['files']);
+		$this->assertEquals($initialSizes['files/container'] + $dataLen, $newSizes['files/container']);
+		$this->assertEquals($initialSizes['files/container/shareddir'] + $dataLen, $newSizes['files/container/shareddir']);
+
+		// no more updates
+		$result = $this->sharedStorage->getWatcher()->checkUpdate('shareddir');
+
+		$this->assertFalse($result);
+	}
+
+	/**
+	 * Tests that writing a file using the shared storage will propagate the file
+	 * size to the owner's parent folders.
+	 */
+	function testSubFolderSizePropagationToOwnerStorage() {
+		$initialSizes = self::getOwnerDirSizes('files/container/shareddir/subdir');
+
+		$textData = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+		$dataLen = strlen($textData);
+		$this->sharedCache->put('shareddir/subdir/bar.txt', array('storage_mtime' => 10));
+		$this->sharedStorage->file_put_contents('shareddir/subdir/bar.txt', $textData);
+		$this->sharedCache->put('shareddir/subdir', array('storage_mtime' => 10));
+
+		// run the propagation code
+		$result = $this->sharedStorage->getWatcher()->checkUpdate('shareddir/subdir');
+
+		$this->assertTrue($result);
+
+		// the owner's parent dirs must have increase size
+		$newSizes = self::getOwnerDirSizes('files/container/shareddir/subdir');
+		$this->assertEquals($initialSizes[''] + $dataLen, $newSizes['']);
+		$this->assertEquals($initialSizes['files'] + $dataLen, $newSizes['files']);
+		$this->assertEquals($initialSizes['files/container'] + $dataLen, $newSizes['files/container']);
+		$this->assertEquals($initialSizes['files/container/shareddir'] + $dataLen, $newSizes['files/container/shareddir']);
+		$this->assertEquals($initialSizes['files/container/shareddir/subdir'] + $dataLen, $newSizes['files/container/shareddir/subdir']);
+
+		// no more updates
+		$result = $this->sharedStorage->getWatcher()->checkUpdate('shareddir/subdir');
+
+		$this->assertFalse($result);
+	}
+
+	function testNoUpdateOnRoot() {
+		// no updates when called for root path
+		$result = $this->sharedStorage->getWatcher()->checkUpdate('');
+
+		$this->assertFalse($result);
+
+		// FIXME: for some reason when running this "naked" test,
+		// there will be remaining nonsensical entries in the
+		// database with a path "test-share-user1/container/..."
+	}
+
+	/**
+	 * Returns the sizes of the path and its parent dirs in a hash
+	 * where the key is the path and the value is the size.
+	 */
+	function getOwnerDirSizes($path) {
+		$result = array();
+
+		while ($path != '' && $path != '' && $path != '.') {
+			$cachedData = $this->ownerCache->get($path);
+			$result[$path] = $cachedData['size'];
+			$path = dirname($path);
+		}
+		$cachedData = $this->ownerCache->get('');
+		$result[''] = $cachedData['size'];
+		return $result;
+	}
+}
diff --git a/lib/private/files/cache/watcher.php b/lib/private/files/cache/watcher.php
index 8bfd4602f3aae9f0ee8ca0233b09be0c5faf8464..58f624c899030743438f3e1eabb0ce809b40be83 100644
--- a/lib/private/files/cache/watcher.php
+++ b/lib/private/files/cache/watcher.php
@@ -15,17 +15,17 @@ class Watcher {
 	/**
 	 * @var \OC\Files\Storage\Storage $storage
 	 */
-	private $storage;
+	protected $storage;
 
 	/**
 	 * @var Cache $cache
 	 */
-	private $cache;
+	protected $cache;
 
 	/**
 	 * @var Scanner $scanner;
 	 */
-	private $scanner;
+	protected $scanner;
 
 	/**
 	 * @param \OC\Files\Storage\Storage $storage
@@ -40,6 +40,7 @@ class Watcher {
 	 * check $path for updates
 	 *
 	 * @param string $path
+	 * @return boolean true if path was updated, false otherwise
 	 */
 	public function checkUpdate($path) {
 		$cachedEntry = $this->cache->get($path);
@@ -53,7 +54,9 @@ class Watcher {
 				$this->cleanFolder($path);
 			}
 			$this->cache->correctFolderSize($path);
+			return true;
 		}
+		return false;
 	}
 
 	/**