194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood// Copyright 2009 The Android Open Source Project
294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <stdio.h>
494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <stdlib.h>
594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <stdarg.h>
694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <string.h>
794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <unistd.h>
894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <fcntl.h>
994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <time.h>
1094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <dirent.h>
1194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <errno.h>
1294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <assert.h>
1394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <ctype.h>
1494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <utime.h>
1594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <sys/stat.h>
1694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <sys/types.h>
1794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <stdint.h>
1894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
1994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <cutils/properties.h>
2094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
2194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#include <private/android_filesystem_config.h>
2294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
2394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#ifndef PATH_MAX
2494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#define PATH_MAX 4096
2594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#endif
2694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
2794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood// First version.
2894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#define FILE_VERSION_1 0xffff0001
2994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
3094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood// Introduces backup all option to header.
3194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#define FILE_VERSION_2 0xffff0002
3294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
3394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#define FILE_VERSION FILE_VERSION_2
3494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
3594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodnamespace android {
3694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
3794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic char nameBuffer[PATH_MAX];
3894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic struct stat statBuffer;
3994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
4094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic char copyBuffer[8192];
4194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic char *backupFilePath = NULL;
4294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
4394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic uint32_t inputFileVersion;
4494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
4594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic int opt_backupAll;
4694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
4794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#define SPECIAL_NO_TOUCH 0
4894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#define SPECIAL_NO_BACKUP 1
4994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
5094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstruct special_dir {
5194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    const char* path;
5294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int type;
5394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood};
5494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
5594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood/* Directory paths that we will not backup/restore */
5694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic const struct special_dir SKIP_PATHS[] = {
5794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    { "/data/misc", SPECIAL_NO_TOUCH },
5894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    { "/data/system/batterystats.bin", SPECIAL_NO_TOUCH },
5994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    { "/data/system/location", SPECIAL_NO_TOUCH },
6094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    { "/data/dalvik-cache", SPECIAL_NO_BACKUP },
6194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    { NULL, 0 },
6294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood};
6394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
6494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood/* This is just copied from the shell's built-in wipe command. */
6594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic int wipe (const char *path)
6694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{
6794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    DIR *dir;
6894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    struct dirent *de;
6994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int ret;
7094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int i;
7194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
7294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    dir = opendir(path);
7394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
7494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (dir == NULL) {
7594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf (stderr, "Error opendir'ing %s: %s\n",
7694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    path, strerror(errno));
7794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 0;
7894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
7994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
8094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    char *filenameOffset;
8194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
8294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    strcpy(nameBuffer, path);
8394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    strcat(nameBuffer, "/");
8494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
8594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    filenameOffset = nameBuffer + strlen(nameBuffer);
8694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
8794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    for (;;) {
8894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        de = readdir(dir);
8994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
9094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (de == NULL) {
9194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            break;
9294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
9394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
9494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (0 == strcmp(de->d_name, ".")
9594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                || 0 == strcmp(de->d_name, "..")
9694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                || 0 == strcmp(de->d_name, "lost+found")
9794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        ) {
9894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            continue;
9994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
10094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
10194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        strcpy(filenameOffset, de->d_name);
10294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        bool noBackup = false;
10394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
10494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        /* See if this is a path we should skip. */
10594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        for (i = 0; SKIP_PATHS[i].path; i++) {
10694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (strcmp(SKIP_PATHS[i].path, nameBuffer) == 0) {
10794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                if (opt_backupAll || SKIP_PATHS[i].type == SPECIAL_NO_BACKUP) {
10894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    // In this case we didn't back up the directory --
10994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    // we do want to wipe its contents, but not the
11094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    // directory itself, since the restore file won't
11194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    // contain the directory.
11294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    noBackup = true;
11394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                }
11494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                break;
11594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
11694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
11794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
11894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (!noBackup && SKIP_PATHS[i].path != NULL) {
11994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            // This is a SPECIAL_NO_TOUCH directory.
12094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            continue;
12194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
12294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
12394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        ret = lstat (nameBuffer, &statBuffer);
12494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
12594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (ret != 0) {
12694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            fprintf(stderr, "warning -- stat() error on '%s': %s\n",
12794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    nameBuffer, strerror(errno));
12894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            continue;
12994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
13094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
13194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if(S_ISDIR(statBuffer.st_mode)) {
13294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            int i;
13394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            char *newpath;
13494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
13594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            newpath = strdup(nameBuffer);
13694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (wipe(newpath) == 0) {
13794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                free(newpath);
13894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                closedir(dir);
13994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                return 0;
14094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
14194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
14294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (!noBackup) {
14394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                ret = rmdir(newpath);
14494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                if (ret != 0) {
14594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    fprintf(stderr, "warning -- rmdir() error on '%s': %s\n",
14694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                        newpath, strerror(errno));
14794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                }
14894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
14994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
15094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            free(newpath);
15194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
15294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            strcpy(nameBuffer, path);
15394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            strcat(nameBuffer, "/");
15494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
15594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        } else {
15694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            // Don't delete the backup file
15794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (backupFilePath && strcmp(backupFilePath, nameBuffer) == 0) {
15894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                continue;
15994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
16094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            ret = unlink(nameBuffer);
16194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
16294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (ret != 0) {
16394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                fprintf(stderr, "warning -- unlink() error on '%s': %s\n",
16494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    nameBuffer, strerror(errno));
16594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
16694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
16794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
16894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
16994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    closedir(dir);
17094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
17194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return 1;
17294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
17394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
17494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic int write_int32(FILE* fh, int32_t val)
17594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{
17694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int res = fwrite(&val, 1, sizeof(val), fh);
17794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (res != sizeof(val)) {
17894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "unable to write int32 (%d bytes): %s\n", res, strerror(errno));
17994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 0;
18094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
18194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
18294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return 1;
18394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
18494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
18594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic int write_int64(FILE* fh, int64_t val)
18694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{
18794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int res = fwrite(&val, 1, sizeof(val), fh);
18894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (res != sizeof(val)) {
18994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "unable to write int64 (%d bytes): %s\n", res, strerror(errno));
19094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 0;
19194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
19294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
19394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return 1;
19494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
19594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
19694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic int copy_file(FILE* dest, FILE* src, off_t size, const char* destName,
19794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        const char* srcName)
19894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{
19994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    errno = 0;
20094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
20194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    off_t origSize = size;
20294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
20394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    while (size > 0) {
20494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        int amt = size > (off_t)sizeof(copyBuffer) ? sizeof(copyBuffer) : (int)size;
20594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        int readLen = fread(copyBuffer, 1, amt, src);
20694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (readLen <= 0) {
20794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (srcName != NULL) {
20894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                fprintf(stderr, "unable to read source (%d of %ld bytes) file '%s': %s\n",
20994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    amt, origSize, srcName, errno != 0 ? strerror(errno) : "unexpected EOF");
21094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            } else {
21194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                fprintf(stderr, "unable to read buffer (%d of %ld bytes): %s\n",
21294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    amt, origSize, errno != 0 ? strerror(errno) : "unexpected EOF");
21394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
21494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            return 0;
21594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
21694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        int writeLen = fwrite(copyBuffer, 1, readLen, dest);
21794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (writeLen != readLen) {
21894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (destName != NULL) {
21994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                fprintf(stderr, "unable to write file (%d of %d bytes) '%s': '%s'\n",
22094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    writeLen, readLen, destName, strerror(errno));
22194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            } else {
22294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                fprintf(stderr, "unable to write buffer (%d of %d bytes): '%s'\n",
22394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    writeLen, readLen, strerror(errno));
22494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
22594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            return 0;
22694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
22794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        size -= readLen;
22894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
22994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return 1;
23094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
23194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
23294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#define TYPE_END 0
23394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#define TYPE_DIR 1
23494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood#define TYPE_FILE 2
23594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
23694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic int write_header(FILE* fh, int type, const char* path, const struct stat* st)
23794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{
23894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int pathLen = strlen(path);
23994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!write_int32(fh, type)) return 0;
24094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!write_int32(fh, pathLen)) return 0;
24194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (fwrite(path, 1, pathLen, fh) != (size_t)pathLen) {
24294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "unable to write: %s\n", strerror(errno));
24394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 0;
24494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
24594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
24694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!write_int32(fh, st->st_uid)) return 0;
24794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!write_int32(fh, st->st_gid)) return 0;
24894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!write_int32(fh, st->st_mode)) return 0;
24994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!write_int64(fh, ((int64_t)st->st_atime)*1000*1000*1000)) return 0;
25094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!write_int64(fh, ((int64_t)st->st_mtime)*1000*1000*1000)) return 0;
25194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!write_int64(fh, ((int64_t)st->st_ctime)*1000*1000*1000)) return 0;
25294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
25394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return 1;
25494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
25594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
25694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic int backup_dir(FILE* fh, const char* srcPath)
25794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{
25894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    DIR *dir;
25994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    struct dirent *de;
26094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    char* fullPath = NULL;
26194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int srcLen = strlen(srcPath);
26294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int result = 1;
26394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int i;
26494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
26594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    dir = opendir(srcPath);
26694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
26794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (dir == NULL) {
26894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf (stderr, "error opendir'ing '%s': %s\n",
26994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    srcPath, strerror(errno));
27094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 0;
27194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
27294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
27394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    for (;;) {
27494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        de = readdir(dir);
27594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
27694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (de == NULL) {
27794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            break;
27894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
27994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
28094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (0 == strcmp(de->d_name, ".")
28194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                || 0 == strcmp(de->d_name, "..")
28294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                || 0 == strcmp(de->d_name, "lost+found")
28394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        ) {
28494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            continue;
28594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
28694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
28794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (fullPath != NULL) {
28894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            free(fullPath);
28994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
29094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fullPath = (char*)malloc(srcLen + strlen(de->d_name) + 2);
29194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        strcpy(fullPath, srcPath);
29294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fullPath[srcLen] = '/';
29394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        strcpy(fullPath+srcLen+1, de->d_name);
29494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
29594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        /* See if this is a path we should skip. */
29694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (!opt_backupAll) {
29794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            for (i = 0; SKIP_PATHS[i].path; i++) {
29894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                if (strcmp(SKIP_PATHS[i].path, fullPath) == 0) {
29994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    break;
30094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                }
30194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
30294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (SKIP_PATHS[i].path != NULL) {
30394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                continue;
30494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
30594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
30694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
30794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        int ret = lstat(fullPath, &statBuffer);
30894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
30994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (ret != 0) {
31094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            fprintf(stderr, "stat() error on '%s': %s\n",
31194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    fullPath, strerror(errno));
31294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            result = 0;
31394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            goto done;
31494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
31594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
31694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if(S_ISDIR(statBuffer.st_mode)) {
31794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            printf("Saving dir %s...\n", fullPath);
31894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
31994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (write_header(fh, TYPE_DIR, fullPath, &statBuffer) == 0) {
32094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                result = 0;
32194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                goto done;
32294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
32394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (backup_dir(fh, fullPath) == 0) {
32494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                result = 0;
32594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                goto done;
32694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
32794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        } else if (S_ISREG(statBuffer.st_mode)) {
32894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            // Skip the backup file
32994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (backupFilePath && strcmp(fullPath, backupFilePath) == 0) {
33094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                printf("Skipping backup file %s...\n", backupFilePath);
33194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                continue;
33294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            } else {
33394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                printf("Saving file %s...\n", fullPath);
33494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
33594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (write_header(fh, TYPE_FILE, fullPath, &statBuffer) == 0) {
33694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                result = 0;
33794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                goto done;
33894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
33994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
34094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            off_t size = statBuffer.st_size;
34194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (!write_int64(fh, size)) {
34294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                result = 0;
34394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                goto done;
34494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
34594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
34694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            FILE* src = fopen(fullPath, "r");
34794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (src == NULL) {
34894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                fprintf(stderr, "unable to open source file '%s': %s\n",
34994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    fullPath, strerror(errno));
35094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                result = 0;
35194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                goto done;
35294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
35394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
35494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            int copyres = copy_file(fh, src, size, NULL, fullPath);
35594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            fclose(src);
35694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (!copyres) {
35794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                result = 0;
35894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                goto done;
35994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
36094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
36194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
36294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
36394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwooddone:
36494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (fullPath != NULL) {
36594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        free(fullPath);
36694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
36794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
36894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    closedir(dir);
36994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
37094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return result;
37194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
37294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
37394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic int backup_data(const char* destPath)
37494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{
37594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int res = -1;
37694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
37794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    FILE* fh = fopen(destPath, "w");
37894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (fh == NULL) {
37994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "unable to open destination '%s': %s\n",
38094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                destPath, strerror(errno));
38194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return -1;
38294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
38394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
38494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    printf("Backing up /data to %s...\n", destPath);
38594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
38694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    // The path that shouldn't be backed up
38794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    backupFilePath = strdup(destPath);
38894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
38994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!write_int32(fh, FILE_VERSION)) goto done;
39094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!write_int32(fh, opt_backupAll)) goto done;
39194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!backup_dir(fh, "/data")) goto done;
39294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!write_int32(fh, 0)) goto done;
39394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
39494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    res = 0;
39594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
39694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwooddone:
39794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (fflush(fh) != 0) {
39894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "error flushing destination '%s': %s\n",
39994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            destPath, strerror(errno));
40094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        res = -1;
40194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        goto donedone;
40294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
40394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (fsync(fileno(fh)) != 0) {
40494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "error syncing destination '%s': %s\n",
40594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            destPath, strerror(errno));
40694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        res = -1;
40794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        goto donedone;
40894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
40994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    fclose(fh);
41094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    sync();
41194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
41294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwooddonedone:
41394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return res;
41494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
41594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
41694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic int32_t read_int32(FILE* fh, int32_t defVal)
41794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{
41894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int32_t val;
41994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (fread(&val, 1, sizeof(val), fh) != sizeof(val)) {
42094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "unable to read: %s\n", strerror(errno));
42194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return defVal;
42294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
42394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
42494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return val;
42594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
42694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
42794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic int64_t read_int64(FILE* fh, int64_t defVal)
42894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{
42994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int64_t val;
43094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (fread(&val, 1, sizeof(val), fh) != sizeof(val)) {
43194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "unable to read: %s\n", strerror(errno));
43294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return defVal;
43394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
43494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
43594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return val;
43694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
43794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
43894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic int read_header(FILE* fh, int* type, char** path, struct stat* st)
43994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{
44094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    *type = read_int32(fh, -1);
44194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (*type == TYPE_END) {
44294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 1;
44394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
44494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
44594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (*type < 0) {
44694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "bad token %d in restore file\n", *type);
44794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 0;
44894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
44994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
45094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int32_t pathLen = read_int32(fh, -1);
45194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (pathLen <= 0) {
45294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "bad path length %d in restore file\n", pathLen);
45394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 0;
45494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
45594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    char* readPath = (char*)malloc(pathLen+1);
45694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (fread(readPath, 1, pathLen, fh) != (size_t)pathLen) {
45794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "truncated path in restore file\n");
45894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        free(readPath);
45994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 0;
46094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
46194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    readPath[pathLen] = 0;
46294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    *path = readPath;
46394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
46494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    st->st_uid = read_int32(fh, -1);
46594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (st->st_uid == (uid_t)-1) {
46694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "bad uid in restore file at '%s'\n", readPath);
46794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 0;
46894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
46994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    st->st_gid = read_int32(fh, -1);
47094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (st->st_gid == (gid_t)-1) {
47194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "bad gid in restore file at '%s'\n", readPath);
47294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 0;
47394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
47494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    st->st_mode = read_int32(fh, -1);
47594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (st->st_mode == (mode_t)-1) {
47694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "bad mode in restore file at '%s'\n", readPath);
47794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 0;
47894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
47994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int64_t ltime = read_int64(fh, -1);
48094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (ltime < 0) {
48194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "bad atime in restore file at '%s'\n", readPath);
48294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 0;
48394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
48494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    st->st_atime = (time_t)(ltime/1000/1000/1000);
48594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    ltime = read_int64(fh, -1);
48694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (ltime < 0) {
48794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "bad mtime in restore file at '%s'\n", readPath);
48894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 0;
48994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
49094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    st->st_mtime = (time_t)(ltime/1000/1000/1000);
49194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    ltime = read_int64(fh, -1);
49294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (ltime < 0) {
49394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "bad ctime in restore file at '%s'\n", readPath);
49494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return 0;
49594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
49694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    st->st_ctime = (time_t)(ltime/1000/1000/1000);
49794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
49894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    st->st_mode &= (S_IRWXU|S_IRWXG|S_IRWXO);
49994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
50094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return 1;
50194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
50294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
50394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic int restore_data(const char* srcPath)
50494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{
50594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int res = -1;
50694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
50794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    FILE* fh = fopen(srcPath, "r");
50894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (fh == NULL) {
50994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "Unable to open source '%s': %s\n",
51094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                srcPath, strerror(errno));
51194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        return -1;
51294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
51394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
51494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    inputFileVersion = read_int32(fh, 0);
51594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (inputFileVersion < FILE_VERSION_1 || inputFileVersion > FILE_VERSION) {
51694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "Restore file has bad version: 0x%x\n", inputFileVersion);
51794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        goto done;
51894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
51994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
52094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (inputFileVersion >= FILE_VERSION_2) {
52194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        opt_backupAll = read_int32(fh, 0);
52294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    } else {
52394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        opt_backupAll = 0;
52494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
52594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
52694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    // The path that shouldn't be deleted
52794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    backupFilePath = strdup(srcPath);
52894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
52994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    printf("Wiping contents of /data...\n");
53094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (!wipe("/data")) {
53194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        goto done;
53294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
53394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
53494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    printf("Restoring from %s to /data...\n", srcPath);
53594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
53694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    while (1) {
53794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        int type;
53894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        char* path = NULL;
53994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (read_header(fh, &type, &path, &statBuffer) == 0) {
54094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            goto done;
54194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
54294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (type == 0) {
54394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            break;
54494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
54594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
54694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        const char* typeName = "?";
54794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
54894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (type == TYPE_DIR) {
54994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            typeName = "dir";
55094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
55194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            printf("Restoring dir %s...\n", path);
55294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
55394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (mkdir(path, statBuffer.st_mode) != 0) {
55494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                if (errno != EEXIST) {
55594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    fprintf(stderr, "unable to create directory '%s': %s\n",
55694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                        path, strerror(errno));
55794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    free(path);
55894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    goto done;
55994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                }
56094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
56194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
56294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        } else if (type == TYPE_FILE) {
56394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            typeName = "file";
56494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            off_t size = read_int64(fh, -1);
56594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (size < 0) {
56694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                fprintf(stderr, "bad file size %ld in restore file\n", size);
56794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                free(path);
56894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                goto done;
56994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
57094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
57194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            printf("Restoring file %s...\n", path);
57294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
57394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            FILE* dest = fopen(path, "w");
57494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (dest == NULL) {
57594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                fprintf(stderr, "unable to open destination file '%s': %s\n",
57694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    path, strerror(errno));
57794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                free(path);
57894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                goto done;
57994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
58094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
58194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            int copyres = copy_file(dest, fh, size, path, NULL);
58294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            fclose(dest);
58394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            if (!copyres) {
58494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                free(path);
58594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                goto done;
58694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            }
58794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
58894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        } else {
58994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            fprintf(stderr, "unknown node type %d\n", type);
59094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            goto done;
59194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
59294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
59394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        // Do this even for directories, since the dir may have already existed
59494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        // so we need to make sure it gets the correct mode.
59594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (chmod(path, statBuffer.st_mode&(S_IRWXU|S_IRWXG|S_IRWXO)) != 0) {
59694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            fprintf(stderr, "unable to chmod destination %s '%s' to 0x%x: %s\n",
59794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                typeName, path, statBuffer.st_mode, strerror(errno));
59894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            free(path);
59994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            goto done;
60094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
60194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
60294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (chown(path, statBuffer.st_uid, statBuffer.st_gid) != 0) {
60394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            fprintf(stderr, "unable to chown destination %s '%s' to uid %d / gid %d: %s\n",
60494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                typeName, path, (int)statBuffer.st_uid, (int)statBuffer.st_gid, strerror(errno));
60594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            free(path);
60694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            goto done;
60794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
60894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
60994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        struct utimbuf timbuf;
61094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        timbuf.actime = statBuffer.st_atime;
61194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        timbuf.modtime = statBuffer.st_mtime;
61294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (utime(path, &timbuf) != 0) {
61394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            fprintf(stderr, "unable to utime destination %s '%s': %s\n",
61494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                typeName, path, strerror(errno));
61594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            free(path);
61694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            goto done;
61794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
61894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
61994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
62094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        free(path);
62194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
62294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
62394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    res = 0;
62494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
62594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwooddone:
62694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    fclose(fh);
62794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
62894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    return res;
62994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
63094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
63194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodstatic void show_help(const char *cmd)
63294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{
63394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    fprintf(stderr,"Usage: %s COMMAND [options] [backup-file-path]\n", cmd);
63494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
63594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    fprintf(stderr, "commands are:\n"
63694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    "  help            Show this help text.\n"
63794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    "  backup          Perform a backup of /data.\n"
63894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    "  restore         Perform a restore of /data.\n");
63994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    fprintf(stderr, "options include:\n"
64094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    "  -h              Show this help text.\n"
64194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    "  -a              Backup all files.\n");
642b82bf9dfc97c44852283630eac24ae92b49f85f6Amith Yamasani    fprintf(stderr, "\n backup-file-path Defaults to /sdcard/backup.dat .\n"
643b82bf9dfc97c44852283630eac24ae92b49f85f6Amith Yamasani                    "                  On devices that emulate the sdcard, you will need to\n"
644b82bf9dfc97c44852283630eac24ae92b49f85f6Amith Yamasani                    "                  explicitly specify the directory it is mapped to,\n"
645b82bf9dfc97c44852283630eac24ae92b49f85f6Amith Yamasani                    "                  to avoid recursive backup or deletion of the backup file\n"
646b82bf9dfc97c44852283630eac24ae92b49f85f6Amith Yamasani                    "                  during restore.\n\n"
647b82bf9dfc97c44852283630eac24ae92b49f85f6Amith Yamasani                    "                  Eg. /data/media/0/backup.dat\n");
64894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    fprintf(stderr, "\nThe %s command allows you to perform low-level\n"
64994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    "backup and restore of the /data partition.  This is\n"
65094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    "where all user data is kept, allowing for a fairly\n"
65194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    "complete restore of a device's state.  Note that\n"
65294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    "because this is low-level, it will only work across\n"
65394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    "builds of the same (or very similar) device software.\n",
65494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                    cmd);
65594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
65694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
65794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood} /* namespace android */
65894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
65994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwoodint main (int argc, char **argv)
66094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood{
66194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int restore = 0;
66294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
66394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (getuid() != AID_ROOT) {
66494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "error -- %s must run as root\n", argv[0]);
66594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        exit(-1);
66694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
66794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
66894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (argc < 2) {
66994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "No command specified.\n");
67094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        android::show_help(argv[0]);
67194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        exit(-1);
67294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
67394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
67494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (0 == strcmp(argv[1], "restore")) {
67594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        restore = 1;
67694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    } else if (0 == strcmp(argv[1], "help")) {
67794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        android::show_help(argv[0]);
67894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        exit(0);
67994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    } else if (0 != strcmp(argv[1], "backup")) {
68094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        fprintf(stderr, "Unknown command: %s\n", argv[1]);
68194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        android::show_help(argv[0]);
68294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        exit(-1);
68394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
68494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
68594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    android::opt_backupAll = 0;
68694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
68794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    optind = 2;
68894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
68994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    for (;;) {
69094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        int ret;
69194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
69294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        ret = getopt(argc, argv, "ah");
69394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
69494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (ret < 0) {
69594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            break;
69694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
69794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
69894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        switch(ret) {
69994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            case 'a':
70094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                android::opt_backupAll = 1;
70194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                if (restore) fprintf(stderr, "Warning: -a option ignored on restore\n");
70294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                break;
70394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            case 'h':
70494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                android::show_help(argv[0]);
70594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                exit(0);
70694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            break;
70794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
70894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            default:
70994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                fprintf(stderr,"Unrecognized Option\n");
71094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                android::show_help(argv[0]);
71194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood                exit(-1);
71294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            break;
71394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
71494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
71594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
71694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    const char* backupFile = "/sdcard/backup.dat";
71794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
71894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (argc > optind) {
71994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        backupFile = argv[optind];
72094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        optind++;
72194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (argc != optind) {
72294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            fprintf(stderr, "Too many arguments\n");
72394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            android::show_help(argv[0]);
72494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            exit(-1);
72594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
72694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
72794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
72894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    printf("Stopping system...\n");
72994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    property_set("ctl.stop", "runtime");
73094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    property_set("ctl.stop", "zygote");
73194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    sleep(1);
73294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
73394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    int res;
73494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    if (restore) {
73594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        res = android::restore_data(backupFile);
73694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (res != 0) {
73794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            // Don't restart system, since the data partition is hosed.
73894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            return res;
73994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
74094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        printf("Restore complete!  Restarting system, cross your fingers...\n");
74194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    } else {
74294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        res = android::backup_data(backupFile);
74394afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        if (res == 0) {
74494afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            printf("Backup complete!  Restarting system...\n");
74594afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        } else {
74694afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood            printf("Restarting system...\n");
74794afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood        }
74894afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    }
74994afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood
75094afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    property_set("ctl.start", "zygote");
75194afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood    property_set("ctl.start", "runtime");
75294afecf4b6f437b3ee9a076242402e421c6c07a6Mike Lockwood}
753