Blame view

sources/apps/files_trashbin/lib/trashbin.php 33.3 KB
03e52840d   Kload   Init
1
  <?php
03e52840d   Kload   Init
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /**
   * 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/>.
   *
   */
  
  namespace OCA\Files_Trashbin;
  
  class Trashbin {
  	// how long do we keep files in the trash bin if no other value is defined in the config file (unit: days)
31b7f2792   Kload   Upgrade to ownclo...
27
  	const DEFAULT_RETENTION_OBLIGATION = 30;
03e52840d   Kload   Init
28
29
30
31
32
33
34
35
36
37
38
39
40
41
  
  	// unit: percentage; 50% of available disk space/quota
  	const DEFAULTMAXSIZE = 50;
  
  	public static function getUidAndFilename($filename) {
  		$uid = \OC\Files\Filesystem::getOwner($filename);
  		\OC\Files\Filesystem::initMountPoints($uid);
  		if ($uid != \OCP\User::getUser()) {
  			$info = \OC\Files\Filesystem::getFileInfo($filename);
  			$ownerView = new \OC\Files\View('/' . $uid . '/files');
  			$filename = $ownerView->getPath($info['fileid']);
  		}
  		return array($uid, $filename);
  	}
31b7f2792   Kload   Upgrade to ownclo...
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  	private static function setUpTrash($user) {
  		$view = new \OC\Files\View('/' . $user);
  		if (!$view->is_dir('files_trashbin')) {
  			$view->mkdir('files_trashbin');
  		}
  		if (!$view->is_dir('files_trashbin/files')) {
  			$view->mkdir('files_trashbin/files');
  		}
  		if (!$view->is_dir('files_trashbin/versions')) {
  			$view->mkdir('files_trashbin/versions');
  		}
  		if (!$view->is_dir('files_trashbin/keyfiles')) {
  			$view->mkdir('files_trashbin/keyfiles');
  		}
  		if (!$view->is_dir('files_trashbin/share-keys')) {
  			$view->mkdir('files_trashbin/share-keys');
  		}
  	}
6d9380f96   Cédric Dupont   Update sources OC...
60
61
62
63
64
65
66
67
  	/**
  	 * copy file to owners trash
  	 * @param string $sourcePath
  	 * @param string $owner
  	 * @param string $ownerPath
  	 * @param integer $timestamp
  	 */
  	private static function copyFilesToOwner($sourcePath, $owner, $ownerPath, $timestamp) {
31b7f2792   Kload   Upgrade to ownclo...
68
69
70
71
72
73
74
75
  		self::setUpTrash($owner);
  
  		$ownerFilename = basename($ownerPath);
  		$ownerLocation = dirname($ownerPath);
  
  		$sourceFilename = basename($sourcePath);
  
  		$view = new \OC\Files\View('/');
6d9380f96   Cédric Dupont   Update sources OC...
76
77
  		$source = \OCP\User::getUser() . '/files_trashbin/files/' . $sourceFilename . '.d' . $timestamp;
  		$target = $owner . '/files_trashbin/files/' . $ownerFilename . '.d' . $timestamp;
31b7f2792   Kload   Upgrade to ownclo...
78
79
80
81
  		self::copy_recursive($source, $target, $view);
  
  
  		if ($view->file_exists($target)) {
6d9380f96   Cédric Dupont   Update sources OC...
82
83
84
  			$query = \OC_DB::prepare("INSERT INTO `*PREFIX*files_trash` (`id`,`timestamp`,`location`,`user`) VALUES (?,?,?,?)");
  			$result = $query->execute(array($ownerFilename, $timestamp, $ownerLocation, $owner));
  			if (!$result) {
31b7f2792   Kload   Upgrade to ownclo...
85
  				\OC_Log::write('files_trashbin', 'trash bin database couldn\'t be updated for the files owner', \OC_log::ERROR);
31b7f2792   Kload   Upgrade to ownclo...
86
87
88
  			}
  		}
  	}
03e52840d   Kload   Init
89
90
91
  	/**
  	 * move file to the trash bin
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
92
  	 * @param string $file_path path to the deleted file/directory relative to the files root directory
03e52840d   Kload   Init
93
94
95
  	 */
  	public static function move2trash($file_path) {
  		$user = \OCP\User::getUser();
31b7f2792   Kload   Upgrade to ownclo...
96
97
98
  		$size = 0;
  		list($owner, $ownerPath) = self::getUidAndFilename($file_path);
  		self::setUpTrash($user);
03e52840d   Kload   Init
99

31b7f2792   Kload   Upgrade to ownclo...
100
  		$view = new \OC\Files\View('/' . $user);
03e52840d   Kload   Init
101
102
103
104
105
  		$path_parts = pathinfo($file_path);
  
  		$filename = $path_parts['basename'];
  		$location = $path_parts['dirname'];
  		$timestamp = time();
03e52840d   Kload   Init
106

31b7f2792   Kload   Upgrade to ownclo...
107
  		$userTrashSize = self::getTrashbinSize($user);
03e52840d   Kload   Init
108
109
110
111
  
  		// disable proxy to prevent recursive calls
  		$proxyStatus = \OC_FileProxy::$enabled;
  		\OC_FileProxy::$enabled = false;
31b7f2792   Kload   Upgrade to ownclo...
112
  		$trashPath = '/files_trashbin/files/' . $filename . '.d' . $timestamp;
6d9380f96   Cédric Dupont   Update sources OC...
113
114
115
116
117
118
119
120
121
  		try {
  			$sizeOfAddedFiles = self::copy_recursive('/files/'.$file_path, $trashPath, $view);
  		} catch (\OCA\Files_Trashbin\Exceptions\CopyRecursiveException $e) {
  			$sizeOfAddedFiles = false;
  			if ($view->file_exists($trashPath)) {
  				$view->deleteAll($trashPath);
  			}
  			\OC_Log::write('files_trashbin', 'Couldn\'t move ' . $file_path . ' to the trash bin', \OC_log::ERROR);
  		}
03e52840d   Kload   Init
122
  		\OC_FileProxy::$enabled = $proxyStatus;
6d9380f96   Cédric Dupont   Update sources OC...
123
  		if ($sizeOfAddedFiles !== false) {
31b7f2792   Kload   Upgrade to ownclo...
124
  			$size = $sizeOfAddedFiles;
6d9380f96   Cédric Dupont   Update sources OC...
125
126
127
  			$query = \OC_DB::prepare("INSERT INTO `*PREFIX*files_trash` (`id`,`timestamp`,`location`,`user`) VALUES (?,?,?,?)");
  			$result = $query->execute(array($filename, $timestamp, $location, $user));
  			if (!$result) {
03e52840d   Kload   Init
128
  				\OC_Log::write('files_trashbin', 'trash bin database couldn\'t be updated', \OC_log::ERROR);
03e52840d   Kload   Init
129
130
131
  			}
  			\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)));
