Raw
1 #include "git-compat-util.h"
2 #include "abspath.h"
3 #include "chdir-notify.h"
4 #include "gettext.h"
5 #include "lockfile.h"
6 #include "object-file.h"
7 #include "odb.h"
8 #include "odb/source.h"
9 #include "odb/source-files.h"
10 #include "odb/source-loose.h"
11 #include "packfile.h"
12 #include "strbuf.h"
13 #include "write-or-die.h"
14
15 static void odb_source_files_reparent(const char *name UNUSED,
16 const char *old_cwd,
17 const char *new_cwd,
18 void *cb_data)
19 {
20 struct odb_source_files *files = cb_data;
21 char *path = reparent_relative_path(old_cwd, new_cwd,
22 files->base.path);
23 free(files->base.path);
24 files->base.path = path;
25 }
26
27 static void odb_source_files_free(struct odb_source *source)
28 {
29 struct odb_source_files *files = odb_source_files_downcast(source);
30 chdir_notify_unregister(NULL, odb_source_files_reparent, files);
31 odb_source_free(&files->loose->base);
32 packfile_store_free(files->packed);
33 odb_source_release(&files->base);
34 free(files);
35 }
36
37 static void odb_source_files_close(struct odb_source *source)
38 {
39 struct odb_source_files *files = odb_source_files_downcast(source);
40 odb_source_close(&files->loose->base);
41 packfile_store_close(files->packed);
42 }
43
44 static void odb_source_files_reprepare(struct odb_source *source)
45 {
46 struct odb_source_files *files = odb_source_files_downcast(source);
47 odb_source_reprepare(&files->loose->base);
48 packfile_store_reprepare(files->packed);
49 }
50
51 static int odb_source_files_read_object_info(struct odb_source *source,
52 const struct object_id *oid,
53 struct object_info *oi,
54 enum object_info_flags flags)
55 {
56 struct odb_source_files *files = odb_source_files_downcast(source);
57
58 if (!packfile_store_read_object_info(files->packed, oid, oi, flags) ||
59 !odb_source_read_object_info(&files->loose->base, oid, oi, flags))
60 return 0;
61
62 return -1;
63 }
64
65 static int odb_source_files_read_object_stream(struct odb_read_stream **out,
66 struct odb_source *source,
67 const struct object_id *oid)
68 {
69 struct odb_source_files *files = odb_source_files_downcast(source);
70 if (!packfile_store_read_object_stream(out, files->packed, oid) ||
71 !odb_source_read_object_stream(out, &files->loose->base, oid))
72 return 0;
73 return -1;
74 }
75
76 static int odb_source_files_for_each_object(struct odb_source *source,
77 const struct object_info *request,
78 odb_for_each_object_cb cb,
79 void *cb_data,
80 const struct odb_for_each_object_options *opts)
81 {
82 struct odb_source_files *files = odb_source_files_downcast(source);
83 int ret;
84
85 if (!(opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY)) {
86 ret = odb_source_for_each_object(&files->loose->base, request, cb, cb_data, opts);
87 if (ret)
88 return ret;
89 }
90
91 ret = packfile_store_for_each_object(files->packed, request, cb, cb_data, opts);
92 if (ret)
93 return ret;
94
95 return 0;
96 }
97
98 static int odb_source_files_count_objects(struct odb_source *source,
99 enum odb_count_objects_flags flags,
100 unsigned long *out)
101 {
102 struct odb_source_files *files = odb_source_files_downcast(source);
103 unsigned long count;
104 int ret;
105
106 ret = packfile_store_count_objects(files->packed, flags, &count);
107 if (ret < 0)
108 goto out;
109
110 if (!(flags & ODB_COUNT_OBJECTS_APPROXIMATE)) {
111 unsigned long loose_count;
112
113 ret = odb_source_count_objects(&files->loose->base, flags, &loose_count);
114 if (ret < 0)
115 goto out;
116
117 count += loose_count;
118 }
119
120 *out = count;
121 ret = 0;
122
123 out:
124 return ret;
125 }
126
127 static int odb_source_files_find_abbrev_len(struct odb_source *source,
128 const struct object_id *oid,
129 unsigned min_len,
130 unsigned *out)
131 {
132 struct odb_source_files *files = odb_source_files_downcast(source);
133 unsigned len = min_len;
134 int ret;
135
136 ret = packfile_store_find_abbrev_len(files->packed, oid, len, &len);
137 if (ret < 0)
138 goto out;
139
140 ret = odb_source_find_abbrev_len(&files->loose->base, oid, len, &len);
141 if (ret < 0)
142 goto out;
143
144 *out = len;
145 ret = 0;
146
147 out:
148 return ret;
149 }
150
151 static int odb_source_files_freshen_object(struct odb_source *source,
152 const struct object_id *oid)
153 {
154 struct odb_source_files *files = odb_source_files_downcast(source);
155 if (packfile_store_freshen_object(files->packed, oid) ||
156 odb_source_freshen_object(&files->loose->base, oid))
157 return 1;
158 return 0;
159 }
160
161 static int odb_source_files_write_object(struct odb_source *source,
162 const void *buf, unsigned long len,
163 enum object_type type,
164 struct object_id *oid,
165 struct object_id *compat_oid,
166 enum odb_write_object_flags flags)
167 {
168 struct odb_source_files *files = odb_source_files_downcast(source);
169 return odb_source_write_object(&files->loose->base, buf, len, type,
170 oid, compat_oid, flags);
171 }
172
173 static int odb_source_files_write_object_stream(struct odb_source *source,
174 struct odb_write_stream *stream,
175 size_t len,
176 struct object_id *oid)
177 {
178 struct odb_source_files *files = odb_source_files_downcast(source);
179 return odb_source_write_object_stream(&files->loose->base, stream, len, oid);
180 }
181
182 static int odb_source_files_begin_transaction(struct odb_source *source,
183 struct odb_transaction **out)
184 {
185 struct odb_transaction *tx = odb_transaction_files_begin(source);
186 if (!tx)
187 return -1;
188 *out = tx;
189 return 0;
190 }
191
192 static int odb_source_files_read_alternates(struct odb_source *source,
193 struct strvec *out)
194 {
195 struct strbuf buf = STRBUF_INIT;
196 char *path;
197
198 path = xstrfmt("%s/info/alternates", source->path);
199 if (strbuf_read_file(&buf, path, 1024) < 0) {
200 warn_on_fopen_errors(path);
201 free(path);
202 return 0;
203 }
204 parse_alternates(buf.buf, '\n', source->path, out);
205
206 strbuf_release(&buf);
207 free(path);
208 return 0;
209 }
210
211 static int odb_source_files_write_alternate(struct odb_source *source,
212 const char *alternate)
213 {
214 struct lock_file lock = LOCK_INIT;
215 char *path = xstrfmt("%s/%s", source->path, "info/alternates");
216 FILE *in, *out;
217 int found = 0;
218 int ret;
219
220 hold_lock_file_for_update(&lock, path, LOCK_DIE_ON_ERROR);
221 out = fdopen_lock_file(&lock, "w");
222 if (!out) {
223 ret = error_errno(_("unable to fdopen alternates lockfile"));
224 goto out;
225 }
226
227 in = fopen(path, "r");
228 if (in) {
229 struct strbuf line = STRBUF_INIT;
230
231 while (strbuf_getline(&line, in) != EOF) {
232 if (!strcmp(alternate, line.buf)) {
233 found = 1;
234 break;
235 }
236 fprintf_or_die(out, "%s\n", line.buf);
237 }
238
239 strbuf_release(&line);
240 fclose(in);
241 } else if (errno != ENOENT) {
242 ret = error_errno(_("unable to read alternates file"));
243 goto out;
244 }
245
246 if (found) {
247 rollback_lock_file(&lock);
248 } else {
249 fprintf_or_die(out, "%s\n", alternate);
250 if (commit_lock_file(&lock)) {
251 ret = error_errno(_("unable to move new alternates file into place"));
252 goto out;
253 }
254 }
255
256 ret = 0;
257
258 out:
259 free(path);
260 return ret;
261 }
262
263 struct odb_source_files *odb_source_files_new(struct object_database *odb,
264 const char *path,
265 bool local)
266 {
267 struct odb_source_files *files;
268
269 CALLOC_ARRAY(files, 1);
270 odb_source_init(&files->base, odb, ODB_SOURCE_FILES, path, local);
271 files->loose = odb_source_loose_new(odb, path, local);
272 files->packed = packfile_store_new(&files->base);
273
274 files->base.free = odb_source_files_free;
275 files->base.close = odb_source_files_close;
276 files->base.reprepare = odb_source_files_reprepare;
277 files->base.read_object_info = odb_source_files_read_object_info;
278 files->base.read_object_stream = odb_source_files_read_object_stream;
279 files->base.for_each_object = odb_source_files_for_each_object;
280 files->base.count_objects = odb_source_files_count_objects;
281 files->base.find_abbrev_len = odb_source_files_find_abbrev_len;
282 files->base.freshen_object = odb_source_files_freshen_object;
283 files->base.write_object = odb_source_files_write_object;
284 files->base.write_object_stream = odb_source_files_write_object_stream;
285 files->base.begin_transaction = odb_source_files_begin_transaction;
286 files->base.read_alternates = odb_source_files_read_alternates;
287 files->base.write_alternate = odb_source_files_write_alternate;
288
289 /*
290 * Ideally, we would only ever store absolute paths in the source. This
291 * is not (yet) possible though because we access and assume relative
292 * paths in the primary ODB source in some user-facing functionality.
293 */
294 if (!is_absolute_path(path))
295 chdir_notify_register(NULL, odb_source_files_reparent, files);
296
297 return files;
298 }