Merge branch 'lt/dirwalk' into next
authorJunio C Hamano <junkio@cox.net>
Fri, 19 May 2006 03:16:03 +0000 (20:16 -0700)
committerJunio C Hamano <junkio@cox.net>
Fri, 19 May 2006 03:16:03 +0000 (20:16 -0700)
* lt/dirwalk:
Prevent bogus paths from being added to the index.

1  2 
cache.h
read-cache.c
update-index.c
diff --combined cache.h
index b1300cd989437e4631d6e4a58b1c32941b5c3b6b,89aa4f6c7ea9c15b4a6d43a91479ff22e5ebacf5..f9b704916d1e5420a9c65ac3a3bcfb9cbb62e134
+++ b/cache.h
@@@ -114,7 -114,6 +114,7 @@@ static inline unsigned int create_ce_mo
  
  extern struct cache_entry **active_cache;
  extern unsigned int active_nr, active_alloc, active_cache_changed;
 +extern struct cache_tree *active_cache_tree;
  
  #define GIT_DIR_ENVIRONMENT "GIT_DIR"
  #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
@@@ -143,6 -142,7 +143,7 @@@ extern void verify_non_filename(const c
  /* Initialize and use the cache information */
  extern int read_cache(void);
  extern int write_cache(int newfd, struct cache_entry **cache, int entries);
+ extern int verify_path(const char *path);
  extern int cache_name_pos(const char *name, int namelen);
  #define ADD_CACHE_OK_TO_ADD 1         /* Ok to add */
  #define ADD_CACHE_OK_TO_REPLACE 2     /* Ok to replace file/directory */
@@@ -252,7 -252,6 +253,7 @@@ extern void *read_object_with_reference
                                        unsigned char *sha1_ret);
  
  const char *show_date(unsigned long time, int timezone);
 +const char *show_rfc2822_date(unsigned long time, int timezone);
  int parse_date(const char *date, char *buf, int bufsize);
  void datestamp(char *buf, int bufsize);
  unsigned long approxidate(const char *);
