Пример #1
0
static int blob_create_internal(git_oid *oid, git_repository *repo, const char *content_path, const char *hint_path, bool try_load_filters)
{
	int error;
	struct stat st;
	git_odb *odb = NULL;
	git_off_t size;

	assert(hint_path || !try_load_filters);

	if ((error = git_path_lstat(content_path, &st)) < 0 || (error = git_repository_odb__weakptr(&odb, repo)) < 0)
		return error;

	size = st.st_size;

	if (S_ISLNK(st.st_mode)) {
		error = write_symlink(oid, odb, content_path, (size_t)size);
	} else {
		git_vector write_filters = GIT_VECTOR_INIT;
		int filter_count = 0;

		if (try_load_filters) {
			/* Load the filters for writing this file to the ODB */
			filter_count = git_filters_load(
				&write_filters, repo, hint_path, GIT_FILTER_TO_ODB);
		}

		if (filter_count < 0) {
			/* Negative value means there was a critical error */
			error = filter_count;
		} else if (filter_count == 0) {
			/* No filters need to be applied to the document: we can stream
			 * directly from disk */
			error = write_file_stream(oid, odb, content_path, size);
		} else {
			/* We need to apply one or more filters */
			error = write_file_filtered(oid, odb, content_path, &write_filters);
		}

		git_filters_free(&write_filters);

		/*
		 * TODO: eventually support streaming filtered files, for files
		 * which are bigger than a given threshold. This is not a priority
		 * because applying a filter in streaming mode changes the final
		 * size of the blob, and without knowing its final size, the blob
		 * cannot be written in stream mode to the ODB.
		 *
		 * The plan is to do streaming writes to a tempfile on disk and then
		 * opening streaming that file to the ODB, using
		 * `write_file_stream`.
		 *
		 * CAREFULLY DESIGNED APIS YO
		 */
	}

	return error;
}
Пример #2
0
static int diff_file_content_load_workdir_file(
	git_diff_file_content *fc, git_buf *path)
{
	int error = 0;
	git_vector filters = GIT_VECTOR_INIT;
	git_buf raw = GIT_BUF_INIT, filtered = GIT_BUF_INIT;
	git_file fd = git_futils_open_ro(git_buf_cstr(path));

	if (fd < 0)
		return fd;

	if (!fc->file->size &&
		!(fc->file->size = git_futils_filesize(fd)))
		goto cleanup;

	if (diff_file_content_binary_by_size(fc))
		goto cleanup;

	if ((error = git_filters_load(
			&filters, fc->repo, fc->file->path, GIT_FILTER_TO_ODB)) < 0)
		goto cleanup;
	/* error >= is a filter count */

	if (error == 0) {
		if (!(error = git_futils_mmap_ro(
				&fc->map, fd, 0, (size_t)fc->file->size)))
			fc->flags |= GIT_DIFF_FLAG__UNMAP_DATA;
		else /* fall through to try readbuffer below */
			giterr_clear();
	}

	if (error != 0) {
		error = git_futils_readbuffer_fd(&raw, fd, (size_t)fc->file->size);
		if (error < 0)
			goto cleanup;

		if (!filters.length)
			git_buf_swap(&filtered, &raw);
		else
			error = git_filters_apply(&filtered, &raw, &filters);

		if (!error) {
			fc->map.len  = git_buf_len(&filtered);
			fc->map.data = git_buf_detach(&filtered);
			fc->flags |= GIT_DIFF_FLAG__FREE_DATA;
		}

		git_buf_free(&raw);
		git_buf_free(&filtered);
	}

cleanup:
	git_filters_free(&filters);
	p_close(fd);

	return error;
}
static int blob_content_to_file(
	git_blob *blob,
	const char *path,
	mode_t entry_filemode,
	git_checkout_opts *opts)
{
	int error = -1, nb_filters = 0;
	mode_t file_mode = opts->file_mode;
	bool dont_free_filtered = false;
	git_buf unfiltered = GIT_BUF_INIT, filtered = GIT_BUF_INIT;
	git_vector filters = GIT_VECTOR_INIT;

	if (opts->disable_filters ||
		(nb_filters = git_filters_load(
			&filters,
			git_object_owner((git_object *)blob),
			path,
			GIT_FILTER_TO_WORKTREE)) == 0) {

		/* Create a fake git_buf from the blob raw data... */
		filtered.ptr = blob->odb_object->raw.data;
		filtered.size = blob->odb_object->raw.len;

		/* ... and make sure it doesn't get unexpectedly freed */
		dont_free_filtered = true;
	}

	if (nb_filters < 0)
		return nb_filters;

	if (nb_filters > 0)	 {
		if ((error = git_blob__getbuf(&unfiltered, blob)) < 0)
			goto cleanup;

		if ((error = git_filters_apply(&filtered, &unfiltered, &filters)) < 0)
			goto cleanup;
	}

	/* Allow overriding of file mode */
	if (!file_mode)
		file_mode = entry_filemode;

	error = buffer_to_file(&filtered, path, opts->dir_mode, opts->file_open_flags, file_mode);

cleanup:
	git_filters_free(&filters);
	git_buf_free(&unfiltered);
	if (!dont_free_filtered)
		git_buf_free(&filtered);

	return error;
}