Merge branch 'fix'
authorJunio C Hamano <junkio@cox.net>
Sun, 14 May 2006 23:20:15 +0000 (16:20 -0700)
committerJunio C Hamano <junkio@cox.net>
Sun, 14 May 2006 23:20:15 +0000 (16:20 -0700)
* fix:
  include header to define uint32_t, necessary on Mac OS X

1  2 
pack-objects.c
sha1_file.c

diff --combined pack-objects.c
@@@ -10,6 -10,7 +10,7 @@@
  #include "tree-walk.h"
  #include <sys/time.h>
  #include <signal.h>
+ #include <stdint.h>
  
  static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list";
  
@@@ -994,7 -995,6 +995,7 @@@ static int type_size_sort(const struct 
  struct unpacked {
        struct object_entry *entry;
        void *data;
 +      struct delta_index *index;
  };
  
  /*
   * more importantly, the bigger file is likely the more recent
   * one.
   */
 -static int try_delta(struct unpacked *cur, struct unpacked *old, unsigned max_depth)
 +static int try_delta(struct unpacked *trg, struct unpacked *src,
 +                   struct delta_index *src_index, unsigned max_depth)
  {
 -      struct object_entry *cur_entry = cur->entry;
 -      struct object_entry *old_entry = old->entry;
 -      unsigned long size, oldsize, delta_size, sizediff;
 -      long max_size;
 +      struct object_entry *trg_entry = trg->entry;
 +      struct object_entry *src_entry = src->entry;
 +      unsigned long size, src_size, delta_size, sizediff, max_size;
        void *delta_buf;
  
        /* Don't bother doing diffs between different types */
 -      if (cur_entry->type != old_entry->type)
 +      if (trg_entry->type != src_entry->type)
                return -1;
  
        /* We do not compute delta to *create* objects we are not
         * going to pack.
         */
 -      if (cur_entry->preferred_base)
 +      if (trg_entry->preferred_base)
                return -1;
  
 -      /* If the current object is at pack edge, take the depth the
 +      /*
 +       * If the current object is at pack edge, take the depth the
         * objects that depend on the current object into account --
         * otherwise they would become too deep.
         */
 -      if (cur_entry->delta_child) {
 -              if (max_depth <= cur_entry->delta_limit)
 +      if (trg_entry->delta_child) {
 +              if (max_depth <= trg_entry->delta_limit)
                        return 0;
 -              max_depth -= cur_entry->delta_limit;
 +              max_depth -= trg_entry->delta_limit;
        }
 -
 -      size = cur_entry->size;
 -      oldsize = old_entry->size;
 -      sizediff = oldsize > size ? oldsize - size : size - oldsize;
 -
 -      if (size < 50)
 -              return -1;
 -      if (old_entry->depth >= max_depth)
 +      if (src_entry->depth >= max_depth)
                return 0;
  
 -      /*
 -       * NOTE!
 -       *
 -       * We always delta from the bigger to the smaller, since that's
 -       * more space-efficient (deletes don't have to say _what_ they
 -       * delete).
 -       */
 +      /* Now some size filtering euristics. */
 +      size = trg_entry->size;
        max_size = size / 2 - 20;
 -      if (cur_entry->delta)
 -              max_size = cur_entry->delta_size-1;
 +      if (trg_entry->delta)
 +              max_size = trg_entry->delta_size-1;
 +      src_size = src_entry->size;
 +      sizediff = src_size < size ? size - src_size : 0;
        if (sizediff >= max_size)
                return 0;
 -      delta_buf = diff_delta(old->data, oldsize,
 -                             cur->data, size, &delta_size, max_size);
 +
 +      delta_buf = create_delta(src_index, trg->data, size, &delta_size, max_size);
        if (!delta_buf)
                return 0;
 -      cur_entry->delta = old_entry;
 -      cur_entry->delta_size = delta_size;
 -      cur_entry->depth = old_entry->depth + 1;
 +
 +      trg_entry->delta = src_entry;
 +      trg_entry->delta_size = delta_size;
 +      trg_entry->depth = src_entry->depth + 1;
        free(delta_buf);
 -      return 0;
 +      return 1;
  }
  
  static void progress_interval(int signum)
@@@ -1102,19 -1110,11 +1103,19 @@@ static void find_deltas(struct object_e
                         */
                        continue;
  
 +              if (entry->size < 50)
 +                      continue;
 +              if (n->index)
 +                      free_delta_index(n->index);
                free(n->data);
                n->entry = entry;
                n->data = read_sha1_file(entry->sha1, type, &size);
                if (size != entry->size)
 -                      die("object %s inconsistent object length (%lu vs %lu)", sha1_to_hex(entry->sha1), size, entry->size);
 +                      die("object %s inconsistent object length (%lu vs %lu)",
 +                          sha1_to_hex(entry->sha1), size, entry->size);
 +              n->index = create_delta_index(n->data, size);
 +              if (!n->index)
 +                      die("out of memory");
  
                j = window;
                while (--j > 0) {
                        m = array + other_idx;
                        if (!m->entry)
                                break;
 -                      if (try_delta(n, m, depth) < 0)
 +                      if (try_delta(n, m, m->index, depth) < 0)
                                break;
                }
  #if 0
        if (progress)
                fputc('\n', stderr);
  
 -      for (i = 0; i < window; ++i)
 +      for (i = 0; i < window; ++i) {
 +              if (array[i].index)
 +                      free_delta_index(array[i].index);
                free(array[i].data);
 +      }
        free(array);
  }
  
@@@ -1243,7 -1240,6 +1244,7 @@@ int main(int argc, char **argv
  
        setup_git_directory();
  
 +      progress = isatty(2);
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
  
                                        usage(pack_usage);
                                continue;
                        }
 +                      if (!strcmp("--progress", arg)) {
 +                              progress = 1;
 +                              continue;
 +                      }
                        if (!strcmp("-q", arg)) {
                                progress = 0;
                                continue;
diff --combined sha1_file.c
@@@ -13,6 -13,7 +13,7 @@@
  #include "commit.h"
  #include "tag.h"
  #include "tree.h"
+ #include <stdint.h>
  
  #ifndef O_NOATIME
  #if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@@@ -108,10 -109,9 +109,10 @@@ int safe_create_leading_directories(cha
  
  char * sha1_to_hex(const unsigned char *sha1)
  {
 -      static char buffer[50];
 +      static int bufno;
 +      static char hexbuffer[4][50];
        static const char hex[] = "0123456789abcdef";
 -      char *buf = buffer;
 +      char *buffer = hexbuffer[3 & ++bufno], *buf = buffer;
        int i;
  
        for (i = 0; i < 20; i++) {
@@@ -217,8 -217,6 +218,8 @@@ char *sha1_pack_index_name(const unsign
  struct alternate_object_database *alt_odb_list;
  static struct alternate_object_database **alt_odb_tail;
  
 +static void read_info_alternates(const char * alternates, int depth);
 +
  /*
   * Prepare alternate object database registry.
   *
   * SHA1, an extra slash for the first level indirection, and the
   * terminating NUL.
   */
 -static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
 -                               const char *relative_base)
 +static int link_alt_odb_entry(const char * entry, int len, const char * relative_base, int depth)
  {
 -      const char *cp, *last;
 -      struct alternate_object_database *ent;
 +      struct stat st;
        const char *objdir = get_object_directory();
 +      struct alternate_object_database *ent;
 +      struct alternate_object_database *alt;
 +      /* 43 = 40-byte + 2 '/' + terminating NUL */
 +      int pfxlen = len;
 +      int entlen = pfxlen + 43;
        int base_len = -1;
  
 +      if (*entry != '/' && relative_base) {
 +              /* Relative alt-odb */
 +              if (base_len < 0)
 +                      base_len = strlen(relative_base) + 1;
 +              entlen += base_len;
 +              pfxlen += base_len;
 +      }
 +      ent = xmalloc(sizeof(*ent) + entlen);
 +
 +      if (*entry != '/' && relative_base) {
 +              memcpy(ent->base, relative_base, base_len - 1);
 +              ent->base[base_len - 1] = '/';
 +              memcpy(ent->base + base_len, entry, len);
 +      }
 +      else
 +              memcpy(ent->base, entry, pfxlen);
 +
 +      ent->name = ent->base + pfxlen + 1;
 +      ent->base[pfxlen + 3] = '/';
 +      ent->base[pfxlen] = ent->base[entlen-1] = 0;
 +
 +      /* Detect cases where alternate disappeared */
 +      if (stat(ent->base, &st) || !S_ISDIR(st.st_mode)) {
 +              error("object directory %s does not exist; "
 +                    "check .git/objects/info/alternates.",
 +                    ent->base);
 +              free(ent);
 +              return -1;
 +      }
 +
 +      /* Prevent the common mistake of listing the same
 +       * thing twice, or object directory itself.
 +       */
 +      for (alt = alt_odb_list; alt; alt = alt->next) {
 +              if (!memcmp(ent->base, alt->base, pfxlen)) {
 +                      free(ent);
 +                      return -1;
 +              }
 +      }
 +      if (!memcmp(ent->base, objdir, pfxlen)) {
 +              free(ent);
 +              return -1;
 +      }
 +
 +      /* add the alternate entry */
 +      *alt_odb_tail = ent;
 +      alt_odb_tail = &(ent->next);
 +      ent->next = NULL;
 +
 +      /* recursively add alternates */
 +      read_info_alternates(ent->base, depth + 1);
 +
 +      ent->base[pfxlen] = '/';
 +
 +      return 0;
 +}
 +
 +static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
 +                               const char *relative_base, int depth)
 +{
 +      const char *cp, *last;
 +
 +      if (depth > 5) {
 +              error("%s: ignoring alternate object stores, nesting too deep.",
 +                              relative_base);
 +              return;
 +      }
 +
        last = alt;
        while (last < ep) {
                cp = last;
                        last = cp + 1;
                        continue;
                }
 -              for ( ; cp < ep && *cp != sep; cp++)
 -                      ;
 +              while (cp < ep && *cp != sep)
 +                      cp++;
                if (last != cp) {
 -                      struct stat st;
 -                      struct alternate_object_database *alt;
 -                      /* 43 = 40-byte + 2 '/' + terminating NUL */
 -                      int pfxlen = cp - last;
 -                      int entlen = pfxlen + 43;
 -
 -                      if (*last != '/' && relative_base) {
 -                              /* Relative alt-odb */
 -                              if (base_len < 0)
 -                                      base_len = strlen(relative_base) + 1;
 -                              entlen += base_len;
 -                              pfxlen += base_len;
 -                      }
 -                      ent = xmalloc(sizeof(*ent) + entlen);
 -
 -                      if (*last != '/' && relative_base) {
 -                              memcpy(ent->base, relative_base, base_len - 1);
 -                              ent->base[base_len - 1] = '/';
 -                              memcpy(ent->base + base_len,
 -                                     last, cp - last);
 -                      }
 -                      else
 -                              memcpy(ent->base, last, pfxlen);
 -
 -                      ent->name = ent->base + pfxlen + 1;
 -                      ent->base[pfxlen + 3] = '/';
 -                      ent->base[pfxlen] = ent->base[entlen-1] = 0;
 -
 -                      /* Detect cases where alternate disappeared */
 -                      if (stat(ent->base, &st) || !S_ISDIR(st.st_mode)) {
 -                              error("object directory %s does not exist; "
 -                                    "check .git/objects/info/alternates.",
 -                                    ent->base);
 -                              goto bad;
 -                      }
 -                      ent->base[pfxlen] = '/';
 -
 -                      /* Prevent the common mistake of listing the same
 -                       * thing twice, or object directory itself.
 -                       */
 -                      for (alt = alt_odb_list; alt; alt = alt->next)
 -                              if (!memcmp(ent->base, alt->base, pfxlen))
 -                                      goto bad;
 -                      if (!memcmp(ent->base, objdir, pfxlen)) {
 -                      bad:
 -                              free(ent);
 -                      }
 -                      else {
 -                              *alt_odb_tail = ent;
 -                              alt_odb_tail = &(ent->next);
 -                              ent->next = NULL;
 +                      if ((*last != '/') && depth) {
 +                              error("%s: ignoring relative alternate object store %s",
 +                                              relative_base, last);
 +                      } else {
 +                              link_alt_odb_entry(last, cp - last,
 +                                              relative_base, depth);
                        }
                }
                while (cp < ep && *cp == sep)
        }
  }
  
 -void prepare_alt_odb(void)
 +static void read_info_alternates(const char * relative_base, int depth)
  {
 -      char path[PATH_MAX];
        char *map;
 -      int fd;
        struct stat st;
 -      char *alt;
 -
 -      alt = getenv(ALTERNATE_DB_ENVIRONMENT);
 -      if (!alt) alt = "";
 -
 -      if (alt_odb_tail)
 -              return;
 -      alt_odb_tail = &alt_odb_list;
 -      link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL);
 +      char path[PATH_MAX];
 +      int fd;
  
 -      sprintf(path, "%s/info/alternates", get_object_directory());
 +      sprintf(path, "%s/info/alternates", relative_base);
        fd = open(path, O_RDONLY);
        if (fd < 0)
                return;
        if (map == MAP_FAILED)
                return;
  
 -      link_alt_odb_entries(map, map + st.st_size, '\n',
 -                           get_object_directory());
 +      link_alt_odb_entries(map, map + st.st_size, '\n', relative_base, depth);
 +
        munmap(map, st.st_size);
  }
  
 +void prepare_alt_odb(void)
 +{
 +      char *alt;
 +
 +      alt = getenv(ALTERNATE_DB_ENVIRONMENT);
 +      if (!alt) alt = "";
 +
 +      if (alt_odb_tail)
 +              return;
 +      alt_odb_tail = &alt_odb_list;
 +      link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL, 0);
 +
 +      read_info_alternates(get_object_directory(), 0);
 +}
 +
  static char *find_sha1_file(const unsigned char *sha1, struct stat *st)
  {
        char *name = sha1_file_name(sha1);