static int ce_compare_link(struct cache_entry *ce, size_t expected_size)
{
int match = -1;
- char *target;
void *buffer;
unsigned long size;
enum object_type type;
- int len;
+ struct strbuf sb = STRBUF_INIT;
- target = xmalloc(expected_size);
- len = readlink(ce->name, target, expected_size);
- if (len != expected_size) {
- free(target);
+ if (strbuf_readlink(&sb, ce->name, expected_size))
return -1;
- }
+
buffer = read_sha1_file(ce->sha1, &type, &size);
- if (!buffer) {
- free(target);
- return -1;
+ if (buffer) {
+ if (size == sb.len)
+ match = memcmp(buffer, sb.buf, size);
+ free(buffer);
}
- if (size == expected_size)
- match = memcmp(buffer, target, size);
- free(buffer);
- free(target);
+ strbuf_release(&sb);
return match;
}
return 0;
}
-static int is_empty_blob_sha1(const unsigned char *sha1)
+int is_empty_blob_sha1(const unsigned char *sha1)
{
static const unsigned char empty_blob_sha1[20] = {
0xe6,0x9d,0xe2,0x9b,0xb2,0xd1,0xd6,0x43,0x4b,0x8b,
if (!ignore_valid && (ce->ce_flags & CE_VALID))
return 0;
+ /*
+ * Intent-to-add entries have not been added, so the index entry
+ * by definition never matches what is in the work tree until it
+ * actually gets added.
+ */
+ if (ce->ce_flags & CE_INTENT_TO_ADD)
+ return DATA_CHANGED | TYPE_CHANGED | MODE_CHANGED;
+
changed = ce_match_stat_basic(ce, st);
/*
ce->ce_flags = namelen;
if (!intent_only)
fill_stat_cache_info(ce, st);
+ else
+ ce->ce_flags |= CE_INTENT_TO_ADD;
if (trust_executable_bit && has_symlinks)
ce->ce_mode = create_ce_mode(st_mode);
die("index file corrupt");
}
+int is_index_unborn(struct index_state *istate)
+{
+ return (!istate->cache_nr && !istate->alloc && !istate->timestamp);
+}
+
int discard_index(struct index_state *istate)
{
istate->cache_nr = 0;
/*
* Read the index file that is potentially unmerged into given
- * index_state, dropping any unmerged entries. Returns true is
+ * index_state, dropping any unmerged entries. Returns true if
* 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;
+ int unmerged = 0;
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;
+ struct cache_entry *new_ce;
+ int size, len;
+
+ if (!ce_stage(ce))
continue;
- }
- *dst++ = ce;
+ unmerged = 1;
+ len = strlen(ce->name);
+ size = cache_entry_size(len);
+ new_ce = xcalloc(1, size);
+ hashcpy(new_ce->sha1, ce->sha1);
+ memcpy(new_ce->name, ce->name, len);
+ new_ce->ce_flags = create_ce_flags(len, 0);
+ new_ce->ce_mode = ce->ce_mode;
+ if (add_index_entry(istate, new_ce, 0))
+ return error("%s: cannot drop to stage #0",
+ ce->name);
+ i = index_name_pos(istate, new_ce->name, len);
}
- istate->cache_nr = dst - istate->cache;
- return !!last;
+ return unmerged;
}
struct update_callback_data
default:
die("unexpected diff status %c", p->status);
case DIFF_STATUS_UNMERGED:
+ /*
+ * ADD_CACHE_IGNORE_REMOVAL is unset if "git
+ * add -u" is calling us, In such a case, a
+ * missing work tree file needs to be removed
+ * if there is an unmerged entry at stage #2,
+ * but such a diff record is followed by
+ * another with DIFF_STATUS_DELETED (and if
+ * there is no stage #2, we won't see DELETED
+ * nor MODIFIED). We can simply continue
+ * either way.
+ */
+ if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL))
+ continue;
+ /*
+ * Otherwise, it is "git add path" is asking
+ * to explicitly add it; we fall through. A
+ * missing work tree file is an error and is
+ * caught by add_file_to_index() in such a
+ * case.
+ */
case DIFF_STATUS_MODIFIED:
case DIFF_STATUS_TYPE_CHANGED:
if (add_file_to_index(&the_index, path, data->flags)) {
return !!data.add_errors;
}
+/*
+ * Returns 1 if the path is an "other" path with respect to
+ * the index; that is, the path is not mentioned in the index at all,
+ * either as a file, a directory with some files in the index,
+ * or as an unmerged entry.
+ *
+ * We helpfully remove a trailing "/" from directories so that
+ * the output of read_directory can be used as-is.
+ */
+int index_name_is_other(const struct index_state *istate, const char *name,
+ int namelen)
+{
+ int pos;
+ if (namelen && name[namelen - 1] == '/')
+ namelen--;
+ pos = index_name_pos(istate, name, namelen);
+ if (0 <= pos)
+ return 0; /* exact match */
+ pos = -pos - 1;
+ if (pos < istate->cache_nr) {
+ struct cache_entry *ce = istate->cache[pos];
+ if (ce_namelen(ce) == namelen &&
+ !memcmp(ce->name, name, namelen))
+ return 0; /* Yup, this one exists unmerged */
+ }
+ return 1;
+}