summaryrefslogtreecommitdiff
path: root/src/blob.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/blob.c')
-rw-r--r--src/blob.c175
1 files changed, 102 insertions, 73 deletions
diff --git a/src/blob.c b/src/blob.c
index 2e4d5f479..2c6d52800 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -60,10 +60,10 @@ int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *b
(error = git_odb_open_wstream(&stream, odb, len, GIT_OBJ_BLOB)) < 0)
return error;
- if ((error = stream->write(stream, buffer, len)) == 0)
- error = stream->finalize_write(oid, stream);
+ if ((error = git_odb_stream_write(stream, buffer, len)) == 0)
+ error = git_odb_stream_finalize_write(oid, stream);
- stream->free(stream);
+ git_odb_stream_free(stream);
return error;
}
@@ -80,12 +80,12 @@ static int write_file_stream(
return error;
if ((fd = git_futils_open_ro(path)) < 0) {
- stream->free(stream);
+ git_odb_stream_free(stream);
return -1;
}
while (!error && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) {
- error = stream->write(stream, buffer, read_len);
+ error = git_odb_stream_write(stream, buffer, read_len);
written += read_len;
}
@@ -97,36 +97,32 @@ static int write_file_stream(
}
if (!error)
- error = stream->finalize_write(oid, stream);
+ error = git_odb_stream_finalize_write(oid, stream);
- stream->free(stream);
+ git_odb_stream_free(stream);
return error;
}
static int write_file_filtered(
git_oid *oid,
+ git_off_t *size,
git_odb *odb,
const char *full_path,
- git_vector *filters)
+ git_filter_list *fl)
{
int error;
- git_buf source = GIT_BUF_INIT;
- git_buf dest = GIT_BUF_INIT;
+ git_buf tgt = GIT_BUF_INIT;
- if ((error = git_futils_readbuffer(&source, full_path)) < 0)
- return error;
-
- error = git_filters_apply(&dest, &source, filters);
-
- /* Free the source as soon as possible. This can be big in memory,
- * and we don't want to ODB write to choke */
- git_buf_free(&source);
+ error = git_filter_list_apply_to_file(&tgt, fl, NULL, full_path);
/* Write the file to disk if it was properly filtered */
- if (!error)
- error = git_odb_write(oid, odb, dest.ptr, dest.size, GIT_OBJ_BLOB);
+ if (!error) {
+ *size = tgt.size;
+
+ error = git_odb_write(oid, odb, tgt.ptr, tgt.size, GIT_OBJ_BLOB);
+ }
- git_buf_free(&dest);
+ git_buf_free(&tgt);
return error;
}
@@ -152,45 +148,67 @@ static int write_symlink(
return error;
}
-static int blob_create_internal(git_oid *oid, git_repository *repo, const char *content_path, const char *hint_path, bool try_load_filters)
+int git_blob__create_from_paths(
+ git_oid *oid,
+ struct stat *out_st,
+ git_repository *repo,
+ const char *content_path,
+ const char *hint_path,
+ mode_t hint_mode,
+ bool try_load_filters)
{
int error;
struct stat st;
git_odb *odb = NULL;
git_off_t size;
+ mode_t mode;
+ git_buf path = GIT_BUF_INIT;
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;
+ if (!content_path) {
+ if (git_repository__ensure_not_bare(repo, "create blob from file") < 0)
+ return GIT_EBAREREPO;
+
+ if (git_buf_joinpath(
+ &path, git_repository_workdir(repo), hint_path) < 0)
+ return -1;
+
+ content_path = path.ptr;
+ }
+
+ if ((error = git_path_lstat(content_path, &st)) < 0 ||
+ (error = git_repository_odb(&odb, repo)) < 0)
+ goto done;
+
+ if (out_st)
+ memcpy(out_st, &st, sizeof(st));
size = st.st_size;
+ mode = hint_mode ? hint_mode : st.st_mode;
- if (S_ISLNK(st.st_mode)) {
+ if (S_ISLNK(mode)) {
error = write_symlink(oid, odb, content_path, (size_t)size);
} else {
- git_vector write_filters = GIT_VECTOR_INIT;
- int filter_count = 0;
+ git_filter_list *fl = NULL;
- if (try_load_filters) {
+ 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);
- }
+ error = git_filter_list_load(
+ &fl, repo, NULL, 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) {
+ if (error < 0)
+ /* well, that didn't work */;
+ else if (fl == NULL)
/* 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 {
+ else {
/* We need to apply one or more filters */
- error = write_file_filtered(oid, odb, content_path, &write_filters);
- }
+ error = write_file_filtered(oid, &size, odb, content_path, fl);
- git_filters_free(&write_filters);
+ git_filter_list_free(fl);
+ }
/*
* TODO: eventually support streaming filtered files, for files
@@ -207,34 +225,21 @@ static int blob_create_internal(git_oid *oid, git_repository *repo, const char *
*/
}
+done:
+ git_odb_free(odb);
+ git_buf_free(&path);
+
return error;
}
-int git_blob_create_fromworkdir(git_oid *oid, git_repository *repo, const char *path)
+int git_blob_create_fromworkdir(
+ git_oid *oid, git_repository *repo, const char *path)
{
- git_buf full_path = GIT_BUF_INIT;
- const char *workdir;
- int error;
-
- if ((error = git_repository__ensure_not_bare(repo, "create blob from file")) < 0)
- return error;
-
- workdir = git_repository_workdir(repo);
-
- if (git_buf_joinpath(&full_path, workdir, path) < 0) {
- git_buf_free(&full_path);
- return -1;
- }
-
- error = blob_create_internal(
- oid, repo, git_buf_cstr(&full_path),
- git_buf_cstr(&full_path) + strlen(workdir), true);
-
- git_buf_free(&full_path);
- return error;
+ return git_blob__create_from_paths(oid, NULL, repo, NULL, path, 0, true);
}
-int git_blob_create_fromdisk(git_oid *oid, git_repository *repo, const char *path)
+int git_blob_create_fromdisk(
+ git_oid *oid, git_repository *repo, const char *path)
{
int error;
git_buf full_path = GIT_BUF_INIT;
@@ -251,8 +256,8 @@ int git_blob_create_fromdisk(git_oid *oid, git_repository *repo, const char *pat
if (workdir && !git__prefixcmp(hintpath, workdir))
hintpath += strlen(workdir);
- error = blob_create_internal(
- oid, repo, git_buf_cstr(&full_path), hintpath, true);
+ error = git_blob__create_from_paths(
+ oid, NULL, repo, git_buf_cstr(&full_path), hintpath, 0, true);
git_buf_free(&full_path);
return error;
@@ -272,17 +277,14 @@ int git_blob_create_fromchunks(
git_filebuf file = GIT_FILEBUF_INIT;
git_buf path = GIT_BUF_INIT;
- if (git_buf_join_n(
- &path, '/', 3,
- git_repository_path(repo),
- GIT_OBJECTS_DIR,
- "streamed") < 0)
- goto cleanup;
+ if (git_buf_joinpath(
+ &path, git_repository_path(repo), GIT_OBJECTS_DIR "streamed") < 0)
+ goto cleanup;
content = git__malloc(BUFFER_SIZE);
GITERR_CHECK_ALLOC(content);
- if (git_filebuf_open(&file, git_buf_cstr(&path), GIT_FILEBUF_TEMPORARY) < 0)
+ if (git_filebuf_open(&file, git_buf_cstr(&path), GIT_FILEBUF_TEMPORARY, 0666) < 0)
goto cleanup;
while (1) {
@@ -303,7 +305,8 @@ int git_blob_create_fromchunks(
if (git_filebuf_flush(&file) < 0)
goto cleanup;
- error = blob_create_internal(oid, repo, file.path_lock, hintpath, hintpath != NULL);
+ error = git_blob__create_from_paths(
+ oid, NULL, repo, file.path_lock, hintpath, 0, hintpath != NULL);
cleanup:
git_buf_free(&path);
@@ -318,8 +321,34 @@ int git_blob_is_binary(git_blob *blob)
assert(blob);
- content.ptr = blob->odb_object->buffer;
- content.size = min(blob->odb_object->cached.size, 4000);
+ content.ptr = blob->odb_object->buffer;
+ content.size = min(blob->odb_object->cached.size, 4000);
+ content.asize = 0;
return git_buf_text_is_binary(&content);
}
+
+int git_blob_filtered_content(
+ git_buf *out,
+ git_blob *blob,
+ const char *path,
+ int check_for_binary_data)
+{
+ int error = 0;
+ git_filter_list *fl = NULL;
+
+ assert(blob && path && out);
+
+ if (check_for_binary_data && git_blob_is_binary(blob))
+ return 0;
+
+ if (!(error = git_filter_list_load(
+ &fl, git_blob_owner(blob), blob, path, GIT_FILTER_TO_WORKTREE))) {
+
+ error = git_filter_list_apply_to_blob(out, fl, blob);
+
+ git_filter_list_free(fl);
+ }
+
+ return error;
+}