Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,6 @@ protected final AsyncTaskResult<Boolean> doInBackground(
if (FileUtils.NOMEDIA_FILE.equals(file.getName()))
MediaConnectionUtils.scanFile(applicationContext, file.getParent(applicationContext));
}

// delete file entry from encrypted database
if (file.getName(applicationContext).endsWith(CryptUtil.CRYPT_EXTENSION)) {
CryptHandler handler = CryptHandler.INSTANCE;
handler.clear(file.getPath());
}
}

return new AsyncTaskResult<>(wasDeleted);
Expand Down Expand Up @@ -162,11 +156,15 @@ public void onPostExecute(AsyncTaskResult<Boolean> result) {
}

private boolean doDeleteFile(@NonNull HybridFileParcelable file) throws Exception {
boolean isEncrypted =
!file.isTrashBin() && file.getName(applicationContext).endsWith(CryptUtil.CRYPT_EXTENSION);
boolean wasDeleted;
switch (file.getMode()) {
case OTG:
DocumentFile documentFile =
OTGUtil.getDocumentFile(file.getPath(), applicationContext, false);
return documentFile.delete();
wasDeleted = documentFile.delete();
break;
case DOCUMENT_FILE:
documentFile =
OTGUtil.getDocumentFile(
Expand All @@ -175,19 +173,21 @@ private boolean doDeleteFile(@NonNull HybridFileParcelable file) throws Exceptio
applicationContext,
OpenMode.DOCUMENT_FILE,
false);
return documentFile.delete();
wasDeleted = documentFile.delete();
break;
case DROPBOX:
case BOX:
case GDRIVE:
case ONEDRIVE:
CloudStorage cloudStorage = dataUtils.getAccount(file.getMode());
try {
cloudStorage.delete(CloudUtil.stripPath(file.getMode(), file.getPath()));
return true;
wasDeleted = true;
} catch (Exception e) {
LOG.warn("failed to delete cloud files", e);
return false;
wasDeleted = false;
}
break;
default:
try {
/* SMB and SFTP (or any remote files that may support in the future) should not be
Expand All @@ -198,11 +198,15 @@ private boolean doDeleteFile(@NonNull HybridFileParcelable file) throws Exceptio
&& !OpenMode.SFTP.equals(file.getMode())) {
return file.moveToBin(applicationContext);
}
return file.delete(applicationContext, rootMode);
wasDeleted = file.delete(applicationContext, rootMode);
} catch (ShellNotRunningException | SmbException e) {
LOG.warn("failed to delete files", e);
throw e;
}
}
if (wasDeleted && isEncrypted) {
CryptHandler.INSTANCE.clear(file.getPath());
}
return wasDeleted;
}
}
11 changes: 11 additions & 0 deletions app/src/main/java/com/amaze/filemanager/database/CryptHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ object CryptHandler {
.subscribe()
}

/**
* Move stored paths without changing entry IDs or passwords. Called from file-operation workers;
* finish before returning so an immediate restore can find the entry at its new path.
*/
fun moveEntry(
oldPath: String,
newPath: String,
) {
database.encryptedEntryDao().move(oldPath, newPath).blockingAwait()
}

/**
* Find [EncryptedEntry] of specified path. Returns null if not exist.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ public interface EncryptedEntryDao {
@Update
Completable update(EncryptedEntry entry);

@Query(
"UPDATE "
+ TABLE_ENCRYPTED
+ " SET "
+ COLUMN_PATH
+ " = :newPath WHERE "
+ COLUMN_PATH
+ " = :oldPath")
Completable move(String oldPath, String newPath);

@Transaction
@Query("DELETE FROM " + TABLE_ENCRYPTED + " WHERE " + COLUMN_PATH + " = :path")
Completable delete(String path);
Expand Down
41 changes: 37 additions & 4 deletions app/src/main/java/com/amaze/filemanager/filesystem/HybridFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,13 @@
import com.amaze.filemanager.adapters.data.LayoutElementParcelable;
import com.amaze.filemanager.application.AppConfig;
import com.amaze.filemanager.database.CloudHandler;
import com.amaze.filemanager.database.CryptHandler;
import com.amaze.filemanager.fileoperations.exceptions.CloudPluginException;
import com.amaze.filemanager.fileoperations.exceptions.ShellNotRunningException;
import com.amaze.filemanager.fileoperations.filesystem.OpenMode;
import com.amaze.filemanager.fileoperations.filesystem.root.NativeOperations;
import com.amaze.filemanager.filesystem.cloud.CloudUtil;
import com.amaze.filemanager.filesystem.files.CryptUtil;
import com.amaze.filemanager.filesystem.files.FileUtils;
import com.amaze.filemanager.filesystem.files.GenericCopyUtil;
import com.amaze.filemanager.filesystem.files.MediaConnectionUtils;
Expand Down Expand Up @@ -1587,25 +1589,51 @@ public void restoreFromBin(Context context) {
}
}

/**
* Rename a local file and finish moving its Amaze metadata before the worker reports success.
* Restore the source if its metadata could not be moved.
*/
public static boolean renameWithEncryptedMetadata(File source, File dest) {
if (!source.renameTo(dest)) {
return false;
}
if (source.getName().endsWith(CryptUtil.CRYPT_EXTENSION)
|| dest.getName().endsWith(CryptUtil.CRYPT_EXTENSION)) {
try {
CryptHandler.INSTANCE.moveEntry(source.getPath(), dest.getPath());
} catch (RuntimeException e) {
LOG.warn("Failed to move encrypted metadata", e);
if (!dest.renameTo(source)) {
LOG.error("Failed to restore file after metadata move failure", e);
throw e;
}
return false;
}
}
return true;
}

public boolean moveToBin(Context context) {
List<TrashBinFile> trashBinFiles = Collections.singletonList(this.toTrashBinFile(context));
TrashBin trashBin = AppConfig.getInstance().getTrashBinInstance();
AtomicBoolean wasMoved = new AtomicBoolean(false);
if (trashBin != null) {
trashBin.moveToBin(
trashBinFiles,
true,
(originalFilePath, trashBinDestination) -> {
File source = new File(originalFilePath);
File dest = new File(trashBinDestination);
return source.renameTo(dest);
wasMoved.set(renameWithEncryptedMetadata(source, dest));
return wasMoved.get();
});
}
return true;
return wasMoved.get();
}

public boolean deletePermanentlyFromBin(Context context) {
List<TrashBinFile> trashBinFiles =
Collections.singletonList(this.toTrashBinRestoreFile(context));
TrashBinFile originalFile = this.toTrashBinRestoreFile(context);
List<TrashBinFile> trashBinFiles = Collections.singletonList(originalFile);
TrashBin trashBin = AppConfig.getInstance().getTrashBinInstance();
AtomicBoolean isDelete = new AtomicBoolean(false);
if (trashBin != null) {
Expand All @@ -1614,6 +1642,11 @@ public boolean deletePermanentlyFromBin(Context context) {
s -> {
LOG.info("deleting from bin at path " + s);
isDelete.set(DeleteOperation.deleteFile(getFile(), context));
if (isDelete.get()
&& originalFile != null
&& originalFile.getPath().endsWith(CryptUtil.CRYPT_EXTENSION)) {
CryptHandler.INSTANCE.clear(getPath());
}
return isDelete.get();
},
true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ class MainActivityViewModel(val applicationContext: Application) :
): Boolean {
val source = File(originalFilePath)
val dest = File(trashBinDestination)
if (!source.renameTo(dest)) {
if (!HybridFile.renameWithEncryptedMetadata(source, dest)) {
return false
}
val hybridFile =
Expand Down Expand Up @@ -284,7 +284,7 @@ class MainActivityViewModel(val applicationContext: Application) :
if (destFile.parentFile != null && !destFile.parentFile!!.exists()) {
destFile.parentFile?.mkdirs()
}
if (!sourceFile.renameTo(destFile)) {
if (!HybridFile.renameWithEncryptedMetadata(sourceFile, destFile)) {
return false
}
val hybridFile =
Expand Down
Loading