]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'nd/hash-object-sanity'
authorJunio C Hamano <gitster@pobox.com>
Mon, 28 Feb 2011 05:58:30 +0000 (21:58 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 28 Feb 2011 05:58:30 +0000 (21:58 -0800)
* nd/hash-object-sanity:
  Make hash-object more robust against malformed objects

Conflicts:
cache.h

1  2 
cache.h
read-cache.c
sha1_file.c

diff --combined cache.h
index 677994a23a71d17ccaff7c5e461e96ec501742b8,9186a56be7309261289222dc8e9726439e550233..5cc2f896dc10cfb8b432fb4b3ee97b0134f73c11
+++ b/cache.h
@@@ -500,23 -500,8 +500,23 @@@ extern int index_name_is_other(const st
  extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
  extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
  
 -extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
 +struct pathspec {
 +      const char **raw; /* get_pathspec() result, not freed by free_pathspec() */
 +      int nr;
 +      int has_wildcard:1;
 +      int recursive:1;
 +      int max_depth;
 +      struct pathspec_item {
 +              const char *match;
 +              int len;
 +              int has_wildcard:1;
 +      } *items;
 +};
 +
 +extern int init_pathspec(struct pathspec *, const char **);
 +extern void free_pathspec(struct pathspec *);
 +extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
- extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
+ extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path, int format_check);
  extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
  extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
  
  #define REFRESH_IGNORE_MISSING        0x0008  /* ignore non-existent */
  #define REFRESH_IGNORE_SUBMODULES     0x0010  /* ignore submodules */
  #define REFRESH_IN_PORCELAIN  0x0020  /* user friendly output, not "needs update" */
 -extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, char *header_msg);
 +extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, const char *header_msg);
  
  struct lock_file {
        struct lock_file *next;
@@@ -691,11 -676,9 +691,11 @@@ static inline void hashclr(unsigned cha
  
  #define EMPTY_TREE_SHA1_HEX \
        "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
 -#define EMPTY_TREE_SHA1_BIN \
 +#define EMPTY_TREE_SHA1_BIN_LITERAL \
         "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
         "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
 +#define EMPTY_TREE_SHA1_BIN \
 +       ((const unsigned char *) EMPTY_TREE_SHA1_BIN_LITERAL)
  
  int git_mkstemp(char *path, size_t n, const char *template);
  
diff --combined read-cache.c
index b97b5668ebc486561686d3e80b536e115dede513,fbc12f3c3e8aac2c0d15d57b023315ce4d5156f6..98d526bd48d2a0e764dd0efb4c6efe4965174c9a
@@@ -92,7 -92,7 +92,7 @@@ static int ce_compare_data(struct cache
  
        if (fd >= 0) {
                unsigned char sha1[20];
-               if (!index_fd(sha1, fd, st, 0, OBJ_BLOB, ce->name))
+               if (!index_fd(sha1, fd, st, 0, OBJ_BLOB, ce->name, 0))
                        match = hashcmp(sha1, ce->sha1);
                /* index_fd() closed the file descriptor already */
        }
@@@ -706,9 -706,30 +706,9 @@@ int ce_same_name(struct cache_entry *a
        return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
  }
  
 -int ce_path_match(const struct cache_entry *ce, const char **pathspec)
 +int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec)
  {
 -      const char *match, *name;
 -      int len;
 -
 -      if (!pathspec)
 -              return 1;
 -
 -      len = ce_namelen(ce);
 -      name = ce->name;
 -      while ((match = *pathspec++) != NULL) {
 -              int matchlen = strlen(match);
 -              if (matchlen > len)
 -                      continue;
 -              if (memcmp(name, match, matchlen))
 -                      continue;
 -              if (matchlen && name[matchlen-1] == '/')
 -                      return 1;
 -              if (name[matchlen] == '/' || !name[matchlen])
 -                      return 1;
 -              if (!matchlen)
 -                      return 1;
 -      }
 -      return 0;
 +      return match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL);
  }
  
  /*
@@@ -1083,7 -1104,7 +1083,7 @@@ static struct cache_entry *refresh_cach
  }
  
  static void show_file(const char * fmt, const char * name, int in_porcelain,
 -                    int * first, char *header_msg)
 +                    int * first, const char *header_msg)
  {
        if (in_porcelain && *first && header_msg) {
                printf("%s\n", header_msg);
  }
  
  int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec,
 -                char *seen, char *header_msg)
 +                char *seen, const char *header_msg)
  {
        int i;
        int has_errors = 0;
diff --combined sha1_file.c
index 27730c334cb433ef749a0efc5353a7f38032559c,58ca85835b6d5d8d45c195139c594711dcac2228..d949b35c3308ae5c06774da7f4fecdc84778d5eb
@@@ -13,6 -13,7 +13,7 @@@
  #include "commit.h"
  #include "tag.h"
  #include "tree.h"
+ #include "tree-walk.h"
  #include "refs.h"
  #include "pack-revindex.h"
  #include "sha1-lookup.h"
@@@ -37,41 -38,6 +38,41 @@@ const unsigned char null_sha1[20]
  
  static int git_open_noatime(const char *name, struct packed_git *p);
  
 +/*
 + * This is meant to hold a *small* number of objects that you would
 + * want read_sha1_file() to be able to return, but yet you do not want
 + * to write them into the object store (e.g. a browse-only
 + * application).
 + */
 +static struct cached_object {
 +      unsigned char sha1[20];
 +      enum object_type type;
 +      void *buf;
 +      unsigned long size;
 +} *cached_objects;
 +static int cached_object_nr, cached_object_alloc;
 +
 +static struct cached_object empty_tree = {
 +      EMPTY_TREE_SHA1_BIN_LITERAL,
 +      OBJ_TREE,
 +      "",
 +      0
 +};
 +
 +static struct cached_object *find_cached_object(const unsigned char *sha1)
 +{
 +      int i;
 +      struct cached_object *co = cached_objects;
 +
 +      for (i = 0; i < cached_object_nr; i++, co++) {
 +              if (!hashcmp(co->sha1, sha1))
 +                      return co;
 +      }
 +      if (!hashcmp(sha1, empty_tree.sha1))
 +              return &empty_tree;
 +      return NULL;
 +}
 +
  int safe_create_leading_directories(char *path)
  {
        char *pos = path + offset_1st_component(path);
@@@ -2020,17 -1986,9 +2021,17 @@@ static int sha1_loose_object_info(cons
  
  int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
  {
 +      struct cached_object *co;
        struct pack_entry e;
        int status;
  
 +      co = find_cached_object(sha1);
 +      if (co) {
 +              if (sizep)
 +                      *sizep = co->size;
 +              return co->type;
 +      }
 +
        if (!find_pack_entry(sha1, &e)) {
                /* Most likely it's a loose object. */
                status = sha1_loose_object_info(sha1, sizep);
@@@ -2076,6 -2034,41 +2077,6 @@@ static void *read_packed_sha1(const uns
        return data;
  }
  
 -/*
 - * This is meant to hold a *small* number of objects that you would
 - * want read_sha1_file() to be able to return, but yet you do not want
 - * to write them into the object store (e.g. a browse-only
 - * application).
 - */
 -static struct cached_object {
 -      unsigned char sha1[20];
 -      enum object_type type;
 -      void *buf;
 -      unsigned long size;
 -} *cached_objects;
 -static int cached_object_nr, cached_object_alloc;
 -
 -static struct cached_object empty_tree = {
 -      EMPTY_TREE_SHA1_BIN,
 -      OBJ_TREE,
 -      "",
 -      0
 -};
 -
 -static struct cached_object *find_cached_object(const unsigned char *sha1)
 -{
 -      int i;
 -      struct cached_object *co = cached_objects;
 -
 -      for (i = 0; i < cached_object_nr; i++, co++) {
 -              if (!hashcmp(co->sha1, sha1))
 -                      return co;
 -      }
 -      if (!hashcmp(sha1, empty_tree.sha1))
 -              return &empty_tree;
 -      return NULL;
 -}
 -
  int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
                      unsigned char *sha1)
  {
@@@ -2479,8 -2472,37 +2480,37 @@@ int has_sha1_file(const unsigned char *
        return has_loose_object(sha1);
  }
  
+ static void check_tree(const void *buf, size_t size)
+ {
+       struct tree_desc desc;
+       struct name_entry entry;
+       init_tree_desc(&desc, buf, size);
+       while (tree_entry(&desc, &entry))
+               /* do nothing
+                * tree_entry() will die() on malformed entries */
+               ;
+ }
+ static void check_commit(const void *buf, size_t size)
+ {
+       struct commit c;
+       memset(&c, 0, sizeof(c));
+       if (parse_commit_buffer(&c, buf, size))
+               die("corrupt commit");
+ }
+ static void check_tag(const void *buf, size_t size)
+ {
+       struct tag t;
+       memset(&t, 0, sizeof(t));
+       if (parse_tag_buffer(&t, buf, size))
+               die("corrupt tag");
+ }
  static int index_mem(unsigned char *sha1, void *buf, size_t size,
-                    int write_object, enum object_type type, const char *path)
+                    int write_object, enum object_type type,
+                    const char *path, int format_check)
  {
        int ret, re_allocated = 0;
  
                        re_allocated = 1;
                }
        }
+       if (format_check) {
+               if (type == OBJ_TREE)
+                       check_tree(buf, size);
+               if (type == OBJ_COMMIT)
+                       check_commit(buf, size);
+               if (type == OBJ_TAG)
+                       check_tag(buf, size);
+       }
  
        if (write_object)
                ret = write_sha1_file(buf, size, typename(type), sha1);
  #define SMALL_FILE_SIZE (32*1024)
  
  int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
-            enum object_type type, const char *path)
+            enum object_type type, const char *path, int format_check)
  {
        int ret;
        size_t size = xsize_t(st->st_size);
                struct strbuf sbuf = STRBUF_INIT;
                if (strbuf_read(&sbuf, fd, 4096) >= 0)
                        ret = index_mem(sha1, sbuf.buf, sbuf.len, write_object,
-                                       type, path);
+                                       type, path, format_check);
                else
                        ret = -1;
                strbuf_release(&sbuf);
        } else if (!size) {
-               ret = index_mem(sha1, NULL, size, write_object, type, path);
+               ret = index_mem(sha1, NULL, size, write_object, type, path,
+                               format_check);
        } else if (size <= SMALL_FILE_SIZE) {
                char *buf = xmalloc(size);
                if (size == read_in_full(fd, buf, size))
                        ret = index_mem(sha1, buf, size, write_object, type,
-                                       path);
+                                       path, format_check);
                else
                        ret = error("short read %s", strerror(errno));
                free(buf);
        } else {
                void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
-               ret = index_mem(sha1, buf, size, write_object, type, path);
+               ret = index_mem(sha1, buf, size, write_object, type, path,
+                               format_check);
                munmap(buf, size);
        }
        close(fd);
@@@ -2554,7 -2586,7 +2594,7 @@@ int index_path(unsigned char *sha1, con
                if (fd < 0)
                        return error("open(\"%s\"): %s", path,
                                     strerror(errno));
-               if (index_fd(sha1, fd, st, write_object, OBJ_BLOB, path) < 0)
+               if (index_fd(sha1, fd, st, write_object, OBJ_BLOB, path, 0) < 0)
                        return error("%s: failed to insert into database",
                                     path);
                break;