예제 #1
0
int git_futils_mmap_ro_file(git_map *out, const char *path)
{
	git_file fd = git_futils_open_ro(path);
	git_off_t len;
	int result;

	if (fd < 0)
		return fd;

	if ((len = git_futils_filesize(fd)) < 0) {
		result = -1;
		goto out;
	}

	if (!git__is_sizet(len)) {
		giterr_set(GITERR_OS, "file `%s` too large to mmap", path);
		result = -1;
		goto out;
	}

	result = git_futils_mmap_ro(out, fd, 0, (size_t)len);
out:
	p_close(fd);
	return result;
}
예제 #2
0
파일: blob.c 프로젝트: brodie/libgit2
static int write_file_stream(
	git_oid *oid, git_odb *odb, const char *path, git_off_t file_size)
{
	int fd, error;
	char buffer[4096];
	git_odb_stream *stream = NULL;
	ssize_t read_len = -1, written = 0;

	if ((error = git_odb_open_wstream(
			&stream, odb, (size_t)file_size, GIT_OBJ_BLOB)) < 0)
		return error;

	if ((fd = git_futils_open_ro(path)) < 0) {
		git_odb_stream_free(stream);
		return -1;
	}

	while (!error && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) {
		error = git_odb_stream_write(stream, buffer, read_len);
		written += read_len;
	}

	p_close(fd);

	if (written != file_size || read_len < 0) {
		giterr_set(GITERR_OS, "Failed to read file into stream");
		error = -1;
	}

	if (!error)
		error = git_odb_stream_finalize_write(oid, stream);

	git_odb_stream_free(stream);
	return error;
}
예제 #3
0
파일: odb_loose.c 프로젝트: csware/libgit2
static int read_header_loose(git_rawobj *out, git_buf *loc)
{
	unsigned char obj[1024];
	int fd, obj_len, error;

	assert(out && loc);

	if (git_buf_oom(loc))
		return -1;

	out->data = NULL;

	if ((error = fd = git_futils_open_ro(loc->ptr)) < 0 ||
		(error = obj_len = p_read(fd, obj, sizeof(obj))) < 0)
		goto done;

	if (!is_zlib_compressed_data(obj, (size_t)obj_len))
		error = read_header_loose_packlike(out, obj, (size_t)obj_len);
	else
		error = read_header_loose_standard(out, obj, (size_t)obj_len);

	if (!error && !git_object_typeisloose(out->type)) {
		giterr_set(GITERR_ZLIB, "failed to read loose object header");
		error = -1;
		goto done;
	}

done:
	if (fd >= 0)
		p_close(fd);
	return error;
}
예제 #4
0
static int diff_file_content_load_workdir_file(
	git_diff_file_content *fc,
	git_buf *path,
	git_diff_options *diff_opts)
{
	int error = 0;
	git_filter_list *fl = NULL;
	git_file fd = git_futils_open_ro(git_buf_cstr(path));
	git_buf raw = GIT_BUF_INIT;

	if (fd < 0)
		return fd;

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

	if ((diff_opts->flags & GIT_DIFF_SHOW_BINARY) == 0 &&
		diff_file_content_binary_by_size(fc))
		goto cleanup;

	if ((error = git_filter_list_load(
			&fl, fc->repo, NULL, fc->file->path,
			GIT_FILTER_TO_ODB, GIT_FILTER_ALLOW_UNSAFE)) < 0)
		goto cleanup;

	/* if there are no filters, try to mmap the file */
	if (fl == NULL) {
		if (!(error = git_futils_mmap_ro(
				&fc->map, fd, 0, (size_t)fc->file->size))) {
			fc->flags |= GIT_DIFF_FLAG__UNMAP_DATA;
			goto cleanup;
		}

		/* if mmap failed, fall through to try readbuffer below */
		giterr_clear();
	}

	if (!(error = git_futils_readbuffer_fd(&raw, fd, (size_t)fc->file->size))) {
		git_buf out = GIT_BUF_INIT;

		error = git_filter_list_apply_to_data(&out, fl, &raw);

		if (out.ptr != raw.ptr)
			git_buf_dispose(&raw);

		if (!error) {
			fc->map.len  = out.size;
			fc->map.data = out.ptr;
			fc->flags |= GIT_DIFF_FLAG__FREE_DATA;
		}
	}

cleanup:
	git_filter_list_free(fl);
	p_close(fd);

	return error;
}
예제 #5
0
파일: diff_file.c 프로젝트: 0CV0/libgit2
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;
}
예제 #6
0
파일: fileops.c 프로젝트: 0CV0/libgit2
int git_futils_readbuffer_updated(
	git_buf *buf, const char *path, time_t *mtime, size_t *size, int *updated)
{
	git_file fd;
	struct stat st;
	bool changed = false;

	assert(buf && path && *path);

	if (updated != NULL)
		*updated = 0;

	if ((fd = git_futils_open_ro(path)) < 0)
		return fd;

	if (p_fstat(fd, &st) < 0 || S_ISDIR(st.st_mode) || !git__is_sizet(st.st_size+1)) {
		p_close(fd);
		giterr_set(GITERR_OS, "Invalid regular file stat for '%s'", path);
		return -1;
	}

	/*
	 * If we were given a time and/or a size, we only want to read the file
	 * if it has been modified.
	 */
	if (size && *size != (size_t)st.st_size)
		changed = true;
	if (mtime && *mtime != st.st_mtime)
		changed = true;
	if (!size && !mtime)
		changed = true;

	if (!changed) {
		p_close(fd);
		return 0;
	}

	if (mtime != NULL)
		*mtime = st.st_mtime;
	if (size != NULL)
		*size = (size_t)st.st_size;

	if (git_futils_readbuffer_fd(buf, fd, (size_t)st.st_size) < 0) {
		p_close(fd);
		return -1;
	}

	p_close(fd);

	if (updated != NULL)
		*updated = 1;

	return 0;
}
예제 #7
0
int git_odb_hashfile(git_oid *out, const char *path, git_otype type)
{
	git_off_t size;
	int result, fd = git_futils_open_ro(path);
	if (fd < 0)
		return fd;

	if ((size = git_futils_filesize(fd)) < 0 || !git__is_sizet(size)) {
		giterr_set(GITERR_OS, "File size overflow for 32-bit systems");
		p_close(fd);
		return -1;
	}

	result = git_odb__hashfd(out, fd, (size_t)size, type);
	p_close(fd);
	return result;
}
예제 #8
0
int git_odb__hashlink(git_oid *out, const char *path)
{
	struct stat st;
	git_off_t size;
	int result;

	if (git_path_lstat(path, &st) < 0)
		return -1;

	size = st.st_size;

	if (!git__is_sizet(size)) {
		giterr_set(GITERR_OS, "File size overflow for 32-bit systems");
		return -1;
	}

	if (S_ISLNK(st.st_mode)) {
		char *link_data;
		ssize_t read_len;

		link_data = (char*) git__malloc((size_t)(size + 1));
		GITERR_CHECK_ALLOC(link_data);

		read_len = p_readlink(path, link_data, (size_t)size);
		link_data[size] = '\0';
		if (read_len != (ssize_t)size) {
			giterr_set(GITERR_OS, "Failed to read symlink data for '%s'", path);
			git__free(link_data);
			return -1;
		}

		result = git_odb_hash(out, link_data, (size_t)size, GIT_OBJ_BLOB);
		git__free(link_data);
	} else {
		int fd = git_futils_open_ro(path);
		if (fd < 0)
			return -1;
		result = git_odb__hashfd(out, fd, (size_t)size, GIT_OBJ_BLOB);
		p_close(fd);
	}

	return result;
}
예제 #9
0
파일: hashsig.c 프로젝트: da-x/gitlib
int git_hashsig_create_fromfile(
    git_hashsig **out,
    const char *path,
    git_hashsig_option_t opts)
{
    char buf[4096];
    ssize_t buflen = 0;
    int error = 0, fd;
    hashsig_in_progress prog = HASHSIG_IN_PROGRESS_INIT;
    git_hashsig *sig = hashsig_alloc(opts);
    GITERR_CHECK_ALLOC(sig);

    if ((fd = git_futils_open_ro(path)) < 0) {
        git__free(sig);
        return fd;
    }

    while (!error) {
        if ((buflen = p_read(fd, buf, sizeof(buf))) <= 0) {
            if ((error = (int)buflen) < 0)
                giterr_set(GITERR_OS,
                           "Read error on '%s' calculating similarity hashes", path);
            break;
        }

        error = hashsig_add_hashes(sig, buf, buflen, &prog);
    }

    p_close(fd);

    if (!error)
        error = hashsig_finalize_hashes(sig);

    if (!error)
        *out = sig;
    else
        git_hashsig_free(sig);

    return error;
}
예제 #10
0
파일: blob.c 프로젝트: ileitch/meanie
static int write_file_stream(
	git_oid *oid, git_odb *odb, const char *path, git_off_t file_size)
{
	int fd, error;
	char buffer[4096];
	git_odb_stream *stream = NULL;

	if ((error = git_odb_open_wstream(
			&stream, odb, (size_t)file_size, GIT_OBJ_BLOB)) < 0)
		return error;

	if ((fd = git_futils_open_ro(path)) < 0) {
		stream->free(stream);
		return -1;
	}

	while (!error && file_size > 0) {
		ssize_t read_len = p_read(fd, buffer, sizeof(buffer));

		if (read_len < 0) {
			giterr_set(
				GITERR_OS, "Failed to create blob. Can't read whole file");
			error = -1;
		}
		else if (!(error = stream->write(stream, buffer, read_len)))
			file_size -= read_len;
	}

	p_close(fd);

	if (!error)
		error = stream->finalize_write(oid, stream);

	stream->free(stream);
	return error;
}
예제 #11
0
int git_futils_readbuffer_updated(
	git_buf *out, const char *path, git_oid *checksum, int *updated)
{
	int error;
	git_file fd;
	struct stat st;
	git_buf buf = GIT_BUF_INIT;
	git_oid checksum_new;

	assert(out && path && *path);

	if (updated != NULL)
		*updated = 0;

	if (p_stat(path, &st) < 0)
		return git_path_set_error(errno, path, "stat");


	if (S_ISDIR(st.st_mode)) {
		giterr_set(GITERR_INVALID, "requested file is a directory");
		return GIT_ENOTFOUND;
	}

	if (!git__is_sizet(st.st_size+1)) {
		giterr_set(GITERR_OS, "invalid regular file stat for '%s'", path);
		return -1;
	}

	if ((fd = git_futils_open_ro(path)) < 0)
		return fd;

	if (git_futils_readbuffer_fd(&buf, fd, (size_t)st.st_size) < 0) {
		p_close(fd);
		return -1;
	}

	p_close(fd);

	if (checksum) {
		if ((error = git_hash_buf(&checksum_new, buf.ptr, buf.size)) < 0) {
			git_buf_free(&buf);
			return error;
		}

		/*
		 * If we were given a checksum, we only want to use it if it's different
		 */
		if (!git_oid__cmp(checksum, &checksum_new)) {
			git_buf_free(&buf);
			if (updated)
				*updated = 0;

			return 0;
		}

		git_oid_cpy(checksum, &checksum_new);
	}

	/*
	 * If we're here, the file did change, or the user didn't have an old version
	 */
	if (updated != NULL)
		*updated = 1;

	git_buf_swap(out, &buf);
	git_buf_free(&buf);

	return 0;
}
예제 #12
0
int git_attr_file__load(
	git_attr_file **out,
	git_repository *repo,
	git_attr_file_entry *entry,
	git_attr_file_source source,
	git_attr_file_parser parser)
{
	int error = 0;
	git_blob *blob = NULL;
	git_buf content = GIT_BUF_INIT;
	const char *data = NULL;
	git_attr_file *file;
	struct stat st;

	*out = NULL;

	switch (source) {
	case GIT_ATTR_FILE__IN_MEMORY:
		/* in-memory attribute file doesn't need data */
		break;
	case GIT_ATTR_FILE__FROM_INDEX: {
		git_oid id;

		if ((error = attr_file_oid_from_index(&id, repo, entry->path)) < 0 ||
			(error = git_blob_lookup(&blob, repo, &id)) < 0)
			return error;

		data = git_blob_rawcontent(blob);
		break;
	}
	case GIT_ATTR_FILE__FROM_FILE: {
		int fd;

		if (p_stat(entry->fullpath, &st) < 0)
			return git_path_set_error(errno, entry->fullpath, "stat");
		if (S_ISDIR(st.st_mode))
			return GIT_ENOTFOUND;

		/* For open or read errors, return ENOTFOUND to skip item */
		/* TODO: issue warning when warning API is available */

		if ((fd = git_futils_open_ro(entry->fullpath)) < 0)
			return GIT_ENOTFOUND;

		error = git_futils_readbuffer_fd(&content, fd, (size_t)st.st_size);
		p_close(fd);

		if (error < 0)
			return GIT_ENOTFOUND;

		data = content.ptr;
		break;
	}
	default:
		giterr_set(GITERR_INVALID, "Unknown file source %d", source);
		return -1;
	}

	if ((error = git_attr_file__new(&file, entry, source)) < 0)
		goto cleanup;

	if (parser && (error = parser(repo, file, data)) < 0) {
		git_attr_file__free(file);
		goto cleanup;
	}

	/* write cache breaker */
	if (source == GIT_ATTR_FILE__FROM_INDEX)
		git_oid_cpy(&file->cache_data.oid, git_blob_id(blob));
	else if (source == GIT_ATTR_FILE__FROM_FILE)
		git_futils_filestamp_set_from_stat(&file->cache_data.stamp, &st);
	/* else always cacheable */

	*out = file;

cleanup:
	git_blob_free(blob);
	git_buf_free(&content);

	return error;
}
예제 #13
0
int git_attr_file__load(
	git_attr_file **out,
	git_repository *repo,
	git_attr_session *attr_session,
	git_attr_file_entry *entry,
	git_attr_file_source source,
	git_attr_file_parser parser)
{
	int error = 0;
	git_blob *blob = NULL;
	git_buf content = GIT_BUF_INIT;
	git_attr_file *file;
	struct stat st;
	bool nonexistent = false;

	*out = NULL;

	switch (source) {
	case GIT_ATTR_FILE__IN_MEMORY:
		/* in-memory attribute file doesn't need data */
		break;
	case GIT_ATTR_FILE__FROM_INDEX: {
		git_oid id;

		if ((error = attr_file_oid_from_index(&id, repo, entry->path)) < 0 ||
			(error = git_blob_lookup(&blob, repo, &id)) < 0)
			return error;

		/* Do not assume that data straight from the ODB is NULL-terminated;
		 * copy the contents of a file to a buffer to work on */
		git_buf_put(&content, git_blob_rawcontent(blob), git_blob_rawsize(blob));
		break;
	}
	case GIT_ATTR_FILE__FROM_FILE: {
		int fd = -1;

		/* For open or read errors, pretend that we got ENOTFOUND. */
		/* TODO: issue warning when warning API is available */

		if (p_stat(entry->fullpath, &st) < 0 ||
			S_ISDIR(st.st_mode) ||
			(fd = git_futils_open_ro(entry->fullpath)) < 0 ||
			(error = git_futils_readbuffer_fd(&content, fd, (size_t)st.st_size)) < 0)
			nonexistent = true;

		if (fd >= 0)
			p_close(fd);

		break;
	}
	default:
		giterr_set(GITERR_INVALID, "Unknown file source %d", source);
		return -1;
	}

	if ((error = git_attr_file__new(&file, entry, source)) < 0)
		goto cleanup;

	/* store the key of the attr_reader; don't bother with cache
	 * invalidation during the same attr reader session.
	 */
	if (attr_session)
		file->session_key = attr_session->key;

	if (parser && (error = parser(repo, file, git_buf_cstr(&content))) < 0) {
		git_attr_file__free(file);
		goto cleanup;
	}

	/* write cache breakers */
	if (nonexistent)
		file->nonexistent = 1;
	else if (source == GIT_ATTR_FILE__FROM_INDEX)
		git_oid_cpy(&file->cache_data.oid, git_blob_id(blob));
	else if (source == GIT_ATTR_FILE__FROM_FILE)
		git_futils_filestamp_set_from_stat(&file->cache_data.stamp, &st);
	/* else always cacheable */

	*out = file;

cleanup:
	git_blob_free(blob);
	git_buf_free(&content);

	return error;
}
예제 #14
0
파일: fileops.c 프로젝트: ileitch/meanie
int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime, int *updated)
{
	git_file fd;
	size_t len;
	struct stat st;

	assert(buf && path && *path);

	if (updated != NULL)
		*updated = 0;

	if ((fd = git_futils_open_ro(path)) < 0)
		return fd;

	if (p_fstat(fd, &st) < 0 || S_ISDIR(st.st_mode) || !git__is_sizet(st.st_size+1)) {
		p_close(fd);
		giterr_set(GITERR_OS, "Invalid regular file stat for '%s'", path);
		return -1;
	}

	/*
	 * If we were given a time, we only want to read the file if it
	 * has been modified.
	 */
	if (mtime != NULL && *mtime >= st.st_mtime) {
		p_close(fd);
		return 0;
	}

	if (mtime != NULL)
		*mtime = st.st_mtime;

	len = (size_t) st.st_size;

	git_buf_clear(buf);

	if (git_buf_grow(buf, len + 1) < 0) {
		p_close(fd);
		return -1;
	}

	buf->ptr[len] = '\0';

	while (len > 0) {
		ssize_t read_size = p_read(fd, buf->ptr, len);

		if (read_size < 0) {
			p_close(fd);
			giterr_set(GITERR_OS, "Failed to read descriptor for '%s'", path);
			return -1;
		}

		len -= read_size;
		buf->size += read_size;
	}

	p_close(fd);

	if (updated != NULL)
		*updated = 1;

	return 0;
}