X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=update-cache.c;h=735d19920d998a3d53dbfd9a68336cc13780ef23;hb=ee267527aa80807f37caf1d00bcf1b5263945adb;hp=893ba8679d5764ba84627558d567268ff2500558;hpb=211232bae64bcc60bbf5d1b5e5b2344c22ed767e;p=git.git diff --git a/update-cache.c b/update-cache.c index 893ba867..735d1992 100644 --- a/update-cache.c +++ b/update-cache.c @@ -15,12 +15,6 @@ */ static int allow_add = 0, allow_remove = 0, not_new = 0; -/* - * update-cache --refresh may not touch anything at all, in which case - * writing 1.6MB of the same thing is a waste. - */ -static int cache_changed = 0; - /* Three functions to allow overloaded pointer return; see linux/err.h */ static inline void *ERR_PTR(long error) { @@ -57,14 +51,13 @@ static void fill_stat_cache_info(struct cache_entry *ce, struct stat *st) ce->ce_size = htonl(st->st_size); } -static int add_file_to_cache_1(char *path) +static int add_file_to_cache(char *path) { int size, namelen; struct cache_entry *ce; struct stat st; int fd; - unsigned int len; - char target[1024]; + char *target; if (lstat(path, &st) < 0) { if (errno == ENOENT || errno == ENOTDIR) { @@ -90,44 +83,21 @@ static int add_file_to_cache_1(char *path) return -1; break; case S_IFLNK: - len = readlink(path, target, sizeof(target)); - if (len == -1 || len+1 > sizeof(target)) + target = xmalloc(st.st_size+1); + if (readlink(path, target, st.st_size+1) != st.st_size) { + free(target); return -1; - if (write_sha1_file(target, len, "blob", ce->sha1)) + } + if (write_sha1_file(target, st.st_size, "blob", ce->sha1)) return -1; + free(target); break; default: return -1; } - if (!cache_changed) { - /* If we have not smudged the cache, be careful - * to keep it clean. Find out if we have a matching - * cache entry that add_cache_entry would replace with, - * and if it matches then do not bother calling it. - */ - int pos = cache_name_pos(ce->name, namelen); - if ((0 <= pos) && - !memcmp(active_cache[pos], ce, sizeof(*ce))) { - free(ce); - /* magic to tell add_file_to_cache that - * we have not updated anything. - */ - return 999; - } - } return add_cache_entry(ce, allow_add); } -static int add_file_to_cache(char *path) -{ - int ret = add_file_to_cache_1(path); - if (ret == 0) - cache_changed = 1; - else if (ret == 999) - ret = 0; - return ret; -} - static int match_data(int fd, void *buffer, unsigned long size) { while (size) { @@ -163,6 +133,33 @@ static int compare_data(struct cache_entry *ce, unsigned long expected_size) return match; } +static int compare_link(struct cache_entry *ce, unsigned long expected_size) +{ + int match = -1; + char *target; + void *buffer; + unsigned long size; + char type[10]; + int len; + + target = xmalloc(expected_size); + len = readlink(ce->name, target, expected_size); + if (len != expected_size) { + free(target); + return -1; + } + buffer = read_sha1_file(ce->sha1, type, &size); + if (!buffer) { + free(target); + return -1; + } + if (size == expected_size) + match = memcmp(buffer, target, size); + free(buffer); + free(target); + return match; +} + /* * "refresh" does not calculate a new sha1 file or bring the * cache up-to-date for mode/content changes. But what it @@ -194,10 +191,19 @@ static struct cache_entry *refresh_entry(struct cache_entry *ce) if (changed & (MODE_CHANGED | TYPE_CHANGED)) return ERR_PTR(-EINVAL); - if (compare_data(ce, st.st_size)) + switch (st.st_mode & S_IFMT) { + case S_IFREG: + if (compare_data(ce, st.st_size)) + return ERR_PTR(-EINVAL); + break; + case S_IFLNK: + if (compare_link(ce, st.st_size)) + return ERR_PTR(-EINVAL); + break; + default: return ERR_PTR(-EINVAL); + } - cache_changed = 1; size = ce_size(ce); updated = xmalloc(size); memcpy(updated, ce, size); @@ -231,6 +237,7 @@ static int refresh_cache(void) } continue; } + active_cache_changed = 1; active_cache[i] = new; } return has_errors; @@ -278,7 +285,6 @@ static int add_cacheinfo(char *arg1, char *arg2, char *arg3) if (!verify_path(arg3)) return -1; - cache_changed = 1; len = strlen(arg3); size = cache_entry_size(len); ce = xmalloc(size); @@ -373,11 +379,7 @@ int main(int argc, char **argv) if (add_file_to_cache(path)) die("Unable to add %s to database", path); } - - if (!cache_changed) - unlink(lockfile); - else if (write_cache(newfd, active_cache, active_nr) || - rename(lockfile, indexfile)) + if (write_cache(newfd, active_cache, active_nr) || rename(lockfile, indexfile)) die("Unable to write new cachefile"); lockfile_name = NULL;