Clean up transport logic in ContentProviderRestoreComponent

This commit is contained in:
Steve Soltys 2017-10-04 21:10:18 -04:00
parent a1a8329299
commit 0a978c37e8

View file

@ -17,6 +17,7 @@ import libcore.io.Streams;
import java.io.*; import java.io.*;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.util.Optional;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
@ -27,8 +28,6 @@ import static com.stevesoltys.backup.transport.component.provider.ContentProvide
import static com.stevesoltys.backup.transport.component.provider.ContentProviderBackupConfiguration.INCREMENTAL_BACKUP_DIRECTORY; import static com.stevesoltys.backup.transport.component.provider.ContentProviderBackupConfiguration.INCREMENTAL_BACKUP_DIRECTORY;
/** /**
* TODO: Clean this up. Much of it was taken from the LocalTransport implementation.
*
* @author Steve Soltys * @author Steve Soltys
*/ */
public class ContentProviderRestoreComponent implements RestoreComponent { public class ContentProviderRestoreComponent implements RestoreComponent {
@ -55,40 +54,6 @@ public class ContentProviderRestoreComponent implements RestoreComponent {
return TRANSPORT_OK; return TRANSPORT_OK;
} }
private ParcelFileDescriptor buildFileDescriptor() throws FileNotFoundException {
ContentResolver contentResolver = configuration.getContext().getContentResolver();
return contentResolver.openFileDescriptor(configuration.getUri(), "r");
}
private ZipInputStream buildInputStream(ParcelFileDescriptor inputFileDescriptor) throws FileNotFoundException {
FileInputStream fileInputStream = new FileInputStream(inputFileDescriptor.getFileDescriptor());
return new ZipInputStream(fileInputStream);
}
private boolean containsPackageFile(String fileName) throws IOException, InvalidKeyException,
InvalidAlgorithmParameterException {
ParcelFileDescriptor inputFileDescriptor = buildFileDescriptor();
ZipInputStream inputStream = buildInputStream(inputFileDescriptor);
ZipEntry zipEntry;
while ((zipEntry = inputStream.getNextEntry()) != null) {
if (zipEntry.getName().startsWith(fileName)) {
IoUtils.closeQuietly(inputStream);
IoUtils.closeQuietly(inputFileDescriptor.getFileDescriptor());
return true;
}
inputStream.closeEntry();
}
IoUtils.closeQuietly(inputStream);
IoUtils.closeQuietly(inputFileDescriptor.getFileDescriptor());
return false;
}
@Override @Override
public RestoreDescription nextRestorePackage() { public RestoreDescription nextRestorePackage() {
Preconditions.checkNotNull(restoreState, "startRestore() not called"); Preconditions.checkNotNull(restoreState, "startRestore() not called");
@ -117,6 +82,39 @@ public class ContentProviderRestoreComponent implements RestoreComponent {
return RestoreDescription.NO_MORE_PACKAGES; return RestoreDescription.NO_MORE_PACKAGES;
} }
private boolean containsPackageFile(String fileName) throws IOException, InvalidKeyException,
InvalidAlgorithmParameterException {
ParcelFileDescriptor inputFileDescriptor = buildInputFileDescriptor();
ZipInputStream inputStream = buildInputStream(inputFileDescriptor);
Optional<ZipEntry> zipEntry = seekToEntry(inputStream, fileName);
IoUtils.closeQuietly(inputFileDescriptor.getFileDescriptor());
return zipEntry.isPresent();
}
private ParcelFileDescriptor buildInputFileDescriptor() throws FileNotFoundException {
ContentResolver contentResolver = configuration.getContext().getContentResolver();
return contentResolver.openFileDescriptor(configuration.getUri(), "r");
}
private ZipInputStream buildInputStream(ParcelFileDescriptor inputFileDescriptor) throws FileNotFoundException {
FileInputStream fileInputStream = new FileInputStream(inputFileDescriptor.getFileDescriptor());
return new ZipInputStream(fileInputStream);
}
private Optional<ZipEntry> seekToEntry(ZipInputStream inputStream, String entryPath) throws IOException {
ZipEntry zipEntry;
while ((zipEntry = inputStream.getNextEntry()) != null) {
if (zipEntry.getName().startsWith(entryPath)) {
return Optional.of(zipEntry);
}
inputStream.closeEntry();
}
return Optional.empty();
}
@Override @Override
public int getRestoreData(ParcelFileDescriptor outputFileDescriptor) { public int getRestoreData(ParcelFileDescriptor outputFileDescriptor) {
Preconditions.checkState(restoreState != null, "startRestore() not called"); Preconditions.checkState(restoreState != null, "startRestore() not called");
@ -138,25 +136,22 @@ public class ContentProviderRestoreComponent implements RestoreComponent {
private int transferIncrementalRestoreData(String packageName, BackupDataOutput backupDataOutput) private int transferIncrementalRestoreData(String packageName, BackupDataOutput backupDataOutput)
throws IOException, InvalidAlgorithmParameterException, InvalidKeyException { throws IOException, InvalidAlgorithmParameterException, InvalidKeyException {
ParcelFileDescriptor inputFileDescriptor = buildFileDescriptor(); ParcelFileDescriptor inputFileDescriptor = buildInputFileDescriptor();
ZipInputStream inputStream = buildInputStream(inputFileDescriptor); ZipInputStream inputStream = buildInputStream(inputFileDescriptor);
ZipEntry zipEntry; Optional<ZipEntry> zipEntryOptional = seekToEntry(inputStream, INCREMENTAL_BACKUP_DIRECTORY + packageName);
while ((zipEntry = inputStream.getNextEntry()) != null) { while (zipEntryOptional.isPresent()) {
String fileName = new File(zipEntryOptional.get().getName()).getName();
if (zipEntry.getName().startsWith(INCREMENTAL_BACKUP_DIRECTORY + packageName)) { String blobKey = new String(Base64.decode(fileName, Base64.DEFAULT));
String fileName = new File(zipEntry.getName()).getName();
String blobKey = new String(Base64.decode(fileName, Base64.DEFAULT));
byte[] backupData = Streams.readFullyNoClose(inputStream);
backupDataOutput.writeEntityHeader(blobKey, backupData.length);
backupDataOutput.writeEntityData(backupData, backupData.length);
}
byte[] backupData = Streams.readFullyNoClose(inputStream);
backupDataOutput.writeEntityHeader(blobKey, backupData.length);
backupDataOutput.writeEntityData(backupData, backupData.length);
inputStream.closeEntry(); inputStream.closeEntry();
zipEntryOptional = seekToEntry(inputStream, INCREMENTAL_BACKUP_DIRECTORY + packageName);
} }
IoUtils.closeQuietly(inputStream);
IoUtils.closeQuietly(inputFileDescriptor.getFileDescriptor()); IoUtils.closeQuietly(inputFileDescriptor.getFileDescriptor());
return TRANSPORT_OK; return TRANSPORT_OK;
} }
@ -173,36 +168,13 @@ public class ContentProviderRestoreComponent implements RestoreComponent {
String name = restoreState.getPackages()[restoreState.getPackageIndex()].packageName; String name = restoreState.getPackages()[restoreState.getPackageIndex()].packageName;
try { try {
inputFileDescriptor = buildFileDescriptor(); inputFileDescriptor = buildInputFileDescriptor();
restoreState.setInputFileDescriptor(inputFileDescriptor); restoreState.setInputFileDescriptor(inputFileDescriptor);
inputStream = buildInputStream(inputFileDescriptor); inputStream = buildInputStream(inputFileDescriptor);
restoreState.setInputStream(inputStream); restoreState.setInputStream(inputStream);
} catch (FileNotFoundException ex) { if (!seekToEntry(inputStream, FULL_BACKUP_DIRECTORY + name).isPresent()) {
Log.e(TAG, "Unable to read archive for " + name, ex);
if (inputFileDescriptor != null) {
IoUtils.closeQuietly(inputFileDescriptor.getFileDescriptor());
}
return TRANSPORT_ERROR;
}
try {
ZipEntry zipEntry;
while ((zipEntry = inputStream.getNextEntry()) != null) {
if (zipEntry.getName().equals(FULL_BACKUP_DIRECTORY + name)) {
break;
}
inputStream.closeEntry();
}
if (zipEntry == null) {
IoUtils.closeQuietly(inputStream);
IoUtils.closeQuietly(inputFileDescriptor.getFileDescriptor()); IoUtils.closeQuietly(inputFileDescriptor.getFileDescriptor());
return TRANSPORT_PACKAGE_REJECTED; return TRANSPORT_PACKAGE_REJECTED;
} }
@ -210,8 +182,9 @@ public class ContentProviderRestoreComponent implements RestoreComponent {
} catch (IOException ex) { } catch (IOException ex) {
Log.e(TAG, "Unable to read archive for " + name, ex); Log.e(TAG, "Unable to read archive for " + name, ex);
IoUtils.closeQuietly(inputStream); if (inputFileDescriptor != null) {
IoUtils.closeQuietly(inputFileDescriptor.getFileDescriptor()); IoUtils.closeQuietly(inputFileDescriptor.getFileDescriptor());
}
return TRANSPORT_PACKAGE_REJECTED; return TRANSPORT_PACKAGE_REJECTED;
} }
} }
@ -228,12 +201,8 @@ public class ContentProviderRestoreComponent implements RestoreComponent {
try { try {
bytesRead = inputStream.read(buffer); bytesRead = inputStream.read(buffer);
if (bytesRead < 0) { if (bytesRead <= 0) {
bytesRead = NO_MORE_DATA; bytesRead = NO_MORE_DATA;
} else if (bytesRead == 0) {
bytesRead = NO_MORE_DATA;
} else { } else {
outputStream.write(buffer, 0, bytesRead); outputStream.write(buffer, 0, bytesRead);
} }
@ -243,20 +212,15 @@ public class ContentProviderRestoreComponent implements RestoreComponent {
return TRANSPORT_ERROR; return TRANSPORT_ERROR;
} finally { } finally {
try { if (bytesRead == NO_MORE_DATA) {
if (bytesRead == NO_MORE_DATA) { if (inputFileDescriptor != null) {
IoUtils.closeQuietly(inputFileDescriptor.getFileDescriptor()); IoUtils.closeQuietly(inputFileDescriptor.getFileDescriptor());
IoUtils.closeQuietly(inputStream);
IoUtils.closeQuietly(outputStream);
fileDescriptor.close();
restoreState.setInputFileDescriptor(null);
restoreState.setInputStream(null);
restoreState.setOutputStream(null);
} }
} catch (IOException ex) { IoUtils.closeQuietly(fileDescriptor.getFileDescriptor());
Log.e(TAG, "Exception while closing socket for restore: ", ex);
restoreState.setInputFileDescriptor(null);
restoreState.setInputStream(null);
restoreState.setOutputStream(null);
} }
} }
@ -290,10 +254,9 @@ public class ContentProviderRestoreComponent implements RestoreComponent {
private void resetFullRestoreState() { private void resetFullRestoreState() {
Preconditions.checkNotNull(restoreState); Preconditions.checkNotNull(restoreState);
Preconditions.checkState(restoreState.getRestoreType() != TYPE_FULL_STREAM); Preconditions.checkState(restoreState.getRestoreType() == TYPE_FULL_STREAM);
IoUtils.closeQuietly(restoreState.getInputFileDescriptor()); IoUtils.closeQuietly(restoreState.getInputFileDescriptor());
IoUtils.closeQuietly(restoreState.getInputStream());
IoUtils.closeQuietly(restoreState.getOutputStream()); IoUtils.closeQuietly(restoreState.getOutputStream());
restoreState = null; restoreState = null;
} }