<commit_before><?php
/**
 * ownCloud - trash bin
 *
 * @author <NAME>
 * @copyright 2013 <NAME> <EMAIL>
 *
 * 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/>.
 *
 */

namespace OCA_Trash;

class Trashbin {
	
	const DEFAULT_RETENTION_OBLIGATION=180; // how long do we keep files in the trash bin if no other value is defined in the config file (unit: days)
	/**
	 * move file to the trash bin
	 * 
	 * @param $file_path path to the deleted file/directory relative to the files root directory
	 */
	public static function move2trash($file_path) {
		$user = \OCP\User::getUser();
		$view = new \OC_FilesystemView('/'. $user);
		if (!$view->is_dir('files_trashbin')) {
			$view->mkdir('files_trashbin');
			$view->mkdir("versions_trashbin");
		}

		$path_parts = pathinfo($file_path);

		$deleted = $path_parts['basename'];
		$location = $path_parts['dirname'];
		$timestamp = time();
		$mime = $view->getMimeType('files'.$file_path);

		if ( $view->is_dir('files'.$file_path) ) {
			$type = 'dir';
		} else {
			$type = 'file';
		}

		self::copy_recursive($file_path, 'files_trashbin/'.$deleted.'.d'.$timestamp, $view);
		
		if ( $view->file_exists('files_trashbin/'.$deleted.'.d'.$timestamp) ) {
			$query = \OC_DB::prepare("INSERT INTO *PREFIX*files_trash (id,timestamp,location,type,mime,user) VALUES (?,?,?,?,?,?)");
			$result = $query->execute(array($deleted, $timestamp, $location, $type, $mime, $user));
			if ( !$result ) { // if file couldn't be added to the database than also don't store it in the trash bin.
				$view->deleteAll('files_trashbin/'.$deleted.'.d'.$timestamp);
				\OC_Log::write('files_trashbin', 'trash bin database couldn\'t be updated', \OC_log::ERROR);
				return;
			}
	
			if ( \OCP\App::isEnabled('files_versions') ) {
				if ( $view->is_dir('files_versions'.$file_path) ) {
					$view->rename('files_versions'.$file_path, 'versions_trashbin/'. $deleted.'.d'.$timestamp);
				} else if ( $versions = \OCA_Versions\Storage::getVersions($file_path) ) {
					foreach ($versions as $v) {
						$view->rename('files_versions'.$v['path'].'.v'.$v['version'], 'versions_trashbin/'. $deleted.'.v'.$v['version'].'.d'.$timestamp);
					}
				}
			}
		} else {
			\OC_Log::write('files_trashbin', 'Couldn\'t move '.$file_path.' to the trash bin' , \OC_log::ERROR);
		}
		
		self::expire();
	}
	
	
	/**
	 * restore files from trash bin
	 * @param $file path to the deleted file
	 * @param $filename name of the file
	 * @param $timestamp time when the file was deleted
	 */
	public static function restore($file, $filename, $timestamp) {

		$user = \OCP\User::getUser();
		$view = new \OC_FilesystemView('/'.$user);
		
		if ( $timestamp ) {
			$query = \OC_DB::prepare('SELECT location,type FROM *PREFIX*files_trash WHERE user=? AND id=? AND timestamp=?');
			$result = $query->execute(array($user,$filename,$timestamp))->fetchAll();
			if ( count($result) != 1 ) {
				\OC_Log::write('files_trashbin', 'trash bin database inconsistent!', \OC_Log::ERROR);
				return false;
			}
			
			// if location no longer exists, restore file in the root directory
			$location = $result[0]['location'];
			if ( $result[0]['location'] != '/' && 
				 (!$view->is_dir('files'.$result[0]['location']) ||
				 !$view->isUpdatable('files'.$result[0]['location'])) ) {
				$location = '';
			}
		} else {
			$path_parts = pathinfo($filename);
			$result[] = array(
					'location' => $path_parts['dirname'],
					'type' => $view->is_dir('/files_trashbin/'.$file) ? 'dir' : 'files',
					);
			$location = '';
		}
		
		$source = \OC_Filesystem::normalizePath('files_trashbin/'.$file);
		$target = \OC_Filesystem::normalizePath('files/'.$location.'/'.$filename);
		
		// we need a  extension in case a file/dir with the same name already exists
		$ext = self::getUniqueExtension($location, $filename, $view);
		$mtime = $view->filemtime($source);
		if( $view->rename($source, $target.$ext) ) {
			$view->touch($target.$ext, $mtime);
			// if versioning app is enabled, copy versions from the trash bin back to the original location
			if ( \OCP\App::isEnabled('files_versions') ) {
				if ( $result[0]['type'] == 'dir' ) {
					$view->rename(\OC_Filesystem::normalizePath('versions_trashbin/'. $file), \OC_Filesystem::normalizePath('files_versions/'.$location.'/'.$filename.$ext));
				} else if ( $versions = self::getVersionsFromTrash($file, $timestamp) ) {
					foreach ($versions as $v) {
						if ($timestamp ) {
							$view->rename('versions_trashbin/'.$filename.'.v'.$v.'.d'.$timestamp, 'files_versions/'.$location.'/'.$filename.$ext.'.v'.$v);
						} else {
							$view->rename('versions_trashbin/'.$file.'.v'.$v, 'files_versions/'.$location.'/'.$filename.$ext.'.v'.$v);
						}
					}
				}
			}

			if ( $timestamp ) {
				$query = \OC_DB::prepare('DELETE FROM *PREFIX*files_trash WHERE user=? AND id=? AND timestamp=?');
				$query->execute(array($user,$filename,$timestamp));
			}

			return true;
		} else {
			\OC_Log::write('files_trashbin', 'Couldn\'t restore file from trash bin, '.$filename , \OC_log::ERROR);
		}

		return false;
	}
	
