@@ -295,18 +295,65 @@ public static function move2trash($file_path, $ownerOnly = false) {
295295
296296 $ configuredTrashbinSize = static ::getConfiguredTrashbinSize ($ owner );
297297 if ($ configuredTrashbinSize >= 0 && $ sourceInfo ->getSize () >= $ configuredTrashbinSize ) {
298+ $ trashStorage ->releaseLock ($ trashInternalPath , ILockingProvider::LOCK_EXCLUSIVE , $ lockingProvider );
298299 return false ;
299300 }
300301
302+ // there is still a possibility that the file has been deleted by a remote user
303+ $ deletedBy = self ::overwriteDeletedBy ($ user );
304+
305+ $ query = Server::get (IDBConnection::class)->getQueryBuilder ();
306+ $ query ->insert ('files_trash ' )
307+ ->setValue ('id ' , $ query ->createNamedParameter ($ filename ))
308+ ->setValue ('timestamp ' , $ query ->createNamedParameter ($ timestamp ))
309+ ->setValue ('location ' , $ query ->createNamedParameter ($ location ))
310+ ->setValue ('user ' , $ query ->createNamedParameter ($ owner ))
311+ ->setValue ('deleted_by ' , $ query ->createNamedParameter ($ deletedBy ));
312+ $ inserted = false ;
301313 try {
302- $ moveSuccessful = true ;
314+ $ inserted = ($ query ->executeStatement () === 1 );
315+ } catch (\Throwable $ e ) {
316+ Server::get (LoggerInterface::class)->error (
317+ 'trash bin database insert failed ' ,
318+ [
319+ 'app ' => 'files_trashbin ' ,
320+ 'exception ' => $ e ,
321+ 'user ' => $ owner ,
322+ 'filename ' => $ filename ,
323+ 'timestamp ' => $ timestamp ,
324+ ]
325+ );
326+ }
327+ if (!$ inserted ) {
328+ Server::get (LoggerInterface::class)->error (
329+ 'trash bin database couldn \'t be updated, skipping trash move ' ,
330+ [
331+ 'app ' => 'files_trashbin ' ,
332+ 'user ' => $ owner ,
333+ 'filename ' => $ filename ,
334+ 'timestamp ' => $ timestamp ,
335+ ]
336+ );
337+ $ trashStorage ->releaseLock ($ trashInternalPath , ILockingProvider::LOCK_EXCLUSIVE , $ lockingProvider );
338+ return false ;
339+ }
303340
341+ $ moveSuccessful = true ;
342+ try {
304343 $ inCache = $ sourceStorage ->getCache ()->inCache ($ sourceInternalPath );
305344 $ trashStorage ->moveFromStorage ($ sourceStorage , $ sourceInternalPath , $ trashInternalPath );
306345 if ($ inCache ) {
307346 $ trashStorage ->getUpdater ()->renameFromStorage ($ sourceStorage , $ sourceInternalPath , $ trashInternalPath );
347+ } else {
348+ $ sizeDifference = $ sourceInfo ->getSize ();
349+ if ($ sizeDifference < 0 ) {
350+ $ sizeDifference = null ;
351+ } else {
352+ $ sizeDifference = (int )$ sizeDifference ;
353+ }
354+ $ trashStorage ->getUpdater ()->update ($ trashInternalPath , null , $ sizeDifference );
308355 }
309- } catch (CopyRecursiveException $ e ) {
356+ } catch (\ Exception $ e ) {
310357 $ moveSuccessful = false ;
311358 if ($ trashStorage ->file_exists ($ trashInternalPath )) {
312359 $ trashStorage ->unlink ($ trashInternalPath );
@@ -327,24 +374,31 @@ public static function move2trash($file_path, $ownerOnly = false) {
327374 } else {
328375 $ trashStorage ->getUpdater ()->remove ($ trashInternalPath );
329376 }
330- return false ;
377+ $ moveSuccessful = false ;
331378 }
332379
333- if ($ moveSuccessful ) {
334- // there is still a possibility that the file has been deleted by a remote user
335- $ deletedBy = self ::overwriteDeletedBy ($ user );
336-
337- $ query = Server::get (IDBConnection::class)->getQueryBuilder ();
338- $ query ->insert ('files_trash ' )
339- ->setValue ('id ' , $ query ->createNamedParameter ($ filename ))
340- ->setValue ('timestamp ' , $ query ->createNamedParameter ($ timestamp ))
341- ->setValue ('location ' , $ query ->createNamedParameter ($ location ))
342- ->setValue ('user ' , $ query ->createNamedParameter ($ owner ))
343- ->setValue ('deleted_by ' , $ query ->createNamedParameter ($ deletedBy ));
344- $ result = $ query ->executeStatement ();
345- if (!$ result ) {
346- Server::get (LoggerInterface::class)->error ('trash bin database couldn \'t be updated ' , ['app ' => 'files_trashbin ' ]);
380+ if (!$ moveSuccessful ) {
381+ Server::get (LoggerInterface::class)->error (
382+ 'trash move failed, removing trash metadata and payload ' ,
383+ [
384+ 'app ' => 'files_trashbin ' ,
385+ 'user ' => $ owner ,
386+ 'filename ' => $ filename ,
387+ 'timestamp ' => $ timestamp ,
388+ ]
389+ );
390+ self ::deleteTrashRow ($ user , $ filename , $ timestamp );
391+ if ($ trashStorage ->file_exists ($ trashInternalPath )) {
392+ if ($ trashStorage ->is_dir ($ trashInternalPath )) {
393+ $ trashStorage ->rmdir ($ trashInternalPath );
394+ } else {
395+ $ trashStorage ->unlink ($ trashInternalPath );
396+ }
347397 }
398+ $ trashStorage ->getUpdater ()->remove ($ trashInternalPath );
399+ }
400+
401+ if ($ moveSuccessful ) {
348402 Util::emitHook ('\OCA\Files_Trashbin\Trashbin ' , 'post_moveToTrash ' , ['filePath ' => Filesystem::normalizePath ($ file_path ),
349403 'trashPath ' => Filesystem::normalizePath (static ::getTrashFilename ($ filename , $ timestamp ))]);
350404
@@ -535,12 +589,7 @@ public static function restore($file, $filename, $timestamp) {
535589 self ::restoreVersions ($ view , $ file , $ filename , $ uniqueFilename , $ location , $ timestamp );
536590
537591 if ($ timestamp ) {
538- $ query = Server::get (IDBConnection::class)->getQueryBuilder ();
539- $ query ->delete ('files_trash ' )
540- ->where ($ query ->expr ()->eq ('user ' , $ query ->createNamedParameter ($ user )))
541- ->andWhere ($ query ->expr ()->eq ('id ' , $ query ->createNamedParameter ($ filename )))
542- ->andWhere ($ query ->expr ()->eq ('timestamp ' , $ query ->createNamedParameter ($ timestamp )));
543- $ query ->executeStatement ();
592+ self ::deleteTrashRow ($ user , $ filename , $ timestamp );
544593 }
545594
546595 return true ;
@@ -679,13 +728,6 @@ public static function delete($filename, $user, $timestamp = null) {
679728 $ size = 0 ;
680729
681730 if ($ timestamp ) {
682- $ query = Server::get (IDBConnection::class)->getQueryBuilder ();
683- $ query ->delete ('files_trash ' )
684- ->where ($ query ->expr ()->eq ('user ' , $ query ->createNamedParameter ($ user )))
685- ->andWhere ($ query ->expr ()->eq ('id ' , $ query ->createNamedParameter ($ filename )))
686- ->andWhere ($ query ->expr ()->eq ('timestamp ' , $ query ->createNamedParameter ($ timestamp )));
687- $ query ->executeStatement ();
688-
689731 $ file = static ::getTrashFilename ($ filename , $ timestamp );
690732 } else {
691733 $ file = $ filename ;
@@ -696,6 +738,9 @@ public static function delete($filename, $user, $timestamp = null) {
696738 try {
697739 $ node = $ userRoot ->get ('/files_trashbin/files/ ' . $ file );
698740 } catch (NotFoundException $ e ) {
741+ if ($ timestamp ) {
742+ self ::deleteTrashRow ($ user , $ filename , $ timestamp );
743+ }
699744 return $ size ;
700745 }
701746
@@ -709,9 +754,22 @@ public static function delete($filename, $user, $timestamp = null) {
709754 $ node ->delete ();
710755 self ::emitTrashbinPostDelete ('/files_trashbin/files/ ' . $ file );
711756
757+ if ($ timestamp ) {
758+ self ::deleteTrashRow ($ user , $ filename , $ timestamp );
759+ }
760+
712761 return $ size ;
713762 }
714763
764+ private static function deleteTrashRow (string $ user , string $ filename , int $ timestamp ): void {
765+ $ query = Server::get (IDBConnection::class)->getQueryBuilder ();
766+ $ query ->delete ('files_trash ' )
767+ ->where ($ query ->expr ()->eq ('user ' , $ query ->createNamedParameter ($ user )))
768+ ->andWhere ($ query ->expr ()->eq ('id ' , $ query ->createNamedParameter ($ filename )))
769+ ->andWhere ($ query ->expr ()->eq ('timestamp ' , $ query ->createNamedParameter ($ timestamp )));
770+ $ query ->executeStatement ();
771+ }
772+
715773 /**
716774 * @param string $file
717775 * @param string $filename
0 commit comments