1*38e8c45fSAndroid Build Coastguard Worker // Copyright 2009 The Android Open Source Project
2*38e8c45fSAndroid Build Coastguard Worker
3*38e8c45fSAndroid Build Coastguard Worker #include <stdio.h>
4*38e8c45fSAndroid Build Coastguard Worker #include <stdlib.h>
5*38e8c45fSAndroid Build Coastguard Worker #include <stdarg.h>
6*38e8c45fSAndroid Build Coastguard Worker #include <string.h>
7*38e8c45fSAndroid Build Coastguard Worker #include <unistd.h>
8*38e8c45fSAndroid Build Coastguard Worker #include <fcntl.h>
9*38e8c45fSAndroid Build Coastguard Worker #include <time.h>
10*38e8c45fSAndroid Build Coastguard Worker #include <dirent.h>
11*38e8c45fSAndroid Build Coastguard Worker #include <errno.h>
12*38e8c45fSAndroid Build Coastguard Worker #include <assert.h>
13*38e8c45fSAndroid Build Coastguard Worker #include <ctype.h>
14*38e8c45fSAndroid Build Coastguard Worker #include <utime.h>
15*38e8c45fSAndroid Build Coastguard Worker #include <sys/stat.h>
16*38e8c45fSAndroid Build Coastguard Worker #include <sys/types.h>
17*38e8c45fSAndroid Build Coastguard Worker #include <stdint.h>
18*38e8c45fSAndroid Build Coastguard Worker
19*38e8c45fSAndroid Build Coastguard Worker #include <cutils/properties.h>
20*38e8c45fSAndroid Build Coastguard Worker
21*38e8c45fSAndroid Build Coastguard Worker #include <private/android_filesystem_config.h>
22*38e8c45fSAndroid Build Coastguard Worker
23*38e8c45fSAndroid Build Coastguard Worker #ifndef PATH_MAX
24*38e8c45fSAndroid Build Coastguard Worker #define PATH_MAX 4096
25*38e8c45fSAndroid Build Coastguard Worker #endif
26*38e8c45fSAndroid Build Coastguard Worker
27*38e8c45fSAndroid Build Coastguard Worker // First version.
28*38e8c45fSAndroid Build Coastguard Worker #define FILE_VERSION_1 0xffff0001
29*38e8c45fSAndroid Build Coastguard Worker
30*38e8c45fSAndroid Build Coastguard Worker // Introduces backup all option to header.
31*38e8c45fSAndroid Build Coastguard Worker #define FILE_VERSION_2 0xffff0002
32*38e8c45fSAndroid Build Coastguard Worker
33*38e8c45fSAndroid Build Coastguard Worker #define FILE_VERSION FILE_VERSION_2
34*38e8c45fSAndroid Build Coastguard Worker
35*38e8c45fSAndroid Build Coastguard Worker namespace android {
36*38e8c45fSAndroid Build Coastguard Worker
37*38e8c45fSAndroid Build Coastguard Worker static char nameBuffer[PATH_MAX];
38*38e8c45fSAndroid Build Coastguard Worker static struct stat statBuffer;
39*38e8c45fSAndroid Build Coastguard Worker
40*38e8c45fSAndroid Build Coastguard Worker static char copyBuffer[8192];
41*38e8c45fSAndroid Build Coastguard Worker static char *backupFilePath = nullptr;
42*38e8c45fSAndroid Build Coastguard Worker
43*38e8c45fSAndroid Build Coastguard Worker static uint32_t inputFileVersion;
44*38e8c45fSAndroid Build Coastguard Worker
45*38e8c45fSAndroid Build Coastguard Worker static int opt_backupAll;
46*38e8c45fSAndroid Build Coastguard Worker
47*38e8c45fSAndroid Build Coastguard Worker #define SPECIAL_NO_TOUCH 0
48*38e8c45fSAndroid Build Coastguard Worker #define SPECIAL_NO_BACKUP 1
49*38e8c45fSAndroid Build Coastguard Worker
50*38e8c45fSAndroid Build Coastguard Worker struct special_dir {
51*38e8c45fSAndroid Build Coastguard Worker const char* path;
52*38e8c45fSAndroid Build Coastguard Worker int type;
53*38e8c45fSAndroid Build Coastguard Worker };
54*38e8c45fSAndroid Build Coastguard Worker
55*38e8c45fSAndroid Build Coastguard Worker /* Directory paths that we will not backup/restore */
56*38e8c45fSAndroid Build Coastguard Worker static const struct special_dir SKIP_PATHS[] = {
57*38e8c45fSAndroid Build Coastguard Worker { "/data/misc", SPECIAL_NO_TOUCH },
58*38e8c45fSAndroid Build Coastguard Worker { "/data/system/batterystats.bin", SPECIAL_NO_TOUCH },
59*38e8c45fSAndroid Build Coastguard Worker { "/data/system/location", SPECIAL_NO_TOUCH },
60*38e8c45fSAndroid Build Coastguard Worker { "/data/dalvik-cache", SPECIAL_NO_BACKUP },
61*38e8c45fSAndroid Build Coastguard Worker { nullptr, 0 },
62*38e8c45fSAndroid Build Coastguard Worker };
63*38e8c45fSAndroid Build Coastguard Worker
64*38e8c45fSAndroid Build Coastguard Worker /* This is just copied from the shell's built-in wipe command. */
wipe(const char * path)65*38e8c45fSAndroid Build Coastguard Worker static int wipe (const char *path)
66*38e8c45fSAndroid Build Coastguard Worker {
67*38e8c45fSAndroid Build Coastguard Worker DIR *dir;
68*38e8c45fSAndroid Build Coastguard Worker struct dirent *de;
69*38e8c45fSAndroid Build Coastguard Worker int ret;
70*38e8c45fSAndroid Build Coastguard Worker int i;
71*38e8c45fSAndroid Build Coastguard Worker
72*38e8c45fSAndroid Build Coastguard Worker dir = opendir(path);
73*38e8c45fSAndroid Build Coastguard Worker
74*38e8c45fSAndroid Build Coastguard Worker if (dir == nullptr) {
75*38e8c45fSAndroid Build Coastguard Worker fprintf (stderr, "Error opendir'ing %s: %s\n",
76*38e8c45fSAndroid Build Coastguard Worker path, strerror(errno));
77*38e8c45fSAndroid Build Coastguard Worker return 0;
78*38e8c45fSAndroid Build Coastguard Worker }
79*38e8c45fSAndroid Build Coastguard Worker
80*38e8c45fSAndroid Build Coastguard Worker char *filenameOffset;
81*38e8c45fSAndroid Build Coastguard Worker
82*38e8c45fSAndroid Build Coastguard Worker strcpy(nameBuffer, path);
83*38e8c45fSAndroid Build Coastguard Worker strcat(nameBuffer, "/");
84*38e8c45fSAndroid Build Coastguard Worker
85*38e8c45fSAndroid Build Coastguard Worker filenameOffset = nameBuffer + strlen(nameBuffer);
86*38e8c45fSAndroid Build Coastguard Worker
87*38e8c45fSAndroid Build Coastguard Worker for (;;) {
88*38e8c45fSAndroid Build Coastguard Worker de = readdir(dir);
89*38e8c45fSAndroid Build Coastguard Worker
90*38e8c45fSAndroid Build Coastguard Worker if (de == nullptr) {
91*38e8c45fSAndroid Build Coastguard Worker break;
92*38e8c45fSAndroid Build Coastguard Worker }
93*38e8c45fSAndroid Build Coastguard Worker
94*38e8c45fSAndroid Build Coastguard Worker if (0 == strcmp(de->d_name, ".")
95*38e8c45fSAndroid Build Coastguard Worker || 0 == strcmp(de->d_name, "..")
96*38e8c45fSAndroid Build Coastguard Worker || 0 == strcmp(de->d_name, "lost+found")
97*38e8c45fSAndroid Build Coastguard Worker ) {
98*38e8c45fSAndroid Build Coastguard Worker continue;
99*38e8c45fSAndroid Build Coastguard Worker }
100*38e8c45fSAndroid Build Coastguard Worker
101*38e8c45fSAndroid Build Coastguard Worker strcpy(filenameOffset, de->d_name);
102*38e8c45fSAndroid Build Coastguard Worker bool noBackup = false;
103*38e8c45fSAndroid Build Coastguard Worker
104*38e8c45fSAndroid Build Coastguard Worker /* See if this is a path we should skip. */
105*38e8c45fSAndroid Build Coastguard Worker for (i = 0; SKIP_PATHS[i].path; i++) {
106*38e8c45fSAndroid Build Coastguard Worker if (strcmp(SKIP_PATHS[i].path, nameBuffer) == 0) {
107*38e8c45fSAndroid Build Coastguard Worker if (opt_backupAll || SKIP_PATHS[i].type == SPECIAL_NO_BACKUP) {
108*38e8c45fSAndroid Build Coastguard Worker // In this case we didn't back up the directory --
109*38e8c45fSAndroid Build Coastguard Worker // we do want to wipe its contents, but not the
110*38e8c45fSAndroid Build Coastguard Worker // directory itself, since the restore file won't
111*38e8c45fSAndroid Build Coastguard Worker // contain the directory.
112*38e8c45fSAndroid Build Coastguard Worker noBackup = true;
113*38e8c45fSAndroid Build Coastguard Worker }
114*38e8c45fSAndroid Build Coastguard Worker break;
115*38e8c45fSAndroid Build Coastguard Worker }
116*38e8c45fSAndroid Build Coastguard Worker }
117*38e8c45fSAndroid Build Coastguard Worker
118*38e8c45fSAndroid Build Coastguard Worker if (!noBackup && SKIP_PATHS[i].path != nullptr) {
119*38e8c45fSAndroid Build Coastguard Worker // This is a SPECIAL_NO_TOUCH directory.
120*38e8c45fSAndroid Build Coastguard Worker continue;
121*38e8c45fSAndroid Build Coastguard Worker }
122*38e8c45fSAndroid Build Coastguard Worker
123*38e8c45fSAndroid Build Coastguard Worker ret = lstat (nameBuffer, &statBuffer);
124*38e8c45fSAndroid Build Coastguard Worker
125*38e8c45fSAndroid Build Coastguard Worker if (ret != 0) {
126*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "warning -- stat() error on '%s': %s\n",
127*38e8c45fSAndroid Build Coastguard Worker nameBuffer, strerror(errno));
128*38e8c45fSAndroid Build Coastguard Worker continue;
129*38e8c45fSAndroid Build Coastguard Worker }
130*38e8c45fSAndroid Build Coastguard Worker
131*38e8c45fSAndroid Build Coastguard Worker if(S_ISDIR(statBuffer.st_mode)) {
132*38e8c45fSAndroid Build Coastguard Worker char *newpath;
133*38e8c45fSAndroid Build Coastguard Worker
134*38e8c45fSAndroid Build Coastguard Worker newpath = strdup(nameBuffer);
135*38e8c45fSAndroid Build Coastguard Worker if (wipe(newpath) == 0) {
136*38e8c45fSAndroid Build Coastguard Worker free(newpath);
137*38e8c45fSAndroid Build Coastguard Worker closedir(dir);
138*38e8c45fSAndroid Build Coastguard Worker return 0;
139*38e8c45fSAndroid Build Coastguard Worker }
140*38e8c45fSAndroid Build Coastguard Worker
141*38e8c45fSAndroid Build Coastguard Worker if (!noBackup) {
142*38e8c45fSAndroid Build Coastguard Worker ret = rmdir(newpath);
143*38e8c45fSAndroid Build Coastguard Worker if (ret != 0) {
144*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "warning -- rmdir() error on '%s': %s\n",
145*38e8c45fSAndroid Build Coastguard Worker newpath, strerror(errno));
146*38e8c45fSAndroid Build Coastguard Worker }
147*38e8c45fSAndroid Build Coastguard Worker }
148*38e8c45fSAndroid Build Coastguard Worker
149*38e8c45fSAndroid Build Coastguard Worker free(newpath);
150*38e8c45fSAndroid Build Coastguard Worker
151*38e8c45fSAndroid Build Coastguard Worker strcpy(nameBuffer, path);
152*38e8c45fSAndroid Build Coastguard Worker strcat(nameBuffer, "/");
153*38e8c45fSAndroid Build Coastguard Worker
154*38e8c45fSAndroid Build Coastguard Worker } else {
155*38e8c45fSAndroid Build Coastguard Worker // Don't delete the backup file
156*38e8c45fSAndroid Build Coastguard Worker if (backupFilePath && strcmp(backupFilePath, nameBuffer) == 0) {
157*38e8c45fSAndroid Build Coastguard Worker continue;
158*38e8c45fSAndroid Build Coastguard Worker }
159*38e8c45fSAndroid Build Coastguard Worker ret = unlink(nameBuffer);
160*38e8c45fSAndroid Build Coastguard Worker
161*38e8c45fSAndroid Build Coastguard Worker if (ret != 0) {
162*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "warning -- unlink() error on '%s': %s\n",
163*38e8c45fSAndroid Build Coastguard Worker nameBuffer, strerror(errno));
164*38e8c45fSAndroid Build Coastguard Worker }
165*38e8c45fSAndroid Build Coastguard Worker }
166*38e8c45fSAndroid Build Coastguard Worker }
167*38e8c45fSAndroid Build Coastguard Worker
168*38e8c45fSAndroid Build Coastguard Worker closedir(dir);
169*38e8c45fSAndroid Build Coastguard Worker
170*38e8c45fSAndroid Build Coastguard Worker return 1;
171*38e8c45fSAndroid Build Coastguard Worker }
172*38e8c45fSAndroid Build Coastguard Worker
write_int32(FILE * fh,int32_t val)173*38e8c45fSAndroid Build Coastguard Worker static int write_int32(FILE* fh, int32_t val)
174*38e8c45fSAndroid Build Coastguard Worker {
175*38e8c45fSAndroid Build Coastguard Worker int res = fwrite(&val, 1, sizeof(val), fh);
176*38e8c45fSAndroid Build Coastguard Worker if (res != sizeof(val)) {
177*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to write int32 (%d bytes): %s\n", res, strerror(errno));
178*38e8c45fSAndroid Build Coastguard Worker return 0;
179*38e8c45fSAndroid Build Coastguard Worker }
180*38e8c45fSAndroid Build Coastguard Worker
181*38e8c45fSAndroid Build Coastguard Worker return 1;
182*38e8c45fSAndroid Build Coastguard Worker }
183*38e8c45fSAndroid Build Coastguard Worker
write_int64(FILE * fh,int64_t val)184*38e8c45fSAndroid Build Coastguard Worker static int write_int64(FILE* fh, int64_t val)
185*38e8c45fSAndroid Build Coastguard Worker {
186*38e8c45fSAndroid Build Coastguard Worker int res = fwrite(&val, 1, sizeof(val), fh);
187*38e8c45fSAndroid Build Coastguard Worker if (res != sizeof(val)) {
188*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to write int64 (%d bytes): %s\n", res, strerror(errno));
189*38e8c45fSAndroid Build Coastguard Worker return 0;
190*38e8c45fSAndroid Build Coastguard Worker }
191*38e8c45fSAndroid Build Coastguard Worker
192*38e8c45fSAndroid Build Coastguard Worker return 1;
193*38e8c45fSAndroid Build Coastguard Worker }
194*38e8c45fSAndroid Build Coastguard Worker
copy_file(FILE * dest,FILE * src,off_t size,const char * destName,const char * srcName)195*38e8c45fSAndroid Build Coastguard Worker static int copy_file(FILE* dest, FILE* src, off_t size, const char* destName,
196*38e8c45fSAndroid Build Coastguard Worker const char* srcName)
197*38e8c45fSAndroid Build Coastguard Worker {
198*38e8c45fSAndroid Build Coastguard Worker errno = 0;
199*38e8c45fSAndroid Build Coastguard Worker
200*38e8c45fSAndroid Build Coastguard Worker off_t origSize = size;
201*38e8c45fSAndroid Build Coastguard Worker
202*38e8c45fSAndroid Build Coastguard Worker while (size > 0) {
203*38e8c45fSAndroid Build Coastguard Worker int amt = size > (off_t)sizeof(copyBuffer) ? sizeof(copyBuffer) : (int)size;
204*38e8c45fSAndroid Build Coastguard Worker int readLen = fread(copyBuffer, 1, amt, src);
205*38e8c45fSAndroid Build Coastguard Worker if (readLen <= 0) {
206*38e8c45fSAndroid Build Coastguard Worker if (srcName != nullptr) {
207*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to read source (%d of %ld bytes) file '%s': %s\n",
208*38e8c45fSAndroid Build Coastguard Worker amt, origSize, srcName, errno != 0 ? strerror(errno) : "unexpected EOF");
209*38e8c45fSAndroid Build Coastguard Worker } else {
210*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to read buffer (%d of %ld bytes): %s\n",
211*38e8c45fSAndroid Build Coastguard Worker amt, origSize, errno != 0 ? strerror(errno) : "unexpected EOF");
212*38e8c45fSAndroid Build Coastguard Worker }
213*38e8c45fSAndroid Build Coastguard Worker return 0;
214*38e8c45fSAndroid Build Coastguard Worker }
215*38e8c45fSAndroid Build Coastguard Worker int writeLen = fwrite(copyBuffer, 1, readLen, dest);
216*38e8c45fSAndroid Build Coastguard Worker if (writeLen != readLen) {
217*38e8c45fSAndroid Build Coastguard Worker if (destName != nullptr) {
218*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to write file (%d of %d bytes) '%s': '%s'\n",
219*38e8c45fSAndroid Build Coastguard Worker writeLen, readLen, destName, strerror(errno));
220*38e8c45fSAndroid Build Coastguard Worker } else {
221*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to write buffer (%d of %d bytes): '%s'\n",
222*38e8c45fSAndroid Build Coastguard Worker writeLen, readLen, strerror(errno));
223*38e8c45fSAndroid Build Coastguard Worker }
224*38e8c45fSAndroid Build Coastguard Worker return 0;
225*38e8c45fSAndroid Build Coastguard Worker }
226*38e8c45fSAndroid Build Coastguard Worker size -= readLen;
227*38e8c45fSAndroid Build Coastguard Worker }
228*38e8c45fSAndroid Build Coastguard Worker return 1;
229*38e8c45fSAndroid Build Coastguard Worker }
230*38e8c45fSAndroid Build Coastguard Worker
231*38e8c45fSAndroid Build Coastguard Worker #define TYPE_END 0
232*38e8c45fSAndroid Build Coastguard Worker #define TYPE_DIR 1
233*38e8c45fSAndroid Build Coastguard Worker #define TYPE_FILE 2
234*38e8c45fSAndroid Build Coastguard Worker
write_header(FILE * fh,int type,const char * path,const struct stat * st)235*38e8c45fSAndroid Build Coastguard Worker static int write_header(FILE* fh, int type, const char* path, const struct stat* st)
236*38e8c45fSAndroid Build Coastguard Worker {
237*38e8c45fSAndroid Build Coastguard Worker int pathLen = strlen(path);
238*38e8c45fSAndroid Build Coastguard Worker if (!write_int32(fh, type)) return 0;
239*38e8c45fSAndroid Build Coastguard Worker if (!write_int32(fh, pathLen)) return 0;
240*38e8c45fSAndroid Build Coastguard Worker if (fwrite(path, 1, pathLen, fh) != (size_t)pathLen) {
241*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to write: %s\n", strerror(errno));
242*38e8c45fSAndroid Build Coastguard Worker return 0;
243*38e8c45fSAndroid Build Coastguard Worker }
244*38e8c45fSAndroid Build Coastguard Worker
245*38e8c45fSAndroid Build Coastguard Worker if (!write_int32(fh, st->st_uid)) return 0;
246*38e8c45fSAndroid Build Coastguard Worker if (!write_int32(fh, st->st_gid)) return 0;
247*38e8c45fSAndroid Build Coastguard Worker if (!write_int32(fh, st->st_mode)) return 0;
248*38e8c45fSAndroid Build Coastguard Worker if (!write_int64(fh, ((int64_t)st->st_atime)*1000*1000*1000)) return 0;
249*38e8c45fSAndroid Build Coastguard Worker if (!write_int64(fh, ((int64_t)st->st_mtime)*1000*1000*1000)) return 0;
250*38e8c45fSAndroid Build Coastguard Worker if (!write_int64(fh, ((int64_t)st->st_ctime)*1000*1000*1000)) return 0;
251*38e8c45fSAndroid Build Coastguard Worker
252*38e8c45fSAndroid Build Coastguard Worker return 1;
253*38e8c45fSAndroid Build Coastguard Worker }
254*38e8c45fSAndroid Build Coastguard Worker
backup_dir(FILE * fh,const char * srcPath)255*38e8c45fSAndroid Build Coastguard Worker static int backup_dir(FILE* fh, const char* srcPath)
256*38e8c45fSAndroid Build Coastguard Worker {
257*38e8c45fSAndroid Build Coastguard Worker DIR *dir;
258*38e8c45fSAndroid Build Coastguard Worker struct dirent *de;
259*38e8c45fSAndroid Build Coastguard Worker char* fullPath = nullptr;
260*38e8c45fSAndroid Build Coastguard Worker int srcLen = strlen(srcPath);
261*38e8c45fSAndroid Build Coastguard Worker int result = 1;
262*38e8c45fSAndroid Build Coastguard Worker int i;
263*38e8c45fSAndroid Build Coastguard Worker
264*38e8c45fSAndroid Build Coastguard Worker dir = opendir(srcPath);
265*38e8c45fSAndroid Build Coastguard Worker
266*38e8c45fSAndroid Build Coastguard Worker if (dir == nullptr) {
267*38e8c45fSAndroid Build Coastguard Worker fprintf (stderr, "error opendir'ing '%s': %s\n",
268*38e8c45fSAndroid Build Coastguard Worker srcPath, strerror(errno));
269*38e8c45fSAndroid Build Coastguard Worker return 0;
270*38e8c45fSAndroid Build Coastguard Worker }
271*38e8c45fSAndroid Build Coastguard Worker
272*38e8c45fSAndroid Build Coastguard Worker for (;;) {
273*38e8c45fSAndroid Build Coastguard Worker de = readdir(dir);
274*38e8c45fSAndroid Build Coastguard Worker
275*38e8c45fSAndroid Build Coastguard Worker if (de == nullptr) {
276*38e8c45fSAndroid Build Coastguard Worker break;
277*38e8c45fSAndroid Build Coastguard Worker }
278*38e8c45fSAndroid Build Coastguard Worker
279*38e8c45fSAndroid Build Coastguard Worker if (0 == strcmp(de->d_name, ".")
280*38e8c45fSAndroid Build Coastguard Worker || 0 == strcmp(de->d_name, "..")
281*38e8c45fSAndroid Build Coastguard Worker || 0 == strcmp(de->d_name, "lost+found")
282*38e8c45fSAndroid Build Coastguard Worker ) {
283*38e8c45fSAndroid Build Coastguard Worker continue;
284*38e8c45fSAndroid Build Coastguard Worker }
285*38e8c45fSAndroid Build Coastguard Worker
286*38e8c45fSAndroid Build Coastguard Worker if (fullPath != nullptr) {
287*38e8c45fSAndroid Build Coastguard Worker free(fullPath);
288*38e8c45fSAndroid Build Coastguard Worker }
289*38e8c45fSAndroid Build Coastguard Worker fullPath = (char*)malloc(srcLen + strlen(de->d_name) + 2);
290*38e8c45fSAndroid Build Coastguard Worker strcpy(fullPath, srcPath);
291*38e8c45fSAndroid Build Coastguard Worker fullPath[srcLen] = '/';
292*38e8c45fSAndroid Build Coastguard Worker strcpy(fullPath+srcLen+1, de->d_name);
293*38e8c45fSAndroid Build Coastguard Worker
294*38e8c45fSAndroid Build Coastguard Worker /* See if this is a path we should skip. */
295*38e8c45fSAndroid Build Coastguard Worker if (!opt_backupAll) {
296*38e8c45fSAndroid Build Coastguard Worker for (i = 0; SKIP_PATHS[i].path; i++) {
297*38e8c45fSAndroid Build Coastguard Worker if (strcmp(SKIP_PATHS[i].path, fullPath) == 0) {
298*38e8c45fSAndroid Build Coastguard Worker break;
299*38e8c45fSAndroid Build Coastguard Worker }
300*38e8c45fSAndroid Build Coastguard Worker }
301*38e8c45fSAndroid Build Coastguard Worker if (SKIP_PATHS[i].path != nullptr) {
302*38e8c45fSAndroid Build Coastguard Worker continue;
303*38e8c45fSAndroid Build Coastguard Worker }
304*38e8c45fSAndroid Build Coastguard Worker }
305*38e8c45fSAndroid Build Coastguard Worker
306*38e8c45fSAndroid Build Coastguard Worker int ret = lstat(fullPath, &statBuffer);
307*38e8c45fSAndroid Build Coastguard Worker
308*38e8c45fSAndroid Build Coastguard Worker if (ret != 0) {
309*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "stat() error on '%s': %s\n",
310*38e8c45fSAndroid Build Coastguard Worker fullPath, strerror(errno));
311*38e8c45fSAndroid Build Coastguard Worker result = 0;
312*38e8c45fSAndroid Build Coastguard Worker goto done;
313*38e8c45fSAndroid Build Coastguard Worker }
314*38e8c45fSAndroid Build Coastguard Worker
315*38e8c45fSAndroid Build Coastguard Worker if(S_ISDIR(statBuffer.st_mode)) {
316*38e8c45fSAndroid Build Coastguard Worker printf("Saving dir %s...\n", fullPath);
317*38e8c45fSAndroid Build Coastguard Worker
318*38e8c45fSAndroid Build Coastguard Worker if (write_header(fh, TYPE_DIR, fullPath, &statBuffer) == 0) {
319*38e8c45fSAndroid Build Coastguard Worker result = 0;
320*38e8c45fSAndroid Build Coastguard Worker goto done;
321*38e8c45fSAndroid Build Coastguard Worker }
322*38e8c45fSAndroid Build Coastguard Worker if (backup_dir(fh, fullPath) == 0) {
323*38e8c45fSAndroid Build Coastguard Worker result = 0;
324*38e8c45fSAndroid Build Coastguard Worker goto done;
325*38e8c45fSAndroid Build Coastguard Worker }
326*38e8c45fSAndroid Build Coastguard Worker } else if (S_ISREG(statBuffer.st_mode)) {
327*38e8c45fSAndroid Build Coastguard Worker // Skip the backup file
328*38e8c45fSAndroid Build Coastguard Worker if (backupFilePath && strcmp(fullPath, backupFilePath) == 0) {
329*38e8c45fSAndroid Build Coastguard Worker printf("Skipping backup file %s...\n", backupFilePath);
330*38e8c45fSAndroid Build Coastguard Worker continue;
331*38e8c45fSAndroid Build Coastguard Worker } else {
332*38e8c45fSAndroid Build Coastguard Worker printf("Saving file %s...\n", fullPath);
333*38e8c45fSAndroid Build Coastguard Worker }
334*38e8c45fSAndroid Build Coastguard Worker if (write_header(fh, TYPE_FILE, fullPath, &statBuffer) == 0) {
335*38e8c45fSAndroid Build Coastguard Worker result = 0;
336*38e8c45fSAndroid Build Coastguard Worker goto done;
337*38e8c45fSAndroid Build Coastguard Worker }
338*38e8c45fSAndroid Build Coastguard Worker
339*38e8c45fSAndroid Build Coastguard Worker off_t size = statBuffer.st_size;
340*38e8c45fSAndroid Build Coastguard Worker if (!write_int64(fh, size)) {
341*38e8c45fSAndroid Build Coastguard Worker result = 0;
342*38e8c45fSAndroid Build Coastguard Worker goto done;
343*38e8c45fSAndroid Build Coastguard Worker }
344*38e8c45fSAndroid Build Coastguard Worker
345*38e8c45fSAndroid Build Coastguard Worker FILE* src = fopen(fullPath, "r");
346*38e8c45fSAndroid Build Coastguard Worker if (src == nullptr) {
347*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to open source file '%s': %s\n",
348*38e8c45fSAndroid Build Coastguard Worker fullPath, strerror(errno));
349*38e8c45fSAndroid Build Coastguard Worker result = 0;
350*38e8c45fSAndroid Build Coastguard Worker goto done;
351*38e8c45fSAndroid Build Coastguard Worker }
352*38e8c45fSAndroid Build Coastguard Worker
353*38e8c45fSAndroid Build Coastguard Worker int copyres = copy_file(fh, src, size, nullptr, fullPath);
354*38e8c45fSAndroid Build Coastguard Worker fclose(src);
355*38e8c45fSAndroid Build Coastguard Worker if (!copyres) {
356*38e8c45fSAndroid Build Coastguard Worker result = 0;
357*38e8c45fSAndroid Build Coastguard Worker goto done;
358*38e8c45fSAndroid Build Coastguard Worker }
359*38e8c45fSAndroid Build Coastguard Worker }
360*38e8c45fSAndroid Build Coastguard Worker }
361*38e8c45fSAndroid Build Coastguard Worker
362*38e8c45fSAndroid Build Coastguard Worker done:
363*38e8c45fSAndroid Build Coastguard Worker if (fullPath != nullptr) {
364*38e8c45fSAndroid Build Coastguard Worker free(fullPath);
365*38e8c45fSAndroid Build Coastguard Worker }
366*38e8c45fSAndroid Build Coastguard Worker
367*38e8c45fSAndroid Build Coastguard Worker closedir(dir);
368*38e8c45fSAndroid Build Coastguard Worker
369*38e8c45fSAndroid Build Coastguard Worker return result;
370*38e8c45fSAndroid Build Coastguard Worker }
371*38e8c45fSAndroid Build Coastguard Worker
backup_data(const char * destPath)372*38e8c45fSAndroid Build Coastguard Worker static int backup_data(const char* destPath)
373*38e8c45fSAndroid Build Coastguard Worker {
374*38e8c45fSAndroid Build Coastguard Worker int res = -1;
375*38e8c45fSAndroid Build Coastguard Worker
376*38e8c45fSAndroid Build Coastguard Worker FILE* fh = fopen(destPath, "w");
377*38e8c45fSAndroid Build Coastguard Worker if (fh == nullptr) {
378*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to open destination '%s': %s\n",
379*38e8c45fSAndroid Build Coastguard Worker destPath, strerror(errno));
380*38e8c45fSAndroid Build Coastguard Worker return -1;
381*38e8c45fSAndroid Build Coastguard Worker }
382*38e8c45fSAndroid Build Coastguard Worker
383*38e8c45fSAndroid Build Coastguard Worker printf("Backing up /data to %s...\n", destPath);
384*38e8c45fSAndroid Build Coastguard Worker
385*38e8c45fSAndroid Build Coastguard Worker // The path that shouldn't be backed up
386*38e8c45fSAndroid Build Coastguard Worker backupFilePath = strdup(destPath);
387*38e8c45fSAndroid Build Coastguard Worker
388*38e8c45fSAndroid Build Coastguard Worker if (!write_int32(fh, FILE_VERSION)) goto done;
389*38e8c45fSAndroid Build Coastguard Worker if (!write_int32(fh, opt_backupAll)) goto done;
390*38e8c45fSAndroid Build Coastguard Worker if (!backup_dir(fh, "/data")) goto done;
391*38e8c45fSAndroid Build Coastguard Worker if (!write_int32(fh, 0)) goto done;
392*38e8c45fSAndroid Build Coastguard Worker
393*38e8c45fSAndroid Build Coastguard Worker res = 0;
394*38e8c45fSAndroid Build Coastguard Worker
395*38e8c45fSAndroid Build Coastguard Worker done:
396*38e8c45fSAndroid Build Coastguard Worker if (fflush(fh) != 0) {
397*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "error flushing destination '%s': %s\n",
398*38e8c45fSAndroid Build Coastguard Worker destPath, strerror(errno));
399*38e8c45fSAndroid Build Coastguard Worker res = -1;
400*38e8c45fSAndroid Build Coastguard Worker goto donedone;
401*38e8c45fSAndroid Build Coastguard Worker }
402*38e8c45fSAndroid Build Coastguard Worker if (fsync(fileno(fh)) != 0) {
403*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "error syncing destination '%s': %s\n",
404*38e8c45fSAndroid Build Coastguard Worker destPath, strerror(errno));
405*38e8c45fSAndroid Build Coastguard Worker res = -1;
406*38e8c45fSAndroid Build Coastguard Worker goto donedone;
407*38e8c45fSAndroid Build Coastguard Worker }
408*38e8c45fSAndroid Build Coastguard Worker fclose(fh);
409*38e8c45fSAndroid Build Coastguard Worker sync();
410*38e8c45fSAndroid Build Coastguard Worker
411*38e8c45fSAndroid Build Coastguard Worker donedone:
412*38e8c45fSAndroid Build Coastguard Worker return res;
413*38e8c45fSAndroid Build Coastguard Worker }
414*38e8c45fSAndroid Build Coastguard Worker
read_int32(FILE * fh,int32_t defVal)415*38e8c45fSAndroid Build Coastguard Worker static int32_t read_int32(FILE* fh, int32_t defVal)
416*38e8c45fSAndroid Build Coastguard Worker {
417*38e8c45fSAndroid Build Coastguard Worker int32_t val;
418*38e8c45fSAndroid Build Coastguard Worker if (fread(&val, 1, sizeof(val), fh) != sizeof(val)) {
419*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to read: %s\n", strerror(errno));
420*38e8c45fSAndroid Build Coastguard Worker return defVal;
421*38e8c45fSAndroid Build Coastguard Worker }
422*38e8c45fSAndroid Build Coastguard Worker
423*38e8c45fSAndroid Build Coastguard Worker return val;
424*38e8c45fSAndroid Build Coastguard Worker }
425*38e8c45fSAndroid Build Coastguard Worker
read_int64(FILE * fh,int64_t defVal)426*38e8c45fSAndroid Build Coastguard Worker static int64_t read_int64(FILE* fh, int64_t defVal)
427*38e8c45fSAndroid Build Coastguard Worker {
428*38e8c45fSAndroid Build Coastguard Worker int64_t val;
429*38e8c45fSAndroid Build Coastguard Worker if (fread(&val, 1, sizeof(val), fh) != sizeof(val)) {
430*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to read: %s\n", strerror(errno));
431*38e8c45fSAndroid Build Coastguard Worker return defVal;
432*38e8c45fSAndroid Build Coastguard Worker }
433*38e8c45fSAndroid Build Coastguard Worker
434*38e8c45fSAndroid Build Coastguard Worker return val;
435*38e8c45fSAndroid Build Coastguard Worker }
436*38e8c45fSAndroid Build Coastguard Worker
read_header(FILE * fh,int * type,char ** path,struct stat * st)437*38e8c45fSAndroid Build Coastguard Worker static int read_header(FILE* fh, int* type, char** path, struct stat* st)
438*38e8c45fSAndroid Build Coastguard Worker {
439*38e8c45fSAndroid Build Coastguard Worker *type = read_int32(fh, -1);
440*38e8c45fSAndroid Build Coastguard Worker if (*type == TYPE_END) {
441*38e8c45fSAndroid Build Coastguard Worker return 1;
442*38e8c45fSAndroid Build Coastguard Worker }
443*38e8c45fSAndroid Build Coastguard Worker
444*38e8c45fSAndroid Build Coastguard Worker if (*type < 0) {
445*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "bad token %d in restore file\n", *type);
446*38e8c45fSAndroid Build Coastguard Worker return 0;
447*38e8c45fSAndroid Build Coastguard Worker }
448*38e8c45fSAndroid Build Coastguard Worker
449*38e8c45fSAndroid Build Coastguard Worker int32_t pathLen = read_int32(fh, -1);
450*38e8c45fSAndroid Build Coastguard Worker if (pathLen <= 0) {
451*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "bad path length %d in restore file\n", pathLen);
452*38e8c45fSAndroid Build Coastguard Worker return 0;
453*38e8c45fSAndroid Build Coastguard Worker }
454*38e8c45fSAndroid Build Coastguard Worker char* readPath = (char*)malloc(pathLen+1);
455*38e8c45fSAndroid Build Coastguard Worker if (fread(readPath, 1, pathLen, fh) != (size_t)pathLen) {
456*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "truncated path in restore file\n");
457*38e8c45fSAndroid Build Coastguard Worker free(readPath);
458*38e8c45fSAndroid Build Coastguard Worker return 0;
459*38e8c45fSAndroid Build Coastguard Worker }
460*38e8c45fSAndroid Build Coastguard Worker readPath[pathLen] = 0;
461*38e8c45fSAndroid Build Coastguard Worker *path = readPath;
462*38e8c45fSAndroid Build Coastguard Worker
463*38e8c45fSAndroid Build Coastguard Worker st->st_uid = read_int32(fh, -1);
464*38e8c45fSAndroid Build Coastguard Worker if (st->st_uid == (uid_t)-1) {
465*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "bad uid in restore file at '%s'\n", readPath);
466*38e8c45fSAndroid Build Coastguard Worker return 0;
467*38e8c45fSAndroid Build Coastguard Worker }
468*38e8c45fSAndroid Build Coastguard Worker st->st_gid = read_int32(fh, -1);
469*38e8c45fSAndroid Build Coastguard Worker if (st->st_gid == (gid_t)-1) {
470*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "bad gid in restore file at '%s'\n", readPath);
471*38e8c45fSAndroid Build Coastguard Worker return 0;
472*38e8c45fSAndroid Build Coastguard Worker }
473*38e8c45fSAndroid Build Coastguard Worker st->st_mode = read_int32(fh, -1);
474*38e8c45fSAndroid Build Coastguard Worker if (st->st_mode == (mode_t)-1) {
475*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "bad mode in restore file at '%s'\n", readPath);
476*38e8c45fSAndroid Build Coastguard Worker return 0;
477*38e8c45fSAndroid Build Coastguard Worker }
478*38e8c45fSAndroid Build Coastguard Worker int64_t ltime = read_int64(fh, -1);
479*38e8c45fSAndroid Build Coastguard Worker if (ltime < 0) {
480*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "bad atime in restore file at '%s'\n", readPath);
481*38e8c45fSAndroid Build Coastguard Worker return 0;
482*38e8c45fSAndroid Build Coastguard Worker }
483*38e8c45fSAndroid Build Coastguard Worker st->st_atime = (time_t)(ltime/1000/1000/1000);
484*38e8c45fSAndroid Build Coastguard Worker ltime = read_int64(fh, -1);
485*38e8c45fSAndroid Build Coastguard Worker if (ltime < 0) {
486*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "bad mtime in restore file at '%s'\n", readPath);
487*38e8c45fSAndroid Build Coastguard Worker return 0;
488*38e8c45fSAndroid Build Coastguard Worker }
489*38e8c45fSAndroid Build Coastguard Worker st->st_mtime = (time_t)(ltime/1000/1000/1000);
490*38e8c45fSAndroid Build Coastguard Worker ltime = read_int64(fh, -1);
491*38e8c45fSAndroid Build Coastguard Worker if (ltime < 0) {
492*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "bad ctime in restore file at '%s'\n", readPath);
493*38e8c45fSAndroid Build Coastguard Worker return 0;
494*38e8c45fSAndroid Build Coastguard Worker }
495*38e8c45fSAndroid Build Coastguard Worker st->st_ctime = (time_t)(ltime/1000/1000/1000);
496*38e8c45fSAndroid Build Coastguard Worker
497*38e8c45fSAndroid Build Coastguard Worker st->st_mode &= (S_IRWXU|S_IRWXG|S_IRWXO);
498*38e8c45fSAndroid Build Coastguard Worker
499*38e8c45fSAndroid Build Coastguard Worker return 1;
500*38e8c45fSAndroid Build Coastguard Worker }
501*38e8c45fSAndroid Build Coastguard Worker
restore_data(const char * srcPath)502*38e8c45fSAndroid Build Coastguard Worker static int restore_data(const char* srcPath)
503*38e8c45fSAndroid Build Coastguard Worker {
504*38e8c45fSAndroid Build Coastguard Worker int res = -1;
505*38e8c45fSAndroid Build Coastguard Worker
506*38e8c45fSAndroid Build Coastguard Worker FILE* fh = fopen(srcPath, "r");
507*38e8c45fSAndroid Build Coastguard Worker if (fh == nullptr) {
508*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "Unable to open source '%s': %s\n",
509*38e8c45fSAndroid Build Coastguard Worker srcPath, strerror(errno));
510*38e8c45fSAndroid Build Coastguard Worker return -1;
511*38e8c45fSAndroid Build Coastguard Worker }
512*38e8c45fSAndroid Build Coastguard Worker
513*38e8c45fSAndroid Build Coastguard Worker inputFileVersion = read_int32(fh, 0);
514*38e8c45fSAndroid Build Coastguard Worker if (inputFileVersion < FILE_VERSION_1 || inputFileVersion > FILE_VERSION) {
515*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "Restore file has bad version: 0x%x\n", inputFileVersion);
516*38e8c45fSAndroid Build Coastguard Worker goto done;
517*38e8c45fSAndroid Build Coastguard Worker }
518*38e8c45fSAndroid Build Coastguard Worker
519*38e8c45fSAndroid Build Coastguard Worker if (inputFileVersion >= FILE_VERSION_2) {
520*38e8c45fSAndroid Build Coastguard Worker opt_backupAll = read_int32(fh, 0);
521*38e8c45fSAndroid Build Coastguard Worker } else {
522*38e8c45fSAndroid Build Coastguard Worker opt_backupAll = 0;
523*38e8c45fSAndroid Build Coastguard Worker }
524*38e8c45fSAndroid Build Coastguard Worker
525*38e8c45fSAndroid Build Coastguard Worker // The path that shouldn't be deleted
526*38e8c45fSAndroid Build Coastguard Worker backupFilePath = strdup(srcPath);
527*38e8c45fSAndroid Build Coastguard Worker
528*38e8c45fSAndroid Build Coastguard Worker printf("Wiping contents of /data...\n");
529*38e8c45fSAndroid Build Coastguard Worker if (!wipe("/data")) {
530*38e8c45fSAndroid Build Coastguard Worker goto done;
531*38e8c45fSAndroid Build Coastguard Worker }
532*38e8c45fSAndroid Build Coastguard Worker
533*38e8c45fSAndroid Build Coastguard Worker printf("Restoring from %s to /data...\n", srcPath);
534*38e8c45fSAndroid Build Coastguard Worker
535*38e8c45fSAndroid Build Coastguard Worker while (1) {
536*38e8c45fSAndroid Build Coastguard Worker int type;
537*38e8c45fSAndroid Build Coastguard Worker char* path = nullptr;
538*38e8c45fSAndroid Build Coastguard Worker if (read_header(fh, &type, &path, &statBuffer) == 0) {
539*38e8c45fSAndroid Build Coastguard Worker goto done;
540*38e8c45fSAndroid Build Coastguard Worker }
541*38e8c45fSAndroid Build Coastguard Worker if (type == 0) {
542*38e8c45fSAndroid Build Coastguard Worker break;
543*38e8c45fSAndroid Build Coastguard Worker }
544*38e8c45fSAndroid Build Coastguard Worker
545*38e8c45fSAndroid Build Coastguard Worker const char* typeName = "?";
546*38e8c45fSAndroid Build Coastguard Worker
547*38e8c45fSAndroid Build Coastguard Worker if (type == TYPE_DIR) {
548*38e8c45fSAndroid Build Coastguard Worker typeName = "dir";
549*38e8c45fSAndroid Build Coastguard Worker
550*38e8c45fSAndroid Build Coastguard Worker printf("Restoring dir %s...\n", path);
551*38e8c45fSAndroid Build Coastguard Worker
552*38e8c45fSAndroid Build Coastguard Worker if (mkdir(path, statBuffer.st_mode) != 0) {
553*38e8c45fSAndroid Build Coastguard Worker if (errno != EEXIST) {
554*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to create directory '%s': %s\n",
555*38e8c45fSAndroid Build Coastguard Worker path, strerror(errno));
556*38e8c45fSAndroid Build Coastguard Worker free(path);
557*38e8c45fSAndroid Build Coastguard Worker goto done;
558*38e8c45fSAndroid Build Coastguard Worker }
559*38e8c45fSAndroid Build Coastguard Worker }
560*38e8c45fSAndroid Build Coastguard Worker
561*38e8c45fSAndroid Build Coastguard Worker } else if (type == TYPE_FILE) {
562*38e8c45fSAndroid Build Coastguard Worker typeName = "file";
563*38e8c45fSAndroid Build Coastguard Worker off_t size = read_int64(fh, -1);
564*38e8c45fSAndroid Build Coastguard Worker if (size < 0) {
565*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "bad file size %ld in restore file\n", size);
566*38e8c45fSAndroid Build Coastguard Worker free(path);
567*38e8c45fSAndroid Build Coastguard Worker goto done;
568*38e8c45fSAndroid Build Coastguard Worker }
569*38e8c45fSAndroid Build Coastguard Worker
570*38e8c45fSAndroid Build Coastguard Worker printf("Restoring file %s...\n", path);
571*38e8c45fSAndroid Build Coastguard Worker
572*38e8c45fSAndroid Build Coastguard Worker FILE* dest = fopen(path, "w");
573*38e8c45fSAndroid Build Coastguard Worker if (dest == nullptr) {
574*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to open destination file '%s': %s\n",
575*38e8c45fSAndroid Build Coastguard Worker path, strerror(errno));
576*38e8c45fSAndroid Build Coastguard Worker free(path);
577*38e8c45fSAndroid Build Coastguard Worker goto done;
578*38e8c45fSAndroid Build Coastguard Worker }
579*38e8c45fSAndroid Build Coastguard Worker
580*38e8c45fSAndroid Build Coastguard Worker int copyres = copy_file(dest, fh, size, path, nullptr);
581*38e8c45fSAndroid Build Coastguard Worker fclose(dest);
582*38e8c45fSAndroid Build Coastguard Worker if (!copyres) {
583*38e8c45fSAndroid Build Coastguard Worker free(path);
584*38e8c45fSAndroid Build Coastguard Worker goto done;
585*38e8c45fSAndroid Build Coastguard Worker }
586*38e8c45fSAndroid Build Coastguard Worker
587*38e8c45fSAndroid Build Coastguard Worker } else {
588*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unknown node type %d\n", type);
589*38e8c45fSAndroid Build Coastguard Worker goto done;
590*38e8c45fSAndroid Build Coastguard Worker }
591*38e8c45fSAndroid Build Coastguard Worker
592*38e8c45fSAndroid Build Coastguard Worker // Do this even for directories, since the dir may have already existed
593*38e8c45fSAndroid Build Coastguard Worker // so we need to make sure it gets the correct mode.
594*38e8c45fSAndroid Build Coastguard Worker if (chmod(path, statBuffer.st_mode&(S_IRWXU|S_IRWXG|S_IRWXO)) != 0) {
595*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to chmod destination %s '%s' to 0x%x: %s\n",
596*38e8c45fSAndroid Build Coastguard Worker typeName, path, statBuffer.st_mode, strerror(errno));
597*38e8c45fSAndroid Build Coastguard Worker free(path);
598*38e8c45fSAndroid Build Coastguard Worker goto done;
599*38e8c45fSAndroid Build Coastguard Worker }
600*38e8c45fSAndroid Build Coastguard Worker
601*38e8c45fSAndroid Build Coastguard Worker if (chown(path, statBuffer.st_uid, statBuffer.st_gid) != 0) {
602*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to chown destination %s '%s' to uid %d / gid %d: %s\n",
603*38e8c45fSAndroid Build Coastguard Worker typeName, path, (int)statBuffer.st_uid, (int)statBuffer.st_gid, strerror(errno));
604*38e8c45fSAndroid Build Coastguard Worker free(path);
605*38e8c45fSAndroid Build Coastguard Worker goto done;
606*38e8c45fSAndroid Build Coastguard Worker }
607*38e8c45fSAndroid Build Coastguard Worker
608*38e8c45fSAndroid Build Coastguard Worker struct utimbuf timbuf;
609*38e8c45fSAndroid Build Coastguard Worker timbuf.actime = statBuffer.st_atime;
610*38e8c45fSAndroid Build Coastguard Worker timbuf.modtime = statBuffer.st_mtime;
611*38e8c45fSAndroid Build Coastguard Worker if (utime(path, &timbuf) != 0) {
612*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "unable to utime destination %s '%s': %s\n",
613*38e8c45fSAndroid Build Coastguard Worker typeName, path, strerror(errno));
614*38e8c45fSAndroid Build Coastguard Worker free(path);
615*38e8c45fSAndroid Build Coastguard Worker goto done;
616*38e8c45fSAndroid Build Coastguard Worker }
617*38e8c45fSAndroid Build Coastguard Worker
618*38e8c45fSAndroid Build Coastguard Worker
619*38e8c45fSAndroid Build Coastguard Worker free(path);
620*38e8c45fSAndroid Build Coastguard Worker }
621*38e8c45fSAndroid Build Coastguard Worker
622*38e8c45fSAndroid Build Coastguard Worker res = 0;
623*38e8c45fSAndroid Build Coastguard Worker
624*38e8c45fSAndroid Build Coastguard Worker done:
625*38e8c45fSAndroid Build Coastguard Worker fclose(fh);
626*38e8c45fSAndroid Build Coastguard Worker
627*38e8c45fSAndroid Build Coastguard Worker return res;
628*38e8c45fSAndroid Build Coastguard Worker }
629*38e8c45fSAndroid Build Coastguard Worker
show_help(const char * cmd)630*38e8c45fSAndroid Build Coastguard Worker static void show_help(const char *cmd)
631*38e8c45fSAndroid Build Coastguard Worker {
632*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr,"Usage: %s COMMAND [options] [backup-file-path]\n", cmd);
633*38e8c45fSAndroid Build Coastguard Worker
634*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "commands are:\n"
635*38e8c45fSAndroid Build Coastguard Worker " help Show this help text.\n"
636*38e8c45fSAndroid Build Coastguard Worker " backup Perform a backup of /data.\n"
637*38e8c45fSAndroid Build Coastguard Worker " restore Perform a restore of /data.\n");
638*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "options include:\n"
639*38e8c45fSAndroid Build Coastguard Worker " -h Show this help text.\n"
640*38e8c45fSAndroid Build Coastguard Worker " -a Backup all files.\n");
641*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "\n backup-file-path Defaults to /sdcard/backup.dat .\n"
642*38e8c45fSAndroid Build Coastguard Worker " On devices that emulate the sdcard, you will need to\n"
643*38e8c45fSAndroid Build Coastguard Worker " explicitly specify the directory it is mapped to,\n"
644*38e8c45fSAndroid Build Coastguard Worker " to avoid recursive backup or deletion of the backup file\n"
645*38e8c45fSAndroid Build Coastguard Worker " during restore.\n\n"
646*38e8c45fSAndroid Build Coastguard Worker " Eg. /data/media/0/backup.dat\n");
647*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "\nThe %s command allows you to perform low-level\n"
648*38e8c45fSAndroid Build Coastguard Worker "backup and restore of the /data partition. This is\n"
649*38e8c45fSAndroid Build Coastguard Worker "where all user data is kept, allowing for a fairly\n"
650*38e8c45fSAndroid Build Coastguard Worker "complete restore of a device's state. Note that\n"
651*38e8c45fSAndroid Build Coastguard Worker "because this is low-level, it will only work across\n"
652*38e8c45fSAndroid Build Coastguard Worker "builds of the same (or very similar) device software.\n",
653*38e8c45fSAndroid Build Coastguard Worker cmd);
654*38e8c45fSAndroid Build Coastguard Worker }
655*38e8c45fSAndroid Build Coastguard Worker
656*38e8c45fSAndroid Build Coastguard Worker } /* namespace android */
657*38e8c45fSAndroid Build Coastguard Worker
main(int argc,char ** argv)658*38e8c45fSAndroid Build Coastguard Worker int main (int argc, char **argv)
659*38e8c45fSAndroid Build Coastguard Worker {
660*38e8c45fSAndroid Build Coastguard Worker int restore = 0;
661*38e8c45fSAndroid Build Coastguard Worker
662*38e8c45fSAndroid Build Coastguard Worker if (getuid() != AID_ROOT) {
663*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "error -- %s must run as root\n", argv[0]);
664*38e8c45fSAndroid Build Coastguard Worker exit(-1);
665*38e8c45fSAndroid Build Coastguard Worker }
666*38e8c45fSAndroid Build Coastguard Worker
667*38e8c45fSAndroid Build Coastguard Worker if (argc < 2) {
668*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "No command specified.\n");
669*38e8c45fSAndroid Build Coastguard Worker android::show_help(argv[0]);
670*38e8c45fSAndroid Build Coastguard Worker exit(-1);
671*38e8c45fSAndroid Build Coastguard Worker }
672*38e8c45fSAndroid Build Coastguard Worker
673*38e8c45fSAndroid Build Coastguard Worker if (0 == strcmp(argv[1], "restore")) {
674*38e8c45fSAndroid Build Coastguard Worker restore = 1;
675*38e8c45fSAndroid Build Coastguard Worker } else if (0 == strcmp(argv[1], "help")) {
676*38e8c45fSAndroid Build Coastguard Worker android::show_help(argv[0]);
677*38e8c45fSAndroid Build Coastguard Worker exit(0);
678*38e8c45fSAndroid Build Coastguard Worker } else if (0 != strcmp(argv[1], "backup")) {
679*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "Unknown command: %s\n", argv[1]);
680*38e8c45fSAndroid Build Coastguard Worker android::show_help(argv[0]);
681*38e8c45fSAndroid Build Coastguard Worker exit(-1);
682*38e8c45fSAndroid Build Coastguard Worker }
683*38e8c45fSAndroid Build Coastguard Worker
684*38e8c45fSAndroid Build Coastguard Worker android::opt_backupAll = 0;
685*38e8c45fSAndroid Build Coastguard Worker
686*38e8c45fSAndroid Build Coastguard Worker optind = 2;
687*38e8c45fSAndroid Build Coastguard Worker
688*38e8c45fSAndroid Build Coastguard Worker for (;;) {
689*38e8c45fSAndroid Build Coastguard Worker int ret;
690*38e8c45fSAndroid Build Coastguard Worker
691*38e8c45fSAndroid Build Coastguard Worker ret = getopt(argc, argv, "ah");
692*38e8c45fSAndroid Build Coastguard Worker
693*38e8c45fSAndroid Build Coastguard Worker if (ret < 0) {
694*38e8c45fSAndroid Build Coastguard Worker break;
695*38e8c45fSAndroid Build Coastguard Worker }
696*38e8c45fSAndroid Build Coastguard Worker
697*38e8c45fSAndroid Build Coastguard Worker switch(ret) {
698*38e8c45fSAndroid Build Coastguard Worker case 'a':
699*38e8c45fSAndroid Build Coastguard Worker android::opt_backupAll = 1;
700*38e8c45fSAndroid Build Coastguard Worker if (restore) fprintf(stderr, "Warning: -a option ignored on restore\n");
701*38e8c45fSAndroid Build Coastguard Worker break;
702*38e8c45fSAndroid Build Coastguard Worker case 'h':
703*38e8c45fSAndroid Build Coastguard Worker android::show_help(argv[0]);
704*38e8c45fSAndroid Build Coastguard Worker exit(0);
705*38e8c45fSAndroid Build Coastguard Worker break;
706*38e8c45fSAndroid Build Coastguard Worker
707*38e8c45fSAndroid Build Coastguard Worker default:
708*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr,"Unrecognized Option\n");
709*38e8c45fSAndroid Build Coastguard Worker android::show_help(argv[0]);
710*38e8c45fSAndroid Build Coastguard Worker exit(-1);
711*38e8c45fSAndroid Build Coastguard Worker break;
712*38e8c45fSAndroid Build Coastguard Worker }
713*38e8c45fSAndroid Build Coastguard Worker }
714*38e8c45fSAndroid Build Coastguard Worker
715*38e8c45fSAndroid Build Coastguard Worker const char* backupFile = "/sdcard/backup.dat";
716*38e8c45fSAndroid Build Coastguard Worker
717*38e8c45fSAndroid Build Coastguard Worker if (argc > optind) {
718*38e8c45fSAndroid Build Coastguard Worker backupFile = argv[optind];
719*38e8c45fSAndroid Build Coastguard Worker optind++;
720*38e8c45fSAndroid Build Coastguard Worker if (argc != optind) {
721*38e8c45fSAndroid Build Coastguard Worker fprintf(stderr, "Too many arguments\n");
722*38e8c45fSAndroid Build Coastguard Worker android::show_help(argv[0]);
723*38e8c45fSAndroid Build Coastguard Worker exit(-1);
724*38e8c45fSAndroid Build Coastguard Worker }
725*38e8c45fSAndroid Build Coastguard Worker }
726*38e8c45fSAndroid Build Coastguard Worker
727*38e8c45fSAndroid Build Coastguard Worker printf("Stopping system...\n");
728*38e8c45fSAndroid Build Coastguard Worker property_set("ctl.stop", "runtime");
729*38e8c45fSAndroid Build Coastguard Worker property_set("ctl.stop", "zygote");
730*38e8c45fSAndroid Build Coastguard Worker sleep(1);
731*38e8c45fSAndroid Build Coastguard Worker
732*38e8c45fSAndroid Build Coastguard Worker int res;
733*38e8c45fSAndroid Build Coastguard Worker if (restore) {
734*38e8c45fSAndroid Build Coastguard Worker res = android::restore_data(backupFile);
735*38e8c45fSAndroid Build Coastguard Worker if (res != 0) {
736*38e8c45fSAndroid Build Coastguard Worker // Don't restart system, since the data partition is hosed.
737*38e8c45fSAndroid Build Coastguard Worker return res;
738*38e8c45fSAndroid Build Coastguard Worker }
739*38e8c45fSAndroid Build Coastguard Worker printf("Restore complete! Restarting system, cross your fingers...\n");
740*38e8c45fSAndroid Build Coastguard Worker } else {
741*38e8c45fSAndroid Build Coastguard Worker res = android::backup_data(backupFile);
742*38e8c45fSAndroid Build Coastguard Worker if (res == 0) {
743*38e8c45fSAndroid Build Coastguard Worker printf("Backup complete! Restarting system...\n");
744*38e8c45fSAndroid Build Coastguard Worker } else {
745*38e8c45fSAndroid Build Coastguard Worker printf("Restarting system...\n");
746*38e8c45fSAndroid Build Coastguard Worker }
747*38e8c45fSAndroid Build Coastguard Worker }
748*38e8c45fSAndroid Build Coastguard Worker
749*38e8c45fSAndroid Build Coastguard Worker property_set("ctl.start", "zygote");
750*38e8c45fSAndroid Build Coastguard Worker property_set("ctl.start", "runtime");
751*38e8c45fSAndroid Build Coastguard Worker }
752