diff --combined read-cache.c
index ed0da38e07cdb3d0a05a12bdebf10d833e53bd08,e8fa6d081285b3e8bdd3ee1912db113d2bc874cc..9a272f89fcbbe1ff5c160b0b522dee6ed33f6e09
@@@ -4,26 -4,11 +4,26 @@@
   * Copyright (C) Linus Torvalds, 2005
   */
  #include "cache.h"
 +#include "cache-tree.h"
 +
 +/* Index extensions.
 + *
 + * The first letter should be 'A'..'Z' for extensions that are not
 + * necessary for a correct operation (i.e. optimization data).
 + * When new extensions are added that _needs_ to be understood in
 + * order to correctly interpret the index file, pick character that
 + * is outside the range, to cause the reader to abort.
 + */
 +
 +#define CACHE_EXT(s) ( (s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]) )
 +#define CACHE_EXT_TREE 0x54524545     /* "TREE" */
  
  struct cache_entry **active_cache = NULL;
  static time_t index_file_timestamp;
  unsigned int active_nr = 0, active_alloc = 0, active_cache_changed = 0;
  
 +struct cache_tree *active_cache_tree = NULL;
 +
  /*
   * This only updates the "non-critical" parts of the directory
   * cache, ie the parts that aren't tracked by GIT, and only used
@@@ -346,6 -331,70 +346,70 @@@ int ce_path_match(const struct cache_en
        return 0;
  }
  
+ /*
+  * We fundamentally don't like some paths: we don't want
+  * dot or dot-dot anywhere, and for obvious reasons don't
+  * want to recurse into ".git" either.
+  *
+  * Also, we don't want double slashes or slashes at the
+  * end that can make pathnames ambiguous.
+  */
+ static int verify_dotfile(const char *rest)
+ {
+       /*
+        * The first character was '.', but that
+        * has already been discarded, we now test
+        * the rest.
+        */
+       switch (*rest) {
+       /* "." is not allowed */
+       case '\0': case '/':
+               return 0;
+       /*
+        * ".git" followed by  NUL or slash is bad. This
+        * shares the path end test with the ".." case.
+        */
+       case 'g':
+               if (rest[1] != 'i')
+                       break;
+               if (rest[2] != 't')
+                       break;
+               rest += 2;
+       /* fallthrough */
+       case '.':
+               if (rest[1] == '\0' || rest[1] == '/')
+                       return 0;
+       }
+       return 1;
+ }
+ int verify_path(const char *path)
+ {
+       char c;
+       goto inside;
+       for (;;) {
+               if (!c)
+                       return 1;
+               if (c == '/') {
+ inside:
+                       c = *path++;
+                       switch (c) {
+                       default:
+                               continue;
+                       case '/': case '\0':
+                               break;
+                       case '.':
+                               if (verify_dotfile(path))
+                                       continue;
+                       }
+                       return 0;
+               }
+               c = *path++;
+       }
+ }
  /*
   * Do we have another file that has the beginning components being a
   * proper superset of the name we're trying to add?
@@@ -487,6 -536,8 +551,8 @@@ int add_cache_entry(struct cache_entry 
  
        if (!ok_to_add)
                return -1;
+       if (!verify_path(ce->name))
+               return -1;
  
        if (!skip_df_check &&
            check_file_directory_conflict(ce, pos, ok_to_replace)) {
@@@ -528,22 -579,6 +594,22 @@@ static int verify_hdr(struct cache_head
        return 0;
  }
  
 +static int read_index_extension(const char *ext, void *data, unsigned long sz)
 +{
 +      switch (CACHE_EXT(ext)) {
 +      case CACHE_EXT_TREE:
 +              active_cache_tree = cache_tree_read(data, sz);
 +              break;
 +      default:
 +              if (*ext < 'A' || 'Z' < *ext)
 +                      return error("index uses %.4s extension, which we do not understand",
 +                                   ext);
 +              fprintf(stderr, "ignoring %.4s extension\n", ext);
 +              break;
 +      }
 +      return 0;
 +}
 +
  int read_cache(void)
  {
        int fd, i;
                active_cache[i] = ce;
        }
        index_file_timestamp = st.st_mtime;
 +      while (offset <= size - 20 - 8) {
 +              /* After an array of active_nr index entries,
 +               * there can be arbitrary number of extended
 +               * sections, each of which is prefixed with
 +               * extension name (4-byte) and section length
 +               * in 4-byte network byte order.
 +               */
 +              unsigned long extsize;
 +              memcpy(&extsize, map + offset + 4, 4);
 +              extsize = ntohl(extsize);
 +              if (read_index_extension(map + offset,
 +                                       map + offset + 8, extsize) < 0)
 +                      goto unmap;
 +              offset += 8;
 +              offset += extsize;
 +      }
        return active_nr;
  
  unmap:
@@@ -642,17 -661,6 +708,17 @@@ static int ce_write(SHA_CTX *context, i
        return 0;
  }
  
 +static int write_index_ext_header(SHA_CTX *context, int fd,
 +                                unsigned long ext, unsigned long sz)
 +{
 +      ext = htonl(ext);
 +      sz = htonl(sz);
 +      if ((ce_write(context, fd, &ext, 4) < 0) ||
 +          (ce_write(context, fd, &sz, 4) < 0))
 +              return -1;
 +      return 0;
 +}
 +
  static int ce_flush(SHA_CTX *context, int fd)
  {
        unsigned int left = write_buffer_len;
@@@ -749,19 -757,5 +815,19 @@@ int write_cache(int newfd, struct cache
                if (ce_write(&c, newfd, ce, ce_size(ce)) < 0)
                        return -1;
        }
 +
 +      /* Write extension data here */
 +      if (active_cache_tree) {
 +              unsigned long sz;
 +              void *data = cache_tree_write(active_cache_tree, &sz);
 +              if (data &&
 +                  !write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sz) &&
 +                  !ce_write(&c, newfd, data, sz))
 +                      ;
 +              else {
 +                      free(data);
 +                      return -1;
 +              }
 +      }
        return ce_flush(&c, newfd);
  }
