X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=read-cache.c;h=c5474d49758b640f8942b1e3eb1a1c8f47c78ed8;hb=9470657ad0d0472e3e3c2e352334f60e7bd777c1;hp=780601f071a0f5ae35b6d379abdd935d79ca92e2;hpb=29e4d3635709778bcc808dbad0477efad82f8d7e;p=git.git diff --git a/read-cache.c b/read-cache.c index 780601f0..c5474d49 100644 --- a/read-cache.c +++ b/read-cache.c @@ -87,7 +87,7 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st) return 0; } -int ce_match_stat(struct cache_entry *ce, struct stat *st) +static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) { unsigned int changed = 0; @@ -143,6 +143,13 @@ int ce_match_stat(struct cache_entry *ce, struct stat *st) if (ce->ce_size != htonl(st->st_size)) changed |= DATA_CHANGED; + return changed; +} + +int ce_match_stat(struct cache_entry *ce, struct stat *st) +{ + unsigned int changed = ce_match_stat_basic(ce, st); + /* * Within 1 second of this sequence: * echo xyzzy >file && git-update-index --add file @@ -594,6 +601,50 @@ static int ce_flush(SHA_CTX *context, int fd) return 0; } +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. + */ + struct stat st; + + if (lstat(ce->name, &st) < 0) + return; + if (ce_match_stat_basic(ce, &st)) + return; + if (ce_modified_check_fs(ce, &st)) { + /* This is "racily clean"; smudge it. Note that this + * is a tricky code. At first glance, it may appear + * that it can break with this sequence: + * + * $ echo xyzzy >frotz + * $ git-update-index --add frotz + * $ : >frotz + * $ sleep 3 + * $ echo filfre >nitfol + * $ git-update-index --add nitfol + * + * but it does not. Whe the second update-index runs, + * it notices that the entry "frotz" has the same timestamp + * as index, and if we were to smudge it by resetting its + * size to zero here, then the object name recorded + * in index is the 6-byte file but the cached stat information + * becomes zero --- which would then match what we would + * obtain from the filesystem next time we stat("frotz"). + * + * However, the second update-index, before calling + * this function, notices that the cached size is 6 + * bytes and what is on the filesystem is an empty + * file, and never calls us, so the cached size information + * for "frotz" stays 6 which does not match the filesystem. + */ + ce->ce_size = htonl(0); + } +} + int write_cache(int newfd, struct cache_entry **cache, int entries) { SHA_CTX c; @@ -616,6 +667,9 @@ int write_cache(int newfd, struct cache_entry **cache, int entries) struct cache_entry *ce = cache[i]; if (!ce->ce_mode) continue; + if (index_file_timestamp && + index_file_timestamp <= ntohl(ce->ce_mtime.sec)) + ce_smudge_racily_clean_entry(ce); if (ce_write(&c, newfd, ce, ce_size(ce)) < 0) return -1; }