+ return add_cache_entry(ce, allow_add);
+}
+
+static int match_data(int fd, void *buffer, unsigned long size)
+{
+ while (size) {
+ char compare[1024];
+ int ret = read(fd, compare, sizeof(compare));
+
+ if (ret <= 0 || ret > size || memcmp(buffer, compare, ret))
+ return -1;
+ size -= ret;
+ buffer += ret;
+ }
+ return 0;
+}
+
+static int compare_data(struct cache_entry *ce, unsigned long expected_size)
+{
+ int match = -1;
+ int fd = open(ce->name, O_RDONLY);
+
+ if (fd >= 0) {
+ void *buffer;
+ unsigned long size;
+ char type[10];
+
+ buffer = read_sha1_file(ce->sha1, type, &size);
+ if (buffer) {
+ if (size == expected_size && !strcmp(type, "blob"))
+ match = match_data(fd, buffer, size);
+ free(buffer);
+ }
+ close(fd);
+ }
+ return match;
+}
+
+/*
+ * "refresh" does not calculate a new sha1 file or bring the
+ * cache up-to-date for mode/content changes. But what it
+ * _does_ do is to "re-match" the stat information of a file
+ * with the cache, so that you can refresh the cache for a
+ * file that hasn't been changed but where the stat entry is
+ * out of date.
+ *
+ * For example, you'd want to do this after doing a "read-tree",
+ * to link up the stat cache details with the proper files.
+ */
+static struct cache_entry *refresh_entry(struct cache_entry *ce)
+{
+ struct stat st;
+ struct cache_entry *updated;
+ int changed, size;
+
+ if (stat(ce->name, &st) < 0)
+ return NULL;
+
+ changed = cache_match_stat(ce, &st);
+ if (!changed)
+ return ce;
+
+ /*
+ * If the mode has changed, there's no point in trying
+ * to refresh the entry - it's not going to match
+ */
+ if (changed & MODE_CHANGED)
+ return NULL;
+
+ if (compare_data(ce, st.st_size))
+ return NULL;
+
+ size = ce_size(ce);
+ updated = malloc(size);
+ memcpy(updated, ce, size);
+ fill_stat_cache_info(updated, &st);
+ return updated;
+}
+
+static void refresh_cache(void)
+{
+ int i;
+
+ for (i = 0; i < active_nr; i++) {
+ struct cache_entry *ce, *new;
+ ce = active_cache[i];
+ if (ce_stage(ce)) {
+ printf("%s: needs merge\n", ce->name);
+ while ((i < active_nr) &&
+ ! strcmp(active_cache[i]->name, ce->name))
+ i++;
+ i--;
+ continue;
+ }
+
+ new = refresh_entry(ce);
+ if (!new) {
+ printf("%s: needs update\n", ce->name);
+ continue;
+ }
+ active_cache[i] = new;
+ }