X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=read-cache.c;h=525d138e90c524d08ef3d9755f1a2486c34adc39;hb=2454ac7b9fbc12db5cca8cd388422360528d7d6f;hp=d801f9d1cf9eca5ddeff2f0af4549bbc1e72423f;hpb=5324a6339acfabdb27c9ef410525eb6b82d05002;p=git.git diff --git a/read-cache.c b/read-cache.c index d801f9d1c..525d138e9 100644 --- a/read-cache.c +++ b/read-cache.c @@ -38,6 +38,22 @@ static void replace_index_entry(struct index_state *istate, int nr, struct cache istate->cache_changed = 1; } +void rename_index_entry_at(struct index_state *istate, int nr, const char *new_name) +{ + struct cache_entry *old = istate->cache[nr], *new; + int namelen = strlen(new_name); + + new = xmalloc(cache_entry_size(namelen)); + copy_cache_entry(new, old); + new->ce_flags &= ~(CE_STATE_MASK | CE_NAMEMASK); + new->ce_flags |= (namelen >= CE_NAMEMASK ? CE_NAMEMASK : namelen); + memcpy(new->name, new_name, namelen + 1); + + cache_tree_invalidate_path(istate->cache_tree, old->name); + remove_index_entry_at(istate, nr); + add_index_entry(istate, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); +} + /* * This only updates the "non-critical" parts of the directory * cache, ie the parts that aren't tracked by GIT, and only used @@ -131,7 +147,7 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st) break; case S_IFDIR: if (S_ISGITLINK(ce->ce_mode)) - return 0; + return ce_compare_gitlink(ce) ? DATA_CHANGED : 0; default: return TYPE_CHANGED; } @@ -171,6 +187,7 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) changed |= TYPE_CHANGED; break; case S_IFGITLINK: + /* We ignore most of the st_xxx fields for gitlinks */ if (!S_ISDIR(st->st_mode)) changed |= TYPE_CHANGED; else if (ce_compare_gitlink(ce)) @@ -181,7 +198,7 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) } if (ce->ce_mtime != (unsigned int) st->st_mtime) changed |= MTIME_CHANGED; - if (ce->ce_ctime != (unsigned int) st->st_ctime) + if (trust_ctime && ce->ce_ctime != (unsigned int) st->st_ctime) changed |= CTIME_CHANGED; if (ce->ce_uid != (unsigned int) st->st_uid || @@ -277,11 +294,22 @@ int ie_modified(const struct index_state *istate, if (changed & (MODE_CHANGED | TYPE_CHANGED)) return changed; - /* Immediately after read-tree or update-index --cacheinfo, - * the length field is zero. For other cases the ce_size - * should match the SHA1 recorded in the index entry. + /* + * Immediately after read-tree or update-index --cacheinfo, + * the length field is zero, as we have never even read the + * lstat(2) information once, and we cannot trust DATA_CHANGED + * returned by ie_match_stat() which in turn was returned by + * ce_match_stat_basic() to signal that the filesize of the + * blob changed. We have to actually go to the filesystem to + * see if the contents match, and if so, should answer "unchanged". + * + * The logic does not apply to gitlinks, as ce_match_stat_basic() + * already has checked the actual HEAD from the filesystem in the + * subproject. If ie_match_stat() already said it is different, + * then we know it is. */ - if ((changed & DATA_CHANGED) && ce->ce_size != 0) + if ((changed & DATA_CHANGED) && + (S_ISGITLINK(ce->ce_mode) || ce->ce_size != 0)) return changed; changed_fs = ce_modified_check_fs(ce, st); @@ -528,7 +556,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st, 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 */ + /* It was suspected to be racily clean, but it turns out to be Ok */ was_same = (alias && !ce_stage(alias) && !hashcmp(alias->sha1, ce->sha1) && @@ -980,7 +1008,10 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p 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; + const char *needs_update_message; + needs_update_message = ((flags & REFRESH_SAY_CHANGED) + ? "locally modified" : "needs update"); for (i = 0; i < istate->cache_nr; i++) { struct cache_entry *ce, *new; int cache_errno = 0; @@ -1019,7 +1050,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p } if (quiet) continue; - printf("%s: needs update\n", ce->name); + printf("%s: %s\n", ce->name, needs_update_message); has_errors = 1; continue; } @@ -1124,7 +1155,7 @@ int read_index_from(struct index_state *istate, const char *path) size_t mmap_size; errno = EBUSY; - if (istate->alloc) + if (istate->initialized) return istate->cache_nr; errno = ENOENT; @@ -1164,6 +1195,7 @@ int read_index_from(struct index_state *istate, const char *path) * index size */ istate->alloc = xmalloc(estimate_cache_size(mmap_size, istate->cache_nr)); + istate->initialized = 1; src_offset = sizeof(*hdr); dst_offset = 0; @@ -1207,15 +1239,22 @@ unmap: die("index file corrupt"); } +int is_index_unborn(struct index_state *istate) +{ + return (!istate->cache_nr && !istate->alloc && !istate->timestamp); +} + int discard_index(struct index_state *istate) { istate->cache_nr = 0; istate->cache_changed = 0; istate->timestamp = 0; + istate->name_hash_initialized = 0; free_hash(&istate->name_hash); cache_tree_free(&(istate->cache_tree)); free(istate->alloc); istate->alloc = NULL; + istate->initialized = 0; /* no need to throw away allocated active_cache */ return 0; @@ -1307,6 +1346,11 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce) * falsely clean entry due to touch-update-touch race, so we leave * everything else as they are. We are called for entries whose * ce_mtime match the index file mtime. + * + * Note that this actually does not do much for gitlinks, for + * which ce_match_stat_basic() always goes to the actual + * contents. The caller checks with is_racy_timestamp() which + * always says "no" for gitlinks, so we are not called for them ;-) */ struct stat st; @@ -1421,23 +1465,56 @@ int write_index(const struct index_state *istate, int newfd) int read_index_unmerged(struct index_state *istate) { int i; - struct cache_entry **dst; - struct cache_entry *last = NULL; + int unmerged = 0; read_index(istate); - dst = istate->cache; for (i = 0; i < istate->cache_nr; i++) { struct cache_entry *ce = istate->cache[i]; - if (ce_stage(ce)) { - remove_name_hash(ce); - if (last && !strcmp(ce->name, last->name)) - continue; - cache_tree_invalidate_path(istate->cache_tree, ce->name); - last = ce; + struct cache_entry *new_ce; + int size, len; + + if (!ce_stage(ce)) continue; - } - *dst++ = ce; + unmerged = 1; + len = strlen(ce->name); + size = cache_entry_size(len); + new_ce = xcalloc(1, size); + hashcpy(new_ce->sha1, ce->sha1); + memcpy(new_ce->name, ce->name, len); + new_ce->ce_flags = create_ce_flags(len, 0); + new_ce->ce_mode = ce->ce_mode; + if (add_index_entry(istate, new_ce, 0)) + return error("%s: cannot drop to stage #0", + ce->name); + i = index_name_pos(istate, new_ce->name, len); + } + return unmerged; +} + +/* + * Returns 1 if the path is an "other" path with respect to + * the index; that is, the path is not mentioned in the index at all, + * either as a file, a directory with some files in the index, + * or as an unmerged entry. + * + * We helpfully remove a trailing "/" from directories so that + * the output of read_directory can be used as-is. + */ +int index_name_is_other(const struct index_state *istate, const char *name, + int namelen) +{ + int pos; + if (namelen && name[namelen - 1] == '/') + namelen--; + pos = index_name_pos(istate, name, namelen); + if (0 <= pos) + return 0; /* exact match */ + pos = -pos - 1; + if (pos < istate->cache_nr) { + struct cache_entry *ce = istate->cache[pos]; + if (ce_namelen(ce) == namelen && + !memcmp(ce->name, name, namelen)) + return 0; /* Yup, this one exists unmerged */ } - istate->cache_nr = dst - istate->cache; - return !!last; + return 1; }