2013-01-18 16:11:29 +04:00
< ? php
2013-01-31 21:04:00 +04:00
/**
* ownCloud - trash bin
*
* @ 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 />.
*
*/
2013-02-08 03:11:54 +04:00
namespace OCA\Files_Trashbin ;
2013-01-18 16:11:29 +04:00
class Trashbin {
2013-02-15 01:46:28 +04:00
// how long do we keep files in the trash bin if no other value is defined in the config file (unit: days)
2013-06-14 17:14:23 +04:00
2013-07-26 17:15:47 +04:00
const DEFAULT_RETENTION_OBLIGATION = 30 ;
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
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' );
2013-05-03 15:00:04 +04:00
$filename = $ownerView -> getPath ( $info [ 'fileid' ]);
}
return array ( $uid , $filename );
}
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
}
if ( ! $view -> is_dir ( 'files_trashbin/keyfiles' )) {
2013-04-20 01:21:06 +04:00
$view -> mkdir ( 'files_trashbin/keyfiles' );
2013-01-31 21:04:00 +04:00
}
2013-05-10 13:12:42 +04:00
if ( ! $view -> is_dir ( 'files_trashbin/share-keys' )) {
$view -> mkdir ( 'files_trashbin/share-keys' );
}
2013-11-25 15:51:32 +04:00
}
private static function copyFilesToOwner ( $sourcePath , $owner , $ownerPath , $timestamp , $type , $mime ) {
self :: setUpTrash ( $owner );
$ownerFilename = basename ( $ownerPath );
$ownerLocation = dirname ( $ownerPath );
$sourceFilename = basename ( $sourcePath );
$view = new \OC\Files\View ( '/' );
$source = \OCP\User :: getUser () . '/files_trashbin/files/' . $sourceFilename . '.d' . $timestamp ;
$target = $owner . '/files_trashbin/files/' . $ownerFilename . '.d' . $timestamp ;
self :: copy_recursive ( $source , $target , $view );
if ( $view -> file_exists ( $target )) {
$query = \OC_DB :: prepare ( " INSERT INTO `*PREFIX*files_trash` (`id`,`timestamp`,`location`,`type`,`mime`,`user`) VALUES (?,?,?,?,?,?) " );
$result = $query -> execute ( array ( $ownerFilename , $timestamp , $ownerLocation , $type , $mime , $owner ));
if ( ! $result ) { // if file couldn't be added to the database than also don't store it in the trash bin.
$view -> deleteAll ( $owner . '/files_trashbin/files/' . $ownerFilename . '.d' . $timestamp );
\OC_Log :: write ( 'files_trashbin' , 'trash bin database couldn\'t be updated for the files owner' , \OC_log :: ERROR );
return ;
}
}
}
/**
* 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 ();
$size = 0 ;
list ( $owner , $ownerPath ) = self :: getUidAndFilename ( $file_path );
self :: setUpTrash ( $user );
$view = new \OC\Files\View ( '/' . $user );
2013-01-31 21:04:00 +04:00
$path_parts = pathinfo ( $file_path );
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
$mime = $view -> getMimeType ( 'files' . $file_path );
2013-01-31 21:04:00 +04:00
2013-06-14 17:14:23 +04:00
if ( $view -> is_dir ( 'files' . $file_path )) {
2013-01-31 21:04:00 +04:00
$type = 'dir' ;
} else {
$type = 'file' ;
}
2013-06-14 17:14:23 +04:00
2013-11-25 15:51:32 +04:00
$userTrashSize = self :: getTrashbinSize ( $user );
if ( $userTrashSize === false || $userTrashSize < 0 ) {
$userTrashSize = self :: calculateSize ( new \OC\Files\View ( '/' . $user . '/files_trashbin' ));
2013-02-07 18:16:29 +04:00
}
2013-05-03 17:18:05 +04:00
// disable proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy :: $enabled ;
\OC_FileProxy :: $enabled = false ;
2013-11-25 15:51:32 +04:00
$trashPath = '/files_trashbin/files/' . $filename . '.d' . $timestamp ;
$sizeOfAddedFiles = self :: copy_recursive ( '/files/' . $file_path , $trashPath , $view );
2013-05-03 17:18:05 +04:00
\OC_FileProxy :: $enabled = $proxyStatus ;
2013-04-22 05:37:55 +04:00
2013-06-14 17:14:23 +04:00
if ( $view -> file_exists ( 'files_trashbin/files/' . $filename . '.d' . $timestamp )) {
2013-11-25 15:51:32 +04:00
$size = $sizeOfAddedFiles ;
2013-03-22 15:47:43 +04:00
$query = \OC_DB :: prepare ( " INSERT INTO `*PREFIX*files_trash` (`id`,`timestamp`,`location`,`type`,`mime`,`user`) VALUES (?,?,?,?,?,?) " );
2013-04-19 12:31:42 +04:00
$result = $query -> execute ( array ( $filename , $timestamp , $location , $type , $mime , $user ));
2013-06-14 17:14:23 +04:00
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/files/' . $filename . '.d' . $timestamp );
2013-01-29 16:36:33 +04:00
\OC_Log :: write ( 'files_trashbin' , 'trash bin database couldn\'t be updated' , \OC_log :: ERROR );
return ;
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
2013-11-25 15:51:32 +04:00
$size += self :: retainVersions ( $file_path , $filename , $timestamp );
$size += self :: retainEncryptionKeys ( $file_path , $filename , $timestamp );
// if owner !== user we need to also add a copy to the owners trash
if ( $user !== $owner ) {
self :: copyFilesToOwner ( $file_path , $owner , $ownerPath , $timestamp , $type , $mime );
}
2013-01-29 16:36:33 +04:00
} else {
2013-06-14 17:14:23 +04:00
\OC_Log :: write ( 'files_trashbin' , 'Couldn\'t move ' . $file_path . ' to the trash bin' , \OC_log :: ERROR );
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 ;
$userTrashSize -= self :: expire ( $userTrashSize , $user );
self :: setTrashbinSize ( $user , $userTrashSize );
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
if ( $owner !== $user ) {
$ownerTrashSize = self :: getTrashbinSize ( $owner );
if ( $ownerTrashSize === false || $ownerTrashSize < 0 ) {
$ownerTrashSize = self :: calculateSize ( new \OC\Files\View ( '/' . $owner . '/files_trashbin' ));
}
$ownerTrashSize += $size ;
$ownerTrashSize -= self :: expire ( $ownerTrashSize , $owner );
self :: setTrashbinSize ( $owner , $ownerTrashSize );
}
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
*
* @ param $file_path path to original file
* @ param $filename of deleted file
* @ param $timestamp when the file was deleted
*
* @ return size of stored versions
*/
2013-07-26 13:45:38 +04:00
private static function retainVersions ( $file_path , $filename , $timestamp ) {
2013-04-19 12:31:42 +04:00
$size = 0 ;
2013-06-14 17:14:23 +04:00
if ( \OCP\App :: isEnabled ( 'files_versions' )) {
2013-04-28 01:51:26 +04:00
2013-06-14 17:14:23 +04:00
// disable proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy :: $enabled ;
\OC_FileProxy :: $enabled = false ;
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 ( '/' );
list ( $owner , $ownerPath ) = self :: getUidAndFilename ( $file_path );
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 ) {
$rootView -> copy ( $owner . '/files_versions/' . $ownerPath , $owner . '/files_trashbin/versions/' . basename ( $ownerPath ) . '.d' . $timestamp );
}
2013-06-14 17:14:23 +04:00
$rootView -> rename ( $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 )) {
2013-06-14 17:14:23 +04:00
foreach ( $versions as $v ) {
$size += $rootView -> filesize ( $owner . '/files_versions' . $v [ 'path' ] . '.v' . $v [ 'version' ]);
2013-11-25 15:51:32 +04:00
if ( $owner !== $user ) {
$rootView -> copy ( $owner . '/files_versions' . $v [ 'path' ] . '.v' . $v [ 'version' ], $owner . '/files_trashbin/versions/' . $v [ 'name' ] . '.v' . $v [ 'version' ] . '.d' . $timestamp );
}
2013-06-14 17:14:23 +04:00
$rootView -> rename ( $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
}
}
2013-04-28 01:51:26 +04:00
2013-06-14 17:14:23 +04:00
// enable proxy
\OC_FileProxy :: $enabled = $proxyStatus ;
2013-04-19 12:31:42 +04:00
}
return $size ;
}
2013-06-14 17:14:23 +04:00
/**
* Move encryption keys to trash so that they can be restored later
*
* @ param $file_path path to original file
* @ param $filename of deleted file
* @ param $timestamp when the file was deleted
*
* @ return size of encryption keys
*/
2013-07-26 13:45:38 +04:00
private static function retainEncryptionKeys ( $file_path , $filename , $timestamp ) {
2013-04-19 12:31:42 +04:00
$size = 0 ;
if ( \OCP\App :: isEnabled ( 'files_encryption' )) {
$user = \OCP\User :: getUser ();
2013-05-03 15:00:04 +04:00
$rootView = new \OC\Files\View ( '/' );
list ( $owner , $ownerPath ) = self :: getUidAndFilename ( $file_path );
2013-06-25 19:17:41 +04:00
$util = new \OCA\Encryption\Util ( new \OC_FilesystemView ( '/' ), $user );
2013-04-19 12:31:42 +04:00
2013-06-14 17:14:23 +04:00
// disable proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy :: $enabled ;
\OC_FileProxy :: $enabled = false ;
2013-04-20 01:21:06 +04:00
2013-06-25 19:17:41 +04:00
if ( $util -> isSystemWideMountPoint ( $ownerPath )) {
$baseDir = '/files_encryption/' ;
} else {
$baseDir = $owner . '/files_encryption/' ;
}
$keyfile = \OC\Files\Filesystem :: normalizePath ( $baseDir . '/keyfiles/' . $ownerPath );
2013-04-22 05:37:55 +04:00
2013-06-14 17:14:23 +04:00
if ( $rootView -> is_dir ( $keyfile ) || $rootView -> file_exists ( $keyfile . '.key' )) {
// move keyfiles
if ( $rootView -> is_dir ( $keyfile )) {
$size += self :: calculateSize ( new \OC\Files\View ( $keyfile ));
2013-11-25 15:51:32 +04:00
if ( $owner !== $user ) {
$rootView -> copy ( $keyfile , $owner . '/files_trashbin/keyfiles/' . basename ( $ownerPath ) . '.d' . $timestamp );
}
2013-06-14 17:14:23 +04:00
$rootView -> rename ( $keyfile , $user . '/files_trashbin/keyfiles/' . $filename . '.d' . $timestamp );
2013-04-19 12:31:42 +04:00
} else {
2013-05-03 15:00:04 +04:00
$size += $rootView -> filesize ( $keyfile . '.key' );
2013-11-25 15:51:32 +04:00
if ( $owner !== $user ) {
$rootView -> copy ( $keyfile . '.key' , $owner . '/files_trashbin/keyfiles/' . basename ( $ownerPath ) . '.key.d' . $timestamp );
}
2013-06-14 17:14:23 +04:00
$rootView -> rename ( $keyfile . '.key' , $user . '/files_trashbin/keyfiles/' . $filename . '.key.d' . $timestamp );
2013-04-19 12:31:42 +04:00
}
}
2013-06-14 17:14:23 +04:00
// retain share keys
2013-06-25 19:17:41 +04:00
$sharekeys = \OC\Files\Filesystem :: normalizePath ( $baseDir . '/share-keys/' . $ownerPath );
2013-04-27 02:15:46 +04:00
2013-05-03 15:00:04 +04:00
if ( $rootView -> is_dir ( $sharekeys )) {
$size += self :: calculateSize ( new \OC\Files\View ( $sharekeys ));
2013-11-25 15:51:32 +04:00
if ( $owner !== $user ) {
$rootView -> copy ( $sharekeys , $owner . '/files_trashbin/share-keys/' . basename ( $ownerPath ) . '.d' . $timestamp );
}
2013-06-14 17:14:23 +04:00
$rootView -> rename ( $sharekeys , $user . '/files_trashbin/share-keys/' . $filename . '.d' . $timestamp );
2013-04-27 02:15:46 +04:00
} else {
2013-06-14 17:14:23 +04:00
// get local path to share-keys
2013-06-14 17:07:06 +04:00
$localShareKeysPath = $rootView -> getLocalFile ( $sharekeys );
$escapedLocalShareKeysPath = preg_replace ( '/(\*|\?|\[)/' , '[$1]' , $localShareKeysPath );
2013-04-27 02:15:46 +04:00
2013-06-14 17:14:23 +04:00
// handle share-keys
$matches = glob ( $escapedLocalShareKeysPath . '*.shareKey' );
foreach ( $matches as $src ) {
// get source file parts
$pathinfo = pathinfo ( $src );
2013-04-27 02:15:46 +04:00
2013-11-25 15:51:32 +04:00
// we only want to keep the users key so we can access the private key
$userShareKey = $filename . '.' . $user . '.shareKey' ;
2013-04-27 02:15:46 +04:00
2013-06-14 17:14:23 +04:00
// if we found the share-key for the owner, we need to move it to files_trashbin
2013-11-25 15:51:32 +04:00
if ( $pathinfo [ 'basename' ] == $userShareKey ) {
2013-04-27 02:15:46 +04:00
2013-06-14 17:14:23 +04:00
// calculate size
$size += $rootView -> filesize ( $sharekeys . '.' . $user . '.shareKey' );
2013-04-27 02:15:46 +04:00
2013-06-14 17:14:23 +04:00
// move file
2013-11-25 15:51:32 +04:00
$rootView -> rename ( $sharekeys . '.' . $user . '.shareKey' , $user . '/files_trashbin/share-keys/' . $userShareKey . '.d' . $timestamp );
} elseif ( $owner !== $user ) {
$ownerShareKey = basename ( $ownerPath ) . '.' . $owner . '.shareKey' ;
if ( $pathinfo [ 'basename' ] == $ownerShareKey ) {
$rootView -> rename ( $sharekeys . '.' . $owner . '.shareKey' , $owner . '/files_trashbin/share-keys/' . $ownerShareKey . '.d' . $timestamp );
}
2013-06-14 17:14:23 +04:00
} else {
// don't keep other share-keys
unlink ( $src );
}
}
}
2013-04-20 01:21:06 +04:00
2013-06-14 17:14:23 +04:00
// enable proxy
\OC_FileProxy :: $enabled = $proxyStatus ;
2013-04-19 12:31:42 +04:00
}
return $size ;
}
2013-02-22 20:21:57 +04:00
2013-01-18 16:11:29 +04:00
/**
* restore files from trash bin
2013-01-22 15:00:04 +04:00
* @ param $file path to the deleted file
2013-01-18 16:11:29 +04:00
* @ param $filename name of the file
* @ param $timestamp time when the file was deleted
2013-06-14 17:14:23 +04:00
*
* @ return bool
*/
2013-01-22 15:00:04 +04:00
public static function restore ( $file , $filename , $timestamp ) {
2013-04-22 05:37:55 +04:00
2013-06-14 17:14:23 +04:00
$user = \OCP\User :: getUser ();
$view = new \OC\Files\View ( '/' . $user );
2013-02-21 15:37:13 +04:00
$trashbinSize = self :: getTrashbinSize ( $user );
2013-06-14 17:14:23 +04:00
if ( $trashbinSize === false || $trashbinSize < 0 ) {
$trashbinSize = self :: calculateSize ( new \OC\Files\View ( '/' . $user . '/files_trashbin' ));
2013-02-07 18:16:29 +04:00
}
2013-06-14 17:14:23 +04:00
if ( $timestamp ) {
2013-03-22 15:47:43 +04:00
$query = \OC_DB :: prepare ( 'SELECT `location`,`type` FROM `*PREFIX*files_trash`'
2013-06-14 17:14:23 +04:00
. ' WHERE `user`=? AND `id`=? AND `timestamp`=?' );
$result = $query -> execute ( array ( $user , $filename , $timestamp )) -> fetchAll ();
2013-04-18 20:28:03 +04:00
if ( count ( $result ) !== 1 ) {
2013-01-30 16:04:32 +04:00
\OC_Log :: write ( 'files_trashbin' , 'trash bin database inconsistent!' , \OC_Log :: ERROR );
2013-01-22 15:00:04 +04:00
return false ;
}
2013-02-22 20:21:57 +04:00
2013-01-31 21:04:00 +04:00
// if location no longer exists, restore file in the root directory
$location = $result [ 0 ][ 'location' ];
2013-04-18 20:28:03 +04:00
if ( $result [ 0 ][ 'location' ] !== '/' &&
2013-06-14 17:14:23 +04:00
( ! $view -> is_dir ( 'files' . $result [ 0 ][ 'location' ]) ||
! $view -> isUpdatable ( 'files' . $result [ 0 ][ 'location' ]))) {
2013-01-31 21:04:00 +04:00
$location = '' ;
2013-01-22 15:00:04 +04:00
}
} else {
2013-02-21 01:17:04 +04:00
$path_parts = pathinfo ( $file );
2013-01-22 15:00:04 +04:00
$result [] = array (
2013-06-14 17:14:23 +04:00
'location' => $path_parts [ 'dirname' ],
'type' => $view -> is_dir ( '/files_trashbin/files/' . $file ) ? 'dir' : 'files' ,
);
2013-01-22 15:00:04 +04:00
$location = '' ;
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 );
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
// disable proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy :: $enabled ;
\OC_FileProxy :: $enabled = false ;
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-07-25 18:20:06 +04:00
if ( $view -> is_dir ( $target )) {
$trashbinSize -= self :: calculateSize ( new \OC\Files\View ( '/' . $user . '/' . $target ));
2013-02-07 18:16:29 +04:00
} else {
2013-07-25 18:20:06 +04:00
$trashbinSize -= $view -> filesize ( $target );
2013-02-07 18:16:29 +04:00
}
2013-04-19 12:35:32 +04:00
2013-07-25 18:20:06 +04:00
$trashbinSize -= self :: restoreVersions ( $view , $file , $filename , $uniqueFilename , $location , $timestamp );
$trashbinSize -= self :: restoreEncryptionKeys ( $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
2013-02-21 15:37:13 +04:00
self :: setTrashbinSize ( $user , $trashbinSize );
2013-04-22 05:37:55 +04:00
2013-06-14 17:14:23 +04:00
// enable proxy
\OC_FileProxy :: $enabled = $proxyStatus ;
2013-04-22 05:37:55 +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
2013-06-14 17:14:23 +04:00
// enable proxy
\OC_FileProxy :: $enabled = $proxyStatus ;
2013-04-22 05:37:55 +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
/**
2013-04-19 12:35:32 +04:00
* @ brief restore versions from trash bin
*
2013-04-20 01:21:06 +04:00
* @ param \OC\Files\View $view file view
2013-04-19 12:35:32 +04:00
* @ param $file complete path to file
2013-07-25 18:20:06 +04:00
* @ param $filename name of file once it was deleted
* @ param $uniqueFilename new file name to restore the file without overwriting existing files
2013-04-19 12:35:32 +04:00
* @ param $location location if file
* @ param $timestamp deleteion time
2013-06-14 17:14:23 +04:00
*
2013-04-19 12:35:32 +04:00
* @ return size of restored versions
*/
2013-07-25 18:20:06 +04:00
private static function restoreVersions ( $view , $file , $filename , $uniqueFilename , $location , $timestamp ) {
2013-04-19 12:35:32 +04:00
$size = 0 ;
2013-07-25 18:20:06 +04:00
2013-04-19 12:35:32 +04:00
if ( \OCP\App :: isEnabled ( 'files_versions' )) {
2013-06-14 17:14:23 +04:00
// disable proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy :: $enabled ;
\OC_FileProxy :: $enabled = false ;
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 );
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 )) {
2013-04-19 12:35:32 +04:00
$size += self :: calculateSize ( new \OC\Files\View ( '/' . $user . '/' . 'files_trashbin/versions/' . $file ));
2013-06-14 17:14:23 +04:00
$rootView -> rename ( \OC\Files\Filesystem :: normalizePath ( $user . '/files_trashbin/versions/' . $file ), \OC\Files\Filesystem :: normalizePath ( $owner . '/files_versions/' . $ownerPath ));
2013-04-19 12:35:32 +04:00
} else if ( $versions = self :: getVersionsFromTrash ( $versionedFile , $timestamp )) {
2013-06-14 17:14:23 +04:00
foreach ( $versions as $v ) {
if ( $timestamp ) {
$size += $view -> filesize ( 'files_trashbin/versions/' . $versionedFile . '.v' . $v . '.d' . $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
$size += $view -> filesize ( 'files_trashbin/versions/' . $versionedFile . '.v' . $v );
$rootView -> rename ( $user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v , $owner . '/files_versions/' . $ownerPath . '.v' . $v );
2013-04-19 12:35:32 +04:00
}
}
}
2013-04-28 01:51:26 +04:00
2013-06-14 17:14:23 +04:00
// enable proxy
\OC_FileProxy :: $enabled = $proxyStatus ;
2013-04-19 12:35:32 +04:00
}
return $size ;
}
2013-06-14 17:14:23 +04:00
/**
* @ brief restore encryption keys from trash bin
*
* @ param \OC\Files\View $view
* @ param $file complete path to file
* @ param $filename name of file
2013-07-25 18:20:06 +04:00
* @ param $uniqueFilename new file name to restore the file without overwriting existing files
2013-06-14 17:14:23 +04:00
* @ param $location location of file
* @ param $timestamp deleteion time
*
* @ return size of restored encrypted file
*/
2013-07-25 18:20:06 +04:00
private static function restoreEncryptionKeys ( $view , $file , $filename , $uniqueFilename , $location , $timestamp ) {
2013-04-19 12:35:32 +04:00
// Take care of encryption keys TODO! Get '.key' in file between file name and delete date (also for permanent delete!)
$size = 0 ;
if ( \OCP\App :: isEnabled ( 'files_encryption' )) {
$user = \OCP\User :: getUser ();
2013-05-03 16:03:42 +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 16:03:42 +04:00
list ( $owner , $ownerPath ) = self :: getUidAndFilename ( $target );
2013-04-20 01:21:06 +04:00
2013-06-25 19:17:41 +04:00
$util = new \OCA\Encryption\Util ( new \OC_FilesystemView ( '/' ), $user );
if ( $util -> isSystemWideMountPoint ( $ownerPath )) {
$baseDir = '/files_encryption/' ;
} else {
$baseDir = $owner . '/files_encryption/' ;
}
2013-06-14 17:14:23 +04:00
$path_parts = pathinfo ( $file );
$source_location = $path_parts [ 'dirname' ];
2013-04-27 02:15:46 +04:00
2013-06-14 17:14:23 +04:00
if ( $view -> is_dir ( '/files_trashbin/keyfiles/' . $file )) {
if ( $source_location != '.' ) {
$keyfile = \OC\Files\Filesystem :: normalizePath ( $user . '/files_trashbin/keyfiles/' . $source_location . '/' . $filename );
$sharekey = \OC\Files\Filesystem :: normalizePath ( $user . '/files_trashbin/share-keys/' . $source_location . '/' . $filename );
2013-04-19 12:35:32 +04:00
} else {
2013-06-14 17:14:23 +04:00
$keyfile = \OC\Files\Filesystem :: normalizePath ( $user . '/files_trashbin/keyfiles/' . $filename );
$sharekey = \OC\Files\Filesystem :: normalizePath ( $user . '/files_trashbin/share-keys/' . $filename );
}
} else {
$keyfile = \OC\Files\Filesystem :: normalizePath ( $user . '/files_trashbin/keyfiles/' . $source_location . '/' . $filename . '.key' );
}
if ( $timestamp ) {
$keyfile .= '.d' . $timestamp ;
2013-11-25 15:51:32 +04:00
$sharekey .= '.d' . $timestamp ;
2013-06-14 17:14:23 +04:00
}
// disable proxy to prevent recursive calls
$proxyStatus = \OC_FileProxy :: $enabled ;
\OC_FileProxy :: $enabled = false ;
if ( $rootView -> file_exists ( $keyfile )) {
// handle directory
if ( $rootView -> is_dir ( $keyfile )) {
2013-04-27 02:15:46 +04:00
2013-06-14 17:14:23 +04:00
// handle keyfiles
$size += self :: calculateSize ( new \OC\Files\View ( $keyfile ));
2013-06-25 19:17:41 +04:00
$rootView -> rename ( $keyfile , $baseDir . '/keyfiles/' . $ownerPath );
2013-06-14 17:14:23 +04:00
// handle share-keys
$size += self :: calculateSize ( new \OC\Files\View ( $sharekey ));
2013-06-25 19:17:41 +04:00
$rootView -> rename ( $sharekey , $baseDir . '/share-keys/' . $ownerPath );
2013-04-19 12:35:32 +04:00
} else {
2013-06-14 17:14:23 +04:00
// handle keyfiles
2013-05-03 16:03:42 +04:00
$size += $rootView -> filesize ( $keyfile );
2013-06-25 19:17:41 +04:00
$rootView -> rename ( $keyfile , $baseDir . '/keyfiles/' . $ownerPath . '.key' );
2013-04-27 02:15:46 +04:00
2013-06-14 17:14:23 +04:00
// handle share-keys
$ownerShareKey = \OC\Files\Filesystem :: normalizePath ( $user . '/files_trashbin/share-keys/' . $source_location . '/' . $filename . '.' . $user . '.shareKey' );
if ( $timestamp ) {
$ownerShareKey .= '.d' . $timestamp ;
}
2013-04-27 02:15:46 +04:00
2013-06-14 17:14:23 +04:00
$size += $rootView -> filesize ( $ownerShareKey );
2013-04-27 02:15:46 +04:00
2013-06-14 17:14:23 +04:00
// move only owners key
2013-06-25 19:17:41 +04:00
$rootView -> rename ( $ownerShareKey , $baseDir . '/share-keys/' . $ownerPath . '.' . $user . '.shareKey' );
2013-04-27 02:15:46 +04:00
2013-06-14 17:14:23 +04:00
// try to re-share if file is shared
$filesystemView = new \OC_FilesystemView ( '/' );
$session = new \OCA\Encryption\Session ( $filesystemView );
$util = new \OCA\Encryption\Util ( $filesystemView , $user );
2013-04-27 02:15:46 +04:00
2013-06-14 17:14:23 +04:00
// fix the file size
$absolutePath = \OC\Files\Filesystem :: normalizePath ( '/' . $owner . '/files/' . $ownerPath );
$util -> fixFileSize ( $absolutePath );
2013-04-27 02:15:46 +04:00
2013-06-14 17:14:23 +04:00
// get current sharing state
$sharingEnabled = \OCP\Share :: isEnabled ();
2013-04-27 02:15:46 +04:00
2013-06-14 17:14:23 +04:00
// get users sharing this file
2013-07-25 18:20:06 +04:00
$usersSharing = $util -> getSharingUsersArray ( $sharingEnabled , $target , $user );
2013-04-27 02:15:46 +04:00
2013-06-14 17:14:23 +04:00
// Attempt to set shareKey
2013-07-25 18:20:06 +04:00
$util -> setSharedFileKeyfiles ( $session , $usersSharing , $target );
2013-04-19 12:35:32 +04:00
}
}
2013-06-14 17:14:23 +04:00
// enable proxy
\OC_FileProxy :: $enabled = $proxyStatus ;
2013-04-19 12:35:32 +04:00
}
return $size ;
}
2013-02-08 03:11:54 +04:00
/**
2013-04-20 01:21:06 +04:00
* @ brief delete file from trash bin permanently
2013-06-14 17:14:23 +04:00
*
2013-02-06 19:23:22 +04:00
* @ param $filename path to the file
2013-02-08 03:11:54 +04:00
* @ param $timestamp of deletion time
2013-06-14 17:14:23 +04:00
*
2013-02-22 20:21:57 +04:00
* @ return size of deleted files
2013-02-08 03:11:54 +04:00
*/
2013-06-14 17:14:23 +04:00
public static function delete ( $filename , $timestamp = null ) {
2013-02-08 03:11:54 +04:00
$user = \OCP\User :: getUser ();
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
2013-02-21 15:37:13 +04:00
$trashbinSize = self :: getTrashbinSize ( $user );
2013-06-14 17:14:23 +04:00
if ( $trashbinSize === false || $trashbinSize < 0 ) {
$trashbinSize = self :: calculateSize ( new \OC\Files\View ( '/' . $user . '/files_trashbin' ));
2013-02-07 18:16:29 +04:00
}
2013-02-22 20:21:57 +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 ));
$file = $filename . '.d' . $timestamp ;
2013-02-06 19:23:22 +04:00
} else {
$file = $filename ;
}
2013-02-22 20:21:57 +04:00
2013-05-03 18:33:18 +04:00
$size += self :: deleteVersions ( $view , $file , $filename , $timestamp );
$size += self :: deleteEncryptionKeys ( $view , $file , $filename , $timestamp );
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
}
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-05-03 18:33:18 +04:00
$trashbinSize -= $size ;
self :: setTrashbinSize ( $user , $trashbinSize );
2013-06-14 17:14:23 +04:00
2013-05-03 18:33:18 +04:00
return $size ;
}
private static function deleteVersions ( $view , $file , $filename , $timestamp ) {
$size = 0 ;
2013-06-14 17:14:23 +04:00
if ( \OCP\App :: isEnabled ( 'files_versions' )) {
2013-05-03 18:33:18 +04:00
$user = \OCP\User :: getUser ();
2013-06-14 17:14:23 +04:00
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 );
} else if ( $versions = self :: getVersionsFromTrash ( $filename , $timestamp )) {
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 ;
}
private static function deleteEncryptionKeys ( $view , $file , $filename , $timestamp ) {
$size = 0 ;
if ( \OCP\App :: isEnabled ( 'files_encryption' )) {
$user = \OCP\User :: getUser ();
if ( $view -> is_dir ( '/files_trashbin/files/' . $file )) {
$keyfile = \OC\Files\Filesystem :: normalizePath ( 'files_trashbin/keyfiles/' . $filename );
2013-06-14 17:14:23 +04:00
$sharekeys = \OC\Files\Filesystem :: normalizePath ( 'files_trashbin/share-keys/' . $filename );
2013-02-25 17:29:31 +04:00
} else {
2013-05-03 18:33:18 +04:00
$keyfile = \OC\Files\Filesystem :: normalizePath ( 'files_trashbin/keyfiles/' . $filename . '.key' );
2013-06-14 17:14:23 +04:00
$sharekeys = \OC\Files\Filesystem :: normalizePath ( 'files_trashbin/share-keys/' . $filename . '.' . $user . '.shareKey' );
2013-05-03 18:33:18 +04:00
}
if ( $timestamp ) {
$keyfile .= '.d' . $timestamp ;
$sharekeys .= '.d' . $timestamp ;
}
if ( $view -> file_exists ( $keyfile )) {
if ( $view -> is_dir ( $keyfile )) {
$size += self :: calculateSize ( new \OC\Files\View ( '/' . $user . '/' . $keyfile ));
$size += self :: calculateSize ( new \OC\Files\View ( '/' . $user . '/' . $sharekeys ));
} else {
$size += $view -> filesize ( $keyfile );
$size += $view -> filesize ( $sharekeys );
}
$view -> unlink ( $keyfile );
$view -> unlink ( $sharekeys );
2013-02-25 17:29:31 +04:00
}
2013-02-07 18:16:29 +04:00
}
2013-02-22 20:21:57 +04:00
return $size ;
2013-02-06 19:23:22 +04:00
}
2013-02-17 02:42:06 +04:00
/**
* check to see whether a file exists in trashbin
2013-02-18 18:49:50 +04:00
* @ param $filename path to the file
* @ param $timestamp of deletion time
2013-02-17 02:42:06 +04:00
* @ return true if file exists , otherwise false
*/
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
/**
* @ brief deletes used space for trash bin in db if user was deleted
*
* @ param type $uid id of deleted user
* @ return result of db delete operation
*/
public static function deleteUser ( $uid ) {
$query = \OC_DB :: prepare ( 'DELETE FROM `*PREFIX*files_trash` WHERE `user`=?' );
$result = $query -> execute ( array ( $uid ));
if ( $result ) {
$query = \OC_DB :: prepare ( 'DELETE FROM `*PREFIX*files_trashsize` WHERE `user`=?' );
return $query -> execute ( array ( $uid ));
}
return false ;
}
2013-04-16 15:51:53 +04:00
/**
* calculate remaining free space for trash bin
*
* @ param $trashbinSize current size of the trash bin
* @ return available free space for trash bin
*/
private static function calculateFreeSpace ( $trashbinSize ) {
$softQuota = true ;
$user = \OCP\User :: getUser ();
$quota = \OC_Preferences :: getValue ( $user , 'files' , 'quota' );
2013-06-14 17:14:23 +04:00
$view = new \OC\Files\View ( '/' . $user );
if ( $quota === null || $quota === 'default' ) {
2013-04-16 15:51:53 +04:00
$quota = \OC_Appconfig :: getValue ( 'files' , 'default_quota' );
}
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 ;
} 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 ) {
$rootInfo = $view -> getFileInfo ( '/files/' );
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
/**
* @ brief resize trash bin if necessary after a new file was added to ownCloud
* @ param string $user user id
*/
public static function resizeTrash ( $user ) {
$size = self :: getTrashbinSize ( $user );
if ( $size === false || $size < 0 ) {
$size = self :: calculateSize ( new \OC\Files\View ( '/' . $user . '/files_trashbin' ));
}
$freeSpace = self :: calculateFreeSpace ( $size );
if ( $freeSpace < 0 ) {
2013-11-25 15:51:32 +04:00
$newSize = $size - self :: expire ( $size , $user );
2013-07-26 13:45:38 +04:00
if ( $newSize !== $size ) {
self :: setTrashbinSize ( $user , $newSize );
}
}
}
2013-08-27 16:39:43 +04:00
2013-01-31 21:04:00 +04:00
/**
* clean up the trash bin
2013-11-25 15:51:32 +04:00
* @ param int $trashbinSize current size of the trash bin
* @ param string $user
* @ return int size of expired files
2013-01-31 21:04:00 +04:00
*/
2013-11-25 15:51:32 +04:00
private static function expire ( $trashbinSize , $user ) {
2013-02-22 20:21:57 +04:00
2013-01-18 18:12:38 +04:00
$user = \OCP\User :: getUser ();
2013-06-14 17:14:23 +04:00
$view = new \OC\Files\View ( '/' . $user );
2013-04-16 15:51:53 +04:00
$availableSpace = self :: calculateFreeSpace ( $trashbinSize );
2013-02-07 18:16:29 +04:00
$size = 0 ;
2013-02-22 20:21:57 +04:00
2013-03-22 15:47:43 +04:00
$query = \OC_DB :: prepare ( 'SELECT `location`,`type`,`id`,`timestamp` FROM `*PREFIX*files_trash` WHERE `user`=?' );
2013-01-18 18:12:38 +04:00
$result = $query -> execute ( array ( $user )) -> fetchAll ();
2013-02-22 20:21:57 +04:00
2013-06-14 17:14:23 +04:00
$retention_obligation = \OC_Config :: getValue ( 'trashbin_retention_obligation' , self :: DEFAULT_RETENTION_OBLIGATION );
2013-02-22 20:21:57 +04:00
2013-01-22 16:19:41 +04:00
$limit = time () - ( $retention_obligation * 86400 );
2013-01-18 18:12:38 +04:00
2013-06-14 17:14:23 +04:00
foreach ( $result as $r ) {
2013-01-18 18:12:38 +04:00
$timestamp = $r [ 'timestamp' ];
$filename = $r [ 'id' ];
2013-06-14 17:14:23 +04:00
if ( $r [ 'timestamp' ] < $limit ) {
2013-02-20 21:00:15 +04:00
$size += self :: delete ( $filename , $timestamp );
2013-06-14 17:14:23 +04:00
\OC_Log :: write ( 'files_trashbin' , 'remove "' . $filename . '" fom trash bin because it is older than ' . $retention_obligation , \OC_log :: INFO );
2013-01-18 18:12:38 +04:00
}
}
2013-06-10 13:03:07 +04:00
$availableSpace += $size ;
2013-02-09 14:07:47 +04:00
// if size limit for trash bin reached, delete oldest files in trash bin
2013-02-07 20:37:46 +04:00
if ( $availableSpace < 0 ) {
2013-03-22 15:47:43 +04:00
$query = \OC_DB :: prepare ( 'SELECT `location`,`type`,`id`,`timestamp` FROM `*PREFIX*files_trash`'
2013-06-14 17:14:23 +04:00
. ' WHERE `user`=? ORDER BY `timestamp` ASC' );
2013-02-07 20:37:46 +04:00
$result = $query -> execute ( array ( $user )) -> fetchAll ();
$length = count ( $result );
$i = 0 ;
2013-06-14 17:14:23 +04:00
while ( $i < $length && $availableSpace < 0 ) {
2013-02-07 20:37:46 +04:00
$tmp = self :: delete ( $result [ $i ][ 'id' ], $result [ $i ][ 'timestamp' ]);
2013-06-14 17:14:23 +04:00
\OC_Log :: write ( 'files_trashbin' , 'remove "' . $result [ $i ][ 'id' ] . '" (' . $tmp . 'B) to meet the limit of trash bin size (50% of available quota)' , \OC_log :: INFO );
2013-02-07 20:37:46 +04:00
$availableSpace += $tmp ;
$size += $tmp ;
$i ++ ;
}
}
2013-02-22 20:21:57 +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
/**
* recursive copy to copy a whole directory
2013-02-22 20:21:57 +04:00
*
2013-01-18 16:11:29 +04:00
* @ param $source source path , relative to the users files directory
* @ param $destination destination path relative to the users root directoy
* @ param $view file view for the users root directory
*/
2013-06-14 17:14:23 +04:00
private static function copy_recursive ( $source , $destination , $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 );
$view -> copy ( $pathDir , $destination . '/' . $i [ 'name' ]);
$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 );
$view -> copy ( $source , $destination );
$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
* @ param $filename name of the file which should be restored
* @ param $timestamp timestamp when the file was deleted
*/
private static function getVersionsFromTrash ( $filename , $timestamp ) {
2013-06-14 17:14:23 +04:00
$view = new \OC\Files\View ( '/' . \OCP\User :: getUser () . '/files_trashbin/versions' );
$versionsName = $view -> getLocalFile ( $filename ) . '.v' ;
2013-06-14 17:07:06 +04:00
$escapedVersionsName = preg_replace ( '/(\*|\?|\[)/' , '[$1]' , $versionsName );
2013-01-31 21:04:00 +04:00
$versions = array ();
2013-06-14 17:14:23 +04:00
if ( $timestamp ) {
2013-02-09 20:27:57 +04:00
// fetch for old versions
2013-06-14 17:14:23 +04:00
$matches = glob ( $escapedVersionsName . '*.d' . $timestamp );
$offset = - strlen ( $timestamp ) - 2 ;
2013-01-22 15:00:04 +04:00
} else {
2013-06-14 17:14:23 +04:00
$matches = glob ( $escapedVersionsName . '*' );
2013-01-31 21:04:00 +04:00
}
2013-02-22 20:21:57 +04:00
2013-06-14 17:14:23 +04:00
foreach ( $matches as $ma ) {
if ( $timestamp ) {
$parts = explode ( '.v' , substr ( $ma , 0 , $offset ));
$versions [] = ( end ( $parts ) );
2013-01-22 15:00:04 +04:00
} else {
2013-06-14 17:14:23 +04:00
$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
* @ param $location where the file should be restored
* @ param $filename name of the file
* @ param $view filesystem view relative to users root directory
* @ return string with unique extension
*/
2013-07-25 18:20:06 +04:00
private static function getUniqueFilename ( $location , $filename , $view ) {
$ext = pathinfo ( $filename , PATHINFO_EXTENSION );
$name = pathinfo ( $filename , PATHINFO_FILENAME );
2013-07-26 14:01:45 +04:00
$l = \OC_L10N :: get ( 'files_trashbin' );
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 ;
2013-07-26 14:01:45 +04:00
$uniqueName = $name . " ( " . $l -> t ( " restored " ) . " ) " . $ext ;
2013-07-25 18:20:06 +04:00
while ( $view -> file_exists ( 'files' . $location . '/' . $uniqueName )) {
2013-07-26 14:01:45 +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
/**
2013-02-07 18:16:29 +04:00
* @ brief get the size from a given root folder
2013-02-22 20:21:57 +04:00
* @ param $view file view on the root folder
* @ return size of the folder
*/
private static function calculateSize ( $view ) {
2013-06-14 17:14:23 +04:00
$root = \OCP\Config :: 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 ;
2013-02-07 18:16:29 +04:00
foreach ( $iterator as $path ) {
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
}
}
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
*
* @ param $user user who owns the trash bin
* @ return mixed trash bin size or false if no trash bin size is stored
*/
private static function getTrashbinSize ( $user ) {
2013-03-22 15:47:43 +04:00
$query = \OC_DB :: prepare ( 'SELECT `size` FROM `*PREFIX*files_trashsize` WHERE `user`=?' );
2013-02-25 17:29:31 +04:00
$result = $query -> execute ( array ( $user )) -> fetchAll ();
if ( $result ) {
2013-07-26 13:45:38 +04:00
return ( int ) $result [ 0 ][ 'size' ];
2013-02-25 17:29:31 +04:00
}
return false ;
}
2013-06-14 17:14:23 +04:00
2013-02-25 17:29:31 +04:00
/**
* write to the database how much space is in use for the trash bin
*
* @ param $user owner of the trash bin
* @ param $size size of the trash bin
*/
private static function setTrashbinSize ( $user , $size ) {
2013-06-14 17:14:23 +04:00
if ( self :: getTrashbinSize ( $user ) === false ) {
2013-03-22 15:47:43 +04:00
$query = \OC_DB :: prepare ( 'INSERT INTO `*PREFIX*files_trashsize` (`size`, `user`) VALUES (?, ?)' );
2013-06-14 17:14:23 +04:00
} else {
2013-03-22 15:47:43 +04:00
$query = \OC_DB :: prepare ( 'UPDATE `*PREFIX*files_trashsize` SET `size`=? WHERE `user`=?' );
2013-02-25 17:29:31 +04:00
}
$query -> execute ( array ( $size , $user ));
2013-02-21 15:37:13 +04:00
}
2013-05-23 01:50:45 +04:00
/**
* register hooks
*/
public static function registerHooks () {
//Listen to delete file signal
\OCP\Util :: connectHook ( 'OC_Filesystem' , 'delete' , " OCA \ Files_Trashbin \ Hooks " , " remove_hook " );
//Listen to delete user signal
\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
\OCP\Util :: connectHook ( 'OC_Filesystem' , 'post_write' , " OCA \ Files_Trashbin \ Hooks " , " post_write_hook " );
2013-05-23 01:50:45 +04:00
}
2013-08-27 16:39:43 +04:00
2013-07-26 13:13:43 +04:00
/**
* @ brief check if trash bin is empty for a given user
* @ param string $user
*/
public static function isEmpty ( $user ) {
2013-08-27 16:39:43 +04:00
$view = new \OC\Files\View ( '/' . $user . '/files_trashbin' );
$content = $view -> getDirectoryContent ( '/files' );
2013-07-26 13:13:43 +04:00
2013-08-27 16:39:43 +04:00
if ( $content ) {
2013-07-26 13:13:43 +04:00
return false ;
}
return true ;
2013-05-23 01:50:45 +04:00
}
2013-07-08 12:53:53 +04:00
public static function preview_icon ( $path ) {
2013-07-29 18:27:40 +04:00
return \OC_Helper :: linkToRoute ( 'core_ajax_trashbin_preview' , array ( 'x' => 36 , 'y' => 36 , 'file' => urlencode ( $path ) ));
2013-07-08 12:53:53 +04:00
}
2013-01-31 21:04:00 +04:00
}