31b7f2792   Kload   Upgrade to ownclo...
132
133
134
135
136
  			$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) {
6d9380f96   Cédric Dupont   Update sources OC...
137
  				self::copyFilesToOwner($file_path, $owner, $ownerPath, $timestamp);
31b7f2792   Kload   Upgrade to ownclo...
138
  			}
03e52840d   Kload   Init
139
  		}
31b7f2792   Kload   Upgrade to ownclo...
140
141
  		$userTrashSize += $size;
  		$userTrashSize -= self::expire($userTrashSize, $user);
03e52840d   Kload   Init
142

31b7f2792   Kload   Upgrade to ownclo...
143
  		// if owner !== user we also need to update the owners trash size
6d9380f96   Cédric Dupont   Update sources OC...
144
  		if ($owner !== $user) {
31b7f2792   Kload   Upgrade to ownclo...
145
  			$ownerTrashSize = self::getTrashbinSize($owner);
31b7f2792   Kload   Upgrade to ownclo...
146
147
  			$ownerTrashSize += $size;
  			$ownerTrashSize -= self::expire($ownerTrashSize, $owner);
31b7f2792   Kload   Upgrade to ownclo...
148
  		}
03e52840d   Kload   Init
149
150
151
152
153
  	}
  
  	/**
  	 * Move file versions to trash so that they can be restored later
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
154
155
156
  	 * @param string $file_path path to original file
  	 * @param string $filename of deleted file
  	 * @param integer $timestamp when the file was deleted
03e52840d   Kload   Init
157
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
158
  	 * @return int size of stored versions
03e52840d   Kload   Init
159
  	 */
