aboutsummaryrefslogtreecommitdiffstats
path: root/entry.c
diff options
context:
space:
mode:
Diffstat (limited to 'entry.c')
-rw-r--r--entry.c50
1 files changed, 39 insertions, 11 deletions
diff --git a/entry.c b/entry.c
index 0a3c451f5f..a0532f1f00 100644
--- a/entry.c
+++ b/entry.c
@@ -113,8 +113,7 @@ static int fstat_output(int fd, const struct checkout *state, struct stat *st)
/* use fstat() only when path == ce->name */
if (fstat_is_reliable() &&
state->refresh_cache && !state->base_dir_len) {
- fstat(fd, st);
- return 1;
+ return !fstat(fd, st);
}
return 0;
}
@@ -161,7 +160,7 @@ static int remove_available_paths(struct string_list_item *item, void *cb_data)
return !available;
}
-int finish_delayed_checkout(struct checkout *state)
+int finish_delayed_checkout(struct checkout *state, int *nr_checkouts)
{
int errs = 0;
unsigned delayed_object_count;
@@ -226,7 +225,7 @@ int finish_delayed_checkout(struct checkout *state)
ce = index_file_exists(state->istate, path->string,
strlen(path->string), 0);
if (ce) {
- errs |= checkout_entry(ce, state, NULL);
+ errs |= checkout_entry(ce, state, NULL, nr_checkouts);
filtered_bytes += ce->ce_stat_data.sd_size;
display_throughput(progress, filtered_bytes);
} else
@@ -264,6 +263,9 @@ static int write_entry(struct cache_entry *ce,
size_t newsize = 0;
struct stat st;
const struct submodule *sub;
+ struct checkout_metadata meta;
+
+ clone_checkout_metadata(&meta, &state->meta, &ce->oid);
if (ce_mode_s_ifmt == S_IFREG) {
struct stream_filter *filter = get_stream_filter(state->istate, ce->name,
@@ -315,13 +317,13 @@ static int write_entry(struct cache_entry *ce,
*/
if (dco && dco->state != CE_NO_DELAY) {
ret = async_convert_to_working_tree(state->istate, ce->name, new_blob,
- size, &buf, dco);
+ size, &buf, &meta, dco);
if (ret && string_list_has_string(&dco->paths, ce->name)) {
free(new_blob);
goto delayed;
}
} else
- ret = convert_to_working_tree(state->istate, ce->name, new_blob, size, &buf);
+ ret = convert_to_working_tree(state->istate, ce->name, new_blob, size, &buf, &meta);
if (ret) {
free(new_blob);
@@ -373,7 +375,7 @@ finish:
if (lstat(ce->name, &st) < 0)
return error_errno("unable to stat just-written file %s",
ce->name);
- fill_stat_cache_info(ce, &st);
+ fill_stat_cache_info(state->istate, ce, &st);
ce->ce_flags |= CE_UPDATE_IN_BASE;
mark_fsmonitor_invalid(state->istate, ce);
state->istate->cache_changed |= CE_ENTRY_CHANGED;
@@ -435,12 +437,23 @@ static void mark_colliding_entries(const struct checkout *state,
* its name is returned in topath[], which must be able to hold at
* least TEMPORARY_FILENAME_LENGTH bytes long.
*/
-int checkout_entry(struct cache_entry *ce,
- const struct checkout *state, char *topath)
+int checkout_entry(struct cache_entry *ce, const struct checkout *state,
+ char *topath, int *nr_checkouts)
{
static struct strbuf path = STRBUF_INIT;
struct stat st;
+ if (ce->ce_flags & CE_WT_REMOVE) {
+ if (topath)
+ /*
+ * No content and thus no path to create, so we have
+ * no pathname to return.
+ */
+ BUG("Can't remove entry to a path");
+ unlink_entry(ce);
+ return 0;
+ }
+
if (topath)
return write_entry(ce, topath, state, 1);
@@ -497,8 +510,6 @@ int checkout_entry(struct cache_entry *ce,
/* If it is a gitlink, leave it alone! */
if (S_ISGITLINK(ce->ce_mode))
return 0;
- if (!state->force)
- return error("%s is a directory", path.buf);
remove_subtree(&path);
} else if (unlink(path.buf))
return error_errno("unable to unlink old '%s'", path.buf);
@@ -506,5 +517,22 @@ int checkout_entry(struct cache_entry *ce,
return 0;
create_directories(path.buf, path.len, state);
+ if (nr_checkouts)
+ (*nr_checkouts)++;
return write_entry(ce, path.buf, state, 0);
}
+
+void unlink_entry(const struct cache_entry *ce)
+{
+ const struct submodule *sub = submodule_from_ce(ce);
+ if (sub) {
+ /* state.force is set at the caller. */
+ submodule_move_head(ce->name, "HEAD", NULL,
+ SUBMODULE_MOVE_HEAD_FORCE);
+ }
+ if (!check_leading_path(ce->name, ce_namelen(ce)))
+ return;
+ if (remove_or_warn(ce->ce_mode, ce->name))
+ return;
+ schedule_dir_for_removal(ce->name, ce_namelen(ce));
+}