read-tree.con commit [PATCH] Consolidate the error handling (2de381f)
   1/*
   2 * GIT - The information manager from hell
   3 *
   4 * Copyright (C) Linus Torvalds, 2005
   5 */
   6#include "cache.h"
   7
   8static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode)
   9{
  10        int len = strlen(pathname);
  11        unsigned int size = cache_entry_size(baselen + len);
  12        struct cache_entry *ce = malloc(size);
  13
  14        memset(ce, 0, size);
  15
  16        ce->st_mode = mode;
  17        ce->namelen = baselen + len;
  18        memcpy(ce->name, base, baselen);
  19        memcpy(ce->name + baselen, pathname, len+1);
  20        memcpy(ce->sha1, sha1, 20);
  21        return add_cache_entry(ce, 1);
  22}
  23
  24static int read_tree(unsigned char *sha1, const char *base, int baselen)
  25{
  26        void *buffer;
  27        unsigned long size;
  28        char type[20];
  29
  30        buffer = read_sha1_file(sha1, type, &size);
  31        if (!buffer)
  32                return -1;
  33        if (strcmp(type, "tree"))
  34                return -1;
  35        while (size) {
  36                int len = strlen(buffer)+1;
  37                unsigned char *sha1 = buffer + len;
  38                char *path = strchr(buffer, ' ')+1;
  39                unsigned int mode;
  40
  41                if (size < len + 20 || sscanf(buffer, "%o", &mode) != 1)
  42                        return -1;
  43
  44                buffer = sha1 + 20;
  45                size -= len + 20;
  46
  47                if (S_ISDIR(mode)) {
  48                        int retval;
  49                        int pathlen = strlen(path);
  50                        char *newbase = malloc(baselen + 1 + pathlen);
  51                        memcpy(newbase, base, baselen);
  52                        memcpy(newbase + baselen, path, pathlen);
  53                        newbase[baselen + pathlen] = '/';
  54                        retval = read_tree(sha1, newbase, baselen + pathlen + 1);
  55                        free(newbase);
  56                        if (retval)
  57                                return -1;
  58                        continue;
  59                }
  60                if (read_one_entry(sha1, base, baselen, path, mode) < 0)
  61                        return -1;
  62        }
  63        return 0;
  64}
  65
  66static int remove_lock = 0;
  67
  68static void remove_lock_file(void)
  69{
  70        if (remove_lock)
  71                unlink(".git/index.lock");
  72}
  73
  74int main(int argc, char **argv)
  75{
  76        int i, newfd;
  77        unsigned char sha1[20];
  78
  79        newfd = open(".git/index.lock", O_RDWR | O_CREAT | O_EXCL, 0600);
  80        if (newfd < 0)
  81                die("unable to create new cachefile");
  82        atexit(remove_lock_file);
  83        remove_lock = 1;
  84
  85        for (i = 1; i < argc; i++) {
  86                const char *arg = argv[i];
  87
  88                /* "-m" stands for "merge" current directory cache */
  89                if (!strcmp(arg, "-m")) {
  90                        if (active_cache)
  91                                die("read-tree: cannot merge old cache on top of new");
  92                        if (read_cache() < 0)
  93                                die("read-tree: corrupt directory cache");
  94                        continue;
  95                }
  96                if (get_sha1_hex(arg, sha1) < 0)
  97                        usage("read-tree [-m] <sha1>");
  98                if (read_tree(sha1, "", 0) < 0)
  99                        die("failed to unpack tree object %s", arg);
 100        }
 101        if (write_cache(newfd, active_cache, active_nr) ||
 102            rename(".git/index.lock", ".git/index"))
 103                die("unable to write new index file");
 104        remove_lock = 0;
 105        return 0;
 106}