in src/attr_file.c [102:226]
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,
bool allow_macros)
{
int error = 0;
git_tree *tree = NULL;
git_tree_entry *tree_entry = NULL;
git_blob *blob = NULL;
git_buf content = GIT_BUF_INIT;
const char *content_str;
git_attr_file *file;
struct stat st;
bool nonexistent = false;
int bom_offset;
git_bom_t bom;
git_oid id;
git_object_size_t blobsize;
*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: {
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 */
blobsize = git_blob_rawsize(blob);
GIT_ERROR_CHECK_BLOBSIZE(blobsize);
git_buf_put(&content, git_blob_rawcontent(blob), (size_t)blobsize);
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;
}
case GIT_ATTR_FILE__FROM_HEAD: {
if ((error = git_repository_head_tree(&tree, repo)) < 0 ||
(error = git_tree_entry_bypath(&tree_entry, tree, entry->path)) < 0 ||
(error = git_blob_lookup(&blob, repo, git_tree_entry_id(tree_entry))) < 0)
goto cleanup;
/*
* Do not assume that data straight from the ODB is NULL-terminated;
* copy the contents of a file to a buffer to work on.
*/
blobsize = git_blob_rawsize(blob);
GIT_ERROR_CHECK_BLOBSIZE(blobsize);
if ((error = git_buf_put(&content,
git_blob_rawcontent(blob), (size_t)blobsize)) < 0)
goto cleanup;
break;
}
default:
git_error_set(GIT_ERROR_INVALID, "unknown file source %d", source);
return -1;
}
if ((error = git_attr_file__new(&file, entry, source)) < 0)
goto cleanup;
/* advance over a UTF8 BOM */
content_str = git_buf_cstr(&content);
bom_offset = git_buf_text_detect_bom(&bom, &content);
if (bom == GIT_BOM_UTF8)
content_str += bom_offset;
/* 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, content_str, allow_macros)) < 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_HEAD)
git_oid_cpy(&file->cache_data.oid, git_tree_id(tree));
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_tree_entry_free(tree_entry);
git_tree_free(tree);
git_buf_dispose(&content);
return error;
}