]>
git.proxmox.com Git - libgit2.git/blob - src/blob.c
2 * Copyright (C) 2009-2012 the libgit2 contributors
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
8 #include "git2/common.h"
9 #include "git2/object.h"
10 #include "git2/repository.h"
16 const void *git_blob_rawcontent(git_blob
*blob
)
19 return blob
->odb_object
->raw
.data
;
22 git_off_t
git_blob_rawsize(git_blob
*blob
)
25 return (git_off_t
)blob
->odb_object
->raw
.len
;
28 int git_blob__getbuf(git_buf
*buffer
, git_blob
*blob
)
31 buffer
, blob
->odb_object
->raw
.data
, blob
->odb_object
->raw
.len
);
34 void git_blob__free(git_blob
*blob
)
36 git_odb_object_free(blob
->odb_object
);
40 int git_blob__parse(git_blob
*blob
, git_odb_object
*odb_obj
)
43 git_cached_obj_incref((git_cached_obj
*)odb_obj
);
44 blob
->odb_object
= odb_obj
;
48 int git_blob_create_frombuffer(git_oid
*oid
, git_repository
*repo
, const void *buffer
, size_t len
)
52 git_odb_stream
*stream
;
54 if ((error
= git_repository_odb__weakptr(&odb
, repo
)) < 0 ||
55 (error
= git_odb_open_wstream(&stream
, odb
, len
, GIT_OBJ_BLOB
)) < 0)
58 if ((error
= stream
->write(stream
, buffer
, len
)) == 0)
59 error
= stream
->finalize_write(oid
, stream
);
65 static int write_file_stream(
66 git_oid
*oid
, git_odb
*odb
, const char *path
, git_off_t file_size
)
70 git_odb_stream
*stream
= NULL
;
71 ssize_t read_len
= -1, written
= 0;
73 if ((error
= git_odb_open_wstream(
74 &stream
, odb
, (size_t)file_size
, GIT_OBJ_BLOB
)) < 0)
77 if ((fd
= git_futils_open_ro(path
)) < 0) {
82 while (!error
&& (read_len
= p_read(fd
, buffer
, sizeof(buffer
))) > 0) {
83 error
= stream
->write(stream
, buffer
, read_len
);
89 if (written
!= file_size
|| read_len
< 0) {
90 giterr_set(GITERR_OS
, "Failed to read file into stream");
95 error
= stream
->finalize_write(oid
, stream
);
101 static int write_file_filtered(
104 const char *full_path
,
108 git_buf source
= GIT_BUF_INIT
;
109 git_buf dest
= GIT_BUF_INIT
;
111 if ((error
= git_futils_readbuffer(&source
, full_path
)) < 0)
114 error
= git_filters_apply(&dest
, &source
, filters
);
116 /* Free the source as soon as possible. This can be big in memory,
117 * and we don't want to ODB write to choke */
118 git_buf_free(&source
);
120 /* Write the file to disk if it was properly filtered */
122 error
= git_odb_write(oid
, odb
, dest
.ptr
, dest
.size
, GIT_OBJ_BLOB
);
128 static int write_symlink(
129 git_oid
*oid
, git_odb
*odb
, const char *path
, size_t link_size
)
135 link_data
= git__malloc(link_size
);
136 GITERR_CHECK_ALLOC(link_data
);
138 read_len
= p_readlink(path
, link_data
, link_size
);
139 if (read_len
!= (ssize_t
)link_size
) {
140 giterr_set(GITERR_OS
, "Failed to create blob. Can't read symlink '%s'", path
);
141 git__free(link_data
);
145 error
= git_odb_write(oid
, odb
, (void *)link_data
, link_size
, GIT_OBJ_BLOB
);
146 git__free(link_data
);
150 static int blob_create_internal(git_oid
*oid
, git_repository
*repo
, const char *content_path
, const char *hint_path
, bool try_load_filters
)
157 assert(hint_path
|| !try_load_filters
);
159 if ((error
= git_path_lstat(content_path
, &st
)) < 0 || (error
= git_repository_odb__weakptr(&odb
, repo
)) < 0)
164 if (S_ISLNK(st
.st_mode
)) {
165 error
= write_symlink(oid
, odb
, content_path
, (size_t)size
);
167 git_vector write_filters
= GIT_VECTOR_INIT
;
168 int filter_count
= 0;
170 if (try_load_filters
) {
171 /* Load the filters for writing this file to the ODB */
172 filter_count
= git_filters_load(
173 &write_filters
, repo
, hint_path
, GIT_FILTER_TO_ODB
);
176 if (filter_count
< 0) {
177 /* Negative value means there was a critical error */
178 error
= filter_count
;
179 } else if (filter_count
== 0) {
180 /* No filters need to be applied to the document: we can stream
181 * directly from disk */
182 error
= write_file_stream(oid
, odb
, content_path
, size
);
184 /* We need to apply one or more filters */
185 error
= write_file_filtered(oid
, odb
, content_path
, &write_filters
);
188 git_filters_free(&write_filters
);
191 * TODO: eventually support streaming filtered files, for files
192 * which are bigger than a given threshold. This is not a priority
193 * because applying a filter in streaming mode changes the final
194 * size of the blob, and without knowing its final size, the blob
195 * cannot be written in stream mode to the ODB.
197 * The plan is to do streaming writes to a tempfile on disk and then
198 * opening streaming that file to the ODB, using
199 * `write_file_stream`.
201 * CAREFULLY DESIGNED APIS YO
208 int git_blob_create_fromworkdir(git_oid
*oid
, git_repository
*repo
, const char *path
)
210 git_buf full_path
= GIT_BUF_INIT
;
214 if ((error
= git_repository__ensure_not_bare(repo
, "create blob from file")) < 0)
217 workdir
= git_repository_workdir(repo
);
219 if (git_buf_joinpath(&full_path
, workdir
, path
) < 0) {
220 git_buf_free(&full_path
);
224 error
= blob_create_internal(oid
, repo
, git_buf_cstr(&full_path
), git_buf_cstr(&full_path
), true);
226 git_buf_free(&full_path
);
230 int git_blob_create_fromdisk(git_oid
*oid
, git_repository
*repo
, const char *path
)
233 git_buf full_path
= GIT_BUF_INIT
;
235 if ((error
= git_path_prettify(&full_path
, path
, NULL
)) < 0) {
236 git_buf_free(&full_path
);
240 error
= blob_create_internal(oid
, repo
, git_buf_cstr(&full_path
), git_buf_cstr(&full_path
), true);
242 git_buf_free(&full_path
);
246 #define BUFFER_SIZE 4096
248 int git_blob_create_fromchunks(
250 git_repository
*repo
,
251 const char *hintpath
,
252 int (*source_cb
)(char *content
, size_t max_length
, void *payload
),
255 int error
= -1, read_bytes
;
256 char *content
= NULL
;
257 git_filebuf file
= GIT_FILEBUF_INIT
;
258 git_buf path
= GIT_BUF_INIT
;
262 git_repository_path(repo
),
267 content
= git__malloc(BUFFER_SIZE
);
268 GITERR_CHECK_ALLOC(content
);
270 if (git_filebuf_open(&file
, git_buf_cstr(&path
), GIT_FILEBUF_TEMPORARY
) < 0)
274 read_bytes
= source_cb(content
, BUFFER_SIZE
, payload
);
276 assert(read_bytes
<= BUFFER_SIZE
);
281 if (git_filebuf_write(&file
, content
, read_bytes
) < 0)
288 if (git_filebuf_flush(&file
) < 0)
291 error
= blob_create_internal(oid
, repo
, file
.path_lock
, hintpath
, hintpath
!= NULL
);
295 git_filebuf_cleanup(&file
);
300 int git_blob_is_binary(git_blob
*blob
)
306 content
.ptr
= blob
->odb_object
->raw
.data
;
307 content
.size
= min(blob
->odb_object
->raw
.len
, 4000);
309 return git_buf_text_is_binary(&content
);