⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dir_hash.c

📁 Android 一些工具
💻 C
字号:
/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include <dirent.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sha1.h>#include <unistd.h>#include <limits.h>#include <sys/stat.h>#include <netinet/in.h>#include <resolv.h>#include <cutils/dir_hash.h>/** * Copies, if it fits within max_output_string bytes, into output_string * a hash of the contents, size, permissions, uid, and gid of the file * specified by path, using the specified algorithm.  Returns the length * of the output string, or a negative number if the buffer is too short. */int get_file_hash(HashAlgorithm algorithm, const char *path,                  char *output_string, size_t max_output_string) {    SHA1_CTX context;    struct stat sb;    unsigned char md[SHA1_DIGEST_LENGTH];    int used;    size_t n;    if (algorithm != SHA_1) {        errno = EINVAL;        return -1;    }    if (stat(path, &sb) != 0) {        return -1;    }    if (S_ISLNK(sb.st_mode)) {        char buf[PATH_MAX];        int len;        len = readlink(path, buf, sizeof(buf));        if (len < 0) {            return -1;        }        SHA1Init(&context);        SHA1Update(&context, (unsigned char *) buf, len);        SHA1Final(md, &context);    } else if (S_ISREG(sb.st_mode)) {        char buf[10000];        FILE *f = fopen(path, "rb");        int len;        if (f == NULL) {            return -1;        }        SHA1Init(&context);        while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {            SHA1Update(&context, (unsigned char *) buf, len);        }        if (ferror(f)) {            fclose(f);            return -1;        }        fclose(f);        SHA1Final(md, &context);    }    if (S_ISLNK(sb.st_mode) || S_ISREG(sb.st_mode)) {        used = b64_ntop(md, SHA1_DIGEST_LENGTH,                        output_string, max_output_string);        if (used < 0) {            errno = ENOSPC;            return -1;        }        n = snprintf(output_string + used, max_output_string - used,                     " %d 0%o %d %d", (int) sb.st_size, sb.st_mode,                     (int) sb.st_uid, (int) sb.st_gid);    } else {        n = snprintf(output_string, max_output_string,                     "- - 0%o %d %d", sb.st_mode,                     (int) sb.st_uid, (int) sb.st_gid);    }    if (n >= max_output_string - used) {        errno = ENOSPC;        return -(used + n);    }    return used + n;}struct list {    char *name;    struct list *next;};static int cmp(const void *a, const void *b) {    struct list *const *ra = a;    struct list *const *rb = b;    return strcmp((*ra)->name, (*rb)->name);}static int recurse(HashAlgorithm algorithm, const char *directory_path,                    struct list **out) {    struct list *list = NULL;    struct list *f;    struct dirent *de;    DIR *d = opendir(directory_path);    if (d == NULL) {        return -1;    }    while ((de = readdir(d)) != NULL) {        if (strcmp(de->d_name, ".") == 0) {            continue;        }        if (strcmp(de->d_name, "..") == 0) {            continue;        }        char *name = malloc(strlen(de->d_name) + 1);        struct list *node = malloc(sizeof(struct list));        if (name == NULL || node == NULL) {            struct list *next;            for (f = list; f != NULL; f = next) {                next = f->next;                free(f->name);                free(f);            }            free(name);            free(node);            return -1;        }        strcpy(name, de->d_name);        node->name = name;        node->next = list;        list = node;    }    closedir(d);    for (f = list; f != NULL; f = f->next) {        struct stat sb;        char *name;        char outstr[NAME_MAX + 100];        char *keep;        struct list *res;        name = malloc(strlen(f->name) + strlen(directory_path) + 2);        if (name == NULL) {            struct list *next;            for (f = list; f != NULL; f = f->next) {                next = f->next;                free(f->name);                free(f);            }            for (f = *out; f != NULL; f = f->next) {                next = f->next;                free(f->name);                free(f);            }            *out = NULL;            return -1;        }        sprintf(name, "%s/%s", directory_path, f->name);        int len = get_file_hash(algorithm, name,                                outstr, sizeof(outstr));        if (len < 0) {            // should not happen            return -1;        }        keep = malloc(len + strlen(name) + 3);        res = malloc(sizeof(struct list));        if (keep == NULL || res == NULL) {            struct list *next;            for (f = list; f != NULL; f = f->next) {                next = f->next;                free(f->name);                free(f);            }            for (f = *out; f != NULL; f = f->next) {                next = f->next;                free(f->name);                free(f);            }            *out = NULL;            free(keep);            free(res);            return -1;        }        sprintf(keep, "%s %s\n", name, outstr);        res->name = keep;        res->next = *out;        *out = res;        if ((stat(name, &sb) == 0) && S_ISDIR(sb.st_mode)) {            if (recurse(algorithm, name, out) < 0) {                struct list *next;                for (f = list; f != NULL; f = next) {                    next = f->next;                    free(f->name);                    free(f);                }                return -1;            }        }    }    struct list *next;    for (f = list; f != NULL; f = next) {        next = f->next;        free(f->name);        free(f);    }}/** * Allocates a string containing the names and hashes of all files recursively * reached under the specified directory_path, using the specified algorithm. * The string is returned as *output_string; the return value is the length * of the string, or a negative number if there was a failure. */int get_recursive_hash_manifest(HashAlgorithm algorithm,                                const char *directory_path,                                char **output_string) {    struct list *out = NULL;    struct list *r;    struct list **list;    int count = 0;    int len = 0;    int retlen = 0;    int i;    char *buf;        if (recurse(algorithm, directory_path, &out) < 0) {        return -1;    }    for (r = out; r != NULL; r = r->next) {        count++;        len += strlen(r->name);    }    list = malloc(count * sizeof(struct list *));    if (list == NULL) {        struct list *next;        for (r = out; r != NULL; r = next) {            next = r->next;            free(r->name);            free(r);        }        return -1;    }    count = 0;    for (r = out; r != NULL; r = r->next) {        list[count++] = r;    }    qsort(list, count, sizeof(struct list *), cmp);    buf = malloc(len + 1);    if (buf == NULL) {        struct list *next;        for (r = out; r != NULL; r = next) {            next = r->next;            free(r->name);            free(r);        }        free(list);        return -1;    }    for (i = 0; i < count; i++) {        int n = strlen(list[i]->name);        strcpy(buf + retlen, list[i]->name);        retlen += n;    }    free(list);    struct list *next;    for (r = out; r != NULL; r = next) {        next = r->next;        free(r->name);        free(r);    }    *output_string = buf;    return retlen;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -