xref: /aosp_15_r20/frameworks/native/cmds/rawbu/backup.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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