4747use OC \Files \View ;
4848use OCA \Files_Trashbin \AppInfo \Application ;
4949use OCA \Files_Trashbin \Command \Expire ;
50+ use OCP \AppFramework \Utility \ITimeFactory ;
5051use OCP \Files \File ;
5152use OCP \Files \Folder ;
5253use OCP \Files \NotFoundException ;
5354use OCP \Files \NotPermittedException ;
55+ use OCP \Lock \ILockingProvider ;
56+ use OCP \Lock \LockedException ;
5457use OCP \User ;
5558
5659class Trashbin {
@@ -220,8 +223,8 @@ private static function copyFilesToUser($sourcePath, $owner, $targetPath, $user,
220223 public static function move2trash ($ file_path , $ ownerOnly = false ) {
221224 // get the user for which the filesystem is setup
222225 $ root = Filesystem::getRoot ();
223- list ( , $ user) = explode ('/ ' , $ root );
224- list ( $ owner , $ ownerPath) = self ::getUidAndFilename ($ file_path );
226+ [ , $ user] = explode ('/ ' , $ root );
227+ [ $ owner , $ ownerPath] = self ::getUidAndFilename ($ file_path );
225228
226229 // if no owner found (ex: ext storage + share link), will use the current user's trashbin then
227230 if (is_null ($ owner )) {
@@ -245,15 +248,36 @@ public static function move2trash($file_path, $ownerOnly = false) {
245248
246249 $ filename = $ path_parts ['basename ' ];
247250 $ location = $ path_parts ['dirname ' ];
248- $ timestamp = time ();
251+ /** @var ITimeFactory $timeFactory */
252+ $ timeFactory = \OC ::$ server ->query (ITimeFactory::class);
253+ $ timestamp = $ timeFactory ->getTime ();
254+
255+ $ lockingProvider = \OC ::$ server ->getLockingProvider ();
249256
250257 // disable proxy to prevent recursive calls
251258 $ trashPath = '/files_trashbin/files/ ' . $ filename . '.d ' . $ timestamp ;
259+ $ gotLock = false ;
260+
261+ while (!$ gotLock ) {
262+ try {
263+ /** @var \OC\Files\Storage\Storage $trashStorage */
264+ [$ trashStorage , $ trashInternalPath ] = $ ownerView ->resolvePath ($ trashPath );
265+
266+ $ trashStorage ->acquireLock ($ trashInternalPath , ILockingProvider::LOCK_EXCLUSIVE , $ lockingProvider );
267+ $ gotLock = true ;
268+ } catch (LockedException $ e ) {
269+ // a file with the same name is being deleted concurrently
270+ // nudge the timestamp a bit to resolve the conflict
271+
272+ $ timestamp = $ timestamp + 1 ;
273+
274+ $ trashPath = '/files_trashbin/files/ ' . $ filename . '.d ' . $ timestamp ;
275+ }
276+ }
252277
253- /** @var \OC\Files\Storage\Storage $trashStorage */
254- list ($ trashStorage , $ trashInternalPath ) = $ ownerView ->resolvePath ($ trashPath );
255278 /** @var \OC\Files\Storage\Storage $sourceStorage */
256- list ($ sourceStorage , $ sourceInternalPath ) = $ ownerView ->resolvePath ('/files/ ' . $ ownerPath );
279+ [$ sourceStorage , $ sourceInternalPath ] = $ ownerView ->resolvePath ('/files/ ' . $ ownerPath );
280+
257281 try {
258282 $ moveSuccessful = true ;
259283 if ($ trashStorage ->file_exists ($ trashInternalPath )) {
@@ -296,6 +320,8 @@ public static function move2trash($file_path, $ownerOnly = false) {
296320 }
297321 }
298322
323+ $ trashStorage ->releaseLock ($ trashInternalPath , ILockingProvider::LOCK_EXCLUSIVE , $ lockingProvider );
324+
299325 self ::scheduleExpire ($ user );
300326
301327 // if owner !== user we also need to update the owners trash size
@@ -345,9 +371,9 @@ private static function retainVersions($filename, $owner, $ownerPath, $timestamp
345371 */
346372 private static function move (View $ view , $ source , $ target ) {
347373 /** @var \OC\Files\Storage\Storage $sourceStorage */
348- list ( $ sourceStorage , $ sourceInternalPath) = $ view ->resolvePath ($ source );
374+ [ $ sourceStorage , $ sourceInternalPath] = $ view ->resolvePath ($ source );
349375 /** @var \OC\Files\Storage\Storage $targetStorage */
350- list ( $ targetStorage , $ targetInternalPath) = $ view ->resolvePath ($ target );
376+ [ $ targetStorage , $ targetInternalPath] = $ view ->resolvePath ($ target );
351377 /** @var \OC\Files\Storage\Storage $ownerTrashStorage */
352378
353379 $ result = $ targetStorage ->moveFromStorage ($ sourceStorage , $ sourceInternalPath , $ targetInternalPath );
@@ -367,9 +393,9 @@ private static function move(View $view, $source, $target) {
367393 */
368394 private static function copy (View $ view , $ source , $ target ) {
369395 /** @var \OC\Files\Storage\Storage $sourceStorage */
370- list ( $ sourceStorage , $ sourceInternalPath) = $ view ->resolvePath ($ source );
396+ [ $ sourceStorage , $ sourceInternalPath] = $ view ->resolvePath ($ source );
371397 /** @var \OC\Files\Storage\Storage $targetStorage */
372- list ( $ targetStorage , $ targetInternalPath) = $ view ->resolvePath ($ target );
398+ [ $ targetStorage , $ targetInternalPath] = $ view ->resolvePath ($ target );
373399 /** @var \OC\Files\Storage\Storage $ownerTrashStorage */
374400
375401 $ result = $ targetStorage ->copyFromStorage ($ sourceStorage , $ sourceInternalPath , $ targetInternalPath );
@@ -465,7 +491,7 @@ private static function restoreVersions(View $view, $file, $filename, $uniqueFil
465491
466492 $ target = Filesystem::normalizePath ('/ ' . $ location . '/ ' . $ uniqueFilename );
467493
468- list ( $ owner , $ ownerPath) = self ::getUidAndFilename ($ target );
494+ [ $ owner , $ ownerPath] = self ::getUidAndFilename ($ target );
469495
470496 // file has been deleted in between
471497 if (empty ($ ownerPath )) {
@@ -731,7 +757,7 @@ public static function expire($user) {
731757 $ dirContent = Helper::getTrashFiles ('/ ' , $ user , 'mtime ' );
732758
733759 // delete all files older then $retention_obligation
734- list ( $ delSize , $ count) = self ::deleteExpiredFiles ($ dirContent , $ user );
760+ [ $ delSize , $ count] = self ::deleteExpiredFiles ($ dirContent , $ user );
735761
736762 $ availableSpace += $ delSize ;
737763
@@ -868,7 +894,7 @@ private static function getVersionsFromTrash($filename, $timestamp, $user) {
868894 //force rescan of versions, local storage may not have updated the cache
869895 if (!self ::$ scannedVersions ) {
870896 /** @var \OC\Files\Storage\Storage $storage */
871- list ( $ storage ,) = $ view ->resolvePath ('/ ' );
897+ [ $ storage ,] = $ view ->resolvePath ('/ ' );
872898 $ storage ->getScanner ()->scan ('files_trashbin/versions ' );
873899 self ::$ scannedVersions = true ;
874900 }
0 commit comments