+ int retval = 0;
+ int len = ce_namelen(ce);
+ int stage = ce_stage(ce);
+ const char *name = ce->name;
+
+ while (pos < active_nr) {
+ struct cache_entry *p = active_cache[pos++];
+
+ if (len >= ce_namelen(p))
+ break;
+ if (memcmp(name, p->name, len))
+ break;
+ if (ce_stage(p) != stage)
+ continue;
+ if (p->name[len] != '/')
+ continue;
+ retval = -1;
+ if (!ok_to_replace)
+ break;
+ remove_cache_entry_at(--pos);
+ }
+ return retval;
+}
+
+/*
+ * Do we have another file with a pathname that is a proper
+ * subset of the name we're trying to add?
+ */
+static int has_dir_name(const struct cache_entry *ce, int pos, int ok_to_replace)
+{
+ int retval = 0;
+ int stage = ce_stage(ce);
+ const char *name = ce->name;
+ const char *slash = name + ce_namelen(ce);
+
+ for (;;) {
+ int len;
+
+ for (;;) {
+ if (*--slash == '/')
+ break;
+ if (slash <= ce->name)
+ return retval;
+ }
+ len = slash - name;
+
+ pos = cache_name_pos(name, ntohs(create_ce_flags(len, stage)));
+ if (pos >= 0) {
+ retval = -1;
+ if (ok_to_replace)
+ break;
+ remove_cache_entry_at(pos);
+ continue;
+ }
+
+ /*
+ * Trivial optimization: if we find an entry that
+ * already matches the sub-directory, then we know
+ * we're ok, and we can exit.
+ */
+ pos = -pos-1;
+ while (pos < active_nr) {
+ struct cache_entry *p = active_cache[pos];
+ if ((ce_namelen(p) <= len) ||
+ (p->name[len] != '/') ||
+ memcmp(p->name, name, len))
+ break; /* not our subdirectory */
+ if (ce_stage(p) == stage)
+ /* p is at the same stage as our entry, and
+ * is a subdirectory of what we are looking
+ * at, so we cannot have conflicts at our
+ * level or anything shorter.
+ */
+ return retval;
+ pos++;
+ }
+ }
+ return retval;
+}