about summary refs log tree commit diff
path: root/third_party/git/entry.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/git/entry.c')
-rw-r--r--third_party/git/entry.c538
1 files changed, 0 insertions, 538 deletions
diff --git a/third_party/git/entry.c b/third_party/git/entry.c
deleted file mode 100644
index a0532f1f00..0000000000
--- a/third_party/git/entry.c
+++ /dev/null
@@ -1,538 +0,0 @@
-#include "cache.h"
-#include "blob.h"
-#include "object-store.h"
-#include "dir.h"
-#include "streaming.h"
-#include "submodule.h"
-#include "progress.h"
-#include "fsmonitor.h"
-
-static void create_directories(const char *path, int path_len,
-			       const struct checkout *state)
-{
-	char *buf = xmallocz(path_len);
-	int len = 0;
-
-	while (len < path_len) {
-		do {
-			buf[len] = path[len];
-			len++;
-		} while (len < path_len && path[len] != '/');
-		if (len >= path_len)
-			break;
-		buf[len] = 0;
-
-		/*
-		 * For 'checkout-index --prefix=<dir>', <dir> is
-		 * allowed to be a symlink to an existing directory,
-		 * and we set 'state->base_dir_len' below, such that
-		 * we test the path components of the prefix with the
-		 * stat() function instead of the lstat() function.
-		 */
-		if (has_dirs_only_path(buf, len, state->base_dir_len))
-			continue; /* ok, it is already a directory. */
-
-		/*
-		 * If this mkdir() would fail, it could be that there
-		 * is already a symlink or something else exists
-		 * there, therefore we then try to unlink it and try
-		 * one more time to create the directory.
-		 */
-		if (mkdir(buf, 0777)) {
-			if (errno == EEXIST && state->force &&
-			    !unlink_or_warn(buf) && !mkdir(buf, 0777))
-				continue;
-			die_errno("cannot create directory at '%s'", buf);
-		}
-	}
-	free(buf);
-}
-
-static void remove_subtree(struct strbuf *path)
-{
-	DIR *dir = opendir(path->buf);
-	struct dirent *de;
-	int origlen = path->len;
-
-	if (!dir)
-		die_errno("cannot opendir '%s'", path->buf);
-	while ((de = readdir(dir)) != NULL) {
-		struct stat st;
-
-		if (is_dot_or_dotdot(de->d_name))
-			continue;
-
-		strbuf_addch(path, '/');
-		strbuf_addstr(path, de->d_name);
-		if (lstat(path->buf, &st))
-			die_errno("cannot lstat '%s'", path->buf);
-		if (S_ISDIR(st.st_mode))
-			remove_subtree(path);
-		else if (unlink(path->buf))
-			die_errno("cannot unlink '%s'", path->buf);
-		strbuf_setlen(path, origlen);
-	}
-	closedir(dir);
-	if (rmdir(path->buf))
-		die_errno("cannot rmdir '%s'", path->buf);
-}
-
-static int create_file(const char *path, unsigned int mode)
-{
-	mode = (mode & 0100) ? 0777 : 0666;
-	return open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
-}
-
-static void *read_blob_entry(const struct cache_entry *ce, unsigned long *size)
-{
-	enum object_type type;
-	void *blob_data = read_object_file(&ce->oid, &type, size);
-
-	if (blob_data) {
-		if (type == OBJ_BLOB)
-			return blob_data;
-		free(blob_data);
-	}
-	return NULL;
-}
-
-static int open_output_fd(char *path, const struct cache_entry *ce, int to_tempfile)
-{
-	int symlink = (ce->ce_mode & S_IFMT) != S_IFREG;
-	if (to_tempfile) {
-		xsnprintf(path, TEMPORARY_FILENAME_LENGTH, "%s",
-			  symlink ? ".merge_link_XXXXXX" : ".merge_file_XXXXXX");
-		return mkstemp(path);
-	} else {
-		return create_file(path, !symlink ? ce->ce_mode : 0666);
-	}
-}
-
-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) {
-		return !fstat(fd, st);
-	}
-	return 0;
-}
-
-static int streaming_write_entry(const struct cache_entry *ce, char *path,
-				 struct stream_filter *filter,
-				 const struct checkout *state, int to_tempfile,
-				 int *fstat_done, struct stat *statbuf)
-{
-	int result = 0;
-	int fd;
-
-	fd = open_output_fd(path, ce, to_tempfile);
-	if (fd < 0)
-		return -1;
-
-	result |= stream_blob_to_fd(fd, &ce->oid, filter, 1);
-	*fstat_done = fstat_output(fd, state, statbuf);
-	result |= close(fd);
-
-	if (result)
-		unlink(path);
-	return result;
-}
-
-void enable_delayed_checkout(struct checkout *state)
-{
-	if (!state->delayed_checkout) {
-		state->delayed_checkout = xmalloc(sizeof(*state->delayed_checkout));
-		state->delayed_checkout->state = CE_CAN_DELAY;
-		string_list_init(&state->delayed_checkout->filters, 0);
-		string_list_init(&state->delayed_checkout->paths, 0);
-	}
-}
-
-static int remove_available_paths(struct string_list_item *item, void *cb_data)
-{
-	struct string_list *available_paths = cb_data;
-	struct string_list_item *available;
-
-	available = string_list_lookup(available_paths, item->string);
-	if (available)
-		available->util = (void *)item->string;
-	return !available;
-}
-
-int finish_delayed_checkout(struct checkout *state, int *nr_checkouts)
-{
-	int errs = 0;
-	unsigned delayed_object_count;
-	off_t filtered_bytes = 0;
-	struct string_list_item *filter, *path;
-	struct progress *progress;
-	struct delayed_checkout *dco = state->delayed_checkout;
-
-	if (!state->delayed_checkout)
-		return errs;
-
-	dco->state = CE_RETRY;
-	delayed_object_count = dco->paths.nr;
-	progress = start_delayed_progress(_("Filtering content"), delayed_object_count);
-	while (dco->filters.nr > 0) {
-		for_each_string_list_item(filter, &dco->filters) {
-			struct string_list available_paths = STRING_LIST_INIT_NODUP;
-			display_progress(progress, delayed_object_count - dco->paths.nr);
-
-			if (!async_query_available_blobs(filter->string, &available_paths)) {
-				/* Filter reported an error */
-				errs = 1;
-				filter->string = "";
-				continue;
-			}
-			if (available_paths.nr <= 0) {
-				/*
-				 * Filter responded with no entries. That means
-				 * the filter is done and we can remove the
-				 * filter from the list (see
-				 * "string_list_remove_empty_items" call below).
-				 */
-				filter->string = "";
-				continue;
-			}
-
-			/*
-			 * In dco->paths we store a list of all delayed paths.
-			 * The filter just send us a list of available paths.
-			 * Remove them from the list.
-			 */
-			filter_string_list(&dco->paths, 0,
-				&remove_available_paths, &available_paths);
-
-			for_each_string_list_item(path, &available_paths) {
-				struct cache_entry* ce;
-
-				if (!path->util) {
-					error("external filter '%s' signaled that '%s' "
-					      "is now available although it has not been "
-					      "delayed earlier",
-					      filter->string, path->string);
-					errs |= 1;
-
-					/*
-					 * Do not ask the filter for available blobs,
-					 * again, as the filter is likely buggy.
-					 */
-					filter->string = "";
-					continue;
-				}
-				ce = index_file_exists(state->istate, path->string,
-						       strlen(path->string), 0);
-				if (ce) {
-					errs |= checkout_entry(ce, state, NULL, nr_checkouts);
-					filtered_bytes += ce->ce_stat_data.sd_size;
-					display_throughput(progress, filtered_bytes);
-				} else
-					errs = 1;
-			}
-		}
-		string_list_remove_empty_items(&dco->filters, 0);
-	}
-	stop_progress(&progress);
-	string_list_clear(&dco->filters, 0);
-
-	/* At this point we should not have any delayed paths anymore. */
-	errs |= dco->paths.nr;
-	for_each_string_list_item(path, &dco->paths) {
-		error("'%s' was not filtered properly", path->string);
-	}
-	string_list_clear(&dco->paths, 0);
-
-	free(dco);
-	state->delayed_checkout = NULL;
-
-	return errs;
-}
-
-static int write_entry(struct cache_entry *ce,
-		       char *path, const struct checkout *state, int to_tempfile)
-{
-	unsigned int ce_mode_s_ifmt = ce->ce_mode & S_IFMT;
-	struct delayed_checkout *dco = state->delayed_checkout;
-	int fd, ret, fstat_done = 0;
-	char *new_blob;
-	struct strbuf buf = STRBUF_INIT;
-	unsigned long size;
-	ssize_t wrote;
-	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,
-								 &ce->oid);
-		if (filter &&
-		    !streaming_write_entry(ce, path, filter,
-					   state, to_tempfile,
-					   &fstat_done, &st))
-			goto finish;
-	}
-
-	switch (ce_mode_s_ifmt) {
-	case S_IFLNK:
-		new_blob = read_blob_entry(ce, &size);
-		if (!new_blob)
-			return error("unable to read sha1 file of %s (%s)",
-				     path, oid_to_hex(&ce->oid));
-
-		/*
-		 * We can't make a real symlink; write out a regular file entry
-		 * with the symlink destination as its contents.
-		 */
-		if (!has_symlinks || to_tempfile)
-			goto write_file_entry;
-
-		ret = symlink(new_blob, path);
-		free(new_blob);
-		if (ret)
-			return error_errno("unable to create symlink %s", path);
-		break;
-
-	case S_IFREG:
-		/*
-		 * We do not send the blob in case of a retry, so do not
-		 * bother reading it at all.
-		 */
-		if (dco && dco->state == CE_RETRY) {
-			new_blob = NULL;
-			size = 0;
-		} else {
-			new_blob = read_blob_entry(ce, &size);
-			if (!new_blob)
-				return error("unable to read sha1 file of %s (%s)",
-					     path, oid_to_hex(&ce->oid));
-		}
-
-		/*
-		 * Convert from git internal format to working tree format
-		 */
-		if (dco && dco->state != CE_NO_DELAY) {
-			ret = async_convert_to_working_tree(state->istate, ce->name, new_blob,
-							    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, &meta);
-
-		if (ret) {
-			free(new_blob);
-			new_blob = strbuf_detach(&buf, &newsize);
-			size = newsize;
-		}
-		/*
-		 * No "else" here as errors from convert are OK at this
-		 * point. If the error would have been fatal (e.g.
-		 * filter is required), then we would have died already.
-		 */
-
-	write_file_entry:
-		fd = open_output_fd(path, ce, to_tempfile);
-		if (fd < 0) {
-			free(new_blob);
-			return error_errno("unable to create file %s", path);
-		}
-
-		wrote = write_in_full(fd, new_blob, size);
-		if (!to_tempfile)
-			fstat_done = fstat_output(fd, state, &st);
-		close(fd);
-		free(new_blob);
-		if (wrote < 0)
-			return error("unable to write file %s", path);
-		break;
-
-	case S_IFGITLINK:
-		if (to_tempfile)
-			return error("cannot create temporary submodule %s", path);
-		if (mkdir(path, 0777) < 0)
-			return error("cannot create submodule directory %s", path);
-		sub = submodule_from_ce(ce);
-		if (sub)
-			return submodule_move_head(ce->name,
-				NULL, oid_to_hex(&ce->oid),
-				state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
-		break;
-
-	default:
-		return error("unknown file mode for %s in index", path);
-	}
-
-finish:
-	if (state->refresh_cache) {
-		assert(state->istate);
-		if (!fstat_done)
-			if (lstat(ce->name, &st) < 0)
-				return error_errno("unable to stat just-written file %s",
-						   ce->name);
-		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;
-	}
-delayed:
-	return 0;
-}
-
-/*
- * This is like 'lstat()', except it refuses to follow symlinks
- * in the path, after skipping "skiplen".
- */
-static int check_path(const char *path, int len, struct stat *st, int skiplen)
-{
-	const char *slash = path + len;
-
-	while (path < slash && *slash != '/')
-		slash--;
-	if (!has_dirs_only_path(path, slash - path, skiplen)) {
-		errno = ENOENT;
-		return -1;
-	}
-	return lstat(path, st);
-}
-
-static void mark_colliding_entries(const struct checkout *state,
-				   struct cache_entry *ce, struct stat *st)
-{
-	int i, trust_ino = check_stat;
-
-#if defined(GIT_WINDOWS_NATIVE) || defined(__CYGWIN__)
-	trust_ino = 0;
-#endif
-
-	ce->ce_flags |= CE_MATCHED;
-
-	for (i = 0; i < state->istate->cache_nr; i++) {
-		struct cache_entry *dup = state->istate->cache[i];
-
-		if (dup == ce)
-			break;
-
-		if (dup->ce_flags & (CE_MATCHED | CE_VALID | CE_SKIP_WORKTREE))
-			continue;
-
-		if ((trust_ino && !match_stat_data(&dup->ce_stat_data, st)) ||
-		    (!trust_ino && !fspathcmp(ce->name, dup->name))) {
-			dup->ce_flags |= CE_MATCHED;
-			break;
-		}
-	}
-}
-
-/*
- * Write the contents from ce out to the working tree.
- *
- * When topath[] is not NULL, instead of writing to the working tree
- * file named by ce, a temporary file is created by this function and
- * 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 *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);
-
-	strbuf_reset(&path);
-	strbuf_add(&path, state->base_dir, state->base_dir_len);
-	strbuf_add(&path, ce->name, ce_namelen(ce));
-
-	if (!check_path(path.buf, path.len, &st, state->base_dir_len)) {
-		const struct submodule *sub;
-		unsigned changed = ie_match_stat(state->istate, ce, &st,
-						 CE_MATCH_IGNORE_VALID | CE_MATCH_IGNORE_SKIP_WORKTREE);
-		/*
-		 * Needs to be checked before !changed returns early,
-		 * as the possibly empty directory was not changed
-		 */
-		sub = submodule_from_ce(ce);
-		if (sub) {
-			int err;
-			if (!is_submodule_populated_gently(ce->name, &err)) {
-				struct stat sb;
-				if (lstat(ce->name, &sb))
-					die(_("could not stat file '%s'"), ce->name);
-				if (!(st.st_mode & S_IFDIR))
-					unlink_or_warn(ce->name);
-
-				return submodule_move_head(ce->name,
-					NULL, oid_to_hex(&ce->oid), 0);
-			} else
-				return submodule_move_head(ce->name,
-					"HEAD", oid_to_hex(&ce->oid),
-					state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
-		}
-
-		if (!changed)
-			return 0;
-		if (!state->force) {
-			if (!state->quiet)
-				fprintf(stderr,
-					"%s already exists, no checkout\n",
-					path.buf);
-			return -1;
-		}
-
-		if (state->clone)
-			mark_colliding_entries(state, ce, &st);
-
-		/*
-		 * We unlink the old file, to get the new one with the
-		 * right permissions (including umask, which is nasty
-		 * to emulate by hand - much easier to let the system
-		 * just do the right thing)
-		 */
-		if (S_ISDIR(st.st_mode)) {
-			/* If it is a gitlink, leave it alone! */
-			if (S_ISGITLINK(ce->ce_mode))
-				return 0;
-			remove_subtree(&path);
-		} else if (unlink(path.buf))
-			return error_errno("unable to unlink old '%s'", path.buf);
-	} else if (state->not_new)
-		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));
-}