31b7f2792   Kload   Upgrade to ownclo...
160
  	private static function retainVersions($file_path, $filename, $timestamp) {
03e52840d   Kload   Init
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  		$size = 0;
  		if (\OCP\App::isEnabled('files_versions')) {
  
  			// disable proxy to prevent recursive calls
  			$proxyStatus = \OC_FileProxy::$enabled;
  			\OC_FileProxy::$enabled = false;
  
  			$user = \OCP\User::getUser();
  			$rootView = new \OC\Files\View('/');
  
  			list($owner, $ownerPath) = self::getUidAndFilename($file_path);
  
  			if ($rootView->is_dir($owner . '/files_versions/' . $ownerPath)) {
  				$size += self::calculateSize(new \OC\Files\View('/' . $owner . '/files_versions/' . $ownerPath));
31b7f2792   Kload   Upgrade to ownclo...
175
  				if ($owner !== $user) {
a293d369c   Kload   Update sources to...
176
  					self::copy_recursive($owner . '/files_versions/' . $ownerPath, $owner . '/files_trashbin/versions/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
31b7f2792   Kload   Upgrade to ownclo...
177
  				}
03e52840d   Kload   Init
178
179
180
181
  				$rootView->rename($owner . '/files_versions/' . $ownerPath, $user . '/files_trashbin/versions/' . $filename . '.d' . $timestamp);
  			} else if ($versions = \OCA\Files_Versions\Storage::getVersions($owner, $ownerPath)) {
  				foreach ($versions as $v) {
  					$size += $rootView->filesize($owner . '/files_versions' . $v['path'] . '.v' . $v['version']);
31b7f2792   Kload   Upgrade to ownclo...
182
183
184
  					if ($owner !== $user) {
  						$rootView->copy($owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $owner . '/files_trashbin/versions/' . $v['name'] . '.v' . $v['version'] . '.d' . $timestamp);
  					}
03e52840d   Kload   Init
185
186
187
188
189
190
191
192
193
194
195
196
197
198
  					$rootView->rename($owner . '/files_versions' . $v['path'] . '.v' . $v['version'], $user . '/files_trashbin/versions/' . $filename . '.v' . $v['version'] . '.d' . $timestamp);
  				}
  			}
  
  			// enable proxy
  			\OC_FileProxy::$enabled = $proxyStatus;
  		}
  
  		return $size;
  	}
  
  	/**
  	 * Move encryption keys to trash so that they can be restored later
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
199
200
201
  	 * @param string $file_path path to original file
  	 * @param string $filename of deleted file
  	 * @param integer $timestamp when the file was deleted
03e52840d   Kload   Init
202
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
203
  	 * @return int size of encryption keys
03e52840d   Kload   Init
204
  	 */
31b7f2792   Kload   Upgrade to ownclo...
205
  	private static function retainEncryptionKeys($file_path, $filename, $timestamp) {
03e52840d   Kload   Init
206
207
208
209
210
211
212
213
  		$size = 0;
  
  		if (\OCP\App::isEnabled('files_encryption')) {
  
  			$user = \OCP\User::getUser();
  			$rootView = new \OC\Files\View('/');
  
  			list($owner, $ownerPath) = self::getUidAndFilename($file_path);
6d9380f96   Cédric Dupont   Update sources OC...
214
  			$util = new \OCA\Encryption\Util(new \OC\Files\View('/'), $user);
03e52840d   Kload   Init
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  
  			// disable proxy to prevent recursive calls
  			$proxyStatus = \OC_FileProxy::$enabled;
  			\OC_FileProxy::$enabled = false;
  
  			if ($util->isSystemWideMountPoint($ownerPath)) {
  				$baseDir = '/files_encryption/';
  			} else {
  				$baseDir = $owner . '/files_encryption/';
  			}
  
  			$keyfile = \OC\Files\Filesystem::normalizePath($baseDir . '/keyfiles/' . $ownerPath);
  
  			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));
31b7f2792   Kload   Upgrade to ownclo...
232
  					if ($owner !== $user) {
a293d369c   Kload   Update sources to...
233
  						self::copy_recursive($keyfile, $owner . '/files_trashbin/keyfiles/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
31b7f2792   Kload   Upgrade to ownclo...
234
  					}
03e52840d   Kload   Init
235
236
237
  					$rootView->rename($keyfile, $user . '/files_trashbin/keyfiles/' . $filename . '.d' . $timestamp);
  				} else {
  					$size += $rootView->filesize($keyfile . '.key');
31b7f2792   Kload   Upgrade to ownclo...
238
239
240
  					if ($owner !== $user) {
  						$rootView->copy($keyfile . '.key', $owner . '/files_trashbin/keyfiles/' . basename($ownerPath) . '.key.d' . $timestamp);
  					}
03e52840d   Kload   Init
241
242
243
244
245
246
247
248
249
  					$rootView->rename($keyfile . '.key', $user . '/files_trashbin/keyfiles/' . $filename . '.key.d' . $timestamp);
  				}
  			}
  
  			// retain share keys
  			$sharekeys = \OC\Files\Filesystem::normalizePath($baseDir . '/share-keys/' . $ownerPath);
  
  			if ($rootView->is_dir($sharekeys)) {
  				$size += self::calculateSize(new \OC\Files\View($sharekeys));
31b7f2792   Kload   Upgrade to ownclo...
250
  				if ($owner !== $user) {
a293d369c   Kload   Update sources to...
251
  					self::copy_recursive($sharekeys, $owner . '/files_trashbin/share-keys/' . basename($ownerPath) . '.d' . $timestamp, $rootView);
31b7f2792   Kload   Upgrade to ownclo...
252
  				}
03e52840d   Kload   Init
253
254
  				$rootView->rename($sharekeys, $user . '/files_trashbin/share-keys/' . $filename . '.d' . $timestamp);
  			} else {
31b7f2792   Kload   Upgrade to ownclo...
255
  				// get local path to share-keys
03e52840d   Kload   Init
256
257
  				$localShareKeysPath = $rootView->getLocalFile($sharekeys);
  				$escapedLocalShareKeysPath = preg_replace('/(\*|\?|\[)/', '[$1]', $localShareKeysPath);
31b7f2792   Kload   Upgrade to ownclo...
258
259
260
261
262
  				// handle share-keys
  				$matches = glob($escapedLocalShareKeysPath . '*.shareKey');
  				foreach ($matches as $src) {
  					// get source file parts
  					$pathinfo = pathinfo($src);
03e52840d   Kload   Init
263

31b7f2792   Kload   Upgrade to ownclo...
264
265
  					// we only want to keep the users key so we can access the private key
  					$userShareKey = $filename . '.' . $user . '.shareKey';
03e52840d   Kload   Init
266
267
  
  					// if we found the share-key for the owner, we need to move it to files_trashbin
31b7f2792   Kload   Upgrade to ownclo...
268
  					if ($pathinfo['basename'] == $userShareKey) {
03e52840d   Kload   Init
269
270
271
272
273
  
  						// calculate size
  						$size += $rootView->filesize($sharekeys . '.' . $user . '.shareKey');
  
  						// move file
31b7f2792   Kload   Upgrade to ownclo...
274
275
276
277
278
279
  						$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);
  						}
03e52840d   Kload   Init
280
  					} else {
03e52840d   Kload   Init
281
282
283
284
285
286
287
288
289
290
291
292
293
294
  						// don't keep other share-keys
  						unlink($src);
  					}
  				}
  			}
  
  			// enable proxy
  			\OC_FileProxy::$enabled = $proxyStatus;
  		}
  		return $size;
  	}
  
  	/**
  	 * restore files from trash bin
6d9380f96   Cédric Dupont   Update sources OC...
295
296
297
298
  	 *
  	 * @param string $file path to the deleted file
  	 * @param string $filename name of the file
  	 * @param int $timestamp time when the file was deleted
03e52840d   Kload   Init
299
300
301
302
  	 *
  	 * @return bool
  	 */
  	public static function restore($file, $filename, $timestamp) {
31b7f2792   Kload   Upgrade to ownclo...
303

03e52840d   Kload   Init
304
305
  		$user = \OCP\User::getUser();
  		$view = new \OC\Files\View('/' . $user);
6d9380f96   Cédric Dupont   Update sources OC...
306
  		$location = '';
03e52840d   Kload   Init
307
  		if ($timestamp) {
6d9380f96   Cédric Dupont   Update sources OC...
308
309
  			$query = \OC_DB::prepare('SELECT `location` FROM `*PREFIX*files_trash`'
  				. ' WHERE `user`=? AND `id`=? AND `timestamp`=?');
03e52840d   Kload   Init
310
  			$result = $query->execute(array($user, $filename, $timestamp))->fetchAll();
31b7f2792   Kload   Upgrade to ownclo...
311
  			if (count($result) !== 1) {
03e52840d   Kload   Init
312
  				\OC_Log::write('files_trashbin', 'trash bin database inconsistent!', \OC_Log::ERROR);
6d9380f96   Cédric Dupont   Update sources OC...
313
314
315
316
317
318
319
320
321
  			} else {
  				$location = $result[0]['location'];
  				// if location no longer exists, restore file in the root directory
  				if ($location !== '/' &&
  					(!$view->is_dir('files' . $location) ||
  						!$view->isUpdatable('files' . $location))
  				) {
  					$location = '';
  				}
03e52840d   Kload   Init
322
  			}
03e52840d   Kload   Init
323
  		}
03e52840d   Kload   Init
324
  		// we need a  extension in case a file/dir with the same name already exists
31b7f2792   Kload   Upgrade to ownclo...
325
326
327
328
  		$uniqueFilename = self::getUniqueFilename($location, $filename, $view);
  
  		$source = \OC\Files\Filesystem::normalizePath('files_trashbin/files/' . $file);
  		$target = \OC\Files\Filesystem::normalizePath('files/' . $location . '/' . $uniqueFilename);
03e52840d   Kload   Init
329
330
331
332
333
334
335
  		$mtime = $view->filemtime($source);
  
  		// disable proxy to prevent recursive calls
  		$proxyStatus = \OC_FileProxy::$enabled;
  		\OC_FileProxy::$enabled = false;
  
  		// restore file
31b7f2792   Kload   Upgrade to ownclo...
336
  		$restoreResult = $view->rename($source, $target);
03e52840d   Kload   Init
337
338
339
340
341
  
  		// handle the restore result
  		if ($restoreResult) {
  			$fakeRoot = $view->getRoot();
  			$view->chroot('/' . $user . '/files');
31b7f2792   Kload   Upgrade to ownclo...
342
  			$view->touch('/' . $location . '/' . $uniqueFilename, $mtime);
03e52840d   Kload   Init
343
  			$view->chroot($fakeRoot);
31b7f2792   Kload   Upgrade to ownclo...
344
  			\OCP\Util::emitHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', array('filePath' => \OC\Files\Filesystem::normalizePath('/' . $location . '/' . $uniqueFilename),
03e52840d   Kload   Init
345
  				'trashPath' => \OC\Files\Filesystem::normalizePath($file)));
