Code

Merge branch 'lt/racy-empty'
authorJunio C Hamano <gitster@pobox.com>
Sun, 22 Jun 2008 21:34:20 +0000 (14:34 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 22 Jun 2008 21:34:20 +0000 (14:34 -0700)
* lt/racy-empty:
  racy-git: an empty blob has a fixed object name

1  2 
read-cache.c

diff --combined read-cache.c
index 8e5fbb619295fe3e4d950e8926d8034d6f825e41,6fa3c21148979791f18bc0b5c3ed76952acad9ff..f83de8c4158e08bab3e0445c4d15caf2d4d105aa
  
  struct index_state the_index;
  
 -static unsigned int hash_name(const char *name, int namelen)
 -{
 -      unsigned int hash = 0x123;
 -
 -      do {
 -              unsigned char c = *name++;
 -              hash = hash*101 + c;
 -      } while (--namelen);
 -      return hash;
 -}
 -
 -static void hash_index_entry(struct index_state *istate, struct cache_entry *ce)
 -{
 -      void **pos;
 -      unsigned int hash;
 -
 -      if (ce->ce_flags & CE_HASHED)
 -              return;
 -      ce->ce_flags |= CE_HASHED;
 -      ce->next = NULL;
 -      hash = hash_name(ce->name, ce_namelen(ce));
 -      pos = insert_hash(hash, ce, &istate->name_hash);
 -      if (pos) {
 -              ce->next = *pos;
 -              *pos = ce;
 -      }
 -}
 -
 -static void lazy_init_name_hash(struct index_state *istate)
 -{
 -      int nr;
 -
 -      if (istate->name_hash_initialized)
 -              return;
 -      for (nr = 0; nr < istate->cache_nr; nr++)
 -              hash_index_entry(istate, istate->cache[nr]);
 -      istate->name_hash_initialized = 1;
 -}
 -
  static void set_index_entry(struct index_state *istate, int nr, struct cache_entry *ce)
  {
 -      ce->ce_flags &= ~CE_UNHASHED;
        istate->cache[nr] = ce;
 -      if (istate->name_hash_initialized)
 -              hash_index_entry(istate, ce);
 +      add_name_hash(istate, ce);
  }
  
  static void replace_index_entry(struct index_state *istate, int nr, struct cache_entry *ce)
  {
        struct cache_entry *old = istate->cache[nr];
  
 -      remove_index_entry(old);
 +      remove_name_hash(old);
        set_index_entry(istate, nr, ce);
        istate->cache_changed = 1;
  }
  
 -int index_name_exists(struct index_state *istate, const char *name, int namelen)
 -{
 -      unsigned int hash = hash_name(name, namelen);
 -      struct cache_entry *ce;
 -
 -      lazy_init_name_hash(istate);
 -      ce = lookup_hash(hash, &istate->name_hash);
 -
 -      while (ce) {
 -              if (!(ce->ce_flags & CE_UNHASHED)) {
 -                      if (!cache_name_compare(name, namelen, ce->name, ce->ce_flags))
 -                              return 1;
 -              }
 -              ce = ce->next;
 -      }
 -      return 0;
 -}
 -
  /*
   * This only updates the "non-critical" parts of the directory
   * cache, ie the parts that aren't tracked by GIT, and only used
@@@ -138,6 -197,16 +138,16 @@@ static int ce_modified_check_fs(struct 
        return 0;
  }
  
+ static int is_empty_blob_sha1(const unsigned char *sha1)
+ {
+       static const unsigned char empty_blob_sha1[20] = {
+               0xe6,0x9d,0xe2,0x9b,0xb2,0xd1,0xd6,0x43,0x4b,0x8b,
+               0x29,0xae,0x77,0x5a,0xd8,0xc2,0xe4,0x8c,0x53,0x91
+       };
+       return !hashcmp(sha1, empty_blob_sha1);
+ }
  static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
  {
        unsigned int changed = 0;
        if (ce->ce_size != (unsigned int) st->st_size)
                changed |= DATA_CHANGED;
  
+       /* Racily smudged entry? */
+       if (!ce->ce_size) {
+               if (!is_empty_blob_sha1(ce->sha1))
+                       changed |= DATA_CHANGED;
+       }
        return changed;
  }
  
  static int is_racy_timestamp(const struct index_state *istate, struct cache_entry *ce)
  {
 -      return (istate->timestamp &&
 +      return (!S_ISGITLINK(ce->ce_mode) &&
 +              istate->timestamp &&
                ((unsigned int)istate->timestamp) <= ce->ce_mtime);
  }
  
@@@ -380,7 -454,7 +396,7 @@@ int remove_index_entry_at(struct index_
  {
        struct cache_entry *ce = istate->cache[pos];
  
 -      remove_index_entry(ce);
 +      remove_name_hash(ce);
        istate->cache_changed = 1;
        istate->cache_nr--;
        if (pos >= istate->cache_nr)
@@@ -430,52 -504,21 +446,52 @@@ static int index_name_pos_also_unmerged
        return pos;
  }
  
 -int add_file_to_index(struct index_state *istate, const char *path, int verbose)
 +static int different_name(struct cache_entry *ce, struct cache_entry *alias)
  {
 -      int size, namelen, pos;
 -      struct stat st;
 -      struct cache_entry *ce;
 -      unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
 +      int len = ce_namelen(ce);
 +      return ce_namelen(alias) != len || memcmp(ce->name, alias->name, len);
 +}
  
 -      if (lstat(path, &st))
 -              die("%s: unable to stat (%s)", path, strerror(errno));
 +/*
 + * If we add a filename that aliases in the cache, we will use the
 + * name that we already have - but we don't want to update the same
 + * alias twice, because that implies that there were actually two
 + * different files with aliasing names!
 + *
 + * So we use the CE_ADDED flag to verify that the alias was an old
 + * one before we accept it as
 + */
 +static struct cache_entry *create_alias_ce(struct cache_entry *ce, struct cache_entry *alias)
 +{
 +      int len;
 +      struct cache_entry *new;
 +
 +      if (alias->ce_flags & CE_ADDED)
 +              die("Will not add file alias '%s' ('%s' already exists in index)", ce->name, alias->name);
 +
 +      /* Ok, create the new entry using the name of the existing alias */
 +      len = ce_namelen(alias);
 +      new = xcalloc(1, cache_entry_size(len));
 +      memcpy(new->name, alias->name, len);
 +      copy_cache_entry(new, ce);
 +      free(ce);
 +      return new;
 +}
  
 -      if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode))
 -              die("%s: can only add regular files, symbolic links or git-directories", path);
 +int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags)
 +{
 +      int size, namelen, was_same;
 +      mode_t st_mode = st->st_mode;
 +      struct cache_entry *ce, *alias;
 +      unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
 +      int verbose = flags & (ADD_CACHE_VERBOSE | ADD_CACHE_PRETEND);
 +      int pretend = flags & ADD_CACHE_PRETEND;
 +
 +      if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode))
 +              return error("%s: can only add regular files, symbolic links or git-directories", path);
  
        namelen = strlen(path);
 -      if (S_ISDIR(st.st_mode)) {
 +      if (S_ISDIR(st_mode)) {
                while (namelen && path[namelen-1] == '/')
                        namelen--;
        }
        ce = xcalloc(1, size);
        memcpy(ce->name, path, namelen);
        ce->ce_flags = namelen;
 -      fill_stat_cache_info(ce, &st);
 +      fill_stat_cache_info(ce, st);
  
        if (trust_executable_bit && has_symlinks)
 -              ce->ce_mode = create_ce_mode(st.st_mode);
 +              ce->ce_mode = create_ce_mode(st_mode);
        else {
                /* If there is an existing entry, pick the mode bits and type
                 * from it, otherwise assume unexecutable regular file.
                int pos = index_name_pos_also_unmerged(istate, path, namelen);
  
                ent = (0 <= pos) ? istate->cache[pos] : NULL;
 -              ce->ce_mode = ce_mode_from_stat(ent, st.st_mode);
 +              ce->ce_mode = ce_mode_from_stat(ent, st_mode);
        }
  
 -      pos = index_name_pos(istate, ce->name, namelen);
 -      if (0 <= pos &&
 -          !ce_stage(istate->cache[pos]) &&
 -          !ie_match_stat(istate, istate->cache[pos], &st, ce_option)) {
 +      alias = index_name_exists(istate, ce->name, ce_namelen(ce), ignore_case);
 +      if (alias && !ce_stage(alias) && !ie_match_stat(istate, alias, st, ce_option)) {
                /* Nothing changed, really */
                free(ce);
 -              ce_mark_uptodate(istate->cache[pos]);
 +              ce_mark_uptodate(alias);
 +              alias->ce_flags |= CE_ADDED;
                return 0;
        }
 -
 -      if (index_path(ce->sha1, path, &st, 1))
 -              die("unable to index file %s", path);
 -      if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
 -              die("unable to add %s to index",path);
 -      if (verbose)
 +      if (index_path(ce->sha1, path, st, 1))
 +              return error("unable to index file %s", path);
 +      if (ignore_case && alias && different_name(ce, alias))
 +              ce = create_alias_ce(ce, alias);
 +      ce->ce_flags |= CE_ADDED;
 +
 +      /* It was suspected to be recily clean, but it turns out to be Ok */
 +      was_same = (alias &&
 +                  !ce_stage(alias) &&
 +                  !hashcmp(alias->sha1, ce->sha1) &&
 +                  ce->ce_mode == alias->ce_mode);
 +
 +      if (pretend)
 +              ;
 +      else if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
 +              return error("unable to add %s to index",path);
 +      if (verbose && !was_same)
                printf("add '%s'\n", path);
        return 0;
  }
  
 +int add_file_to_index(struct index_state *istate, const char *path, int flags)
 +{
 +      struct stat st;
 +      if (lstat(path, &st))
 +              die("%s: unable to stat (%s)", path, strerror(errno));
 +      return add_to_index(istate, path, &st, flags);
 +}
 +
  struct cache_entry *make_cache_entry(unsigned int mode,
                const unsigned char *sha1, const char *path, int stage,
                int refresh)
