mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-05-15 14:32:49 +00:00
Protect writes of the vault file against corruption with AtomicFile
This adds a recovery mechanism for (probably extremely rare) cases where the app may be killed before it is finished writing the vault file to disk. In the example below, we see that AtomicFile moved ``aegis.json`` to ``aegis.json.bak`` before writing to ``aegis.json``. ``` bonito:/ # ls -lah /data/data/com.beemdevelopment.aegis.debug/files total 27M drwxrwx--x 2 u0_a306 u0_a306 3.4K 2020-02-02 13:22 . drwx------ 6 u0_a306 u0_a306 3.4K 2020-02-01 19:51 .. -rw------- 1 u0_a306 u0_a306 19M 2020-02-02 13:22 aegis.json -rw------- 1 u0_a306 u0_a306 34M 2020-02-02 13:21 aegis.json.bak ``` Because the app was killed before it could finish writing, it is only 19M in size, instead of the expected 34M. The next time the app starts, AtomicFile will notice that the .bak file is still present, and use that instead of the corrupted ``aegis.json`` file.
This commit is contained in:
parent
833e75ade1
commit
4ba3caeaf4
1 changed files with 16 additions and 11 deletions
|
@ -3,13 +3,13 @@ package com.beemdevelopment.aegis.vault;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.core.util.AtomicFile;
|
||||
|
||||
import com.beemdevelopment.aegis.services.NotificationService;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
@ -41,12 +41,9 @@ public class VaultManager {
|
|||
public void load() throws VaultManagerException {
|
||||
assertState(true, false);
|
||||
|
||||
try (FileInputStream file = _context.openFileInput(FILENAME)) {
|
||||
byte[] fileBytes = new byte[(int) file.getChannel().size()];
|
||||
DataInputStream stream = new DataInputStream(file);
|
||||
stream.readFully(fileBytes);
|
||||
stream.close();
|
||||
|
||||
AtomicFile file = new AtomicFile(new File(_context.getFilesDir(), FILENAME));
|
||||
try {
|
||||
byte[] fileBytes = file.readFully();
|
||||
_file = VaultFile.fromBytes(fileBytes);
|
||||
_encrypt = _file.isEncrypted();
|
||||
if (!isEncryptionEnabled()) {
|
||||
|
@ -77,11 +74,19 @@ public class VaultManager {
|
|||
}
|
||||
}
|
||||
|
||||
public static void save(Context context, VaultFile file) throws VaultManagerException {
|
||||
byte[] bytes = file.toBytes();
|
||||
try (FileOutputStream stream = context.openFileOutput(FILENAME, Context.MODE_PRIVATE)) {
|
||||
public static void save(Context context, VaultFile vaultFile) throws VaultManagerException {
|
||||
byte[] bytes = vaultFile.toBytes();
|
||||
AtomicFile file = new AtomicFile(new File(context.getFilesDir(), FILENAME));
|
||||
|
||||
FileOutputStream stream = null;
|
||||
try {
|
||||
stream = file.startWrite();
|
||||
stream.write(bytes);
|
||||
file.finishWrite(stream);
|
||||
} catch (IOException e) {
|
||||
if (stream != null) {
|
||||
file.failWrite(stream);
|
||||
}
|
||||
throw new VaultManagerException(e);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue