source src/reader.c
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 | - | } |