diff options
Diffstat (limited to 'read-cache.c')
-rw-r--r-- | read-cache.c | 257 |
1 files changed, 157 insertions, 100 deletions
diff --git a/read-cache.c b/read-cache.c index d97e3bf7cd..33dd676ccb 100644 --- a/read-cache.c +++ b/read-cache.c @@ -67,6 +67,61 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n add_index_entry(istate, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE); } +void fill_stat_data(struct stat_data *sd, struct stat *st) +{ + sd->sd_ctime.sec = (unsigned int)st->st_ctime; + sd->sd_mtime.sec = (unsigned int)st->st_mtime; + sd->sd_ctime.nsec = ST_CTIME_NSEC(*st); + sd->sd_mtime.nsec = ST_MTIME_NSEC(*st); + sd->sd_dev = st->st_dev; + sd->sd_ino = st->st_ino; + sd->sd_uid = st->st_uid; + sd->sd_gid = st->st_gid; + sd->sd_size = st->st_size; +} + +int match_stat_data(const struct stat_data *sd, struct stat *st) +{ + int changed = 0; + + if (sd->sd_mtime.sec != (unsigned int)st->st_mtime) + changed |= MTIME_CHANGED; + if (trust_ctime && check_stat && + sd->sd_ctime.sec != (unsigned int)st->st_ctime) + changed |= CTIME_CHANGED; + +#ifdef USE_NSEC + if (check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st)) + changed |= MTIME_CHANGED; + if (trust_ctime && check_stat && + sd->sd_ctime.nsec != ST_CTIME_NSEC(*st)) + changed |= CTIME_CHANGED; +#endif + + if (check_stat) { + if (sd->sd_uid != (unsigned int) st->st_uid || + sd->sd_gid != (unsigned int) st->st_gid) + changed |= OWNER_CHANGED; + if (sd->sd_ino != (unsigned int) st->st_ino) + changed |= INODE_CHANGED; + } + +#ifdef USE_STDEV + /* + * st_dev breaks on network filesystems where different + * clients will have different views of what "device" + * the filesystem is on + */ + if (check_stat && sd->sd_dev != (unsigned int) st->st_dev) + changed |= INODE_CHANGED; +#endif + + if (sd->sd_size != (unsigned int) st->st_size) + changed |= DATA_CHANGED; + + return changed; +} + /* * This only updates the "non-critical" parts of the directory * cache, ie the parts that aren't tracked by GIT, and only used @@ -74,15 +129,7 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n */ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st) { - ce->ce_ctime.sec = (unsigned int)st->st_ctime; - ce->ce_mtime.sec = (unsigned int)st->st_mtime; - ce->ce_ctime.nsec = ST_CTIME_NSEC(*st); - ce->ce_mtime.nsec = ST_MTIME_NSEC(*st); - ce->ce_dev = st->st_dev; - ce->ce_ino = st->st_ino; - ce->ce_uid = st->st_uid; - ce->ce_gid = st->st_gid; - ce->ce_size = st->st_size; + fill_stat_data(&ce->ce_stat_data, st); if (assume_unchanged) ce->ce_flags |= CE_VALID; @@ -91,7 +138,7 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st) ce_mark_uptodate(ce); } -static int ce_compare_data(struct cache_entry *ce, struct stat *st) +static int ce_compare_data(const struct cache_entry *ce, struct stat *st) { int match = -1; int fd = open(ce->name, O_RDONLY); @@ -105,7 +152,7 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st) return match; } -static int ce_compare_link(struct cache_entry *ce, size_t expected_size) +static int ce_compare_link(const struct cache_entry *ce, size_t expected_size) { int match = -1; void *buffer; @@ -126,7 +173,7 @@ static int ce_compare_link(struct cache_entry *ce, size_t expected_size) return match; } -static int ce_compare_gitlink(struct cache_entry *ce) +static int ce_compare_gitlink(const struct cache_entry *ce) { unsigned char sha1[20]; @@ -143,7 +190,7 @@ static int ce_compare_gitlink(struct cache_entry *ce) return hashcmp(sha1, ce->sha1); } -static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st) +static int ce_modified_check_fs(const struct cache_entry *ce, struct stat *st) { switch (st->st_mode & S_IFMT) { case S_IFREG: @@ -163,7 +210,7 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st) return 0; } -static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) +static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st) { unsigned int changed = 0; @@ -195,43 +242,11 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) default: die("internal error: ce_mode is %o", ce->ce_mode); } - if (ce->ce_mtime.sec != (unsigned int)st->st_mtime) - changed |= MTIME_CHANGED; - if (trust_ctime && check_stat && - ce->ce_ctime.sec != (unsigned int)st->st_ctime) - changed |= CTIME_CHANGED; - -#ifdef USE_NSEC - if (check_stat && ce->ce_mtime.nsec != ST_MTIME_NSEC(*st)) - changed |= MTIME_CHANGED; - if (trust_ctime && check_stat && - ce->ce_ctime.nsec != ST_CTIME_NSEC(*st)) - changed |= CTIME_CHANGED; -#endif - - if (check_stat) { - if (ce->ce_uid != (unsigned int) st->st_uid || - ce->ce_gid != (unsigned int) st->st_gid) - changed |= OWNER_CHANGED; - if (ce->ce_ino != (unsigned int) st->st_ino) - changed |= INODE_CHANGED; - } - -#ifdef USE_STDEV - /* - * st_dev breaks on network filesystems where different - * clients will have different views of what "device" - * the filesystem is on - */ - if (check_stat && ce->ce_dev != (unsigned int) st->st_dev) - changed |= INODE_CHANGED; -#endif - if (ce->ce_size != (unsigned int) st->st_size) - changed |= DATA_CHANGED; + changed |= match_stat_data(&ce->ce_stat_data, st); /* Racily smudged entry? */ - if (!ce->ce_size) { + if (!ce->ce_stat_data.sd_size) { if (!is_empty_blob_sha1(ce->sha1)) changed |= DATA_CHANGED; } @@ -239,23 +254,24 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) return changed; } -static int is_racy_timestamp(const struct index_state *istate, struct cache_entry *ce) +static int is_racy_timestamp(const struct index_state *istate, + const struct cache_entry *ce) { return (!S_ISGITLINK(ce->ce_mode) && istate->timestamp.sec && #ifdef USE_NSEC /* nanosecond timestamped files can also be racy! */ - (istate->timestamp.sec < ce->ce_mtime.sec || - (istate->timestamp.sec == ce->ce_mtime.sec && - istate->timestamp.nsec <= ce->ce_mtime.nsec)) + (istate->timestamp.sec < ce->ce_stat_data.sd_mtime.sec || + (istate->timestamp.sec == ce->ce_stat_data.sd_mtime.sec && + istate->timestamp.nsec <= ce->ce_stat_data.sd_mtime.nsec)) #else - istate->timestamp.sec <= ce->ce_mtime.sec + istate->timestamp.sec <= ce->ce_stat_data.sd_mtime.sec #endif ); } int ie_match_stat(const struct index_state *istate, - struct cache_entry *ce, struct stat *st, + const struct cache_entry *ce, struct stat *st, unsigned int options) { unsigned int changed; @@ -311,7 +327,8 @@ int ie_match_stat(const struct index_state *istate, } int ie_modified(const struct index_state *istate, - struct cache_entry *ce, struct stat *st, unsigned int options) + const struct cache_entry *ce, + struct stat *st, unsigned int options) { int changed, changed_fs; @@ -340,7 +357,7 @@ int ie_modified(const struct index_state *istate, * then we know it is. */ if ((changed & DATA_CHANGED) && - (S_ISGITLINK(ce->ce_mode) || ce->ce_size != 0)) + (S_ISGITLINK(ce->ce_mode) || ce->ce_stat_data.sd_size != 0)) return changed; changed_fs = ce_modified_check_fs(ce, st); @@ -472,7 +489,7 @@ int remove_index_entry_at(struct index_state *istate, int pos) } /* - * Remove all cache ententries marked for removal, that is where + * Remove all cache entries marked for removal, that is where * CE_REMOVE is set in ce_flags. This is much more effective than * calling remove_index_entry_at() for each entry to be removed. */ @@ -626,7 +643,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st, if (*ptr == '/') { struct cache_entry *foundce; ++ptr; - foundce = index_name_exists(istate, ce->name, ptr - ce->name, ignore_case); + foundce = index_dir_exists(istate, ce->name, ptr - ce->name - 1); if (foundce) { memcpy((void *)startPtr, foundce->name + (startPtr - ce->name), ptr - startPtr); startPtr = ptr; @@ -635,7 +652,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st, } } - alias = index_name_exists(istate, ce->name, ce_namelen(ce), ignore_case); + alias = index_file_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); @@ -705,7 +722,7 @@ struct cache_entry *make_cache_entry(unsigned int mode, return ce; } -int ce_same_name(struct cache_entry *a, struct cache_entry *b) +int ce_same_name(const struct cache_entry *a, const struct cache_entry *b) { int len = ce_namelen(a); return ce_namelen(b) == len && !memcmp(a->name, b->name, len); @@ -1097,7 +1114,8 @@ static void show_file(const char * fmt, const char * name, int in_porcelain, printf(fmt, name); } -int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec, +int refresh_index(struct index_state *istate, unsigned int flags, + const struct pathspec *pathspec, char *seen, const char *header_msg) { int i; @@ -1132,7 +1150,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p continue; if (pathspec && - !match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen)) + !match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, seen)) filtered = 1; if (ce_stage(ce)) { @@ -1212,14 +1230,14 @@ static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int reall struct ondisk_cache_entry { struct cache_time ctime; struct cache_time mtime; - unsigned int dev; - unsigned int ino; - unsigned int mode; - unsigned int uid; - unsigned int gid; - unsigned int size; + uint32_t dev; + uint32_t ino; + uint32_t mode; + uint32_t uid; + uint32_t gid; + uint32_t size; unsigned char sha1[20]; - unsigned short flags; + uint16_t flags; char name[FLEX_ARRAY]; /* more */ }; @@ -1231,15 +1249,15 @@ struct ondisk_cache_entry { struct ondisk_cache_entry_extended { struct cache_time ctime; struct cache_time mtime; - unsigned int dev; - unsigned int ino; - unsigned int mode; - unsigned int uid; - unsigned int gid; - unsigned int size; + uint32_t dev; + uint32_t ino; + uint32_t mode; + uint32_t uid; + uint32_t gid; + uint32_t size; unsigned char sha1[20]; - unsigned short flags; - unsigned short flags2; + uint16_t flags; + uint16_t flags2; char name[FLEX_ARRAY]; /* more */ }; @@ -1322,16 +1340,16 @@ static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *on { struct cache_entry *ce = xmalloc(cache_entry_size(len)); - ce->ce_ctime.sec = ntoh_l(ondisk->ctime.sec); - ce->ce_mtime.sec = ntoh_l(ondisk->mtime.sec); - ce->ce_ctime.nsec = ntoh_l(ondisk->ctime.nsec); - ce->ce_mtime.nsec = ntoh_l(ondisk->mtime.nsec); - ce->ce_dev = ntoh_l(ondisk->dev); - ce->ce_ino = ntoh_l(ondisk->ino); + ce->ce_stat_data.sd_ctime.sec = ntoh_l(ondisk->ctime.sec); + ce->ce_stat_data.sd_mtime.sec = ntoh_l(ondisk->mtime.sec); + ce->ce_stat_data.sd_ctime.nsec = ntoh_l(ondisk->ctime.nsec); + ce->ce_stat_data.sd_mtime.nsec = ntoh_l(ondisk->mtime.nsec); + ce->ce_stat_data.sd_dev = ntoh_l(ondisk->dev); + ce->ce_stat_data.sd_ino = ntoh_l(ondisk->ino); ce->ce_mode = ntoh_l(ondisk->mode); - ce->ce_uid = ntoh_l(ondisk->uid); - ce->ce_gid = ntoh_l(ondisk->gid); - ce->ce_size = ntoh_l(ondisk->size); + ce->ce_stat_data.sd_uid = ntoh_l(ondisk->uid); + ce->ce_stat_data.sd_gid = ntoh_l(ondisk->gid); + ce->ce_stat_data.sd_size = ntoh_l(ondisk->size); ce->ce_flags = flags & ~CE_NAMEMASK; ce->ce_namelen = len; hashcpy(ce->sha1, ondisk->sha1); @@ -1609,7 +1627,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce) * The only thing we care about in this function is to smudge the * 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. + * ce_stat_data.sd_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 @@ -1648,7 +1666,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce) * file, and never calls us, so the cached size information * for "frotz" stays 6 which does not match the filesystem. */ - ce->ce_size = 0; + ce->ce_stat_data.sd_size = 0; } } @@ -1658,16 +1676,16 @@ static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk, { short flags; - ondisk->ctime.sec = htonl(ce->ce_ctime.sec); - ondisk->mtime.sec = htonl(ce->ce_mtime.sec); - ondisk->ctime.nsec = htonl(ce->ce_ctime.nsec); - ondisk->mtime.nsec = htonl(ce->ce_mtime.nsec); - ondisk->dev = htonl(ce->ce_dev); - ondisk->ino = htonl(ce->ce_ino); + ondisk->ctime.sec = htonl(ce->ce_stat_data.sd_ctime.sec); + ondisk->mtime.sec = htonl(ce->ce_stat_data.sd_mtime.sec); + ondisk->ctime.nsec = htonl(ce->ce_stat_data.sd_ctime.nsec); + ondisk->mtime.nsec = htonl(ce->ce_stat_data.sd_mtime.nsec); + ondisk->dev = htonl(ce->ce_stat_data.sd_dev); + ondisk->ino = htonl(ce->ce_stat_data.sd_ino); ondisk->mode = htonl(ce->ce_mode); - ondisk->uid = htonl(ce->ce_uid); - ondisk->gid = htonl(ce->ce_gid); - ondisk->size = htonl(ce->ce_size); + ondisk->uid = htonl(ce->ce_stat_data.sd_uid); + ondisk->gid = htonl(ce->ce_stat_data.sd_gid); + ondisk->size = htonl(ce->ce_stat_data.sd_size); hashcpy(ondisk->sha1, ce->sha1); flags = ce->ce_flags; @@ -1743,7 +1761,7 @@ static int has_racy_timestamp(struct index_state *istate) } /* - * Opportunisticly update the index but do not complain if we can't + * Opportunistically update the index but do not complain if we can't */ void update_index_if_able(struct index_state *istate, struct lock_file *lockfile) { @@ -1800,8 +1818,17 @@ int write_index(struct index_state *istate, int newfd) continue; if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce)) ce_smudge_racily_clean_entry(ce); - if (is_null_sha1(ce->sha1)) - return error("cache entry has null sha1: %s", ce->name); + if (is_null_sha1(ce->sha1)) { + static const char msg[] = "cache entry has null sha1: %s"; + static int allow = -1; + + if (allow < 0) + allow = git_env_bool("GIT_ALLOW_NULL_SHA1", 0); + if (allow) + warning(msg, ce->name); + else + return error(msg, ce->name); + } if (ce_write_entry(&c, newfd, ce, previous_name) < 0) return -1; } @@ -1934,3 +1961,33 @@ void *read_blob_data_from_index(struct index_state *istate, const char *path, un *size = sz; return data; } + +void stat_validity_clear(struct stat_validity *sv) +{ + free(sv->sd); + sv->sd = NULL; +} + +int stat_validity_check(struct stat_validity *sv, const char *path) +{ + struct stat st; + + if (stat(path, &st) < 0) + return sv->sd == NULL; + if (!sv->sd) + return 0; + return S_ISREG(st.st_mode) && !match_stat_data(sv->sd, &st); +} + +void stat_validity_update(struct stat_validity *sv, int fd) +{ + struct stat st; + + if (fstat(fd, &st) < 0 || !S_ISREG(st.st_mode)) + stat_validity_clear(sv); + else { + if (!sv->sd) + sv->sd = xcalloc(1, sizeof(struct stat_data)); + fill_stat_data(sv->sd, &st); + } +} |