]> git.proxmox.com Git - libgit2.git/blob - src/libgit2/reader.c
New upstream version 1.5.0+ds
[libgit2.git] / src / libgit2 / reader.c
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 static int tree_reader_read(
26 git_str *out,
27 git_oid *out_id,
28 git_filemode_t *out_filemode,
29 git_reader *_reader,
30 const char *filename)
31 {
32 tree_reader *reader = (tree_reader *)_reader;
33 git_tree_entry *tree_entry = NULL;
34 git_blob *blob = NULL;
35 git_object_size_t blobsize;
36 int error;
37
38 if ((error = git_tree_entry_bypath(&tree_entry, reader->tree, filename)) < 0 ||
39 (error = git_blob_lookup(&blob, git_tree_owner(reader->tree), git_tree_entry_id(tree_entry))) < 0)
40 goto done;
41
42 blobsize = git_blob_rawsize(blob);
43 GIT_ERROR_CHECK_BLOBSIZE(blobsize);
44
45 if ((error = git_str_set(out, git_blob_rawcontent(blob), (size_t)blobsize)) < 0)
46 goto done;
47
48 if (out_id)
49 git_oid_cpy(out_id, git_tree_entry_id(tree_entry));
50
51 if (out_filemode)
52 *out_filemode = git_tree_entry_filemode(tree_entry);
53
54 done:
55 git_blob_free(blob);
56 git_tree_entry_free(tree_entry);
57 return error;
58 }
59
60 int git_reader_for_tree(git_reader **out, git_tree *tree)
61 {
62 tree_reader *reader;
63
64 GIT_ASSERT_ARG(out);
65 GIT_ASSERT_ARG(tree);
66
67 reader = git__calloc(1, sizeof(tree_reader));
68 GIT_ERROR_CHECK_ALLOC(reader);
69
70 reader->reader.read = tree_reader_read;
71 reader->tree = tree;
72
73 *out = (git_reader *)reader;
74 return 0;
75 }
76
77 /* workdir reader */
78
79 typedef struct {
80 git_reader reader;
81 git_repository *repo;
82 git_index *index;
83 } workdir_reader;
84
85 static int workdir_reader_read(
86 git_str *out,
87 git_oid *out_id,
88 git_filemode_t *out_filemode,
89 git_reader *_reader,
90 const char *filename)
91 {
92 workdir_reader *reader = (workdir_reader *)_reader;
93 git_str path = GIT_STR_INIT;
94 struct stat st;
95 git_filemode_t filemode;
96 git_filter_list *filters = NULL;
97 const git_index_entry *idx_entry;
98 git_oid id;
99 int error;
100
101 if ((error = git_repository_workdir_path(&path, reader->repo, filename)) < 0)
102 goto done;
103
104 if ((error = p_lstat(path.ptr, &st)) < 0) {
105 if (error == -1 && errno == ENOENT)
106 error = GIT_ENOTFOUND;
107
108 git_error_set(GIT_ERROR_OS, "could not stat '%s'", path.ptr);
109 goto done;
110 }
111
112 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 if ((error = git_filter_list_load(&filters, reader->repo, NULL, filename,
120 GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT)) < 0)
121 goto done;
122
123 if ((error = git_filter_list__apply_to_file(out,
124 filters, reader->repo, path.ptr)) < 0)
125 goto done;
126
127 if (out_id || reader->index) {
128 if ((error = git_odb_hash(&id, out->ptr, out->size, GIT_OBJECT_BLOB)) < 0)
129 goto done;
130 }
131
132 if (reader->index) {
133 if (!(idx_entry = git_index_get_bypath(reader->index, filename, 0)) ||
134 filemode != idx_entry->mode ||
135 !git_oid_equal(&id, &idx_entry->id)) {
136 error = GIT_READER_MISMATCH;
137 goto done;
138 }
139 }
140
141 if (out_id)
142 git_oid_cpy(out_id, &id);
143
144 if (out_filemode)
145 *out_filemode = filemode;
146
147 done:
148 git_filter_list_free(filters);
149 git_str_dispose(&path);
150 return error;
151 }
152
153 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 GIT_ASSERT_ARG(out);
162 GIT_ASSERT_ARG(repo);
163
164 reader = git__calloc(1, sizeof(workdir_reader));
165 GIT_ERROR_CHECK_ALLOC(reader);
166
167 reader->reader.read = workdir_reader_read;
168 reader->repo = repo;
169
170 if (validate_index &&
171 (error = git_repository_index__weakptr(&reader->index, repo)) < 0) {
172 git__free(reader);
173 return error;
174 }
175
176 *out = (git_reader *)reader;
177 return 0;
178 }
179
180 /* index reader */
181
182 typedef struct {
183 git_reader reader;
184 git_repository *repo;
185 git_index *index;
186 } index_reader;
187
188 static int index_reader_read(
189 git_str *out,
190 git_oid *out_id,
191 git_filemode_t *out_filemode,
192 git_reader *_reader,
193 const char *filename)
194 {
195 index_reader *reader = (index_reader *)_reader;
196 const git_index_entry *entry;
197 git_blob *blob;
198 int error;
199
200 if ((entry = git_index_get_bypath(reader->index, filename, 0)) == NULL)
201 return GIT_ENOTFOUND;
202
203 if ((error = git_blob_lookup(&blob, reader->repo, &entry->id)) < 0)
204 goto done;
205
206 if (out_id)
207 git_oid_cpy(out_id, &entry->id);
208
209 if (out_filemode)
210 *out_filemode = entry->mode;
211
212 error = git_blob__getbuf(out, blob);
213
214 done:
215 git_blob_free(blob);
216 return error;
217 }
218
219 int git_reader_for_index(
220 git_reader **out,
221 git_repository *repo,
222 git_index *index)
223 {
224 index_reader *reader;
225 int error;
226
227 GIT_ASSERT_ARG(out);
228 GIT_ASSERT_ARG(repo);
229
230 reader = git__calloc(1, sizeof(index_reader));
231 GIT_ERROR_CHECK_ALLOC(reader);
232
233 reader->reader.read = index_reader_read;
234 reader->repo = repo;
235
236 if (index) {
237 reader->index = index;
238 } else if ((error = git_repository_index__weakptr(&reader->index, repo)) < 0) {
239 git__free(reader);
240 return error;
241 }
242
243 *out = (git_reader *)reader;
244 return 0;
245 }
246
247 /* generic */
248
249 int git_reader_read(
250 git_str *out,
251 git_oid *out_id,
252 git_filemode_t *out_filemode,
253 git_reader *reader,
254 const char *filename)
255 {
256 GIT_ASSERT_ARG(out);
257 GIT_ASSERT_ARG(reader);
258 GIT_ASSERT_ARG(filename);
259
260 return reader->read(out, out_id, out_filemode, reader, filename);
261 }
262
263 void git_reader_free(git_reader *reader)
264 {
265 if (!reader)
266 return;
267
268 git__free(reader);
269 }