blob: cfd0a651300d1492e66e8af0cc729bbdf3dfac7a [file] [log] [blame]
Christopher Tate4a627c72011-04-01 14:43:32 -07001/*
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
Christopher Tate75a99702011-05-18 16:28:19 -070019import 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
Christopher Tate4a627c72011-04-01 14:43:32 -070030/**
31 * Global constant definitions et cetera related to the full-backup-to-fd
Christopher Tate79ec80d2011-06-24 14:58:49 -070032 * binary format. Nothing in this namespace is part of any API; it's all
33 * hidden details of the current implementation gathered into one location.
Christopher Tate4a627c72011-04-01 14:43:32 -070034 *
35 * @hide
36 */
37public class FullBackup {
Christopher Tate75a99702011-05-18 16:28:19 -070038 static final String TAG = "FullBackup";
Christopher Tate4a627c72011-04-01 14:43:32 -070039
Christopher Tate75a99702011-05-18 16:28:19 -070040 public static final String APK_TREE_TOKEN = "a";
41 public static final String OBB_TREE_TOKEN = "obb";
42 public static final String ROOT_TREE_TOKEN = "r";
43 public static final String DATA_TREE_TOKEN = "f";
44 public static final String DATABASE_TREE_TOKEN = "db";
45 public static final String SHAREDPREFS_TREE_TOKEN = "sp";
Christopher Tate416c39e2013-02-14 16:55:46 -080046 public static final String MANAGED_EXTERNAL_TREE_TOKEN = "ef";
Christopher Tate75a99702011-05-18 16:28:19 -070047 public static final String CACHE_TREE_TOKEN = "c";
48 public static final String SHARED_STORAGE_TOKEN = "shared";
49
50 public static final String APPS_PREFIX = "apps/";
Christopher Tateb0628bf2011-06-02 15:08:13 -070051 public static final String SHARED_PREFIX = SHARED_STORAGE_TOKEN + "/";
Christopher Tate75a99702011-05-18 16:28:19 -070052
53 public static final String FULL_BACKUP_INTENT_ACTION = "fullback";
54 public static final String FULL_RESTORE_INTENT_ACTION = "fullrest";
55 public static final String CONF_TOKEN_INTENT_EXTRA = "conftoken";
56
Christopher Tate79ec80d2011-06-24 14:58:49 -070057 /**
58 * @hide
59 */
Christopher Tate4a627c72011-04-01 14:43:32 -070060 static public native int backupToTar(String packageName, String domain,
61 String linkdomain, String rootpath, String path, BackupDataOutput output);
Christopher Tate75a99702011-05-18 16:28:19 -070062
Christopher Tate79ec80d2011-06-24 14:58:49 -070063 /**
64 * Copy data from a socket to the given File location on permanent storage. The
Christopher Tatef6d6fa82012-09-26 15:25:59 -070065 * modification time and access mode of the resulting file will be set if desired,
66 * although group/all rwx modes will be stripped: the restored file will not be
67 * accessible from outside the target application even if the original file was.
Christopher Tate79ec80d2011-06-24 14:58:49 -070068 * If the {@code type} parameter indicates that the result should be a directory,
69 * the socket parameter may be {@code null}; even if it is valid, no data will be
70 * read from it in this case.
71 * <p>
72 * If the {@code mode} argument is negative, then the resulting output file will not
73 * have its access mode or last modification time reset as part of this operation.
74 *
75 * @param data Socket supplying the data to be copied to the output file. If the
76 * output is a directory, this may be {@code null}.
77 * @param size Number of bytes of data to copy from the socket to the file. At least
78 * this much data must be available through the {@code data} parameter.
79 * @param type Must be either {@link BackupAgent#TYPE_FILE} for ordinary file data
80 * or {@link BackupAgent#TYPE_DIRECTORY} for a directory.
81 * @param mode Unix-style file mode (as used by the chmod(2) syscall) to be set on
Christopher Tatef6d6fa82012-09-26 15:25:59 -070082 * the output file or directory. group/all rwx modes are stripped even if set
83 * in this parameter. If this parameter is negative then neither
84 * the mode nor the mtime values will be applied to the restored file.
Christopher Tate79ec80d2011-06-24 14:58:49 -070085 * @param mtime A timestamp in the standard Unix epoch that will be imposed as the
86 * last modification time of the output file. if the {@code mode} parameter is
87 * negative then this parameter will be ignored.
88 * @param outFile Location within the filesystem to place the data. This must point
Christopher Tate46cc43c2013-02-19 14:08:59 -080089 * to a location that is writeable by the caller, preferably using an absolute path.
Christopher Tate79ec80d2011-06-24 14:58:49 -070090 * @throws IOException
91 */
92 static public void restoreFile(ParcelFileDescriptor data,
93 long size, int type, long mode, long mtime, File outFile) throws IOException {
94 if (type == BackupAgent.TYPE_DIRECTORY) {
Christopher Tate75a99702011-05-18 16:28:19 -070095 // Canonically a directory has no associated content, so we don't need to read
96 // anything from the pipe in this case. Just create the directory here and
97 // drop down to the final metadata adjustment.
98 if (outFile != null) outFile.mkdirs();
99 } else {
100 FileOutputStream out = null;
101
102 // Pull the data from the pipe, copying it to the output file, until we're done
103 try {
104 if (outFile != null) {
105 File parent = outFile.getParentFile();
106 if (!parent.exists()) {
107 // in practice this will only be for the default semantic directories,
108 // and using the default mode for those is appropriate.
Christopher Tate75a99702011-05-18 16:28:19 -0700109 parent.mkdirs();
110 }
111 out = new FileOutputStream(outFile);
112 }
113 } catch (IOException e) {
114 Log.e(TAG, "Unable to create/open file " + outFile.getPath(), e);
115 }
116
117 byte[] buffer = new byte[32 * 1024];
118 final long origSize = size;
119 FileInputStream in = new FileInputStream(data.getFileDescriptor());
120 while (size > 0) {
121 int toRead = (size > buffer.length) ? buffer.length : (int)size;
122 int got = in.read(buffer, 0, toRead);
123 if (got <= 0) {
124 Log.w(TAG, "Incomplete read: expected " + size + " but got "
125 + (origSize - size));
126 break;
127 }
128 if (out != null) {
129 try {
130 out.write(buffer, 0, got);
131 } catch (IOException e) {
132 // Problem writing to the file. Quit copying data and delete
133 // the file, but of course keep consuming the input stream.
134 Log.e(TAG, "Unable to write to file " + outFile.getPath(), e);
135 out.close();
136 out = null;
137 outFile.delete();
138 }
139 }
140 size -= got;
141 }
142 if (out != null) out.close();
143 }
144
145 // Now twiddle the state to match the backup, assuming all went well
Christopher Tate79ec80d2011-06-24 14:58:49 -0700146 if (mode >= 0 && outFile != null) {
Christopher Tate75a99702011-05-18 16:28:19 -0700147 try {
Christopher Tatef6d6fa82012-09-26 15:25:59 -0700148 // explicitly prevent emplacement of files accessible by outside apps
149 mode &= 0700;
Christopher Tate75a99702011-05-18 16:28:19 -0700150 Libcore.os.chmod(outFile.getPath(), (int)mode);
151 } catch (ErrnoException e) {
152 e.rethrowAsIOException();
153 }
154 outFile.setLastModified(mtime);
155 }
156 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700157}