2013-01-18 16:11:29 +04:00
< ? php
2013-01-31 21:04:00 +04:00
/**
2015-03-26 13:44:34 +03:00
* @ author Bart Visscher < bartv @ thisnet . nl >
* @ author Bastien Ho < bastienho @ urbancube . fr >
* @ author Björn Schießle < schiessle @ owncloud . com >
* @ author Florin Peter < github @ florin - peter . de >
* @ author Georg Ehrke < georg @ owncloud . com >
* @ author Jörn Friedrich Dreyer < jfd @ butonic . de >
* @ author Lukas Reschke < lukas @ owncloud . com >
2015-10-05 21:54:56 +03:00
* @ author Martin Mattel < martin . mattel @ diemattels . at >
2015-03-26 13:44:34 +03:00
* @ author Morris Jobke < hey @ morrisjobke . de >
* @ author Qingping Hou < dave2008713 @ gmail . com >
* @ author Robin Appelman < icewind @ owncloud . com >
* @ author Robin McCorkell < rmccorkell @ karoshi . org . uk >
2015-10-26 15:54:55 +03:00
* @ author Roeland Jago Douma < rullzer @ owncloud . com >
2015-03-26 13:44:34 +03:00
* @ author Sjors van der Pluijm < sjors @ desjors . nl >
* @ author Thomas Müller < thomas . mueller @ tmit . eu >
* @ author Victor Dubiniuk < dubiniuk @ owncloud . com >
* @ author Vincent Petry < pvince81 @ owncloud . com >
2013-01-31 21:04:00 +04:00
*
2015-03-26 13:44:34 +03:00
* @ copyright Copyright ( c ) 2015 , ownCloud , Inc .
* @ license AGPL - 3.0
2013-01-31 21:04:00 +04:00
*
2015-03-26 13:44:34 +03:00
* This code is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License , version 3 ,
* as published by the Free Software Foundation .
2013-01-31 21:04:00 +04:00
*
2015-03-26 13:44:34 +03:00
* This program is distributed in the hope that it will be useful ,
2013-01-31 21:04:00 +04:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2015-03-26 13:44:34 +03:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
2013-01-31 21:04:00 +04:00
*
2015-03-26 13:44:34 +03:00
* You should have received a copy of the GNU Affero General Public License , version 3 ,
* along with this program . If not , see < http :// www . gnu . org / licenses />
2013-01-31 21:04:00 +04:00
*
*/
2015-02-26 13:37:37 +03:00
2013-02-08 03:11:54 +04:00
namespace OCA\Files_Trashbin ;
2013-01-18 16:11:29 +04:00
2014-08-08 17:00:47 +04:00
use OC\Files\Filesystem ;
2015-05-19 15:22:09 +03:00
use OC\Files\View ;
2015-07-30 22:31:18 +03:00
use OCA\Files_Trashbin\AppInfo\Application ;
2015-03-02 17:25:50 +03:00
use OCA\Files_Trashbin\Command\Expire ;
2015-06-15 15:10:10 +03:00
use OCP\Files\NotFoundException ;
2014-08-08 17:00:47 +04:00
2013-01-18 16:11:29 +04:00
class Trashbin {
2013-02-15 01:46:28 +04:00
// unit: percentage; 50% of available disk space/quota
2013-06-14 17:14:23 +04:00
const DEFAULTMAXSIZE = 50 ;
2013-02-22 20:21:57 +04:00
2015-03-02 14:48:08 +03:00
/**
* Whether versions have already be rescanned during this PHP request
*
* @ var bool
*/
private static $scannedVersions = false ;
2015-06-09 18:01:31 +03:00
/**
* Ensure we dont need to scan the file during the move to trash
2015-06-15 16:43:19 +03:00
* by triggering the scan in the pre - hook
2015-06-09 18:01:31 +03:00
*
* @ param array $params
*/
public static function ensureFileScannedHook ( $params ) {
self :: getUidAndFilename ( $params [ 'path' ]);
}
2015-06-15 15:10:10 +03:00
/**
* @ param string $filename
* @ return array
* @ throws \OC\User\NoUserException
*/
2013-05-03 15:00:04 +04:00
public static function getUidAndFilename ( $filename ) {
$uid = \OC\Files\Filesystem :: getOwner ( $filename );
\OC\Files\Filesystem :: initMountPoints ( $uid );
2013-06-14 17:14:23 +04:00
if ( $uid != \OCP\User :: getUser ()) {
2013-05-03 15:00:04 +04:00
$info = \OC\Files\Filesystem :: getFileInfo ( $filename );
2013-06-14 17:14:23 +04:00
$ownerView = new \OC\Files\View ( '/' . $uid . '/files' );
2015-06-15 15:10:10 +03:00
try {
$filename = $ownerView -> getPath ( $info [ 'fileid' ]);
} catch ( NotFoundException $e ) {
$filename = null ;
}
2013-05-03 15:00:04 +04:00
}
2015-06-15 15:10:10 +03:00
return [ $uid , $filename ];
2013-05-03 15:00:04 +04:00
}
2014-08-27 13:28:31 +04:00
/**
* get original location of files for user
*
* @ param string $user
* @ return array ( filename => array ( timestamp => original location ))
*/
public static function getLocations ( $user ) {
$query = \OC_DB :: prepare ( 'SELECT `id`, `timestamp`, `location`'
. ' FROM `*PREFIX*files_trash` WHERE `user`=?' );
$result = $query -> execute ( array ( $user ));
$array = array ();
while ( $row = $result -> fetchRow ()) {
if ( isset ( $array [ $row [ 'id' ]])) {
$array [ $row [ 'id' ]][ $row [ 'timestamp' ]] = $row [ 'location' ];
} else {
$array [ $row [ 'id' ]] = array ( $row [ 'timestamp' ] => $row [ 'location' ]);
}
}
return $array ;
}
/**
* get original location of file
*
* @ param string $user
* @ param string $filename
* @ param string $timestamp
* @ return string original location
*/
public static function getLocation ( $user , $filename , $timestamp ) {
$query = \OC_DB :: prepare ( 'SELECT `location` FROM `*PREFIX*files_trash`'
. ' WHERE `user`=? AND `id`=? AND `timestamp`=?' );
$result = $query -> execute ( array ( $user , $filename , $timestamp )) -> fetchAll ();
if ( isset ( $result [ 0 ][ 'location' ])) {
return $result [ 0 ][ 'location' ];
} else {
return false ;
}
}
2013-11-25 15:51:32 +04:00
private static function setUpTrash ( $user ) {
2013-06-14 17:14:23 +04:00
$view = new \OC\Files\View ( '/' . $user );
2013-01-31 21:04:00 +04:00
if ( ! $view -> is_dir ( 'files_trashbin' )) {
$view -> mkdir ( 'files_trashbin' );
2013-05-10 13:12:42 +04:00
}
if ( ! $view -> is_dir ( 'files_trashbin/files' )) {
2013-04-20 01:21:06 +04:00
$view -> mkdir ( 'files_trashbin/files' );
2013-05-10 13:12:42 +04:00
}
if ( ! $view -> is_dir ( 'files_trashbin/versions' )) {
2013-04-20 01:21:06 +04:00
$view -> mkdir ( 'files_trashbin/versions' );
2013-05-10 13:12:42 +04:00
}
2014-11-10 14:40:24 +03:00
if ( ! $view -> is_dir ( 'files_trashbin/keys' )) {
$view -> mkdir ( 'files_trashbin/keys' );
2013-05-10 13:12:42 +04:00
}
2013-11-25 15:51:32 +04:00
}
2014-02-06 19:30:58 +04:00
/**
2014-05-19 19:50:53 +04:00
* copy file to owners trash
2015-05-19 15:22:09 +03:00
*
2014-02-25 23:46:41 +04:00
* @ param string $sourcePath
2014-02-06 19:30:58 +04:00
* @ param string $owner
2015-09-30 15:35:11 +03:00
* @ param $targetPath
* @ param $user
2014-02-06 19:30:58 +04:00
* @ param integer $timestamp
*/
2015-09-30 15:35:11 +03:00
private static function copyFilesToUser ( $sourcePath , $owner , $targetPath , $user , $timestamp ) {
2013-11-25 15:51:32 +04:00
self :: setUpTrash ( $owner );
2015-09-30 15:35:11 +03:00
$targetFilename = basename ( $targetPath );
$targetLocation = dirname ( $targetPath );
2013-11-25 15:51:32 +04:00
$sourceFilename = basename ( $sourcePath );
$view = new \OC\Files\View ( '/' );
2015-09-30 15:35:11 +03:00
$target = $user . '/files_trashbin/files/' . $targetFilename . '.d' . $timestamp ;
$source = $owner . '/files_trashbin/files/' . $sourceFilename . '.d' . $timestamp ;
2013-11-25 15:51:32 +04:00
self :: copy_recursive ( $source , $target , $view );
if ( $view -> file_exists ( $target )) {
2014-02-25 23:46:41 +04:00
$query = \OC_DB :: prepare ( " INSERT INTO `*PREFIX*files_trash` (`id`,`timestamp`,`location`,`user`) VALUES (?,?,?,?) " );
2015-09-30 15:35:11 +03:00
$result = $query -> execute ( array ( $targetFilename , $timestamp , $targetLocation , $user ));
2014-02-25 23:46:41 +04:00
if ( ! $result ) {
2015-07-03 15:06:40 +03:00
\OCP\Util :: writeLog ( 'files_trashbin' , 'trash bin database couldn\'t be updated for the files owner' , \OCP\Util :: ERROR );
2013-11-25 15:51:32 +04:00
}
}
}
/**
* move file to the trash bin
*
2014-05-13 15:29:25 +04:00
* @ param string $file_path path to the deleted file / directory relative to the files root directory
2015-09-30 15:35:11 +03:00
* @ return bool
2013-11-25 15:51:32 +04:00
*/
public static function move2trash ( $file_path ) {
2014-08-08 17:00:47 +04:00
// get the user for which the filesystem is setup
$root = Filesystem :: getRoot ();
list (, $user ) = explode ( '/' , $root );
2013-11-25 15:51:32 +04:00
$size = 0 ;
list ( $owner , $ownerPath ) = self :: getUidAndFilename ( $file_path );
2014-09-19 21:01:02 +04:00
2015-09-30 15:35:11 +03:00
$ownerView = new \OC\Files\View ( '/' . $owner );
2014-09-19 21:01:02 +04:00
// file has been deleted in between
2015-09-30 15:35:11 +03:00
if ( ! $ownerView -> file_exists ( '/files/' . $ownerPath )) {
2015-01-14 23:06:26 +03:00
return true ;
2014-09-19 21:01:02 +04:00
}
2013-11-25 15:51:32 +04:00
self :: setUpTrash ( $user );
2015-06-02 17:44:25 +03:00
if ( $owner !== $user ) {
// also setup for owner
self :: setUpTrash ( $owner );
}
2013-11-25 15:51:32 +04:00
2015-09-30 15:35:11 +03:00
$path_parts = pathinfo ( $ownerPath );
2013-01-31 21:04:00 +04:00
2013-04-19 12:31:42 +04:00
$filename = $path_parts [ 'basename' ];
2013-01-31 21:04:00 +04:00
$location = $path_parts [ 'dirname' ];
$timestamp = time ();
2013-06-14 17:14:23 +04:00
2013-11-25 15:51:32 +04:00
$userTrashSize = self :: getTrashbinSize ( $user );
2013-05-03 17:18:05 +04:00
// disable proxy to prevent recursive calls
2013-11-25 15:51:32 +04:00
$trashPath = '/files_trashbin/files/' . $filename . '.d' . $timestamp ;
2015-05-13 15:09:07 +03:00
/** @var \OC\Files\Storage\Storage $trashStorage */
2015-09-30 15:35:11 +03:00
list ( $trashStorage , $trashInternalPath ) = $ownerView -> resolvePath ( $trashPath );
2015-05-13 15:09:07 +03:00
/** @var \OC\Files\Storage\Storage $sourceStorage */
2015-09-30 15:35:11 +03:00
list ( $sourceStorage , $sourceInternalPath ) = $ownerView -> resolvePath ( '/files/' . $ownerPath );
2014-07-14 19:03:36 +04:00
try {
2015-05-13 15:09:07 +03:00
$sizeOfAddedFiles = $sourceStorage -> filesize ( $sourceInternalPath );
if ( $trashStorage -> file_exists ( $trashInternalPath )) {
$trashStorage -> unlink ( $trashInternalPath );
2015-01-28 17:16:55 +03:00
}
2015-05-13 15:09:07 +03:00
$trashStorage -> moveFromStorage ( $sourceStorage , $sourceInternalPath , $trashInternalPath );
2014-07-14 19:03:36 +04:00
} catch ( \OCA\Files_Trashbin\Exceptions\CopyRecursiveException $e ) {
$sizeOfAddedFiles = false ;
2015-05-13 15:09:07 +03:00
if ( $trashStorage -> file_exists ( $trashInternalPath )) {
$trashStorage -> unlink ( $trashInternalPath );
2014-07-14 19:03:36 +04:00
}
2015-07-03 15:06:40 +03:00
\OCP\Util :: writeLog ( 'files_trashbin' , 'Couldn\'t move ' . $file_path . ' to the trash bin' , \OCP\Util :: ERROR );
2014-07-14 19:03:36 +04:00
}
2013-04-22 05:37:55 +04:00
2015-05-13 15:09:07 +03:00
if ( $sourceStorage -> file_exists ( $sourceInternalPath )) { // failed to delete the original file, abort
$sourceStorage -> unlink ( $sourceInternalPath );
2015-01-28 17:35:49 +03:00
return false ;
}
2015-11-25 15:53:31 +03:00
$trashStorage -> getUpdater () -> renameFromStorage ( $sourceStorage , $sourceInternalPath , $trashInternalPath );
2015-05-13 15:54:43 +03:00
2014-07-14 19:03:36 +04:00
if ( $sizeOfAddedFiles !== false ) {
2013-11-25 15:51:32 +04:00
$size = $sizeOfAddedFiles ;
2014-02-25 23:46:41 +04:00
$query = \OC_DB :: prepare ( " INSERT INTO `*PREFIX*files_trash` (`id`,`timestamp`,`location`,`user`) VALUES (?,?,?,?) " );
2015-09-30 15:35:11 +03:00
$result = $query -> execute ( array ( $filename , $timestamp , $location , $owner ));
2014-02-25 23:46:41 +04:00
if ( ! $result ) {
2015-07-03 15:06:40 +03:00
\OCP\Util :: writeLog ( 'files_trashbin' , 'trash bin database couldn\'t be updated' , \OCP\Util :: ERROR );
2013-01-31 21:04:00 +04:00
}
2013-06-14 17:14:23 +04:00
\OCP\Util :: emitHook ( '\OCA\Files_Trashbin\Trashbin' , 'post_moveToTrash' , array ( 'filePath' => \OC\Files\Filesystem :: normalizePath ( $file_path ),
'trashPath' => \OC\Files\Filesystem :: normalizePath ( $filename . '.d' . $timestamp )));
2013-04-19 12:31:42 +04:00
2015-09-30 15:35:11 +03:00
$size += self :: retainVersions ( $filename , $owner , $ownerPath , $timestamp );
2013-11-25 15:51:32 +04:00
// if owner !== user we need to also add a copy to the owners trash
if ( $user !== $owner ) {
2015-09-30 15:35:11 +03:00
self :: copyFilesToUser ( $ownerPath , $owner , $file_path , $user , $timestamp );
2013-11-25 15:51:32 +04:00
}
2013-01-18 16:11:29 +04:00
}
2013-04-16 15:51:53 +04:00
2013-11-25 15:51:32 +04:00
$userTrashSize += $size ;
2015-03-02 17:25:50 +03:00
self :: scheduleExpire ( $userTrashSize , $user );
2013-02-25 14:14:06 +04:00
2013-11-25 15:51:32 +04:00
// if owner !== user we also need to update the owners trash size
2014-03-17 19:35:08 +04:00
if ( $owner !== $user ) {
2013-11-25 15:51:32 +04:00
$ownerTrashSize = self :: getTrashbinSize ( $owner );
$ownerTrashSize += $size ;
2015-03-02 17:25:50 +03:00
self :: scheduleExpire ( $ownerTrashSize , $owner );
2013-11-25 15:51:32 +04:00
}
2015-01-14 23:06:26 +03:00
return ( $sizeOfAddedFiles === false ) ? false : true ;
2013-01-18 16:11:29 +04:00
}
2013-02-22 20:21:57 +04:00
2013-06-14 17:14:23 +04:00
/**
* Move file versions to trash so that they can be restored later
*
2014-05-13 15:29:25 +04:00
* @ param string $filename of deleted file
2015-06-02 17:44:25 +03:00
* @ param string $owner owner user id
* @ param string $ownerPath path relative to the owner ' s home storage
2014-02-06 19:30:58 +04:00
* @ param integer $timestamp when the file was deleted
2013-06-14 17:14:23 +04:00
*
2014-05-13 15:29:25 +04:00
* @ return int size of stored versions
2013-06-14 17:14:23 +04:00
*/
2015-09-30 15:35:11 +03:00
private static function retainVersions ( $filename , $owner , $ownerPath , $timestamp ) {
2013-04-19 12:31:42 +04:00
$size = 0 ;
2015-06-02 17:44:25 +03:00
if ( \OCP\App :: isEnabled ( 'files_versions' ) && ! empty ( $ownerPath )) {
2013-04-28 01:51:26 +04:00
2013-06-14 17:14:23 +04:00
$user = \OCP\User :: getUser ();
2013-05-03 19:14:43 +04:00
$rootView = new \OC\Files\View ( '/' );
2013-06-14 17:14:23 +04:00
if ( $rootView -> is_dir ( $owner . '/files_versions/' . $ownerPath )) {
$size += self :: calculateSize ( new \OC\Files\View ( '/' . $owner . '/files_versions/' . $ownerPath ));
2013-11-25 15:51:32 +04:00
if ( $owner !== $user ) {
2014-01-15 17:27:23 +04:00
self :: copy_recursive ( $owner . '/files_versions/' . $ownerPath , $owner . '/files_trashbin/versions/' . basename ( $ownerPath ) . '.d' . $timestamp , $rootView );
2013-11-25 15:51:32 +04:00
}
2015-05-19 15:22:09 +03:00
self :: move ( $rootView , $owner . '/files_versions/' . $ownerPath , $user . '/files_trashbin/versions/' . $filename . '.d' . $timestamp );
2013-05-03 19:14:43 +04:00
} else if ( $versions = \OCA\Files_Versions\Storage :: getVersions ( $owner , $ownerPath )) {
2015-05-13 15:09:07 +03:00
2013-06-14 17:14:23 +04:00
foreach ( $versions as $v ) {
2015-05-19 15:22:09 +03:00
$size += $rootView -> filesize ( $owner . '/files_versions/' . $v [ 'path' ] . '.v' . $v [ 'version' ]);
2013-11-25 15:51:32 +04:00
if ( $owner !== $user ) {
2015-05-19 15:22:09 +03:00
self :: copy ( $rootView , $owner . '/files_versions' . $v [ 'path' ] . '.v' . $v [ 'version' ], $owner . '/files_trashbin/versions/' . $v [ 'name' ] . '.v' . $v [ 'version' ] . '.d' . $timestamp );
2013-11-25 15:51:32 +04:00
}
2015-05-19 15:22:09 +03:00
self :: move ( $rootView , $owner . '/files_versions' . $v [ 'path' ] . '.v' . $v [ 'version' ], $user . '/files_trashbin/versions/' . $filename . '.v' . $v [ 'version' ] . '.d' . $timestamp );
2013-04-19 12:31:42 +04:00
}
}
}
return $size ;
}
2015-05-19 15:22:09 +03:00
/**
* Move a file or folder on storage level
*
* @ param View $view
* @ param string $source
* @ param string $target
* @ return bool
*/
private static function move ( View $view , $source , $target ) {
/** @var \OC\Files\Storage\Storage $sourceStorage */
list ( $sourceStorage , $sourceInternalPath ) = $view -> resolvePath ( $source );
/** @var \OC\Files\Storage\Storage $targetStorage */
list ( $targetStorage , $targetInternalPath ) = $view -> resolvePath ( $target );
/** @var \OC\Files\Storage\Storage $ownerTrashStorage */
$result = $targetStorage -> moveFromStorage ( $sourceStorage , $sourceInternalPath , $targetInternalPath );
if ( $result ) {
2015-11-25 15:53:31 +03:00
$targetStorage -> getUpdater () -> renameFromStorage ( $sourceStorage , $sourceInternalPath , $targetInternalPath );
2015-05-19 15:22:09 +03:00
}
return $result ;
}
/**
* Copy a file or folder on storage level
*
* @ param View $view
* @ param string $source
* @ param string $target
* @ return bool
*/
private static function copy ( View $view , $source , $target ) {
/** @var \OC\Files\Storage\Storage $sourceStorage */
list ( $sourceStorage , $sourceInternalPath ) = $view -> resolvePath ( $source );
/** @var \OC\Files\Storage\Storage $targetStorage */
list ( $targetStorage , $targetInternalPath ) = $view -> resolvePath ( $target );
/** @var \OC\Files\Storage\Storage $ownerTrashStorage */
$result = $targetStorage -> copyFromStorage ( $sourceStorage , $sourceInternalPath , $targetInternalPath );
if ( $result ) {
2015-11-25 15:53:31 +03:00
$targetStorage -> getUpdater () -> update ( $targetInternalPath );
2015-05-19 15:22:09 +03:00
}
return $result ;
}
2013-01-18 16:11:29 +04:00
/**
2015-05-12 14:14:57 +03:00
* Restore a file or folder from trash bin
2014-03-17 19:35:08 +04:00
*
2015-05-12 14:14:57 +03:00
* @ param string $file path to the deleted file / folder relative to " files_trashbin/files/ " ,
* including the timestamp suffix " .d12345678 "
* @ param string $filename name of the file / folder
* @ param int $timestamp time when the file / folder was deleted
2013-06-14 17:14:23 +04:00
*
2015-05-12 14:14:57 +03:00
* @ return bool true on success , false otherwise
2013-06-14 17:14:23 +04:00
*/
2013-01-22 15:00:04 +04:00
public static function restore ( $file , $filename , $timestamp ) {
2013-06-14 17:14:23 +04:00
$user = \OCP\User :: getUser ();
$view = new \OC\Files\View ( '/' . $user );
2014-02-25 23:46:41 +04:00
$location = '' ;
2013-06-14 17:14:23 +04:00
if ( $timestamp ) {
2014-08-27 13:28:31 +04:00
$location = self :: getLocation ( $user , $filename , $timestamp );
if ( $location === false ) {
2015-04-09 13:36:10 +03:00
\OCP\Util :: writeLog ( 'files_trashbin' , 'trash bin database inconsistent!' , \OCP\Util :: ERROR );
2014-02-25 23:46:41 +04:00
} else {
// if location no longer exists, restore file in the root directory
if ( $location !== '/' &&
2015-01-14 23:06:26 +03:00
( ! $view -> is_dir ( 'files/' . $location ) ||
2015-05-19 15:22:09 +03:00
! $view -> isCreatable ( 'files/' . $location ))
2014-03-17 19:35:08 +04:00
) {
2014-02-25 23:46:41 +04:00
$location = '' ;
}
2013-01-22 15:00:04 +04:00
}
2013-01-18 16:11:29 +04:00
}
2013-06-14 17:14:23 +04:00
2013-01-18 17:09:22 +04:00
// we need a extension in case a file/dir with the same name already exists
2013-07-25 18:20:06 +04:00
$uniqueFilename = self :: getUniqueFilename ( $location , $filename , $view );
$source = \OC\Files\Filesystem :: normalizePath ( 'files_trashbin/files/' . $file );
$target = \OC\Files\Filesystem :: normalizePath ( 'files/' . $location . '/' . $uniqueFilename );
2015-05-12 14:14:57 +03:00
if ( ! $view -> file_exists ( $source )) {
return false ;
}
2013-01-31 13:50:02 +04:00
$mtime = $view -> filemtime ( $source );
2013-04-20 01:21:06 +04:00
2013-06-14 17:14:23 +04:00
// restore file
2013-07-25 18:20:06 +04:00
$restoreResult = $view -> rename ( $source , $target );
2013-04-20 01:21:06 +04:00
2013-06-14 17:14:23 +04:00
// handle the restore result
if ( $restoreResult ) {
2013-05-10 14:05:11 +04:00
$fakeRoot = $view -> getRoot ();
2013-06-14 17:14:23 +04:00
$view -> chroot ( '/' . $user . '/files' );
2013-07-25 18:20:06 +04:00
$view -> touch ( '/' . $location . '/' . $uniqueFilename , $mtime );
2013-05-10 14:05:11 +04:00
$view -> chroot ( $fakeRoot );
2013-07-25 18:20:06 +04:00
\OCP\Util :: emitHook ( '\OCA\Files_Trashbin\Trashbin' , 'post_restore' , array ( 'filePath' => \OC\Files\Filesystem :: normalizePath ( '/' . $location . '/' . $uniqueFilename ),
2013-06-14 17:14:23 +04:00
'trashPath' => \OC\Files\Filesystem :: normalizePath ( $file )));
2013-04-19 12:35:32 +04:00
2014-02-26 00:35:54 +04:00
self :: restoreVersions ( $view , $file , $filename , $uniqueFilename , $location , $timestamp );
2013-04-19 12:35:32 +04:00
2013-06-14 17:14:23 +04:00
if ( $timestamp ) {
2013-03-22 15:47:43 +04:00
$query = \OC_DB :: prepare ( 'DELETE FROM `*PREFIX*files_trash` WHERE `user`=? AND `id`=? AND `timestamp`=?' );
2013-06-14 17:14:23 +04:00
$query -> execute ( array ( $user , $filename , $timestamp ));
2013-01-22 15:00:04 +04:00
}
2013-01-18 17:09:22 +04:00
return true ;
2013-01-18 16:11:29 +04:00
}
2013-01-18 17:09:22 +04:00
return false ;
2013-01-18 16:11:29 +04:00
}
2013-02-22 20:21:57 +04:00
2013-06-14 17:14:23 +04:00
/**
2014-05-19 19:50:53 +04:00
* restore versions from trash bin
2013-04-19 12:35:32 +04:00
*
2013-04-20 01:21:06 +04:00
* @ param \OC\Files\View $view file view
2014-05-13 15:29:25 +04:00
* @ param string $file complete path to file
* @ param string $filename name of file once it was deleted
2014-02-06 19:30:58 +04:00
* @ param string $uniqueFilename new file name to restore the file without overwriting existing files
2014-05-13 15:29:25 +04:00
* @ param string $location location if file
2014-10-24 16:13:40 +04:00
* @ param int $timestamp deletion time
* @ return bool
2013-04-19 12:35:32 +04:00
*/
2014-10-24 16:13:40 +04:00
private static function restoreVersions ( \OC\Files\View $view , $file , $filename , $uniqueFilename , $location , $timestamp ) {
2013-07-25 18:20:06 +04:00
2013-04-19 12:35:32 +04:00
if ( \OCP\App :: isEnabled ( 'files_versions' )) {
2013-04-28 01:51:26 +04:00
2013-06-14 17:14:23 +04:00
$user = \OCP\User :: getUser ();
2013-05-03 19:14:43 +04:00
$rootView = new \OC\Files\View ( '/' );
2013-07-25 18:20:06 +04:00
$target = \OC\Files\Filesystem :: normalizePath ( '/' . $location . '/' . $uniqueFilename );
2013-05-03 19:14:43 +04:00
list ( $owner , $ownerPath ) = self :: getUidAndFilename ( $target );
2014-09-19 21:01:02 +04:00
// file has been deleted in between
if ( empty ( $ownerPath )) {
return false ;
}
2013-04-19 12:35:32 +04:00
if ( $timestamp ) {
$versionedFile = $filename ;
} else {
$versionedFile = $file ;
}
2013-04-28 01:51:26 +04:00
2013-06-14 17:14:23 +04:00
if ( $view -> is_dir ( '/files_trashbin/versions/' . $file )) {
$rootView -> rename ( \OC\Files\Filesystem :: normalizePath ( $user . '/files_trashbin/versions/' . $file ), \OC\Files\Filesystem :: normalizePath ( $owner . '/files_versions/' . $ownerPath ));
2015-03-10 13:47:52 +03:00
} else if ( $versions = self :: getVersionsFromTrash ( $versionedFile , $timestamp , $user )) {
2013-06-14 17:14:23 +04:00
foreach ( $versions as $v ) {
if ( $timestamp ) {
$rootView -> rename ( $user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v . '.d' . $timestamp , $owner . '/files_versions/' . $ownerPath . '.v' . $v );
2013-04-19 12:35:32 +04:00
} else {
2013-06-14 17:14:23 +04:00
$rootView -> rename ( $user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v , $owner . '/files_versions/' . $ownerPath . '.v' . $v );
2013-04-19 12:35:32 +04:00
}
}
}
}
}
2013-12-02 14:39:53 +04:00
/**
2014-05-19 19:50:53 +04:00
* delete all files from the trash
2013-12-02 14:39:53 +04:00
*/
public static function deleteAll () {
$user = \OCP\User :: getUser ();
$view = new \OC\Files\View ( '/' . $user );
$view -> deleteAll ( 'files_trashbin' );
$query = \OC_DB :: prepare ( 'DELETE FROM `*PREFIX*files_trash` WHERE `user`=?' );
$query -> execute ( array ( $user ));
2015-03-25 01:02:14 +03:00
$view -> mkdir ( 'files_trashbin' );
$view -> mkdir ( 'files_trashbin/files' );
2013-12-02 14:39:53 +04:00
return true ;
}
2013-02-08 03:11:54 +04:00
/**
2014-05-19 19:50:53 +04:00
* delete file from trash bin permanently
2013-06-14 17:14:23 +04:00
*
2014-05-13 15:29:25 +04:00
* @ param string $filename path to the file
2014-06-17 22:08:40 +04:00
* @ param string $user
2014-05-13 15:29:25 +04:00
* @ param int $timestamp of deletion time
2013-06-14 17:14:23 +04:00
*
2014-05-13 15:29:25 +04:00
* @ return int size of deleted files
2013-02-08 03:11:54 +04:00
*/
2014-06-17 22:08:40 +04:00
public static function delete ( $filename , $user , $timestamp = null ) {
2013-06-14 17:14:23 +04:00
$view = new \OC\Files\View ( '/' . $user );
2013-02-25 17:29:31 +04:00
$size = 0 ;
2013-06-14 17:14:23 +04:00
if ( $timestamp ) {
2013-03-22 15:47:43 +04:00
$query = \OC_DB :: prepare ( 'DELETE FROM `*PREFIX*files_trash` WHERE `user`=? AND `id`=? AND `timestamp`=?' );
2013-06-14 17:14:23 +04:00
$query -> execute ( array ( $user , $filename , $timestamp ));
$file = $filename . '.d' . $timestamp ;
2013-02-06 19:23:22 +04:00
} else {
$file = $filename ;
}
2013-02-22 20:21:57 +04:00
2015-03-10 13:47:52 +03:00
$size += self :: deleteVersions ( $view , $file , $filename , $timestamp , $user );
2013-06-14 17:14:23 +04:00
if ( $view -> is_dir ( '/files_trashbin/files/' . $file )) {
$size += self :: calculateSize ( new \OC\Files\View ( '/' . $user . '/files_trashbin/files/' . $file ));
2013-05-03 18:33:18 +04:00
} else {
2013-06-14 17:14:23 +04:00
$size += $view -> filesize ( '/files_trashbin/files/' . $file );
2013-05-03 18:33:18 +04:00
}
2014-03-11 17:10:12 +04:00
\OC_Hook :: emit ( '\OCP\Trashbin' , 'preDelete' , array ( 'path' => '/files_trashbin/files/' . $file ));
2013-06-14 17:14:23 +04:00
$view -> unlink ( '/files_trashbin/files/' . $file );
2013-11-12 17:03:50 +04:00
\OC_Hook :: emit ( '\OCP\Trashbin' , 'delete' , array ( 'path' => '/files_trashbin/files/' . $file ));
2013-06-14 17:14:23 +04:00
2013-05-03 18:33:18 +04:00
return $size ;
}
2014-02-06 19:30:58 +04:00
/**
* @ param \OC\Files\View $view
2014-10-24 16:13:40 +04:00
* @ param $file
* @ param $filename
* @ param $timestamp
* @ return int
2014-02-06 19:30:58 +04:00
*/
2015-03-10 13:47:52 +03:00
private static function deleteVersions ( \OC\Files\View $view , $file , $filename , $timestamp , $user ) {
2013-05-03 18:33:18 +04:00
$size = 0 ;
2013-06-14 17:14:23 +04:00
if ( \OCP\App :: isEnabled ( 'files_versions' )) {
if ( $view -> is_dir ( 'files_trashbin/versions/' . $file )) {
$size += self :: calculateSize ( new \OC\Files\view ( '/' . $user . '/files_trashbin/versions/' . $file ));
$view -> unlink ( 'files_trashbin/versions/' . $file );
2015-03-10 13:47:52 +03:00
} else if ( $versions = self :: getVersionsFromTrash ( $filename , $timestamp , $user )) {
2013-02-06 19:23:22 +04:00
foreach ( $versions as $v ) {
2013-06-14 17:14:23 +04:00
if ( $timestamp ) {
$size += $view -> filesize ( '/files_trashbin/versions/' . $filename . '.v' . $v . '.d' . $timestamp );
$view -> unlink ( '/files_trashbin/versions/' . $filename . '.v' . $v . '.d' . $timestamp );
2013-02-06 19:23:22 +04:00
} else {
2013-06-14 17:14:23 +04:00
$size += $view -> filesize ( '/files_trashbin/versions/' . $filename . '.v' . $v );
$view -> unlink ( '/files_trashbin/versions/' . $filename . '.v' . $v );
2013-02-06 19:23:22 +04:00
}
}
}
2013-02-08 03:11:54 +04:00
}
2013-05-03 18:33:18 +04:00
return $size ;
}
2013-02-17 02:42:06 +04:00
/**
* check to see whether a file exists in trashbin
2014-03-17 19:35:08 +04:00
*
2014-05-13 15:29:25 +04:00
* @ param string $filename path to the file
* @ param int $timestamp of deletion time
* @ return bool true if file exists , otherwise false
2013-02-17 02:42:06 +04:00
*/
2013-06-14 17:14:23 +04:00
public static function file_exists ( $filename , $timestamp = null ) {
2013-02-17 02:42:06 +04:00
$user = \OCP\User :: getUser ();
2013-06-14 17:14:23 +04:00
$view = new \OC\Files\View ( '/' . $user );
2013-02-18 18:49:50 +04:00
if ( $timestamp ) {
2013-06-14 17:14:23 +04:00
$filename = $filename . '.d' . $timestamp ;
2013-02-18 18:49:50 +04:00
} else {
$filename = $filename ;
}
2013-06-14 17:14:23 +04:00
$target = \OC\Files\Filesystem :: normalizePath ( 'files_trashbin/files/' . $filename );
2013-02-17 02:42:06 +04:00
return $view -> file_exists ( $target );
}
2013-04-11 14:37:52 +04:00
/**
2014-05-19 19:50:53 +04:00
* deletes used space for trash bin in db if user was deleted
2013-04-11 14:37:52 +04:00
*
2014-06-05 12:44:32 +04:00
* @ param string $uid id of deleted user
2014-05-13 15:29:25 +04:00
* @ return bool result of db delete operation
2013-04-11 14:37:52 +04:00
*/
public static function deleteUser ( $uid ) {
$query = \OC_DB :: prepare ( 'DELETE FROM `*PREFIX*files_trash` WHERE `user`=?' );
2014-06-05 12:44:32 +04:00
return $query -> execute ( array ( $uid ));
2013-04-11 14:37:52 +04:00
}
2013-04-16 15:51:53 +04:00
/**
* calculate remaining free space for trash bin
*
2014-02-06 19:30:58 +04:00
* @ param integer $trashbinSize current size of the trash bin
2014-06-17 22:08:40 +04:00
* @ param string $user
2014-05-13 15:29:25 +04:00
* @ return int available free space for trash bin
2013-04-16 15:51:53 +04:00
*/
2014-06-17 22:08:40 +04:00
private static function calculateFreeSpace ( $trashbinSize , $user ) {
2014-12-04 18:48:07 +03:00
$config = \OC :: $server -> getConfig ();
2013-04-16 15:51:53 +04:00
$softQuota = true ;
2014-12-04 18:48:07 +03:00
$quota = $config -> getUserValue ( $user , 'files' , 'quota' , null );
2013-06-14 17:14:23 +04:00
$view = new \OC\Files\View ( '/' . $user );
if ( $quota === null || $quota === 'default' ) {
2014-12-04 18:48:07 +03:00
$quota = $config -> getAppValue ( 'files' , 'default_quota' , null );
2013-04-16 15:51:53 +04:00
}
2013-06-14 17:14:23 +04:00
if ( $quota === null || $quota === 'none' ) {
2013-04-16 15:51:53 +04:00
$quota = \OC\Files\Filesystem :: free_space ( '/' );
$softQuota = false ;
2015-10-15 16:46:26 +03:00
// inf or unknown free space
if ( $quota < 0 ) {
$quota = PHP_INT_MAX ;
2014-10-10 20:26:43 +04:00
}
2013-04-16 15:51:53 +04:00
} else {
$quota = \OCP\Util :: computerFileSize ( $quota );
}
// calculate available space for trash bin
// subtract size of files and current trash bin size from quota
if ( $softQuota ) {
2014-01-20 20:10:09 +04:00
$rootInfo = $view -> getFileInfo ( '/files/' , false );
2013-06-14 17:14:23 +04:00
$free = $quota - $rootInfo [ 'size' ]; // remaining free space for user
if ( $free > 0 ) {
2013-04-16 15:51:53 +04:00
$availableSpace = ( $free * self :: DEFAULTMAXSIZE / 100 ) - $trashbinSize ; // how much space can be used for versions
} else {
2013-06-14 17:14:23 +04:00
$availableSpace = $free - $trashbinSize ;
2013-04-16 15:51:53 +04:00
}
} else {
$availableSpace = $quota ;
}
return $availableSpace ;
}
2013-07-26 13:45:38 +04:00
/**
2014-05-19 19:50:53 +04:00
* resize trash bin if necessary after a new file was added to ownCloud
2015-05-19 15:22:09 +03:00
*
2013-07-26 13:45:38 +04:00
* @ param string $user user id
*/
public static function resizeTrash ( $user ) {
$size = self :: getTrashbinSize ( $user );
2014-06-17 22:08:40 +04:00
$freeSpace = self :: calculateFreeSpace ( $size , $user );
2013-07-26 13:45:38 +04:00
if ( $freeSpace < 0 ) {
2015-03-02 17:25:50 +03:00
self :: scheduleExpire ( $size , $user );
2013-07-26 13:45:38 +04:00
}
}
2013-08-27 16:39:43 +04:00
2013-01-31 21:04:00 +04:00
/**
* clean up the trash bin
2014-03-17 19:35:08 +04:00
*
2015-03-02 17:25:50 +03:00
* @ param int $trashBinSize current size of the trash bin
2013-11-25 15:51:32 +04:00
* @ param string $user
2013-01-31 21:04:00 +04:00
*/
2015-03-02 17:25:50 +03:00
public static function expire ( $trashBinSize , $user ) {
$availableSpace = self :: calculateFreeSpace ( $trashBinSize , $user );
2013-02-07 18:16:29 +04:00
$size = 0 ;
2013-02-22 20:21:57 +04:00
2014-06-17 22:08:40 +04:00
$dirContent = Helper :: getTrashFiles ( '/' , $user , 'mtime' );
2014-06-17 15:51:49 +04:00
// delete all files older then $retention_obligation
2015-07-30 22:31:18 +03:00
list ( $delSize , $count ) = self :: deleteExpiredFiles ( $dirContent , $user );
2014-06-17 15:51:49 +04:00
$size += $delSize ;
$availableSpace += $size ;
// delete files from trash until we meet the trash bin size limit again
2014-06-17 22:08:40 +04:00
$size += self :: deleteFiles ( array_slice ( $dirContent , $count ), $user , $availableSpace );
2015-03-02 17:25:50 +03:00
}
2014-06-17 15:51:49 +04:00
2015-03-02 17:25:50 +03:00
/**@ param int $trashBinSize current size of the trash bin
* @ param string $user
*/
private static function scheduleExpire ( $trashBinSize , $user ) {
// let the admin disable auto expire
2015-07-30 22:31:18 +03:00
$application = new Application ();
$expiration = $application -> getContainer () -> query ( 'Expiration' );
if ( $expiration -> isEnabled ()) {
\OC :: $server -> getCommandBus () -> push ( new Expire ( $user , $trashBinSize ));
2015-03-02 17:25:50 +03:00
}
2014-06-17 15:51:49 +04:00
}
/**
* if the size limit for the trash bin is reached , we delete the oldest
* files in the trash bin until we meet the limit again
2015-05-19 15:22:09 +03:00
*
2014-06-17 15:51:49 +04:00
* @ param array $files
2014-06-17 22:08:40 +04:00
* @ param string $user
* @ param int $availableSpace available disc space
2014-06-17 15:51:49 +04:00
* @ return int size of deleted files
*/
2014-06-18 00:30:11 +04:00
protected static function deleteFiles ( $files , $user , $availableSpace ) {
2015-07-30 22:31:18 +03:00
$application = new Application ();
$expiration = $application -> getContainer () -> query ( 'Expiration' );
2014-06-17 15:51:49 +04:00
$size = 0 ;
2014-06-03 18:45:11 +04:00
2014-06-17 15:51:49 +04:00
if ( $availableSpace < 0 ) {
foreach ( $files as $file ) {
2015-07-30 22:31:18 +03:00
if ( $availableSpace < 0 && $expiration -> isExpired ( $file [ 'mtime' ], true )) {
2014-06-17 22:08:40 +04:00
$tmp = self :: delete ( $file [ 'name' ], $user , $file [ 'mtime' ]);
2015-07-03 15:06:40 +03:00
\OCP\Util :: writeLog ( 'files_trashbin' , 'remove "' . $file [ 'name' ] . '" (' . $tmp . 'B) to meet the limit of trash bin size (50% of available quota)' , \OCP\Util :: INFO );
2014-06-17 15:51:49 +04:00
$availableSpace += $tmp ;
$size += $tmp ;
} else {
break ;
}
}
}
return $size ;
}
/**
* delete files older then max storage time
*
* @ param array $files list of files sorted by mtime
2014-06-17 22:08:40 +04:00
* @ param string $user
2014-06-17 15:51:49 +04:00
* @ return array size of deleted files and number of deleted files
*/
2015-08-11 22:21:32 +03:00
public static function deleteExpiredFiles ( $files , $user ) {
2015-07-30 22:31:18 +03:00
$application = new Application ();
$expiration = $application -> getContainer () -> query ( 'Expiration' );
2014-06-17 15:51:49 +04:00
$size = 0 ;
$count = 0 ;
foreach ( $files as $file ) {
2014-06-03 18:45:11 +04:00
$timestamp = $file [ 'mtime' ];
2014-06-17 15:51:49 +04:00
$filename = $file [ 'name' ];
2015-07-30 22:31:18 +03:00
if ( $expiration -> isExpired ( $timestamp )) {
2014-06-17 15:51:49 +04:00
$count ++ ;
2014-06-17 22:08:40 +04:00
$size += self :: delete ( $filename , $user , $timestamp );
2015-09-16 22:06:57 +03:00
\OC :: $server -> getLogger () -> info (
'Remove "' . $filename . '" from trashbin because it exceeds max retention obligation term.' ,
[ 'app' => 'files_trashbin' ]
);
2014-06-17 15:51:49 +04:00
} else {
break ;
2013-02-07 20:37:46 +04:00
}
}
2013-02-22 20:21:57 +04:00
2014-06-17 15:51:49 +04:00
return array ( $size , $count );
2013-01-18 16:11:29 +04:00
}
2013-02-22 20:21:57 +04:00
2013-01-18 16:11:29 +04:00
/**
* recursive copy to copy a whole directory
2013-02-22 20:21:57 +04:00
*
2014-02-06 19:30:58 +04:00
* @ param string $source source path , relative to the users files directory
* @ param string $destination destination path relative to the users root directoy
* @ param \OC\Files\View $view file view for the users root directory
2014-10-24 16:13:40 +04:00
* @ return int
* @ throws Exceptions\CopyRecursiveException
2013-01-18 16:11:29 +04:00
*/
2014-10-24 16:13:40 +04:00
private static function copy_recursive ( $source , $destination , \OC\Files\View $view ) {
2013-02-07 18:16:29 +04:00
$size = 0 ;
2013-11-25 15:51:32 +04:00
if ( $view -> is_dir ( $source )) {
2013-06-14 17:14:23 +04:00
$view -> mkdir ( $destination );
2013-11-25 15:51:32 +04:00
$view -> touch ( $destination , $view -> filemtime ( $source ));
foreach ( $view -> getDirectoryContent ( $source ) as $i ) {
2013-06-14 17:14:23 +04:00
$pathDir = $source . '/' . $i [ 'name' ];
2013-11-25 15:51:32 +04:00
if ( $view -> is_dir ( $pathDir )) {
2013-06-14 17:14:23 +04:00
$size += self :: copy_recursive ( $pathDir , $destination . '/' . $i [ 'name' ], $view );
2013-01-18 16:11:29 +04:00
} else {
2013-11-25 15:51:32 +04:00
$size += $view -> filesize ( $pathDir );
2014-07-14 19:03:36 +04:00
$result = $view -> copy ( $pathDir , $destination . '/' . $i [ 'name' ]);
if ( ! $result ) {
throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException ();
}
2013-11-25 15:51:32 +04:00
$view -> touch ( $destination . '/' . $i [ 'name' ], $view -> filemtime ( $pathDir ));
2013-01-18 16:11:29 +04:00
}
}
} else {
2013-11-25 15:51:32 +04:00
$size += $view -> filesize ( $source );
2014-07-14 19:03:36 +04:00
$result = $view -> copy ( $source , $destination );
if ( ! $result ) {
throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException ();
}
2013-11-25 15:51:32 +04:00
$view -> touch ( $destination , $view -> filemtime ( $source ));
2013-01-18 16:11:29 +04:00
}
2013-02-07 18:16:29 +04:00
return $size ;
2013-01-18 16:11:29 +04:00
}
2013-02-22 20:21:57 +04:00
2013-01-18 16:11:29 +04:00
/**
* find all versions which belong to the file we want to restore
2014-03-17 19:35:08 +04:00
*
2014-05-13 15:29:25 +04:00
* @ param string $filename name of the file which should be restored
* @ param int $timestamp timestamp when the file was deleted
2014-10-10 20:26:43 +04:00
* @ return array
2013-01-18 16:11:29 +04:00
*/
2015-03-10 13:47:52 +03:00
private static function getVersionsFromTrash ( $filename , $timestamp , $user ) {
$view = new \OC\Files\View ( '/' . $user . '/files_trashbin/versions' );
2013-01-31 21:04:00 +04:00
$versions = array ();
2014-10-10 20:26:43 +04:00
//force rescan of versions, local storage may not have updated the cache
2015-03-02 14:48:08 +03:00
if ( ! self :: $scannedVersions ) {
/** @var \OC\Files\Storage\Storage $storage */
2015-05-19 15:22:09 +03:00
list ( $storage ,) = $view -> resolvePath ( '/' );
2015-03-02 14:48:08 +03:00
$storage -> getScanner () -> scan ( 'files_trashbin/versions' );
self :: $scannedVersions = true ;
}
2014-10-10 20:26:43 +04:00
2013-06-14 17:14:23 +04:00
if ( $timestamp ) {
2013-02-09 20:27:57 +04:00
// fetch for old versions
2014-10-10 20:26:43 +04:00
$matches = $view -> searchRaw ( $filename . '.v%.d' . $timestamp );
2013-06-14 17:14:23 +04:00
$offset = - strlen ( $timestamp ) - 2 ;
2013-01-22 15:00:04 +04:00
} else {
2014-10-10 20:26:43 +04:00
$matches = $view -> searchRaw ( $filename . '.v%' );
2013-01-31 21:04:00 +04:00
}
2013-02-22 20:21:57 +04:00
2014-04-13 17:46:37 +04:00
if ( is_array ( $matches )) {
foreach ( $matches as $ma ) {
if ( $timestamp ) {
2014-10-10 20:26:43 +04:00
$parts = explode ( '.v' , substr ( $ma [ 'path' ], 0 , $offset ));
2014-04-13 17:46:37 +04:00
$versions [] = ( end ( $parts ));
} else {
$parts = explode ( '.v' , $ma );
$versions [] = ( end ( $parts ));
}
2013-01-22 15:00:04 +04:00
}
2013-01-18 16:11:29 +04:00
}
return $versions ;
}
2013-02-22 20:21:57 +04:00
2013-01-18 16:11:29 +04:00
/**
* find unique extension for restored file if a file with the same name already exists
2014-03-17 19:35:08 +04:00
*
2014-05-13 15:29:25 +04:00
* @ param string $location where the file should be restored
* @ param string $filename name of the file
2014-02-06 19:30:58 +04:00
* @ param \OC\Files\View $view filesystem view relative to users root directory
2013-01-18 16:11:29 +04:00
* @ return string with unique extension
*/
2014-10-24 16:13:40 +04:00
private static function getUniqueFilename ( $location , $filename , \OC\Files\View $view ) {
2013-07-25 18:20:06 +04:00
$ext = pathinfo ( $filename , PATHINFO_EXTENSION );
$name = pathinfo ( $filename , PATHINFO_FILENAME );
2014-08-31 12:05:59 +04:00
$l = \OC :: $server -> getL10N ( 'files_trashbin' );
2013-07-25 18:20:06 +04:00
2015-05-12 14:14:57 +03:00
$location = '/' . trim ( $location , '/' );
2013-07-25 18:20:06 +04:00
// if extension is not empty we set a dot in front of it
if ( $ext !== '' ) {
$ext = '.' . $ext ;
}
2013-06-14 17:14:23 +04:00
if ( $view -> file_exists ( 'files' . $location . '/' . $filename )) {
2013-07-25 18:20:06 +04:00
$i = 2 ;
2014-03-17 19:35:08 +04:00
$uniqueName = $name . " ( " . $l -> t ( " restored " ) . " ) " . $ext ;
2013-07-25 18:20:06 +04:00
while ( $view -> file_exists ( 'files' . $location . '/' . $uniqueName )) {
2014-03-17 19:35:08 +04:00
$uniqueName = $name . " ( " . $l -> t ( " restored " ) . " " . $i . " ) " . $ext ;
2013-01-31 21:04:00 +04:00
$i ++ ;
}
2013-07-25 18:20:06 +04:00
return $uniqueName ;
2013-01-18 16:11:29 +04:00
}
2013-07-25 18:20:06 +04:00
return $filename ;
2013-01-18 16:11:29 +04:00
}
2013-02-22 20:21:57 +04:00
/**
2014-05-19 19:50:53 +04:00
* get the size from a given root folder
2015-05-19 15:22:09 +03:00
*
2014-02-06 19:30:58 +04:00
* @ param \OC\Files\View $view file view on the root folder
* @ return integer size of the folder
2013-02-22 20:21:57 +04:00
*/
private static function calculateSize ( $view ) {
2014-12-17 13:12:37 +03:00
$root = \OC :: $server -> getConfig () -> getSystemValue ( 'datadirectory' ) . $view -> getAbsolutePath ( '' );
2013-02-19 00:48:08 +04:00
if ( ! file_exists ( $root )) {
return 0 ;
}
2013-06-14 17:14:23 +04:00
$iterator = new \RecursiveIteratorIterator ( new \RecursiveDirectoryIterator ( $root ), \RecursiveIteratorIterator :: CHILD_FIRST );
2013-02-22 20:21:57 +04:00
$size = 0 ;
2015-05-19 15:22:09 +03:00
/**
2014-04-28 21:32:25 +04:00
* RecursiveDirectoryIterator on an NFS path isn ' t iterable with foreach
* This bug is fixed in PHP 5.5 . 9 or before
* See #8376
*/
$iterator -> rewind ();
while ( $iterator -> valid ()) {
$path = $iterator -> current ();
2013-06-14 17:14:23 +04:00
$relpath = substr ( $path , strlen ( $root ) - 1 );
if ( ! $view -> is_dir ( $relpath )) {
2013-02-07 18:16:29 +04:00
$size += $view -> filesize ( $relpath );
2013-02-22 20:21:57 +04:00
}
2014-04-28 21:32:25 +04:00
$iterator -> next ();
2013-02-22 20:21:57 +04:00
}
return $size ;
2013-02-07 18:16:29 +04:00
}
2013-02-21 15:37:13 +04:00
2013-02-25 17:29:31 +04:00
/**
* get current size of trash bin from a given user
*
2014-05-13 15:29:25 +04:00
* @ param string $user user who owns the trash bin
2014-05-06 15:56:22 +04:00
* @ return integer trash bin size
2013-02-25 17:29:31 +04:00
*/
private static function getTrashbinSize ( $user ) {
2014-02-26 00:35:54 +04:00
$view = new \OC\Files\View ( '/' . $user );
$fileInfo = $view -> getFileInfo ( '/files_trashbin' );
2014-05-06 15:56:22 +04:00
return isset ( $fileInfo [ 'size' ]) ? $fileInfo [ 'size' ] : 0 ;
2013-02-21 15:37:13 +04:00
}
2013-05-23 01:50:45 +04:00
/**
* register hooks
*/
public static function registerHooks () {
2015-01-14 23:06:26 +03:00
// create storage wrapper on setup
2015-04-01 18:12:06 +03:00
\OCP\Util :: connectHook ( 'OC_Filesystem' , 'preSetup' , 'OCA\Files_Trashbin\Storage' , 'setupStorage' );
2013-05-23 01:50:45 +04:00
//Listen to delete user signal
2015-01-14 23:06:26 +03:00
\OCP\Util :: connectHook ( 'OC_User' , 'pre_deleteUser' , 'OCA\Files_Trashbin\Hooks' , 'deleteUser_hook' );
2013-07-26 13:45:38 +04:00
//Listen to post write hook
2015-01-14 23:06:26 +03:00
\OCP\Util :: connectHook ( 'OC_Filesystem' , 'post_write' , 'OCA\Files_Trashbin\Hooks' , 'post_write_hook' );
2015-01-26 14:22:22 +03:00
// pre and post-rename, disable trash logic for the copy+unlink case
2015-06-09 18:01:31 +03:00
\OCP\Util :: connectHook ( 'OC_Filesystem' , 'delete' , 'OCA\Files_Trashbin\Trashbin' , 'ensureFileScannedHook' );
2015-01-26 14:22:22 +03:00
\OCP\Util :: connectHook ( 'OC_Filesystem' , 'rename' , 'OCA\Files_Trashbin\Storage' , 'preRenameHook' );
\OCP\Util :: connectHook ( 'OC_Filesystem' , 'post_rename' , 'OCA\Files_Trashbin\Storage' , 'postRenameHook' );
2013-05-23 01:50:45 +04:00
}
2013-08-27 16:39:43 +04:00
2013-07-26 13:13:43 +04:00
/**
2014-05-19 19:50:53 +04:00
* check if trash bin is empty for a given user
2015-05-19 15:22:09 +03:00
*
2013-07-26 13:13:43 +04:00
* @ param string $user
2014-10-24 16:13:40 +04:00
* @ return bool
2013-07-26 13:13:43 +04:00
*/
public static function isEmpty ( $user ) {
2013-08-27 16:39:43 +04:00
$view = new \OC\Files\View ( '/' . $user . '/files_trashbin' );
2014-04-13 16:47:08 +04:00
if ( $view -> is_dir ( '/files' ) && $dh = $view -> opendir ( '/files' )) {
while ( $file = readdir ( $dh )) {
2015-09-21 15:09:28 +03:00
if ( ! \OC\Files\Filesystem :: isIgnoredDir ( $file )) {
2014-04-13 16:47:08 +04:00
return false ;
}
2014-03-17 20:03:32 +04:00
}
}
return true ;
2013-05-23 01:50:45 +04:00
}
2013-07-08 12:53:53 +04:00
2014-10-24 16:13:40 +04:00
/**
* @ param $path
* @ return string
*/
2013-07-08 12:53:53 +04:00
public static function preview_icon ( $path ) {
2015-09-30 11:49:48 +03:00
return \OCP\Util :: linkToRoute ( 'core_ajax_trashbin_preview' , array ( 'x' => 32 , 'y' => 32 , 'file' => $path ));
2013-07-08 12:53:53 +04:00
}
2013-01-31 21:04:00 +04:00
}