2021-06-27 20:44:35 +00:00
|
|
|
package androidx.core.util;
|
|
|
|
|
|
|
|
import android.util.Log;
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.annotation.Nullable;
|
2021-12-21 23:37:30 +00:00
|
|
|
import b.d.b.a.a;
|
2021-06-27 20:44:35 +00:00
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.io.FileNotFoundException;
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
import java.io.IOException;
|
2022-03-02 20:59:20 +00:00
|
|
|
/* loaded from: classes.dex */
|
2021-06-27 20:44:35 +00:00
|
|
|
public class AtomicFile {
|
2021-09-29 00:45:08 +00:00
|
|
|
private static final String LOG_TAG = "AtomicFile";
|
2021-06-27 20:44:35 +00:00
|
|
|
private final File mBaseName;
|
2021-09-29 00:45:08 +00:00
|
|
|
private final File mLegacyBackupName;
|
|
|
|
private final File mNewName;
|
2021-06-27 20:44:35 +00:00
|
|
|
|
|
|
|
public AtomicFile(@NonNull File file) {
|
|
|
|
this.mBaseName = file;
|
2021-09-29 00:45:08 +00:00
|
|
|
this.mNewName = new File(file.getPath() + ".new");
|
|
|
|
this.mLegacyBackupName = new File(file.getPath() + ".bak");
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void rename(@NonNull File file, @NonNull File file2) {
|
|
|
|
if (file2.isDirectory() && !file2.delete()) {
|
|
|
|
Log.e(LOG_TAG, "Failed to delete file which is a directory " + file2);
|
|
|
|
}
|
|
|
|
if (!file.renameTo(file2)) {
|
|
|
|
Log.e(LOG_TAG, "Failed to rename " + file + " to " + file2);
|
|
|
|
}
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private static boolean sync(@NonNull FileOutputStream fileOutputStream) {
|
|
|
|
try {
|
|
|
|
fileOutputStream.getFD().sync();
|
|
|
|
return true;
|
|
|
|
} catch (IOException unused) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void delete() {
|
|
|
|
this.mBaseName.delete();
|
2021-09-29 00:45:08 +00:00
|
|
|
this.mNewName.delete();
|
|
|
|
this.mLegacyBackupName.delete();
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void failWrite(@Nullable FileOutputStream fileOutputStream) {
|
|
|
|
if (fileOutputStream != null) {
|
2021-09-29 00:45:08 +00:00
|
|
|
if (!sync(fileOutputStream)) {
|
|
|
|
Log.e(LOG_TAG, "Failed to sync file output stream");
|
|
|
|
}
|
2021-06-27 20:44:35 +00:00
|
|
|
try {
|
|
|
|
fileOutputStream.close();
|
|
|
|
} catch (IOException e) {
|
2021-09-29 00:45:08 +00:00
|
|
|
Log.e(LOG_TAG, "Failed to close file output stream", e);
|
|
|
|
}
|
|
|
|
if (!this.mNewName.delete()) {
|
2022-03-22 15:40:06 +00:00
|
|
|
StringBuilder S = a.S("Failed to delete new file ");
|
|
|
|
S.append(this.mNewName);
|
|
|
|
Log.e(LOG_TAG, S.toString());
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void finishWrite(@Nullable FileOutputStream fileOutputStream) {
|
|
|
|
if (fileOutputStream != null) {
|
2021-09-29 00:45:08 +00:00
|
|
|
if (!sync(fileOutputStream)) {
|
|
|
|
Log.e(LOG_TAG, "Failed to sync file output stream");
|
|
|
|
}
|
2021-06-27 20:44:35 +00:00
|
|
|
try {
|
|
|
|
fileOutputStream.close();
|
|
|
|
} catch (IOException e) {
|
2021-09-29 00:45:08 +00:00
|
|
|
Log.e(LOG_TAG, "Failed to close file output stream", e);
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
2021-09-29 00:45:08 +00:00
|
|
|
rename(this.mNewName, this.mBaseName);
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
public File getBaseFile() {
|
|
|
|
return this.mBaseName;
|
|
|
|
}
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
public FileInputStream openRead() throws FileNotFoundException {
|
2021-09-29 00:45:08 +00:00
|
|
|
if (this.mLegacyBackupName.exists()) {
|
|
|
|
rename(this.mLegacyBackupName, this.mBaseName);
|
|
|
|
}
|
|
|
|
if (this.mNewName.exists() && this.mBaseName.exists() && !this.mNewName.delete()) {
|
2022-03-22 15:40:06 +00:00
|
|
|
StringBuilder S = a.S("Failed to delete outdated new file ");
|
|
|
|
S.append(this.mNewName);
|
|
|
|
Log.e(LOG_TAG, S.toString());
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
|
|
|
return new FileInputStream(this.mBaseName);
|
|
|
|
}
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
public byte[] readFully() throws IOException {
|
|
|
|
FileInputStream openRead = openRead();
|
|
|
|
try {
|
|
|
|
byte[] bArr = new byte[openRead.available()];
|
|
|
|
int i = 0;
|
|
|
|
while (true) {
|
|
|
|
int read = openRead.read(bArr, i, bArr.length - i);
|
|
|
|
if (read <= 0) {
|
|
|
|
return bArr;
|
|
|
|
}
|
|
|
|
i += read;
|
|
|
|
int available = openRead.available();
|
|
|
|
if (available > bArr.length - i) {
|
2022-03-02 20:59:20 +00:00
|
|
|
byte[] bArr2 = new byte[available + i];
|
2021-06-27 20:44:35 +00:00
|
|
|
System.arraycopy(bArr, 0, bArr2, 0, i);
|
|
|
|
bArr = bArr2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
openRead.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
public FileOutputStream startWrite() throws IOException {
|
2021-09-29 00:45:08 +00:00
|
|
|
if (this.mLegacyBackupName.exists()) {
|
|
|
|
rename(this.mLegacyBackupName, this.mBaseName);
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
|
|
|
try {
|
2021-09-29 00:45:08 +00:00
|
|
|
return new FileOutputStream(this.mNewName);
|
2021-06-27 20:44:35 +00:00
|
|
|
} catch (FileNotFoundException unused) {
|
2021-09-29 00:45:08 +00:00
|
|
|
if (this.mNewName.getParentFile().mkdirs()) {
|
2021-06-27 20:44:35 +00:00
|
|
|
try {
|
2021-09-29 00:45:08 +00:00
|
|
|
return new FileOutputStream(this.mNewName);
|
|
|
|
} catch (FileNotFoundException e) {
|
2022-03-22 15:40:06 +00:00
|
|
|
StringBuilder S = a.S("Failed to create new file ");
|
|
|
|
S.append(this.mNewName);
|
|
|
|
throw new IOException(S.toString(), e);
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
|
|
|
} else {
|
2022-03-22 15:40:06 +00:00
|
|
|
StringBuilder S2 = a.S("Failed to create directory for ");
|
|
|
|
S2.append(this.mNewName);
|
|
|
|
throw new IOException(S2.toString());
|
2021-06-27 20:44:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|