From dca0fda2ad84401f984410a7b9ae2526e47234bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Schie=C3=9Fle?= <schiessle@owncloud.com>
Date: Thu, 10 Jan 2013 18:04:30 +0100
Subject: [PATCH] keep track of the size of the versions directory

---
 apps/files_versions/lib/hooks.php    | 18 +++----
 apps/files_versions/lib/versions.php | 78 ++++++++++++++++++++++++----
 2 files changed, 78 insertions(+), 18 deletions(-)

diff --git a/apps/files_versions/lib/hooks.php b/apps/files_versions/lib/hooks.php
index e897a81f7a..736d9cd868 100644
--- a/apps/files_versions/lib/hooks.php
+++ b/apps/files_versions/lib/hooks.php
@@ -39,15 +39,15 @@ class Hooks {
 	 * cleanup the versions directory if the actual file gets deleted
 	 */
 	public static function remove_hook($params) {
-		$versions_fileview = \OCP\Files::getStorage('files_versions');
-		$rel_path =  $params['path'];
-		$abs_path = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath('').$rel_path.'.v';
-		if(Storage::isversioned($rel_path)) {
-			$versions = Storage::getVersions($rel_path);
-			foreach ($versions as $v) {
-				unlink($abs_path . $v['version']);
-			}
-		}
+		if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') {
+		
+			$versions = new Storage( new \OC_FilesystemView('') );
+		
+			$path = $params[\OC_Filesystem::signal_param_path];
+		
+			if($path<>'') $versions->delete( $path );
+		
+		}
 	}
 
 	/**
diff --git a/apps/files_versions/lib/versions.php b/apps/files_versions/lib/versions.php
index 58e4a2ce13..fc8adf646a 100644
--- a/apps/files_versions/lib/versions.php
+++ b/apps/files_versions/lib/versions.php
@@ -82,14 +82,39 @@ class Storage {
 			}
 
 			// store a new version of a file
-			$users_view->copy('files'.$filename, 'files_versions'.$filename.'.v'.$users_view->filemtime('files'.$filename));
-
+			$result = $users_view->copy('files'.$filename, 'files_versions'.$filename.'.v'.$users_view->filemtime('files'.$filename));
+			if (  ($versionsSize = \OCP\Config::getAppValue('files_versions', 'size')) === null ) {
+				$versionsSize = self::calculateSize($uid);
+			}
+			$versionsSize += $users_view->filesize('files'.$filename);
+			
 			// expire old revisions if necessary
-			Storage::expire($filename);
+			self::expire($filename, $versionsSize);
 		}
 	}
 
 
+	/**
+	 * Delete versions of a file
+	 */
+	public static function delete($filename) {
+		list($uid, $filename) = self::getUidAndFilename($filename);
+		$versions_fileview = new \OC_FilesystemView('/'.$uid .'/files_versions');
+		
+		$abs_path = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath('').$filename.'.v';
+		if(Storage::isversioned($filename)) {
+			$versions = self::getVersions($filename);
+			if (  ($versionsSize = \OCP\Config::getAppValue('files_versions', 'size')) === null ) {
+				$versionsSize = self::calculateSize($uid);
+			}
+			foreach ($versions as $v) {
+				unlink($abs_path . $v['version']);
+				$versionsSize -= $v['size'];
+			}
+			\OCP\Config::setAppValue('files_versions', 'size', $versionsSize);
+		}
+	}
+	
 	/**
 	 * rollback to an old version of a file.
 	 */
@@ -216,13 +241,37 @@ class Storage {
 		}
 
 	}
+
+	/**
+	 * @brief get the size of all stored versions from a given user
+	 * @param $uid id from the user
+	 * @return size of vesions
+	 */
+	private static function calculateSize($uid) {
+		if( \OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true' ) {
+			$versions_fileview = new \OC_FilesystemView('/'.$uid.'/files_versions');
+			$versionsRoot = \OCP\Config::getSystemValue('datadirectory').$versions_fileview->getAbsolutePath('');
+				
+			$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($versionsRoot), \RecursiveIteratorIterator::CHILD_FIRST);
+				
+			$size = 0;
+							
+			foreach ($iterator as $path) {
+				if ( preg_match('/^.+\.v(\d+)$/', $path, $match) ) {
+					$relpath = substr($path, strlen($versionsRoot)-1);
+					$size += $versions_fileview->filesize($relpath);
+				}
+			}
+			
+			return $size;
+		}
+	}
 	
 	/**
 	 * @brief returns all stored file versions from a given user
 	 * @param $uid id to the user
 	 * @return array with contains two arrays 'all' which contains all versions sorted by age and 'by_file' which contains all versions sorted by filename
 	 */
-	
 	private static function getAllVersions($uid) {
 		if( \OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true' ) {
 			$versions_fileview = new \OC_FilesystemView('/'.$uid.'/files_versions');
@@ -280,7 +329,7 @@ class Storage {
 	/**
 	 * @brief Erase a file's versions which exceed the set quota
 	 */
-	public static function expire($filename) {
+	public static function expire($filename, $versionsSize = null) {
 		if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') {
 			list($uid, $filename) = self::getUidAndFilename($filename);			
 			$versions_fileview = new \OC_FilesystemView('/'.$uid.'/files_versions');
@@ -293,13 +342,20 @@ class Storage {
 			if ( $quota == null ) {
 				$quota = \OC_Filesystem::free_space('/');
 			}
-
+			
+			if ( $versionsSize === null ) {
+				if (  ($versionsSize = \OCP\Config::getAppValue('files_versions', 'size')) === null ) {
+					$versionsSize = self::calculateSize($uid);
+				}
+			}
+			
 			$rootInfo = \OC_FileCache::get('', '/'. $uid . '/files');
 			$free = $quota-$rootInfo['size']; // remaining free space for user
-
 			if ( $free > 0 ) {
-				$availableSpace = 100* self::DEFAULTMAXSIZE / ($free); // how much space can be used for versions
-			} // otherwise available space negative and we need to reach at least 0 at the end of the expiration process;
+				$availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $versionsSize; // how much space can be used for versions
+			} else {
+				$availableSpace = $free-$versionsSize;
+			} 
 
 			// after every 1000s run reduce the number of all versions not only for the current file 
 			$random = rand(0, 1000);
@@ -334,6 +390,7 @@ class Storage {
 							//distance between two version to small, delete version
 							$versions_fileview->unlink($versions[$i]['path'].'.v'.$versions[$i]['version']);
 							$availableSpace += $versions[$i]['size'];
+							$versionsSize -= $versions[$i]['size'];
 						} else {
 							$nextVersion = $versions[$i]['version'] - $step;
 						}
@@ -355,10 +412,13 @@ class Storage {
 			$i = 0; 
 			while ($availableSpace < 0) {
 				$versions_fileview->unlink($all_versions[$i]['path'].'.v'.$all_versions[$i]['version']);
+				$versionsSize -= $all_versions[$i]['size'];
 				$availableSpace += $all_versions[$i]['size'];
 				$i++;
 				if ($i = $numOfVersions-2) break; // keep at least the last version
 			}
+		
+			\OCP\Config::setAppValue('files_versions', 'size', $versionsSize);
 		}
 	}
 }
-- 
GitLab