X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=read-cache.c;h=8f96fd17226e26c4b8a1497aace5b9fffb664bbe;hb=72130808173d3dfee85f2a29548fa9fec33a5351;hp=6fa3c21148979791f18bc0b5c3ed76952acad9ff;hpb=f49c2c22fef520fd69ff26869c26dc58a834de2c;p=git.git diff --git a/read-cache.c b/read-cache.c index 6fa3c2114..8f96fd172 100644 --- a/read-cache.c +++ b/read-cache.c @@ -23,78 +23,35 @@ 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) +void rename_index_entry_at(struct index_state *istate, int nr, const char *new_name) { - 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; + 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); } /* @@ -190,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; } @@ -230,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)) @@ -240,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 || @@ -273,7 +231,8 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) 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); } @@ -335,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); @@ -454,7 +424,7 @@ int remove_index_entry_at(struct index_state *istate, int pos) { 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) @@ -504,21 +474,52 @@ static int index_name_pos_also_unmerged(struct index_state *istate, 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; +} + +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.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); + 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--; } @@ -526,10 +527,10 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose) 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. @@ -538,28 +539,46 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose) 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 racily 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) @@ -918,6 +937,15 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate, 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; @@ -978,13 +1006,20 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p 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; + 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; 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)) @@ -1015,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; } @@ -1120,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; @@ -1160,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; @@ -1208,10 +1244,12 @@ 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; @@ -1303,6 +1341,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; @@ -1386,7 +1429,7 @@ int write_index(const struct index_state *istate, int newfd) 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; @@ -1406,3 +1449,34 @@ int write_index(const struct index_state *istate, int newfd) } return ce_flush(&c, newfd); } + +/* + * Read the index file that is potentially unmerged into given + * index_state, dropping any unmerged entries. Returns true is + * the index is unmerged. Callers who want to refuse to work + * from an unmerged state can call this and check its return value, + * instead of calling read_cache(). + */ +int read_index_unmerged(struct index_state *istate) +{ + int i; + struct cache_entry **dst; + struct cache_entry *last = NULL; + + 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; + continue; + } + *dst++ = ce; + } + istate->cache_nr = dst - istate->cache; + return !!last; +}