FullBackup.java revision b0628bfd5aac480a0d412ac96b8af1d97ac01c30
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.app.backup; 18 19import android.os.ParcelFileDescriptor; 20import android.util.Log; 21 22import java.io.File; 23import java.io.FileInputStream; 24import java.io.FileOutputStream; 25import java.io.IOException; 26 27import libcore.io.ErrnoException; 28import libcore.io.Libcore; 29 30/** 31 * Global constant definitions et cetera related to the full-backup-to-fd 32 * binary format. 33 * 34 * @hide 35 */ 36public class FullBackup { 37 static final String TAG = "FullBackup"; 38 39 public static final String APK_TREE_TOKEN = "a"; 40 public static final String OBB_TREE_TOKEN = "obb"; 41 public static final String ROOT_TREE_TOKEN = "r"; 42 public static final String DATA_TREE_TOKEN = "f"; 43 public static final String DATABASE_TREE_TOKEN = "db"; 44 public static final String SHAREDPREFS_TREE_TOKEN = "sp"; 45 public static final String CACHE_TREE_TOKEN = "c"; 46 public static final String SHARED_STORAGE_TOKEN = "shared"; 47 48 public static final String APPS_PREFIX = "apps/"; 49 public static final String SHARED_PREFIX = SHARED_STORAGE_TOKEN + "/"; 50 51 public static final String FULL_BACKUP_INTENT_ACTION = "fullback"; 52 public static final String FULL_RESTORE_INTENT_ACTION = "fullrest"; 53 public static final String CONF_TOKEN_INTENT_EXTRA = "conftoken"; 54 55 public static final int TYPE_EOF = 0; 56 public static final int TYPE_FILE = 1; 57 public static final int TYPE_DIRECTORY = 2; 58 public static final int TYPE_SYMLINK = 3; 59 60 static public native int backupToTar(String packageName, String domain, 61 String linkdomain, String rootpath, String path, BackupDataOutput output); 62 63 static public void restoreToFile(ParcelFileDescriptor data, 64 long size, int type, long mode, long mtime, File outFile, 65 boolean doChmod) throws IOException { 66 if (type == FullBackup.TYPE_DIRECTORY) { 67 // Canonically a directory has no associated content, so we don't need to read 68 // anything from the pipe in this case. Just create the directory here and 69 // drop down to the final metadata adjustment. 70 if (outFile != null) outFile.mkdirs(); 71 } else { 72 FileOutputStream out = null; 73 74 // Pull the data from the pipe, copying it to the output file, until we're done 75 try { 76 if (outFile != null) { 77 File parent = outFile.getParentFile(); 78 if (!parent.exists()) { 79 // in practice this will only be for the default semantic directories, 80 // and using the default mode for those is appropriate. 81 // TODO: support the edge case of apps that have adjusted the 82 // permissions on these core directories 83 parent.mkdirs(); 84 } 85 out = new FileOutputStream(outFile); 86 } 87 } catch (IOException e) { 88 Log.e(TAG, "Unable to create/open file " + outFile.getPath(), e); 89 } 90 91 byte[] buffer = new byte[32 * 1024]; 92 final long origSize = size; 93 FileInputStream in = new FileInputStream(data.getFileDescriptor()); 94 while (size > 0) { 95 int toRead = (size > buffer.length) ? buffer.length : (int)size; 96 int got = in.read(buffer, 0, toRead); 97 if (got <= 0) { 98 Log.w(TAG, "Incomplete read: expected " + size + " but got " 99 + (origSize - size)); 100 break; 101 } 102 if (out != null) { 103 try { 104 out.write(buffer, 0, got); 105 } catch (IOException e) { 106 // Problem writing to the file. Quit copying data and delete 107 // the file, but of course keep consuming the input stream. 108 Log.e(TAG, "Unable to write to file " + outFile.getPath(), e); 109 out.close(); 110 out = null; 111 outFile.delete(); 112 } 113 } 114 size -= got; 115 } 116 if (out != null) out.close(); 117 } 118 119 // Now twiddle the state to match the backup, assuming all went well 120 if (doChmod && outFile != null) { 121 try { 122 Libcore.os.chmod(outFile.getPath(), (int)mode); 123 } catch (ErrnoException e) { 124 e.rethrowAsIOException(); 125 } 126 outFile.setLastModified(mtime); 127 } 128 } 129} 130