03e52840d   Kload   Init
346

6d9380f96   Cédric Dupont   Update sources OC...
347
348
  			self::restoreVersions($view, $file, $filename, $uniqueFilename, $location, $timestamp);
  			self::restoreEncryptionKeys($view, $file, $filename, $uniqueFilename, $location, $timestamp);
03e52840d   Kload   Init
349
350
351
352
353
  
  			if ($timestamp) {
  				$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=? AND `id`=? AND `timestamp`=?');
  				$query->execute(array($user, $filename, $timestamp));
  			}
03e52840d   Kload   Init
354
355
356
357
358
  			// enable proxy
  			\OC_FileProxy::$enabled = $proxyStatus;
  
  			return true;
  		}
31b7f2792   Kload   Upgrade to ownclo...
359
360
  		// enable proxy
  		\OC_FileProxy::$enabled = $proxyStatus;
03e52840d   Kload   Init
361
362
363
364
  		return false;
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
365
  	 * restore versions from trash bin
03e52840d   Kload   Init
366
367
  	 *
  	 * @param \OC\Files\View $view file view
6d9380f96   Cédric Dupont   Update sources OC...
368
369
370
371
372
  	 * @param string $file complete path to file
  	 * @param string $filename name of file once it was deleted
  	 * @param string $uniqueFilename new file name to restore the file without overwriting existing files
  	 * @param string $location location if file
  	 * @param int $timestamp deleteion time
03e52840d   Kload   Init
373
  	 *
03e52840d   Kload   Init
374
  	 */
