diff options
Diffstat (limited to 'core/java/android/app/backup/FullBackup.java')
-rw-r--r-- | core/java/android/app/backup/FullBackup.java | 110 |
1 files changed, 99 insertions, 11 deletions
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java index 9850566..dfb0dd7 100644 --- a/core/java/android/app/backup/FullBackup.java +++ b/core/java/android/app/backup/FullBackup.java @@ -16,6 +16,17 @@ package android.app.backup; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +import libcore.io.ErrnoException; +import libcore.io.Libcore; + /** * Global constant definitions et cetera related to the full-backup-to-fd * binary format. @@ -23,18 +34,95 @@ package android.app.backup; * @hide */ public class FullBackup { - public static String APK_TREE_TOKEN = "a"; - public static String OBB_TREE_TOKEN = "obb"; - public static String ROOT_TREE_TOKEN = "r"; - public static String DATA_TREE_TOKEN = "f"; - public static String DATABASE_TREE_TOKEN = "db"; - public static String SHAREDPREFS_TREE_TOKEN = "sp"; - public static String CACHE_TREE_TOKEN = "c"; - - public static String FULL_BACKUP_INTENT_ACTION = "fullback"; - public static String FULL_RESTORE_INTENT_ACTION = "fullrest"; - public static String CONF_TOKEN_INTENT_EXTRA = "conftoken"; + static final String TAG = "FullBackup"; + + public static final String APK_TREE_TOKEN = "a"; + public static final String OBB_TREE_TOKEN = "obb"; + public static final String ROOT_TREE_TOKEN = "r"; + public static final String DATA_TREE_TOKEN = "f"; + public static final String DATABASE_TREE_TOKEN = "db"; + public static final String SHAREDPREFS_TREE_TOKEN = "sp"; + public static final String CACHE_TREE_TOKEN = "c"; + public static final String SHARED_STORAGE_TOKEN = "shared"; + + public static final String APPS_PREFIX = "apps/"; + public static final String SHARED_PREFIX = "shared/"; + + public static final String FULL_BACKUP_INTENT_ACTION = "fullback"; + public static final String FULL_RESTORE_INTENT_ACTION = "fullrest"; + public static final String CONF_TOKEN_INTENT_EXTRA = "conftoken"; + + public static final int TYPE_EOF = 0; + public static final int TYPE_FILE = 1; + public static final int TYPE_DIRECTORY = 2; + public static final int TYPE_SYMLINK = 3; static public native int backupToTar(String packageName, String domain, String linkdomain, String rootpath, String path, BackupDataOutput output); + + static public void restoreToFile(ParcelFileDescriptor data, + long size, int type, long mode, long mtime, File outFile) throws IOException { + if (type == FullBackup.TYPE_DIRECTORY) { + // Canonically a directory has no associated content, so we don't need to read + // anything from the pipe in this case. Just create the directory here and + // drop down to the final metadata adjustment. + if (outFile != null) outFile.mkdirs(); + } else { + FileOutputStream out = null; + + // Pull the data from the pipe, copying it to the output file, until we're done + try { + if (outFile != null) { + File parent = outFile.getParentFile(); + if (!parent.exists()) { + // in practice this will only be for the default semantic directories, + // and using the default mode for those is appropriate. + // TODO: support the edge case of apps that have adjusted the + // permissions on these core directories + parent.mkdirs(); + } + out = new FileOutputStream(outFile); + } + } catch (IOException e) { + Log.e(TAG, "Unable to create/open file " + outFile.getPath(), e); + } + + byte[] buffer = new byte[32 * 1024]; + final long origSize = size; + FileInputStream in = new FileInputStream(data.getFileDescriptor()); + while (size > 0) { + int toRead = (size > buffer.length) ? buffer.length : (int)size; + int got = in.read(buffer, 0, toRead); + if (got <= 0) { + Log.w(TAG, "Incomplete read: expected " + size + " but got " + + (origSize - size)); + break; + } + if (out != null) { + try { + out.write(buffer, 0, got); + } catch (IOException e) { + // Problem writing to the file. Quit copying data and delete + // the file, but of course keep consuming the input stream. + Log.e(TAG, "Unable to write to file " + outFile.getPath(), e); + out.close(); + out = null; + outFile.delete(); + } + } + size -= got; + } + if (out != null) out.close(); + } + + // Now twiddle the state to match the backup, assuming all went well + if (outFile != null) { + try { + Libcore.os.chmod(outFile.getPath(), (int)mode); + } catch (ErrnoException e) { + e.rethrowAsIOException(); + } + outFile.setLastModified(mtime); + } + } } |