Line Flow Count Block(s) Source
1 - /*
2 - * Copyright (C) the libgit2 contributors. All rights reserved.
3 - *
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.
6 - */
7 -
8 - #include "reader.h"
9 -
10 - #include "futils.h"
11 - #include "blob.h"
12 -
13 - #include "git2/tree.h"
14 - #include "git2/blob.h"
15 - #include "git2/index.h"
16 - #include "git2/repository.h"
17 -
18 - /* tree reader */
19 -
20 - typedef struct {
21 - git_reader reader;
22 - git_tree *tree;
23 - } tree_reader;
24 -
25 ##### 2 static int tree_reader_read(
26 - git_buf *out,
27 - git_oid *out_id,
28 - git_filemode_t *out_filemode,
29 - git_reader *_reader,
30 - const char *filename)
31 - {
32 ##### 2 tree_reader *reader = (tree_reader *)_reader;
33 ##### 2 git_tree_entry *tree_entry = NULL;
34 ##### 2 git_blob *blob = NULL;
35 - git_object_size_t blobsize;
36 - int error;
37 -
38 ##### 2,3,6,7 if ((error = git_tree_entry_bypath(&tree_entry, reader->tree, filename)) < 0 ||
39 ##### 4,5 (error = git_blob_lookup(&blob, git_tree_owner(reader->tree), git_tree_entry_id(tree_entry))) < 0)
40 - goto done;
41 -
42 ##### 8 blobsize = git_blob_rawsize(blob);
43 ##### 9-12 GIT_ERROR_CHECK_BLOBSIZE(blobsize);
44 -
45 ##### 13-15 if ((error = git_buf_set(out, git_blob_rawcontent(blob), (size_t)blobsize)) < 0)
46 ##### 16 goto done;
47 -
48 ##### 17 if (out_id)
49 ##### 18,19 git_oid_cpy(out_id, git_tree_entry_id(tree_entry));
50 -
51 ##### 20 if (out_filemode)
52 ##### 21,22 *out_filemode = git_tree_entry_filemode(tree_entry);
53 -
54 - done:
55 ##### 23 git_blob_free(blob);
56 ##### 24 git_tree_entry_free(tree_entry);
57 ##### 25 return error;
58 - }
59 -
60 2 2 int git_reader_for_tree(git_reader **out, git_tree *tree)
61 - {
62 - tree_reader *reader;
63 -
64 2 2-4 assert(out && tree);
65 -
66 2 5 reader = git__calloc(1, sizeof(tree_reader));
67 2 6,7 GIT_ERROR_CHECK_ALLOC(reader);
68 -
69 2 8 reader->reader.read = tree_reader_read;
70 2 8 reader->tree = tree;
71 -
72 2 8 *out = (git_reader *)reader;
73 2 8 return 0;
74 - }
75 -
76 - /* workdir reader */
77 -
78 - typedef struct {
79 - git_reader reader;
80 - git_repository *repo;
81 - git_index *index;
82 - } workdir_reader;
83 -
84 57 2 static int workdir_reader_read(
85 - git_buf *out,
86 - git_oid *out_id,
87 - git_filemode_t *out_filemode,
88 - git_reader *_reader,
89 - const char *filename)
90 - {
91 57 2 workdir_reader *reader = (workdir_reader *)_reader;
92 57 2 git_buf path = GIT_BUF_INIT;
93 - struct stat st;
94 - git_filemode_t filemode;
95 57 2 git_filter_list *filters = NULL;
96 - const git_index_entry *idx_entry;
97 - git_oid id;
98 - int error;
99 -
100 57 2-4 if ((error = git_buf_joinpath(&path,
101 57 2 git_repository_workdir(reader->repo), filename)) < 0)
102 ##### 5 goto done;
103 -
104 57 6,7 if ((error = p_lstat(path.ptr, &st)) < 0) {
105 ##### 8-10 if (error == -1 && errno == ENOENT)
106 ##### 11 error = GIT_ENOTFOUND;
107 -
108 ##### 12 git_error_set(GIT_ERROR_OS, "could not stat '%s'", path.ptr);
109 ##### 13 goto done;
110 - }
111 -
112 57 14 filemode = git_futils_canonical_mode(st.st_mode);
113 -
114 - /*
115 - * Patch application - for example - uses the filtered version of
116 - * the working directory data to match git. So we will run the
117 - * workdir -> ODB filter on the contents in this workdir reader.
118 - */
119 57 15,16 if ((error = git_filter_list_load(&filters, reader->repo, NULL, filename,
120 - GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT)) < 0)
121 ##### 17 goto done;
122 -
123 57 18,19 if ((error = git_filter_list_apply_to_file(out,
124 57 18 filters, reader->repo, path.ptr)) < 0)
125 ##### 20 goto done;
126 -
127 57 21,22 if (out_id || reader->index) {
128 57 23,24 if ((error = git_odb_hash(&id, out->ptr, out->size, GIT_OBJECT_BLOB)) < 0)
129 ##### 25 goto done;
130 - }
131 -
132 57 26 if (reader->index) {
133 39 27-29 if (!(idx_entry = git_index_get_bypath(reader->index, filename, 0)) ||
134 38 29,31 filemode != idx_entry->mode ||
135 37 30 !git_oid_equal(&id, &idx_entry->id)) {
136 3 32 error = GIT_READER_MISMATCH;
137 3 32 goto done;
138 - }
139 - }
140 -
141 54 33 if (out_id)
142 54 34 git_oid_cpy(out_id, &id);
143 -
144 54 35 if (out_filemode)
145 54 36 *out_filemode = filemode;
146 -
147 - done:
148 57 37 git_filter_list_free(filters);
149 57 38 git_buf_dispose(&path);
150 57 39 return error;
151 - }
152 -
153 40 2 int git_reader_for_workdir(
154 - git_reader **out,
155 - git_repository *repo,
156 - bool validate_index)
157 - {
158 - workdir_reader *reader;
159 - int error;
160 -
161 40 2-4 assert(out && repo);
162 -
163 40 5 reader = git__calloc(1, sizeof(workdir_reader));
164 40 6,7 GIT_ERROR_CHECK_ALLOC(reader);
165 -
166 40 8 reader->reader.read = workdir_reader_read;
167 40 8 reader->repo = repo;
168 -
169 40 8-10 if (validate_index &&
170 27 9 (error = git_repository_index__weakptr(&reader->index, repo)) < 0) {
171 ##### 11 git__free(reader);
172 ##### 12 return error;
173 - }
174 -
175 40 13 *out = (git_reader *)reader;
176 40 13 return 0;
177 - }
178 -
179 - /* index reader */
180 -
181 - typedef struct {
182 - git_reader reader;
183 - git_repository *repo;
184 - git_index *index;
185 - } index_reader;
186 -
187 98 2 static int index_reader_read(
188 - git_buf *out,
189 - git_oid *out_id,
190 - git_filemode_t *out_filemode,
191 - git_reader *_reader,
192 - const char *filename)
193 - {
194 98 2 index_reader *reader = (index_reader *)_reader;
195 - const git_index_entry *entry;
196 - git_blob *blob;
197 - int error;
198 -
199 98 2,3 if ((entry = git_index_get_bypath(reader->index, filename, 0)) == NULL)
200 74 4 return GIT_ENOTFOUND;
201 -
202 24 5,6 if ((error = git_blob_lookup(&blob, reader->repo, &entry->id)) < 0)
203 ##### 7 goto done;
204 -
205 24 8 if (out_id)
206 24 9 git_oid_cpy(out_id, &entry->id);
207 -
208 24 10 if (out_filemode)
209 24 11 *out_filemode = entry->mode;
210 -
211 24 12 error = git_blob__getbuf(out, blob);
212 -
213 - done:
214 24 13 git_blob_free(blob);
215 24 14 return error;
216 - }
217 -
218 68 2 int git_reader_for_index(
219 - git_reader **out,
220 - git_repository *repo,
221 - git_index *index)
222 - {
223 - index_reader *reader;
224 - int error;
225 -
226 68 2-4 assert(out && repo);
227 -
228 68 5 reader = git__calloc(1, sizeof(index_reader));
229 68 6,7 GIT_ERROR_CHECK_ALLOC(reader);
230 -
231 68 8 reader->reader.read = index_reader_read;
232 68 8 reader->repo = repo;
233 -
234 68 8 if (index) {
235 55 9 reader->index = index;
236 13 10,11 } else if ((error = git_repository_index__weakptr(&reader->index, repo)) < 0) {
237 ##### 12 git__free(reader);
238 ##### 13 return error;
239 - }
240 -
241 68 14 *out = (git_reader *)reader;
242 68 14 return 0;
243 - }
244 -
245 - /* generic */
246 -
247 155 2 int git_reader_read(
248 - git_buf *out,
249 - git_oid *out_id,
250 - git_filemode_t *out_filemode,
251 - git_reader *reader,
252 - const char *filename)
253 - {
254 155 2-5 assert(out && reader && filename);
255 -
256 155 6 return reader->read(out, out_id, out_filemode, reader, filename);
257 - }
258 -
259 110 2 void git_reader_free(git_reader *reader)
260 - {
261 110 2 if (!reader)
262 110 3,5 return;
263 -
264 110 4 git__free(reader);
265 - }