@@@ -893,15 -918,6 +909,15 @@@ static struct cache_entry *refresh_cach
        if (ce_uptodate(ce))
                return ce;
  
 +      /*
 +       * CE_VALID means the user promised us that the change to
 +       * the work tree does not matter and told us not to worry.
 +       */
 +      if (!ignore_valid && (ce->ce_flags & CE_VALID)) {
 +              ce_mark_uptodate(ce);
 +              return ce;
 +      }
 +
        if (lstat(ce->name, &st) < 0) {
                if (err)
                        *err = errno;
@@@ -962,7 -978,6 +978,7 @@@ int refresh_index(struct index_state *i
        int allow_unmerged = (flags & REFRESH_UNMERGED) != 0;
        int quiet = (flags & REFRESH_QUIET) != 0;
        int not_new = (flags & REFRESH_IGNORE_MISSING) != 0;
 +      int ignore_submodules = (flags & REFRESH_IGNORE_SUBMODULES) != 0;
        unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;
  
        for (i = 0; i < istate->cache_nr; i++) {
                int cache_errno = 0;
  
                ce = istate->cache[i];
 +              if (ignore_submodules && S_ISGITLINK(ce->ce_mode))
 +                      continue;
 +
                if (ce_stage(ce)) {
                        while ((i < istate->cache_nr) &&
                               ! strcmp(istate->cache[i]->name, ce->name))
@@@ -1374,7 -1386,7 +1390,7 @@@ int write_index(const struct index_stat
                struct cache_entry *ce = cache[i];
                if (ce->ce_flags & CE_REMOVE)
                        continue;
 -              if (is_racy_timestamp(istate, ce))
 +              if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce))
                        ce_smudge_racily_clean_entry(ce);
                if (ce_write_entry(&c, newfd, ce) < 0)
                        return -1;