	/**
	 * delete file from trash bin permanently
	 * @param $filename path to the file
	 * @param $timestamp of deletion time
	 * @return true/false
	 */
	public static function delete($filename, $timestamp=null) {
	
		$user = \OCP\User::getUser();
		$view = new \OC_FilesystemView('/'.$user);
	
		if ( $timestamp ) {
			$query = \OC_DB::prepare('DELETE FROM *PREFIX*files_trash WHERE user=? AND id=? AND timestamp=?');
			$query->execute(array($user,$filename,$timestamp))->fetchAll();
			$file = $filename.'.d'.$timestamp;
		} else {
			$file = $filename;
		}
		
		if ( \OCP\App::isEnabled('files_versions') ) {
			if ($view->is_dir('versions_trashbin/'.$file)) {
				$view->unlink('versions_trashbin/'.$file);
			} else if ( $versions = self::getVersionsFromTrash($file, $timestamp) ) {
				foreach ($versions as $v) {
					if ($timestamp ) {
						$view->unlink('versions_trashbin/'.$filename.'.v'.$v.'.d'.$timestamp);
					} else {
						$view->unlink('versions_trashbin/'.$file.'.v'.$v);
					}
				}
			}
		}
	
		$view->unlink('/files_trashbin/'.$file);
		
		return true;<commit_msg>copy&paste bug, no fetchAll() needed here<commit_after><?php
/**
 * ownCloud - trash bin
 *
 * @author <NAME>
 * @copyright 2013 <NAME> <EMAIL>
 *
 * 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/>.
 *
 */

namespace OCA_Trash;

class Trashbin {
	
	const DEFAULT_RETENTION_OBLIGATION=180; // how long do we keep files in the trash bin if no other value is defined in the config file (unit: days)
	/**
	 * move file to the trash bin
	 * 
	 * @param $file_path path to the deleted file/directory relative to the files root directory
	 */
	public static function move2trash($file_path) {
		$user = \OCP\User::getUser();
		$view = new \OC_FilesystemView('/'. $user);
		if (!$view->is_dir('files_trashbin')) {
			$view->mkdir('files_trashbin');
			$view->mkdir("versions_trashbin");
		}

		$path_parts = pathinfo($file_path);

		$deleted = $path_parts['basename'];
		$location = $path_parts['dirname'];
		$timestamp = time();
		$mime = $view->getMimeType('files'.$file_path);

		if ( $view->is_dir('files'.$file_path) ) {
			$type = 'dir';
		} else {
			$type = 'file';
		}

		self::copy_recursive($file_path, 'files_trashbin/'.$deleted.'.d'.$timestamp, $view);
		
		if ( $view->file_exists('files_trashbin/'.$deleted.'.d'.$timestamp) ) {
			$query = \OC_DB::prepare("INSERT INTO *PREFIX*files_trash (id,timestamp,location,type,mime,user) VALUES (?,?,?,?,?,?)");
			$result = $query->execute(array($deleted, $timestamp, $location, $type, $mime, $user));
			if ( !$result ) { // if file couldn't be added to the database than also don't store it in the trash bin.
				$view->deleteAll('files_trashbin/'.$deleted.'.d'.$timestamp);
				\OC_Log::write('files_trashbin', 'trash bin database couldn\'t be updated', \OC_log::ERROR);
				return;
			}
	
			if ( \OCP\App::isEnabled('files_versions') ) {
				if ( $view->is_dir('files_versions'.$file_path) ) {
					$view->rename('files_versions'.$file_path, 'versions_trashbin/'. $deleted.'.d'.$timestamp);
				} else if ( $versions = \OCA_Versions\Storage::getVersions($file_path) ) {
					foreach ($versions as $v) {
						$view->rename('files_versions'.$v['path'].'.v'.$v['version'], 'versions_trashbin/'. $deleted.'.v'.$v['version'].'.d'.$timestamp);
					}
				}
			}
		} else {
			\OC_Log::write('files_trashbin', 'Couldn\'t move '.$file_path.' to the trash bin' , \OC_log::ERROR);
		}
		
		self::expire();
	}
	
	
	/**
	 * restore files from trash bin
	 * @param $file path to the deleted file
	 * @param $filename name of the file
	 * @param $timestamp time when the file was deleted
	 */
	public static function restore($file, $filename, $timestamp) {

		$user = \OCP\User::getUser();
		$view = new \OC_FilesystemView('/'.$user);
		
		if ( $timestamp ) {
			$query = \OC_DB::prepare('SELECT location,type FROM *PREFIX*files_trash WHERE user=? AND id=? AND timestamp=?');
			$result = $query->execute(array($user,$filename,$timestamp))->fetchAll();
			if ( count($result) != 1 ) {
				\OC_Log::write('files_trashbin', 'trash bin database inconsistent!', \OC_Log::ERROR);
				return false;
			}
			
			// if location no longer exists, restore file in the root directory
			$location = $result[0]['location'];
			if ( $result[0]['location'] != '/' && 
				 (!$view->is_dir('files'.$result[0]['location']) ||
				 !$view->isUpdatable('files'.$result[0]['location'])) ) {
				$location = '';
			}
		} else {
			$path_parts = pathinfo($filename);
			$result[] = array(
					'location' => $path_parts['dirname'],
					'type' => $view->is_dir('/files_trashbin/'.$file) ? 'dir' : 'files',
					);
			$location = '';
		}
		
		$source = \OC_Filesystem::normalizePath('files_trashbin/'.$file);
		$target = \OC_Filesystem::normalizePath('files/'.$location.'/'.$filename);
		
		// we need a  extension in case a file/dir with the same name already exists
		$ext = self::getUniqueExtension($location, $filename, $view);
		$mtime = $view->filemtime($source);
		if( $view->rename($source, $target.$ext) ) {
			$view->touch($target.$ext, $mtime);
			// if versioning app is enabled, copy versions from the trash bin back to the original location
			if ( \OCP\App::isEnabled('files_versions') ) {
				if ( $result[0]['type'] == 'dir' ) {
					$view->rename(\OC_Filesystem::normalizePath('versions_trashbin/'. $file), \OC_Filesystem::normalizePath('files_versions/'.$location.'/'.$filename.$ext));
				} else if ( $versions = self::getVersionsFromTrash($file, $timestamp) ) {
					foreach ($versions as $v) {
						if ($timestamp ) {
							$view->rename('versions_trashbin/'.$filename.'.v'.$v.'.d'.$timestamp, 'files_versions/'.$location.'/'.$filename.$ext.'.v'.$v);
						} else {
							$view->rename('versions_trashbin/'.$file.'.v'.$v, 'files_versions/'.$location.'/'.$filename.$ext.'.v'.$v);
						}
					}
				}
			}

			if ( $timestamp ) {
				$query = \OC_DB::prepare('DELETE FROM *PREFIX*files_trash WHERE user=? AND id=? AND timestamp=?');
				$query->execute(array($user,$filename,$timestamp));
			}

			return true;
		} else {
			\OC_Log::write('files_trashbin', 'Couldn\'t restore file from trash bin, '.$filename , \OC_log::ERROR);
		}

		return false;
	}
	
	/**
	 * delete file from trash bin permanently
	 * @param $filename path to the file
	 * @param $timestamp of deletion time
	 * @return true/false
	 */
	public static function delete($filename, $timestamp=null) {
	
		$user = \OCP\User::getUser();
		$view = new \OC_FilesystemView('/'.$user);
	
		if ( $timestamp ) {
			$query = \OC_DB::prepare('DELETE FROM *PREFIX*files_trash WHERE user=? AND id=? AND timestamp=?');
			$query->execute(array($user,$filename,$timestamp));
			$file = $filename.'.d'.$timestamp;
		} else {
			$file = $filename;
		}
		
		if ( \OCP\App::isEnabled('files_versions') ) {
			if ($view->is_dir('versions_trashbin/'.$file)) {
				$view->unlink('versions_trashbin/'.$file);
			} else if ( $versions = self::getVersionsFromTrash($file, $timestamp) ) {
				foreach ($versions as $v) {
					if ($timestamp ) {
						$view->unlink('versions_trashbin/'.$filename.'.v'.$v.'.d'.$timestamp);
					} else {
						$view->unlink('versions_trashbin/'.$file.'.v'.$v);
					}
				}
			}
		}
	
		$view->unlink('/files_trashbin/'.$file);
		
		return true;
{'fraction_non_alphanumeric': 0.18316318982097943, 'fraction_numerical': 0.0022192632046160675, 'mean_word_length': 3.718673647469459, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 74, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4491530', 'n_tokens_mistral': 5074, 'n_tokens_neox': 4493, 'n_words': 1048}