diff --git a/db_structure.xml b/db_structure.xml
index 7b6829aa30192c85f0ef43054ac6e99960b54d5e..f1f025728193e98dc3b3d0861f4c14a238272e9b 100644
--- a/db_structure.xml
+++ b/db_structure.xml
@@ -225,6 +225,14 @@
 				<length>4</length>
 			</field>
 
+			<field>
+				<name>etag</name>
+				<type>text</type>
+				<default></default>
+				<notnull>true</notnull>
+				<length>40</length>
+			</field>
+
 			<index>
 				<name>fs_storage_path_hash</name>
 				<unique>true</unique>
diff --git a/lib/connector/sabre/directory.php b/lib/connector/sabre/directory.php
index 8d4dd92a3d41cd6e0a4bb09e2c943cfcd65035b7..a72015793668c9716f8998a68506db7a9014b835 100644
--- a/lib/connector/sabre/directory.php
+++ b/lib/connector/sabre/directory.php
@@ -121,8 +121,8 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node implements Sa
 		$paths = array();
 		foreach($folder_content as $info) {
 			$paths[] = $this->path.'/'.$info['name'];
+			$properties[$this->path.'/'.$info['name']][self::GETETAG_PROPERTYNAME] = $info['etag'];
 		}
-		$properties = array_fill_keys($paths, array());
 		if(count($paths)>0) {
 			//
 			// the number of arguments within IN conditions are limited in most databases
diff --git a/lib/connector/sabre/file.php b/lib/connector/sabre/file.php
index 1770b491280ac5d54ea9cb60e0a0f73e2e7f02bd..1c18a391742aabbc87519310b6a7b57ae1a364c8 100644
--- a/lib/connector/sabre/file.php
+++ b/lib/connector/sabre/file.php
@@ -98,16 +98,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements Sabre_D
 		if (isset($properties[self::GETETAG_PROPERTYNAME])) {
 			return $properties[self::GETETAG_PROPERTYNAME];
 		}
-		return $this->getETagPropertyForPath($this->path);
-	}
-
-	/**
-	 * Creates a ETag for this path.
-	 * @param string $path Path of the file
-	 * @return string|null Returns null if the ETag can not effectively be determined
-	 */
-	static protected function createETag($path) {
-		return \OC\Files\Filesystem::hash('md5', $path);
+		return null;
 	}
 
 	/**
diff --git a/lib/connector/sabre/node.php b/lib/connector/sabre/node.php
index ad08bd434f2236870e6c86a410f5890a92334916..93d8fc477d6fabfb9ad0718e355b04686827c67c 100644
--- a/lib/connector/sabre/node.php
+++ b/lib/connector/sabre/node.php
@@ -190,6 +190,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
 			while( $row = $result->fetchRow()) {
 				$this->property_cache[$row['propertyname']] = $row['propertyvalue'];
 			}
+			$this->property_cache[self::GETETAG_PROPERTYNAME] = $this->getETagPropertyForPath($this->path);
 		}
 
 		// if the array was empty, we need to return everything
@@ -210,38 +211,11 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr
 	 * @return string|null Returns null if the ETag can not effectively be determined
 	 */
 	static public function getETagPropertyForPath($path) {
-		$tag = \OC\Files\Filesystem::getETag($path);
-		if (empty($tag)) {
-			return null;
+		$data = \OC\Files\Filesystem::getFileInfo($path);
+		if (isset($data['etag'])) {
+			return '"'.$data['etag'].'"';
 		}
-		$etag = '"'.$tag.'"';
-		$query = OC_DB::prepare( 'INSERT INTO `*PREFIX*properties` (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)' );
-		$query->execute( array( OC_User::getUser(), $path, self::GETETAG_PROPERTYNAME, $etag ));
-		return $etag;
+		return null;
 	}
 
-	/**
-	 * @brief Remove the ETag from the cache.
-	 * @param string $path Path of the file
-	 */
-	static public function removeETagPropertyForPath($path) {
-		// remove tags from this and parent paths
-		$paths = array();
-		while ($path != '/' && $path != '.' && $path != '' && $path != '\\') {
-			$paths[] = $path;
-			$path = dirname($path);
-		}
-		if (empty($paths)) {
-			return;
-		}
-		$paths[] = $path;
-		$path_placeholders = join(',', array_fill(0, count($paths), '?'));
-		$query = OC_DB::prepare( 'DELETE FROM `*PREFIX*properties`'
-			.' WHERE `userid` = ?'
-			.' AND `propertyname` = ?'
-			.' AND `propertypath` IN ('.$path_placeholders.')'
-			);
-		$vals = array( OC_User::getUser(), self::GETETAG_PROPERTYNAME );
-		$query->execute(array_merge( $vals, $paths ));
-	}
 }