31b7f2792   Kload   Upgrade to ownclo...
375
  	private static function restoreVersions($view, $file, $filename, $uniqueFilename, $location, $timestamp) {
31b7f2792   Kload   Upgrade to ownclo...
376

03e52840d   Kload   Init
377
378
379
380
381
382
383
  		if (\OCP\App::isEnabled('files_versions')) {
  			// disable proxy to prevent recursive calls
  			$proxyStatus = \OC_FileProxy::$enabled;
  			\OC_FileProxy::$enabled = false;
  
  			$user = \OCP\User::getUser();
  			$rootView = new \OC\Files\View('/');
31b7f2792   Kload   Upgrade to ownclo...
384
  			$target = \OC\Files\Filesystem::normalizePath('/' . $location . '/' . $uniqueFilename);
03e52840d   Kload   Init
385
386
387
388
389
390
391
392
393
394
  
  			list($owner, $ownerPath) = self::getUidAndFilename($target);
  
  			if ($timestamp) {
  				$versionedFile = $filename;
  			} else {
  				$versionedFile = $file;
  			}
  
  			if ($view->is_dir('/files_trashbin/versions/' . $file)) {
03e52840d   Kload   Init
395
396
397
398
  				$rootView->rename(\OC\Files\Filesystem::normalizePath($user . '/files_trashbin/versions/' . $file), \OC\Files\Filesystem::normalizePath($owner . '/files_versions/' . $ownerPath));
  			} else if ($versions = self::getVersionsFromTrash($versionedFile, $timestamp)) {
  				foreach ($versions as $v) {
  					if ($timestamp) {
03e52840d   Kload   Init
399
400
  						$rootView->rename($user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v . '.d' . $timestamp, $owner . '/files_versions/' . $ownerPath . '.v' . $v);
  					} else {
03e52840d   Kload   Init
401
402
403
404
405
406
407
408
  						$rootView->rename($user . '/files_trashbin/versions/' . $versionedFile . '.v' . $v, $owner . '/files_versions/' . $ownerPath . '.v' . $v);
  					}
  				}
  			}
  
  			// enable proxy
  			\OC_FileProxy::$enabled = $proxyStatus;
  		}
03e52840d   Kload   Init
409
410
411
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
412
  	 * restore encryption keys from trash bin
03e52840d   Kload   Init
413
414
  	 *
  	 * @param \OC\Files\View $view
6d9380f96   Cédric Dupont   Update sources OC...
415
416
417
418
419
  	 * @param string $file complete path to file
  	 * @param string $filename name of file
  	 * @param string $uniqueFilename new file name to restore the file without overwriting existing files
  	 * @param string $location location of file
  	 * @param int $timestamp deleteion time
03e52840d   Kload   Init
420
  	 *
03e52840d   Kload   Init
421
  	 */
31b7f2792   Kload   Upgrade to ownclo...
422
  	private static function restoreEncryptionKeys($view, $file, $filename, $uniqueFilename, $location, $timestamp) {
03e52840d   Kload   Init
423
  		// Take care of encryption keys TODO! Get '.key' in file between file name and delete date (also for permanent delete!)
03e52840d   Kload   Init
424
425
426
  		if (\OCP\App::isEnabled('files_encryption')) {
  			$user = \OCP\User::getUser();
  			$rootView = new \OC\Files\View('/');
31b7f2792   Kload   Upgrade to ownclo...
427
  			$target = \OC\Files\Filesystem::normalizePath('/' . $location . '/' . $uniqueFilename);
03e52840d   Kload   Init
428
429
  
  			list($owner, $ownerPath) = self::getUidAndFilename($target);
6d9380f96   Cédric Dupont   Update sources OC...
430
  			$util = new \OCA\Encryption\Util(new \OC\Files\View('/'), $user);
03e52840d   Kload   Init
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
  
  			if ($util->isSystemWideMountPoint($ownerPath)) {
  				$baseDir = '/files_encryption/';
  			} else {
  				$baseDir = $owner . '/files_encryption/';
  			}
  
  			$path_parts = pathinfo($file);
  			$source_location = $path_parts['dirname'];
  
  			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);
  				} else {
  					$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;
  			}
  
  			// 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)) {
  
  					// handle keyfiles
03e52840d   Kload   Init
466
467
468
469
470
471
  					$rootView->rename($keyfile, $baseDir . '/keyfiles/' . $ownerPath);
  
  					// handle share-keys
  					if ($timestamp) {
  						$sharekey .= '.d' . $timestamp;
  					}
03e52840d   Kload   Init
472
473
474
  					$rootView->rename($sharekey, $baseDir . '/share-keys/' . $ownerPath);
  				} else {
  					// handle keyfiles
03e52840d   Kload   Init
475
476
477
478
479
480
481
  					$rootView->rename($keyfile, $baseDir . '/keyfiles/' . $ownerPath . '.key');
  
  					// handle share-keys
  					$ownerShareKey = \OC\Files\Filesystem::normalizePath($user . '/files_trashbin/share-keys/' . $source_location . '/' . $filename . '.' . $user . '.shareKey');
  					if ($timestamp) {
  						$ownerShareKey .= '.d' . $timestamp;
  					}
03e52840d   Kload   Init
482
483
484
485
  					// move only owners key
  					$rootView->rename($ownerShareKey, $baseDir . '/share-keys/' . $ownerPath . '.' . $user . '.shareKey');
  
  					// try to re-share if file is shared
6d9380f96   Cédric Dupont   Update sources OC...
486
  					$filesystemView = new \OC\Files\View('/');
03e52840d   Kload   Init
487
488
489
490
491
492
493
494
495
  					$session = new \OCA\Encryption\Session($filesystemView);
  					$util = new \OCA\Encryption\Util($filesystemView, $user);
  
  					// fix the file size
  					$absolutePath = \OC\Files\Filesystem::normalizePath('/' . $owner . '/files/' . $ownerPath);
  					$util->fixFileSize($absolutePath);
  
  					// get current sharing state
  					$sharingEnabled = \OCP\Share::isEnabled();
03e52840d   Kload   Init
496
  					// get users sharing this file
6d9380f96   Cédric Dupont   Update sources OC...
497
  					$usersSharing = $util->getSharingUsersArray($sharingEnabled, $target);
03e52840d   Kload   Init
498
499
  
  					// Attempt to set shareKey
31b7f2792   Kload   Upgrade to ownclo...
500
  					$util->setSharedFileKeyfiles($session, $usersSharing, $target);
03e52840d   Kload   Init
501
502
503
504
505
506
  				}
  			}
  
  			// enable proxy
  			\OC_FileProxy::$enabled = $proxyStatus;
  		}
03e52840d   Kload   Init
507
508
509
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
510
  	 * delete all files from the trash
31b7f2792   Kload   Upgrade to ownclo...
511
512
513
514
515
  	 */
  	public static function deleteAll() {
  		$user = \OCP\User::getUser();
  		$view = new \OC\Files\View('/' . $user);
  		$view->deleteAll('files_trashbin');
31b7f2792   Kload   Upgrade to ownclo...
516
517
518
519
520
521
522
523
  		$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=?');
  		$query->execute(array($user));
  
  		return true;
  	}
  
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
524
  	 * delete file from trash bin permanently
31b7f2792   Kload   Upgrade to ownclo...
525
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
526
527
528
  	 * @param string $filename path to the file
  	 * @param string $user
  	 * @param int $timestamp of deletion time
31b7f2792   Kload   Upgrade to ownclo...
529
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
530
  	 * @return int size of deleted files
03e52840d   Kload   Init
531
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
532
  	public static function delete($filename, $user, $timestamp = null) {
03e52840d   Kload   Init
533
534
  		$view = new \OC\Files\View('/' . $user);
  		$size = 0;
03e52840d   Kload   Init
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
  		if ($timestamp) {
  			$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=? AND `id`=? AND `timestamp`=?');
  			$query->execute(array($user, $filename, $timestamp));
  			$file = $filename . '.d' . $timestamp;
  		} else {
  			$file = $filename;
  		}
  
  		$size += self::deleteVersions($view, $file, $filename, $timestamp);
  		$size += self::deleteEncryptionKeys($view, $file, $filename, $timestamp);
  
  		if ($view->is_dir('/files_trashbin/files/' . $file)) {
  			$size += self::calculateSize(new \OC\Files\View('/' . $user . '/files_trashbin/files/' . $file));
  		} else {
  			$size += $view->filesize('/files_trashbin/files/' . $file);
  		}
6d9380f96   Cédric Dupont   Update sources OC...
551
  		\OC_Hook::emit('\OCP\Trashbin', 'preDelete', array('path' => '/files_trashbin/files/' . $file));
03e52840d   Kload   Init
552
  		$view->unlink('/files_trashbin/files/' . $file);
31b7f2792   Kload   Upgrade to ownclo...
553
  		\OC_Hook::emit('\OCP\Trashbin', 'delete', array('path' => '/files_trashbin/files/' . $file));
03e52840d   Kload   Init
554
555
556
  
  		return $size;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
557
558
559
  	/**
  	 * @param \OC\Files\View $view
  	 */
03e52840d   Kload   Init
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  	private static function deleteVersions($view, $file, $filename, $timestamp) {
  		$size = 0;
  		if (\OCP\App::isEnabled('files_versions')) {
  			$user = \OCP\User::getUser();
  			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)) {
  				foreach ($versions as $v) {
  					if ($timestamp) {
  						$size += $view->filesize('/files_trashbin/versions/' . $filename . '.v' . $v . '.d' . $timestamp);
  						$view->unlink('/files_trashbin/versions/' . $filename . '.v' . $v . '.d' . $timestamp);
  					} else {
  						$size += $view->filesize('/files_trashbin/versions/' . $filename . '.v' . $v);
  						$view->unlink('/files_trashbin/versions/' . $filename . '.v' . $v);
  					}
  				}
  			}
  		}