diff --combined update-index.c
index f6b09a4800b01f3c1675e87a91ea458e7172f169,859efc79164cb86f5bdd65ba72ba087ccb8f0ae9..21448cc5cc3bfc13f2b21675e89f901d0d7067be
@@@ -6,7 -6,6 +6,7 @@@
  #include "cache.h"
  #include "strbuf.h"
  #include "quote.h"
 +#include "cache-tree.h"
  #include "tree-walk.h"
  
  /*
@@@ -72,7 -71,6 +72,7 @@@ static int mark_valid(const char *path
                        active_cache[pos]->ce_flags &= ~htons(CE_VALID);
                        break;
                }
 +              cache_tree_invalidate_path(active_cache_tree, path);
                active_cache_changed = 1;
                return 0;
        }
@@@ -86,12 -84,6 +86,12 @@@ static int add_file_to_cache(const cha
        struct stat st;
  
        status = lstat(path, &st);
 +
 +      /* We probably want to do this in remove_file_from_cache() and
 +       * add_cache_entry() instead...
 +       */
 +      cache_tree_invalidate_path(active_cache_tree, path);
 +
        if (status < 0 || S_ISDIR(st.st_mode)) {
                /* When we used to have "path" and now we want to add
                 * "path/file", we need a way to remove "path" before
@@@ -243,70 -235,6 +243,6 @@@ static int refresh_cache(int really
                active_cache[i] = new;
        }
        return has_errors;
- }
- /*
-  * We fundamentally don't like some paths: we don't want
-  * dot or dot-dot anywhere, and for obvious reasons don't
-  * want to recurse into ".git" either.
-  *
-  * Also, we don't want double slashes or slashes at the
-  * end that can make pathnames ambiguous.
-  */
- static int verify_dotfile(const char *rest)
- {
-       /*
-        * The first character was '.', but that
-        * has already been discarded, we now test
-        * the rest.
-        */
-       switch (*rest) {
-       /* "." is not allowed */
-       case '\0': case '/':
-               return 0;
-       /*
-        * ".git" followed by  NUL or slash is bad. This
-        * shares the path end test with the ".." case.
-        */
-       case 'g':
-               if (rest[1] != 'i')
-                       break;
-               if (rest[2] != 't')
-                       break;
-               rest += 2;
-       /* fallthrough */
-       case '.':
-               if (rest[1] == '\0' || rest[1] == '/')
-                       return 0;
-       }
-       return 1;
- }
- static int verify_path(const char *path)
- {
-       char c;
-       goto inside;
-       for (;;) {
-               if (!c)
-                       return 1;
-               if (c == '/') {
- inside:
-                       c = *path++;
-                       switch (c) {
-                       default:
-                               continue;
-                       case '/': case '\0':
-                               break;
-                       case '.':
-                               if (verify_dotfile(path))
-                                       continue;
-                       }
-                       return 0;
-               }
-               c = *path++;
-       }
  }
  
  static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
                return error("%s: cannot add to the index - missing --add option?",
                             path);
        report("add '%s'", path);
 +      cache_tree_invalidate_path(active_cache_tree, path);
        return 0;
  }
  
@@@ -359,7 -286,6 +295,7 @@@ static void chmod_path(int flip, const 
        default:
                goto fail;
        }
 +      cache_tree_invalidate_path(active_cache_tree, path);
        active_cache_changed = 1;
        report("chmod %cx '%s'", flip, path);
        return;
@@@ -381,7 -307,6 +317,7 @@@ static void update_one(const char *path
                        die("Unable to mark file %s", path);
                goto free_return;
        }
 +      cache_tree_invalidate_path(active_cache_tree, path);
  
        if (force_remove) {
                if (remove_file_from_cache(p))
@@@ -460,7 -385,6 +396,7 @@@ static void read_index_info(int line_te
                                free(path_name);
                        continue;
                }
 +              cache_tree_invalidate_path(active_cache_tree, path_name);
  
                if (!mode) {
                        /* mode == 0 means there is no such path -- remove */
@@@ -567,7 -491,6 +503,7 @@@ static int unresolve_one(const char *pa
                goto free_return;
        }
  
 +      cache_tree_invalidate_path(active_cache_tree, path);
        remove_file_from_cache(path);
        if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) {
                error("%s: cannot add our version to the index.", path);