diff --git a/lib/files/cache/cache.php b/lib/files/cache/cache.php
index 0001c2752da1b848dbd1b3c7711529d8b45845a8..5c306c2ed161f144c68f5fd0e374be743ab519bf 100644
--- a/lib/files/cache/cache.php
+++ b/lib/files/cache/cache.php
@@ -114,7 +114,7 @@ class Cache {
 			$params = array($file);
 		}
 		$query = \OC_DB::prepare(
-			'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`
+			'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`
 			 FROM `*PREFIX*filecache` ' . $where);
 		$result = $query->execute($params);
 		$data = $result->fetchRow();
@@ -147,7 +147,7 @@ class Cache {
 		$fileId = $this->getId($folder);
 		if ($fileId > -1) {
 			$query = \OC_DB::prepare(
-				'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`
+				'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`
 			 	 FROM `*PREFIX*filecache` WHERE parent = ? ORDER BY `name` ASC');
 			$result = $query->execute(array($fileId));
 			$files = $result->fetchAll();
@@ -225,8 +225,7 @@ class Cache {
 	 * @return array
 	 */
 	function buildParts(array $data) {
-		$fields = array('path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'encrypted');
-
+		$fields = array('path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'encrypted', 'etag');
 		$params = array();
 		$queryParts = array();
 		foreach ($data as $name => $value) {
@@ -379,7 +378,7 @@ class Cache {
 	 */
 	public function search($pattern) {
 		$query = \OC_DB::prepare('
-			SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`
+			SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`
 			FROM `*PREFIX*filecache` WHERE `name` LIKE ? AND `storage` = ?'
 		);
 		$result = $query->execute(array($pattern, $this->numericId));
@@ -405,7 +404,7 @@ class Cache {
 			$where = '`mimepart` = ?';
 		}
 		$query = \OC_DB::prepare('
-			SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`
+			SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`
 			FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?'
 		);
 		$mimetype = $this->getMimetypeId($mimetype);
diff --git a/lib/files/cache/scanner.php b/lib/files/cache/scanner.php
index 526d4a2aab5799027f13b4c731f7ca7f524c9bee..b62a093cec7bbaaf61659037ab611d882f2bdff4 100644
--- a/lib/files/cache/scanner.php
+++ b/lib/files/cache/scanner.php
@@ -50,6 +50,7 @@ class Scanner {
 		} else {
 			$data['size'] = $this->storage->filesize($path);
 		}
+		$data['etag'] = $this->storage->getETag($path);
 		return $data;
 	}
 
diff --git a/lib/files/cache/updater.php b/lib/files/cache/updater.php
index c14adba3e5578869c9565b67b760f037251bd78a..8b0d38350332881a48ccb3e1b176926655b65245 100644
--- a/lib/files/cache/updater.php
+++ b/lib/files/cache/updater.php
@@ -35,6 +35,7 @@ class Updater {
 			$scanner = $storage->getScanner($internalPath);
 			$scanner->scan($internalPath, Scanner::SCAN_SHALLOW);
 			$cache->correctFolderSize($internalPath);
+			self::eTagUpdate($path);
 		}
 	}
 
@@ -48,6 +49,29 @@ class Updater {
 			$cache = $storage->getCache($internalPath);
 			$cache->remove($internalPath);
 			$cache->correctFolderSize($internalPath);
+			self::eTagUpdate($path);
+		}
+	}
+
+	static public function eTagUpdate($path) {
+		if ($path !== '' && $path !== '/') {
+			$parent = dirname($path);
+			if ($parent === '.') {
+				$parent = '';
+			}
+			/**
+			* @var \OC\Files\Storage\Storage $storage
+			* @var string $internalPath
+			*/
+			list($storage, $internalPath) = self::resolvePath($parent);
+			if ($storage) {
+				$cache = $storage->getCache();
+				$id = $cache->getId($internalPath);
+				if ($id !== -1) {
+					$cache->update($id, array('etag' => $storage->getETag($internalPath)));
+					self::eTagUpdate($parent);
+				}
+			}
 		}
 	}
 
diff --git a/lib/files/filesystem.php b/lib/files/filesystem.php
index b3ba62c3a493597376037fe61fd4aa0056492cea..28e8b046896e18a4620e2b90ca1870c0a506488d 100644
--- a/lib/files/filesystem.php
+++ b/lib/files/filesystem.php
@@ -585,23 +585,6 @@ class Filesystem {
 		return self::$defaultInstance->hasUpdated($path, $time);
 	}
 
-	static public function removeETagHook($params, $root = false) {
-		if (isset($params['path'])) {
-			$path = $params['path'];
-		} else {
-			$path = $params['oldpath'];
-		}
-
-		if ($root) { // reduce path to the required part of it (no 'username/files')
-			$fakeRootView = new View($root);
-			$count = 1;
-			$path = str_replace(\OC_App::getStorage("files")->getAbsolutePath(''), "", $fakeRootView->getAbsolutePath($path), $count);
-		}
-
-		$path = self::normalizePath($path);
-		\OC_Connector_Sabre_Node::removeETagPropertyForPath($path);
-	}
-
 	/**
 	 * normalize a path
 	 *
@@ -685,10 +668,6 @@ class Filesystem {
 	}
 }
 
-\OC_Hook::connect('OC_Filesystem', 'post_write', 'OC_Filesystem', 'removeETagHook');
-\OC_Hook::connect('OC_Filesystem', 'post_delete', 'OC_Filesystem', 'removeETagHook');
-\OC_Hook::connect('OC_Filesystem', 'post_rename', 'OC_Filesystem', 'removeETagHook');
-
 \OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Updater', 'writeHook');
 \OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Updater', 'deleteHook');
 \OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook');
diff --git a/lib/files/storage/common.php b/lib/files/storage/common.php
index e859d447f396eb9d1b82f01014b526dd55b3da3a..591803f0440988895b1aed1daf1e1475396d70bd 100644
--- a/lib/files/storage/common.php
+++ b/lib/files/storage/common.php
@@ -274,7 +274,7 @@ abstract class Common implements \OC\Files\Storage\Storage {
 			$hash = call_user_func($ETagFunction, $path);
 			return $hash;
 		}else{
-			return uniqid('', true);
+			return uniqid();
 		}
 	}
 }
diff --git a/lib/files/view.php b/lib/files/view.php
index fa031b7478d627872322aa73cded21f0bf9a609f..06027910123985c455d0a33808f81c095ffab8e2 100644
--- a/lib/files/view.php
+++ b/lib/files/view.php
@@ -462,8 +462,6 @@ class View {
 						Filesystem::signal_post_write,
 						array(Filesystem::signal_param_path => $path2)
 					);
-				} else { // no real copy, file comes from somewhere else, e.g. version rollback -> just update the file cache and the webdav properties without all the other post_write actions
-					Filesystem::removeETagHook(array("path" => $path2), $this->fakeRoot);
 				}
 				return $result;
 			} else {
diff --git a/lib/filesystem.php b/lib/filesystem.php
index 20b5ab279097a909e0f28d309baeb84507017816..57cca9023031fcb3171b98075d852e9a4b797b6f 100644
--- a/lib/filesystem.php
+++ b/lib/filesystem.php
@@ -398,13 +398,6 @@ class OC_Filesystem {
 		return \OC\Files\Filesystem::hasUpdated($path, $time);
 	}
 
-	/**
-	 * @deprecated OC_Filesystem is replaced by \OC\Files\Filesystem
-	 */
-	static public function removeETagHook($params, $root = false) {
-		\OC\Files\Filesystem::removeETagHook($params, $root);
-	}
-
 	/**
 	 * normalize a path
 	 *
diff --git a/lib/util.php b/lib/util.php
index e814a3a32df45d03599dfc1edc69e9b677808b5a..faae962859a70f7708ac8e2220501862dbba9f75 100755
--- a/lib/util.php
+++ b/lib/util.php
@@ -74,7 +74,7 @@ class OC_Util {
 	 */
 	public static function getVersion() {
 		// hint: We only can count up. So the internal version number of ownCloud 4.5 will be 4.90.0. This is not visible to the user
-		return array(4,91,06);
+		return array(4,91,07);
 	}
 
 	/**
diff --git a/tests/lib/files/cache/updater.php b/tests/lib/files/cache/updater.php
index d19966c1910563a31bce75aa7e7698331f048a1e..cad3d9d46fc398fd2c70ebaa89bfa5fb2b214e72 100644
--- a/tests/lib/files/cache/updater.php
+++ b/tests/lib/files/cache/updater.php
@@ -70,14 +70,18 @@ class Updater extends \PHPUnit_Framework_TestCase {
 	public function testWrite() {
 		$textSize = strlen("dummy file data\n");
 		$imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo.png');
-		$cachedData = $this->cache->get('');
-		$this->assertEquals(3 * $textSize + $imageSize, $cachedData['size']);
+		$rootCachedData = $this->cache->get('');
+		$this->assertEquals(3 * $textSize + $imageSize, $rootCachedData['size']);
 
+		$fooCachedData = $this->cache->get('foo.txt');
 		Filesystem::file_put_contents('foo.txt', 'asd');
 		$cachedData = $this->cache->get('foo.txt');
 		$this->assertEquals(3, $cachedData['size']);
+		$this->assertNotEquals($fooCachedData['etag'], $cachedData['etag']);
 		$cachedData = $this->cache->get('');
 		$this->assertEquals(2 * $textSize + $imageSize + 3, $cachedData['size']);
+		$this->assertNotEquals($rootCachedData['etag'], $cachedData['etag']);
+		$rootCachedData = $cachedData;
 
 		$this->assertFalse($this->cache->inCache('bar.txt'));
 		Filesystem::file_put_contents('bar.txt', 'asd');
@@ -86,38 +90,50 @@ class Updater extends \PHPUnit_Framework_TestCase {
 		$this->assertEquals(3, $cachedData['size']);
 		$cachedData = $this->cache->get('');
 		$this->assertEquals(2 * $textSize + $imageSize + 2 * 3, $cachedData['size']);
+		$this->assertNotEquals($rootCachedData['etag'], $cachedData['etag']);
 	}
 
 	public function testDelete() {
 		$textSize = strlen("dummy file data\n");
 		$imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo.png');
-		$cachedData = $this->cache->get('');
-		$this->assertEquals(3 * $textSize + $imageSize, $cachedData['size']);
+		$rootCachedData = $this->cache->get('');
+		$this->assertEquals(3 * $textSize + $imageSize, $rootCachedData['size']);
 
 		$this->assertTrue($this->cache->inCache('foo.txt'));
 		Filesystem::unlink('foo.txt', 'asd');
 		$this->assertFalse($this->cache->inCache('foo.txt'));
 		$cachedData = $this->cache->get('');
 		$this->assertEquals(2 * $textSize + $imageSize, $cachedData['size']);
+		$this->assertNotEquals($rootCachedData['etag'], $cachedData['etag']);
+		$rootCachedData = $cachedData;
 
 		Filesystem::mkdir('bar_folder');
 		$this->assertTrue($this->cache->inCache('bar_folder'));
+		$cachedData = $this->cache->get('');
+		$this->assertNotEquals($rootCachedData['etag'], $cachedData['etag']);
+		$rootCachedData = $cachedData;
 		Filesystem::rmdir('bar_folder');
 		$this->assertFalse($this->cache->inCache('bar_folder'));
+		$cachedData = $this->cache->get('');
+		$this->assertNotEquals($rootCachedData['etag'], $cachedData['etag']);
 	}
 
 	public function testRename() {
 		$textSize = strlen("dummy file data\n");
 		$imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo.png');
-		$cachedData = $this->cache->get('');
-		$this->assertEquals(3 * $textSize + $imageSize, $cachedData['size']);
+		$rootCachedData = $this->cache->get('');
+		$this->assertEquals(3 * $textSize + $imageSize, $rootCachedData['size']);
 
 		$this->assertTrue($this->cache->inCache('foo.txt'));
+		$fooCachedData = $this->cache->get('foo.txt');
 		$this->assertFalse($this->cache->inCache('bar.txt'));
 		Filesystem::rename('foo.txt', 'bar.txt');
 		$this->assertFalse($this->cache->inCache('foo.txt'));
 		$this->assertTrue($this->cache->inCache('bar.txt'));
+		$cachedData = $this->cache->get('foo.txt');
+		$this->assertNotEquals($fooCachedData['etag'], $cachedData['etag']);
 		$cachedData = $this->cache->get('');
 		$this->assertEquals(3 * $textSize + $imageSize, $cachedData['size']);
+		$this->assertNotEquals($rootCachedData['etag'], $cachedData['etag']);
 	}
 }