03e52840d   Kload   Init
579
580
  		return $size;
  	}
6d9380f96   Cédric Dupont   Update sources OC...
581
582
583
  	/**
  	 * @param \OC\Files\View $view
  	 */
03e52840d   Kload   Init
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
  	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);
  				$sharekeys = \OC\Files\Filesystem::normalizePath('files_trashbin/share-keys/' . $filename);
  			} else {
  				$keyfile = \OC\Files\Filesystem::normalizePath('files_trashbin/keyfiles/' . $filename . '.key');
  				$sharekeys = \OC\Files\Filesystem::normalizePath('files_trashbin/share-keys/' . $filename . '.' . $user . '.shareKey');
  			}
  			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);
  			}
  		}
03e52840d   Kload   Init
612
613
614
615
616
  		return $size;
  	}
  
  	/**
  	 * check to see whether a file exists in trashbin
6d9380f96   Cédric Dupont   Update sources OC...
617
618
619
620
  	 *
  	 * @param string $filename path to the file
  	 * @param int $timestamp of deletion time
  	 * @return bool true if file exists, otherwise false
03e52840d   Kload   Init
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
  	 */
  	public static function file_exists($filename, $timestamp = null) {
  		$user = \OCP\User::getUser();
  		$view = new \OC\Files\View('/' . $user);
  
  		if ($timestamp) {
  			$filename = $filename . '.d' . $timestamp;
  		} else {
  			$filename = $filename;
  		}
  
  		$target = \OC\Files\Filesystem::normalizePath('files_trashbin/files/' . $filename);
  		return $view->file_exists($target);
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
637
  	 * deletes used space for trash bin in db if user was deleted
03e52840d   Kload   Init
638
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
639
640
  	 * @param string $uid id of deleted user
  	 * @return bool result of db delete operation
03e52840d   Kload   Init
641
642
643
  	 */
  	public static function deleteUser($uid) {
  		$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=?');
6d9380f96   Cédric Dupont   Update sources OC...
644
  		return $query->execute(array($uid));
03e52840d   Kload   Init
645
646
647
648
649
  	}
  
  	/**
  	 * calculate remaining free space for trash bin
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
650
651
652
  	 * @param integer $trashbinSize current size of the trash bin
  	 * @param string $user
  	 * @return int available free space for trash bin
03e52840d   Kload   Init
653
  	 */
6d9380f96   Cédric Dupont   Update sources OC...
654
  	private static function calculateFreeSpace($trashbinSize, $user) {
03e52840d   Kload   Init
655
  		$softQuota = true;
03e52840d   Kload   Init
656
657
658
  		$quota = \OC_Preferences::getValue($user, 'files', 'quota');
  		$view = new \OC\Files\View('/' . $user);
  		if ($quota === null || $quota === 'default') {
6d9380f96   Cédric Dupont   Update sources OC...
659
  			$quota = \OC::$server->getAppConfig()->getValue('files', 'default_quota');
03e52840d   Kload   Init
660
661
662
663
664
665
666
667
668
669
670
  		}
  		if ($quota === null || $quota === 'none') {
  			$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) {
a293d369c   Kload   Update sources to...
671
  			$rootInfo = $view->getFileInfo('/files/', false);
03e52840d   Kload   Init
672
673
674
675
676
677
678
679
680
681
682
683
684
685
  			$free = $quota - $rootInfo['size']; // remaining free space for user
  			if ($free > 0) {
  				$availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $trashbinSize; // how much space can be used for versions
  			} else {
  				$availableSpace = $free - $trashbinSize;
  			}
  		} else {
  			$availableSpace = $quota;
  		}
  
  		return $availableSpace;
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
686
  	 * resize trash bin if necessary after a new file was added to ownCloud
31b7f2792   Kload   Upgrade to ownclo...
687
688
689
690
691
  	 * @param string $user user id
  	 */
  	public static function resizeTrash($user) {
  
  		$size = self::getTrashbinSize($user);
6d9380f96   Cédric Dupont   Update sources OC...
692
  		$freeSpace = self::calculateFreeSpace($size, $user);
31b7f2792   Kload   Upgrade to ownclo...
693
694
  
  		if ($freeSpace < 0) {
6d9380f96   Cédric Dupont   Update sources OC...
695
  			self::expire($size, $user);
31b7f2792   Kload   Upgrade to ownclo...
696
697
698
699
  		}
  	}
  
  	/**
03e52840d   Kload   Init
700
  	 * clean up the trash bin
6d9380f96   Cédric Dupont   Update sources OC...
701
  	 *
31b7f2792   Kload   Upgrade to ownclo...
702
703
704
  	 * @param int $trashbinSize current size of the trash bin
  	 * @param string $user
  	 * @return int size of expired files
03e52840d   Kload   Init
705
  	 */
31b7f2792   Kload   Upgrade to ownclo...
706
707
708
709
710
711
712
  	private static function expire($trashbinSize, $user) {
  
  		// let the admin disable auto expire
  		$autoExpire = \OC_Config::getValue('trashbin_auto_expire', true);
  		if ($autoExpire === false) {
  			return 0;
  		}
03e52840d   Kload   Init
713

6d9380f96   Cédric Dupont   Update sources OC...
714
  		$availableSpace = self::calculateFreeSpace($trashbinSize, $user);
03e52840d   Kload   Init
715
  		$size = 0;
03e52840d   Kload   Init
716
717
718
  		$retention_obligation = \OC_Config::getValue('trashbin_retention_obligation', self::DEFAULT_RETENTION_OBLIGATION);
  
  		$limit = time() - ($retention_obligation * 86400);
6d9380f96   Cédric Dupont   Update sources OC...
719
720
721
722
723
724
  		$dirContent = Helper::getTrashFiles('/', $user, 'mtime');
  
  		// delete all files older then $retention_obligation
  		list($delSize, $count) = self::deleteExpiredFiles($dirContent, $user, $limit, $retention_obligation);
  
  		$size += $delSize;
31b7f2792   Kload   Upgrade to ownclo...
725
  		$availableSpace += $size;
6d9380f96   Cédric Dupont   Update sources OC...
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
  
  		// delete files from trash until we meet the trash bin size limit again
  		$size += self::deleteFiles(array_slice($dirContent, $count), $user, $availableSpace);
  
  		return $size;
  	}
  
  	/**
  	 * 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
  	 * @param array $files
  	 * @param string $user
  	 * @param int $availableSpace available disc space
  	 * @return int size of deleted files
  	 */
  	protected static function deleteFiles($files, $user, $availableSpace) {
  		$size = 0;
03e52840d   Kload   Init
743
  		if ($availableSpace < 0) {
6d9380f96   Cédric Dupont   Update sources OC...
744
745
746
747
748
749
750
751
752
  			foreach ($files as $file) {
  				if ($availableSpace < 0) {
  					$tmp = self::delete($file['name'], $user, $file['mtime']);
  					\OC_Log::write('files_trashbin', 'remove "' . $file['name'] . '" (' . $tmp . 'B) to meet the limit of trash bin size (50% of available quota)', \OC_log::INFO);
  					$availableSpace += $tmp;
  					$size += $tmp;
  				} else {
  					break;
  				}
03e52840d   Kload   Init
753
754
  			}
  		}
03e52840d   Kload   Init
755
756
757
758
  		return $size;
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
  	 * delete files older then max storage time
  	 *
  	 * @param array $files list of files sorted by mtime
  	 * @param string $user
  	 * @param int $limit files older then limit should be deleted
  	 * @param int $retention_obligation max age of file in days
  	 * @return array size of deleted files and number of deleted files
  	 */
  	protected static function deleteExpiredFiles($files, $user, $limit, $retention_obligation) {
  		$size = 0;
  		$count = 0;
  		foreach ($files as $file) {
  			$timestamp = $file['mtime'];
  			$filename = $file['name'];
  			if ($timestamp < $limit) {
  				$count++;
  				$size += self::delete($filename, $user, $timestamp);
  				\OC_Log::write('files_trashbin', 'remove "' . $filename . '" from trash bin because it is older than ' . $retention_obligation, \OC_log::INFO);
  			} else {
  				break;
  			}
  		}
  
  		return array($size, $count);
  	}
  
  	/**
03e52840d   Kload   Init
786
787
  	 * recursive copy to copy a whole directory
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
788
789
790
  	 * @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
03e52840d   Kload   Init
791
792
793
  	 */
  	private static function copy_recursive($source, $destination, $view) {
  		$size = 0;
31b7f2792   Kload   Upgrade to ownclo...
794
  		if ($view->is_dir($source)) {
03e52840d   Kload   Init
795
  			$view->mkdir($destination);
31b7f2792   Kload   Upgrade to ownclo...
796
797
  			$view->touch($destination, $view->filemtime($source));
  			foreach ($view->getDirectoryContent($source) as $i) {
03e52840d   Kload   Init
798
  				$pathDir = $source . '/' . $i['name'];
31b7f2792   Kload   Upgrade to ownclo...
799
  				if ($view->is_dir($pathDir)) {
03e52840d   Kload   Init
800
801
  					$size += self::copy_recursive($pathDir, $destination . '/' . $i['name'], $view);
  				} else {
31b7f2792   Kload   Upgrade to ownclo...
802
  					$size += $view->filesize($pathDir);
6d9380f96   Cédric Dupont   Update sources OC...
803
804
805
806
  					$result = $view->copy($pathDir, $destination . '/' . $i['name']);
  					if (!$result) {
  						throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException();
  					}
31b7f2792   Kload   Upgrade to ownclo...
807
  					$view->touch($destination . '/' . $i['name'], $view->filemtime($pathDir));
03e52840d   Kload   Init
808
809
810
  				}
  			}
  		} else {
31b7f2792   Kload   Upgrade to ownclo...
811
  			$size += $view->filesize($source);
6d9380f96   Cédric Dupont   Update sources OC...
812
813
814
815
  			$result = $view->copy($source, $destination);
  			if (!$result) {
  				throw new \OCA\Files_Trashbin\Exceptions\CopyRecursiveException();
  			}
31b7f2792   Kload   Upgrade to ownclo...
816
  			$view->touch($destination, $view->filemtime($source));
03e52840d   Kload   Init
817
818
819
820
821
822
  		}
  		return $size;
  	}
  
  	/**
  	 * find all versions which belong to the file we want to restore
6d9380f96   Cédric Dupont   Update sources OC...
823
824
825
  	 *
  	 * @param string $filename name of the file which should be restored
  	 * @param int $timestamp timestamp when the file was deleted
03e52840d   Kload   Init
826
827
  	 */
  	private static function getVersionsFromTrash($filename, $timestamp) {
31b7f2792   Kload   Upgrade to ownclo...
828
829
  		$view = new \OC\Files\View('/' . \OCP\User::getUser() . '/files_trashbin/versions');
  		$versionsName = $view->getLocalFile($filename) . '.v';
03e52840d   Kload   Init
830
831
832
833
  		$escapedVersionsName = preg_replace('/(\*|\?|\[)/', '[$1]', $versionsName);
  		$versions = array();
  		if ($timestamp) {
  			// fetch for old versions
31b7f2792   Kload   Upgrade to ownclo...
834
835
  			$matches = glob($escapedVersionsName . '*.d' . $timestamp);
  			$offset = -strlen($timestamp) - 2;
03e52840d   Kload   Init
836
  		} else {
31b7f2792   Kload   Upgrade to ownclo...
837
  			$matches = glob($escapedVersionsName . '*');
03e52840d   Kload   Init
838
  		}
6d9380f96   Cédric Dupont   Update sources OC...
839
840
841
842
843
844
845
846
847
  		if (is_array($matches)) {
  			foreach ($matches as $ma) {
  				if ($timestamp) {
  					$parts = explode('.v', substr($ma, 0, $offset));
  					$versions[] = (end($parts));
  				} else {
  					$parts = explode('.v', $ma);
  					$versions[] = (end($parts));
  				}
03e52840d   Kload   Init
848
849
850
851
852
853
854
  			}
  		}
  		return $versions;
  	}
  
  	/**
  	 * find unique extension for restored file if a file with the same name already exists
6d9380f96   Cédric Dupont   Update sources OC...
855
856
857
858
  	 *
  	 * @param string $location where the file should be restored
  	 * @param string $filename name of the file
  	 * @param \OC\Files\View $view filesystem view relative to users root directory
03e52840d   Kload   Init
859
860
  	 * @return string with unique extension
  	 */
31b7f2792   Kload   Upgrade to ownclo...
861
862
863
864
865
866
867
868
869
  	private static function getUniqueFilename($location, $filename, $view) {
  		$ext = pathinfo($filename, PATHINFO_EXTENSION);
  		$name = pathinfo($filename, PATHINFO_FILENAME);
  		$l = \OC_L10N::get('files_trashbin');
  
  		// if extension is not empty we set a dot in front of it
  		if ($ext !== '') {
  			$ext = '.' . $ext;
  		}
03e52840d   Kload   Init
870
  		if ($view->file_exists('files' . $location . '/' . $filename)) {
31b7f2792   Kload   Upgrade to ownclo...
871
  			$i = 2;
6d9380f96   Cédric Dupont   Update sources OC...
872
  			$uniqueName = $name . " (" . $l->t("restored") . ")" . $ext;
31b7f2792   Kload   Upgrade to ownclo...
873
  			while ($view->file_exists('files' . $location . '/' . $uniqueName)) {
6d9380f96   Cédric Dupont   Update sources OC...
874
  				$uniqueName = $name . " (" . $l->t("restored") . " " . $i . ")" . $ext;
03e52840d   Kload   Init
875
876
  				$i++;
  			}
31b7f2792   Kload   Upgrade to ownclo...
877
878
  
  			return $uniqueName;
03e52840d   Kload   Init
879
  		}
31b7f2792   Kload   Upgrade to ownclo...
880
881
  
  		return $filename;
03e52840d   Kload   Init
882
883
884
  	}
  
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
885
886
887
  	 * get the size from a given root folder
  	 * @param \OC\Files\View $view file view on the root folder
  	 * @return integer size of the folder
03e52840d   Kload   Init
888
889
890
891
892
893
894
895
  	 */
  	private static function calculateSize($view) {
  		$root = \OCP\Config::getSystemValue('datadirectory') . $view->getAbsolutePath('');
  		if (!file_exists($root)) {
  			return 0;
  		}
  		$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($root), \RecursiveIteratorIterator::CHILD_FIRST);
  		$size = 0;
6d9380f96   Cédric Dupont   Update sources OC...
896
897
898
899
900
901
902
903
                  /**
  		 * 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();
03e52840d   Kload   Init
904
905
906
907
  			$relpath = substr($path, strlen($root) - 1);
  			if (!$view->is_dir($relpath)) {
  				$size += $view->filesize($relpath);
  			}
6d9380f96   Cédric Dupont   Update sources OC...
908
  			$iterator->next();
03e52840d   Kload   Init
909
910
911
912
913
914
915
  		}
  		return $size;
  	}
  
  	/**
  	 * get current size of trash bin from a given user
  	 *
6d9380f96   Cédric Dupont   Update sources OC...
916
917
  	 * @param string $user user who owns the trash bin
  	 * @return integer trash bin size
03e52840d   Kload   Init
918
919
  	 */
  	private static function getTrashbinSize($user) {
6d9380f96   Cédric Dupont   Update sources OC...
920
921
922
  		$view = new \OC\Files\View('/' . $user);
  		$fileInfo = $view->getFileInfo('/files_trashbin');
  		return isset($fileInfo['size']) ? $fileInfo['size'] : 0;
03e52840d   Kload   Init
923
924
925
926
927
928
929
930
931
932
  	}
  
  	/**
  	 * 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");
31b7f2792   Kload   Upgrade to ownclo...
933
934
  		//Listen to post write hook
  		\OCP\Util::connectHook('OC_Filesystem', 'post_write', "OCA\Files_Trashbin\Hooks", "post_write_hook");
03e52840d   Kload   Init
935
  	}
31b7f2792   Kload   Upgrade to ownclo...
936
  	/**
6d9380f96   Cédric Dupont   Update sources OC...
937
  	 * check if trash bin is empty for a given user
31b7f2792   Kload   Upgrade to ownclo...
938
939
940
941
942
  	 * @param string $user
  	 */
  	public static function isEmpty($user) {
  
  		$view = new \OC\Files\View('/' . $user . '/files_trashbin');
6d9380f96   Cédric Dupont   Update sources OC...
943
944
945
946
947
948
  		if ($view->is_dir('/files') && $dh = $view->opendir('/files')) {
  			while ($file = readdir($dh)) {
  				if ($file !== '.' and $file !== '..') {
  					return false;
  				}
  			}
31b7f2792   Kload   Upgrade to ownclo...
949
  		}
31b7f2792   Kload   Upgrade to ownclo...
950
951
952
953
  		return true;
  	}
  
  	public static function preview_icon($path) {
6d9380f96   Cédric Dupont   Update sources OC...
954
  		return \OC_Helper::linkToRoute('core_ajax_trashbin_preview', array('x' => 36, 'y' => 36, 'file' => $path));
31b7f2792   Kload   Upgrade to ownclo...
955
  	}
03e52840d   Kload   Init
956
  }