]> git.proxmox.com Git - libgit2.git/blob - src/odb_loose.c
Renamed git_oid_match to git_oid_ncmp.
[libgit2.git] / src / odb_loose.c
1 /*
2 * This file is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2,
4 * as published by the Free Software Foundation.
5 *
6 * In addition to the permissions in the GNU General Public License,
7 * the authors give you unlimited permission to link the compiled
8 * version of this file into combinations with other programs,
9 * and to distribute those combinations without any restriction
10 * coming from the use of this file. (The General Public License
11 * restrictions do apply in other respects; for example, they cover
12 * modification of the file, and distribution when not linked into
13 * a combined executable.)
14 *
15 * This file is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; see the file COPYING. If not, write to
22 * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26 #include "common.h"
27 #include "git2/zlib.h"
28 #include "git2/object.h"
29 #include "fileops.h"
30 #include "hash.h"
31 #include "odb.h"
32 #include "oid.h"
33 #include "delta-apply.h"
34 #include "filebuf.h"
35
36 #include "git2/odb_backend.h"
37 #include "git2/types.h"
38
39 typedef struct { /* object header data */
40 git_otype type; /* object type */
41 size_t size; /* object size */
42 } obj_hdr;
43
44 typedef struct {
45 git_odb_stream stream;
46 git_filebuf fbuf;
47 int finished;
48 } loose_writestream;
49
50 typedef struct loose_backend {
51 git_odb_backend parent;
52
53 int object_zlib_level; /** loose object zlib compression level. */
54 int fsync_object_files; /** loose object file fsync flag. */
55 char *objects_dir;
56 } loose_backend;
57
58 /* State structure for exploring directories,
59 * in order to locate objects matching a short oid.
60 */
61 typedef struct {
62 size_t dir_len;
63 unsigned char short_oid[GIT_OID_HEXSZ]; /* hex formatted oid to match */
64 unsigned int short_oid_len;
65 int found; /* number of matching
66 * objects already found */
67 unsigned char res_oid[GIT_OID_HEXSZ]; /* hex formatted oid of
68 * the object found */
69 } loose_locate_object_state;
70
71
72
73 /***********************************************************
74 *
75 * MISCELANEOUS HELPER FUNCTIONS
76 *
77 ***********************************************************/
78
79 static size_t object_file_name(char *name, size_t n, char *dir, const git_oid *id)
80 {
81 size_t len = strlen(dir);
82
83 /* check length: 43 = 40 hex sha1 chars + 2 * '/' + '\0' */
84 if (len+43 > n)
85 return len+43;
86
87 /* the object dir: eg $GIT_DIR/objects */
88 strcpy(name, dir);
89 if (name[len-1] != '/')
90 name[len++] = '/';
91
92 /* loose object filename: aa/aaa... (41 bytes) */
93 git_oid_pathfmt(&name[len], id);
94 name[len+41] = '\0';
95
96 return 0;
97 }
98
99
100 static size_t get_binary_object_header(obj_hdr *hdr, gitfo_buf *obj)
101 {
102 unsigned char c;
103 unsigned char *data = obj->data;
104 size_t shift, size, used = 0;
105
106 if (obj->len == 0)
107 return 0;
108
109 c = data[used++];
110 hdr->type = (c >> 4) & 7;
111
112 size = c & 15;
113 shift = 4;
114 while (c & 0x80) {
115 if (obj->len <= used)
116 return 0;
117 if (sizeof(size_t) * 8 <= shift)
118 return 0;
119 c = data[used++];
120 size += (c & 0x7f) << shift;
121 shift += 7;
122 }
123 hdr->size = size;
124
125 return used;
126 }
127
128 static size_t get_object_header(obj_hdr *hdr, unsigned char *data)
129 {
130 char c, typename[10];
131 size_t size, used = 0;
132
133 /*
134 * type name string followed by space.
135 */
136 while ((c = data[used]) != ' ') {
137 typename[used++] = c;
138 if (used >= sizeof(typename))
139 return 0;
140 }
141 typename[used] = 0;
142 if (used == 0)
143 return 0;
144 hdr->type = git_object_string2type(typename);
145 used++; /* consume the space */
146
147 /*
148 * length follows immediately in decimal (without
149 * leading zeros).
150 */
151 size = data[used++] - '0';
152 if (size > 9)
153 return 0;
154 if (size) {
155 while ((c = data[used]) != '\0') {
156 size_t d = c - '0';
157 if (d > 9)
158 break;
159 used++;
160 size = size * 10 + d;
161 }
162 }
163 hdr->size = size;
164
165 /*
166 * the length must be followed by a zero byte
167 */
168 if (data[used++] != '\0')
169 return 0;
170
171 return used;
172 }
173
174
175
176 /***********************************************************
177 *
178 * ZLIB RELATED FUNCTIONS
179 *
180 ***********************************************************/
181
182 static void init_stream(z_stream *s, void *out, size_t len)
183 {
184 memset(s, 0, sizeof(*s));
185 s->next_out = out;
186 s->avail_out = len;
187 }
188
189 static void set_stream_input(z_stream *s, void *in, size_t len)
190 {
191 s->next_in = in;
192 s->avail_in = len;
193 }
194
195 static void set_stream_output(z_stream *s, void *out, size_t len)
196 {
197 s->next_out = out;
198 s->avail_out = len;
199 }
200
201
202 static int start_inflate(z_stream *s, gitfo_buf *obj, void *out, size_t len)
203 {
204 int status;
205
206 init_stream(s, out, len);
207 set_stream_input(s, obj->data, obj->len);
208
209 if ((status = inflateInit(s)) < Z_OK)
210 return status;
211
212 return inflate(s, 0);
213 }
214
215 static int finish_inflate(z_stream *s)
216 {
217 int status = Z_OK;
218
219 while (status == Z_OK)
220 status = inflate(s, Z_FINISH);
221
222 inflateEnd(s);
223
224 if ((status != Z_STREAM_END) || (s->avail_in != 0))
225 return git__throw(GIT_ERROR, "Failed to finish inflation. Stream aborted prematurely");
226
227 return GIT_SUCCESS;
228 }
229
230 static int is_zlib_compressed_data(unsigned char *data)
231 {
232 unsigned int w;
233
234 w = ((unsigned int)(data[0]) << 8) + data[1];
235 return data[0] == 0x78 && !(w % 31);
236 }
237
238 static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
239 {
240 z_stream zs;
241 int status = Z_OK;
242
243 memset(&zs, 0x0, sizeof(zs));
244
245 zs.next_out = out;
246 zs.avail_out = outlen;
247
248 zs.next_in = in;
249 zs.avail_in = inlen;
250
251 if (inflateInit(&zs) < Z_OK)
252 return git__throw(GIT_ERROR, "Failed to inflate buffer");
253
254 while (status == Z_OK)
255 status = inflate(&zs, Z_FINISH);
256
257 inflateEnd(&zs);
258
259 if ((status != Z_STREAM_END) /*|| (zs.avail_in != 0) */)
260 return git__throw(GIT_ERROR, "Failed to inflate buffer. Stream aborted prematurely");
261
262 if (zs.total_out != outlen)
263 return git__throw(GIT_ERROR, "Failed to inflate buffer. Stream aborted prematurely");
264
265 return GIT_SUCCESS;
266 }
267
268 static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr)
269 {
270 unsigned char *buf, *head = hb;
271 size_t tail;
272
273 /*
274 * allocate a buffer to hold the inflated data and copy the
275 * initial sequence of inflated data from the tail of the
276 * head buffer, if any.
277 */
278 if ((buf = git__malloc(hdr->size + 1)) == NULL) {
279 inflateEnd(s);
280 return NULL;
281 }
282 tail = s->total_out - used;
283 if (used > 0 && tail > 0) {
284 if (tail > hdr->size)
285 tail = hdr->size;
286 memcpy(buf, head + used, tail);
287 }
288 used = tail;
289
290 /*
291 * inflate the remainder of the object data, if any
292 */
293 if (hdr->size < used)
294 inflateEnd(s);
295 else {
296 set_stream_output(s, buf + used, hdr->size - used);
297 if (finish_inflate(s)) {
298 free(buf);
299 return NULL;
300 }
301 }
302
303 return buf;
304 }
305
306 /*
307 * At one point, there was a loose object format that was intended to
308 * mimic the format used in pack-files. This was to allow easy copying
309 * of loose object data into packs. This format is no longer used, but
310 * we must still read it.
311 */
312 static int inflate_packlike_loose_disk_obj(git_rawobj *out, gitfo_buf *obj)
313 {
314 unsigned char *in, *buf;
315 obj_hdr hdr;
316 size_t len, used;
317
318 /*
319 * read the object header, which is an (uncompressed)
320 * binary encoding of the object type and size.
321 */
322 if ((used = get_binary_object_header(&hdr, obj)) == 0)
323 return git__throw(GIT_ERROR, "Failed to inflate loose object. Object has no header");
324
325 if (!git_object_typeisloose(hdr.type))
326 return git__throw(GIT_ERROR, "Failed to inflate loose object. Wrong object type");
327
328 /*
329 * allocate a buffer and inflate the data into it
330 */
331 buf = git__malloc(hdr.size + 1);
332 if (!buf)
333 return GIT_ENOMEM;
334
335 in = ((unsigned char *)obj->data) + used;
336 len = obj->len - used;
337 if (inflate_buffer(in, len, buf, hdr.size)) {
338 free(buf);
339 return git__throw(GIT_ERROR, "Failed to inflate loose object. Could not inflate buffer");
340 }
341 buf[hdr.size] = '\0';
342
343 out->data = buf;
344 out->len = hdr.size;
345 out->type = hdr.type;
346
347 return GIT_SUCCESS;
348 }
349
350 static int inflate_disk_obj(git_rawobj *out, gitfo_buf *obj)
351 {
352 unsigned char head[64], *buf;
353 z_stream zs;
354 obj_hdr hdr;
355 size_t used;
356
357 /*
358 * check for a pack-like loose object
359 */
360 if (!is_zlib_compressed_data(obj->data))
361 return inflate_packlike_loose_disk_obj(out, obj);
362
363 /*
364 * inflate the initial part of the io buffer in order
365 * to parse the object header (type and size).
366 */
367 if (start_inflate(&zs, obj, head, sizeof(head)) < Z_OK)
368 return git__throw(GIT_ERROR, "Failed to inflate disk object. Could not inflate buffer");
369
370 if ((used = get_object_header(&hdr, head)) == 0)
371 return git__throw(GIT_ERROR, "Failed to inflate disk object. Object has no header");
372
373 if (!git_object_typeisloose(hdr.type))
374 return git__throw(GIT_ERROR, "Failed to inflate disk object. Wrong object type");
375
376 /*
377 * allocate a buffer and inflate the object data into it
378 * (including the initial sequence in the head buffer).
379 */
380 if ((buf = inflate_tail(&zs, head, used, &hdr)) == NULL)
381 return GIT_ENOMEM;
382 buf[hdr.size] = '\0';
383
384 out->data = buf;
385 out->len = hdr.size;
386 out->type = hdr.type;
387
388 return GIT_SUCCESS;
389 }
390
391
392
393
394
395
396 /***********************************************************
397 *
398 * ODB OBJECT READING & WRITING
399 *
400 * Backend for the public API; read headers and full objects
401 * from the ODB. Write raw data to the ODB.
402 *
403 ***********************************************************/
404
405 static int read_loose(git_rawobj *out, const char *loc)
406 {
407 int error;
408 gitfo_buf obj = GITFO_BUF_INIT;
409
410 assert(out && loc);
411
412 out->data = NULL;
413 out->len = 0;
414 out->type = GIT_OBJ_BAD;
415
416 if (gitfo_read_file(&obj, loc) < 0)
417 return git__throw(GIT_ENOTFOUND, "Failed to read loose object. File not found");
418
419 error = inflate_disk_obj(out, &obj);
420 gitfo_free_buf(&obj);
421
422 return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to read loose object");
423 }
424
425 static int read_header_loose(git_rawobj *out, const char *loc)
426 {
427 int error = GIT_SUCCESS, z_return = Z_ERRNO, read_bytes;
428 git_file fd;
429 z_stream zs;
430 obj_hdr header_obj;
431 unsigned char raw_buffer[16], inflated_buffer[64];
432
433 assert(out && loc);
434
435 out->data = NULL;
436
437 if ((fd = gitfo_open(loc, O_RDONLY)) < 0)
438 return git__throw(GIT_ENOTFOUND, "Failed to read loose object header. File not found");
439
440 init_stream(&zs, inflated_buffer, sizeof(inflated_buffer));
441
442 if (inflateInit(&zs) < Z_OK) {
443 error = GIT_EZLIB;
444 goto cleanup;
445 }
446
447 do {
448 if ((read_bytes = read(fd, raw_buffer, sizeof(raw_buffer))) > 0) {
449 set_stream_input(&zs, raw_buffer, read_bytes);
450 z_return = inflate(&zs, 0);
451 } else {
452 z_return = Z_STREAM_END;
453 break;
454 }
455 } while (z_return == Z_OK);
456
457 if ((z_return != Z_STREAM_END && z_return != Z_BUF_ERROR)
458 || get_object_header(&header_obj, inflated_buffer) == 0
459 || git_object_typeisloose(header_obj.type) == 0) {
460 error = GIT_EOBJCORRUPTED;
461 goto cleanup;
462 }
463
464 out->len = header_obj.size;
465 out->type = header_obj.type;
466
467 cleanup:
468 finish_inflate(&zs);
469 gitfo_close(fd);
470
471 if (error < GIT_SUCCESS)
472 return git__throw(error, "Failed to read loose object header. Header is corrupted");
473
474 return GIT_SUCCESS;
475 }
476
477 static int locate_object(char *object_location, loose_backend *backend, const git_oid *oid)
478 {
479 object_file_name(object_location, GIT_PATH_MAX, backend->objects_dir, oid);
480 return gitfo_exists(object_location);
481 }
482
483 /* Explore an entry of a directory and see if it matches a short oid */
484 int fn_locate_object_short_oid(void *state, char *pathbuf) {
485 loose_locate_object_state *sstate = (loose_locate_object_state *)state;
486
487 size_t pathbuf_len = strlen(pathbuf);
488 if (pathbuf_len - sstate->dir_len != GIT_OID_HEXSZ - 2) {
489 /* Entry cannot be an object. Continue to next entry */
490 return GIT_SUCCESS;
491 }
492
493 if (!gitfo_exists(pathbuf) && gitfo_isdir(pathbuf)) {
494 /* We are already in the directory matching the 2 first hex characters */
495 if (!git_oid_ncmp_hex(sstate->short_oid_len-2, sstate->short_oid+2, (unsigned char *)pathbuf + sstate->dir_len)) {
496 if (!sstate->found) {
497 sstate->res_oid[0] = sstate->short_oid[0];
498 sstate->res_oid[1] = sstate->short_oid[1];
499 memcpy(sstate->res_oid+2, pathbuf+sstate->dir_len, GIT_OID_HEXSZ-2);
500 }
501 sstate->found++;
502 }
503 }
504 if (sstate->found > 1)
505 return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Ambiguous sha1 prefix within loose objects");
506
507 return GIT_SUCCESS;
508 }
509
510 /* Locate an object matching a given short oid */
511 static int locate_object_short_oid(char *object_location, git_oid *res_oid, loose_backend *backend, const git_oid *short_oid, unsigned int len)
512 {
513 char *objects_dir = backend->objects_dir;
514 size_t dir_len = strlen(objects_dir);
515 loose_locate_object_state state;
516 int error;
517
518 if (dir_len+43 > GIT_PATH_MAX)
519 return git__throw(GIT_ERROR, "Failed to locate object from short oid. Object path too long");
520
521 strcpy(object_location, objects_dir);
522
523 /* Add a separator if not already there */
524 if (object_location[dir_len-1] != '/')
525 object_location[dir_len++] = '/';
526
527 /* Convert raw oid to hex formatted oid */
528 git_oid_fmt((char *)state.short_oid, short_oid);
529 /* Explore OBJ_DIR/xx/ where xx is the beginning of hex formatted short oid */
530 sprintf(object_location+dir_len, "%.2s/", state.short_oid);
531
532 /* Check that directory exists */
533 if (gitfo_exists(object_location) || gitfo_isdir(object_location))
534 return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found");
535
536 state.dir_len = dir_len+3;
537 state.short_oid_len = len;
538 state.found = 0;
539 /* Explore directory to find a unique object matching short_oid */
540 error = gitfo_dirent(object_location, GIT_PATH_MAX, fn_locate_object_short_oid, &state);
541 if (error) {
542 return git__rethrow(error, "Failed to locate object from short oid");
543 }
544 if (!state.found) {
545 return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found");
546 }
547
548 /* Convert obtained hex formatted oid to raw */
549 error = git_oid_mkstr(res_oid, (char *)state.res_oid);
550 if (error) {
551 return git__rethrow(error, "Failed to locate object from short oid");
552 }
553
554 /* Update the location according to the oid obtained */
555 git_oid_pathfmt(object_location+dir_len, res_oid);
556
557 return GIT_SUCCESS;
558 }
559
560
561
562
563
564
565
566
567
568 /***********************************************************
569 *
570 * LOOSE BACKEND PUBLIC API
571 *
572 * Implement the git_odb_backend API calls
573 *
574 ***********************************************************/
575
576 int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
577 {
578 char object_path[GIT_PATH_MAX];
579 git_rawobj raw;
580 int error;
581
582 assert(backend && oid);
583
584 raw.len = 0;
585 raw.type = GIT_OBJ_BAD;
586
587 if (locate_object(object_path, (loose_backend *)backend, oid) < 0)
588 return git__throw(GIT_ENOTFOUND, "Failed to read loose backend header. Object not found");
589
590 if ((error = read_header_loose(&raw, object_path)) < GIT_SUCCESS)
591 return error;
592
593 *len_p = raw.len;
594 *type_p = raw.type;
595 return GIT_SUCCESS;
596 }
597
598 int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
599 {
600 char object_path[GIT_PATH_MAX];
601 git_rawobj raw;
602 int error;
603
604 assert(backend && oid);
605
606 if (locate_object(object_path, (loose_backend *)backend, oid) < 0)
607 return git__throw(GIT_ENOTFOUND, "Failed to read loose backend. Object not found");
608
609 if ((error = read_loose(&raw, object_path)) < GIT_SUCCESS)
610 return git__rethrow(error, "Failed to read loose backend");
611
612 *buffer_p = raw.data;
613 *len_p = raw.len;
614 *type_p = raw.type;
615
616 return GIT_SUCCESS;
617 }
618
619 int loose_backend__read_prefix(
620 git_oid *out_oid,
621 void **buffer_p,
622 size_t *len_p,
623 git_otype *type_p,
624 git_odb_backend *backend,
625 const git_oid *short_oid,
626 unsigned int len)
627 {
628 if (len < GIT_OID_MINPREFIXLEN)
629 return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read loose backend. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN);
630
631 if (len >= GIT_OID_HEXSZ) {
632 /* We can fall back to regular read method */
633 int error = loose_backend__read(buffer_p, len_p, type_p, backend, short_oid);
634 if (error == GIT_SUCCESS)
635 git_oid_cpy(out_oid, short_oid);
636
637 return error;
638 } else {
639 char object_path[GIT_PATH_MAX];
640 git_rawobj raw;
641 int error;
642
643 assert(backend && short_oid);
644
645 if ((error = locate_object_short_oid(object_path, out_oid, (loose_backend *)backend, short_oid, len)) < 0) {
646 return git__rethrow(error, "Failed to read loose backend");
647 }
648
649 if ((error = read_loose(&raw, object_path)) < GIT_SUCCESS)
650 return git__rethrow(error, "Failed to read loose backend");
651
652 *buffer_p = raw.data;
653 *len_p = raw.len;
654 *type_p = raw.type;
655 }
656
657 return GIT_SUCCESS;
658 }
659
660 int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
661 {
662 char object_path[GIT_PATH_MAX];
663
664 assert(backend && oid);
665
666 return locate_object(object_path, (loose_backend *)backend, oid) == GIT_SUCCESS;
667 }
668
669 int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream)
670 {
671 loose_writestream *stream = (loose_writestream *)_stream;
672 loose_backend *backend = (loose_backend *)_stream->backend;
673
674 int error;
675 char final_path[GIT_PATH_MAX];
676
677 if ((error = git_filebuf_hash(oid, &stream->fbuf)) < GIT_SUCCESS)
678 return git__rethrow(error, "Failed to write loose backend");
679
680 if (object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid))
681 return GIT_ENOMEM;
682
683 if ((error = gitfo_mkdir_2file(final_path)) < GIT_SUCCESS)
684 return git__rethrow(error, "Failed to write loose backend");
685
686 stream->finished = 1;
687 return git_filebuf_commit_at(&stream->fbuf, final_path);
688 }
689
690 int loose_backend__stream_write(git_odb_stream *_stream, const char *data, size_t len)
691 {
692 loose_writestream *stream = (loose_writestream *)_stream;
693 return git_filebuf_write(&stream->fbuf, data, len);
694 }
695
696 void loose_backend__stream_free(git_odb_stream *_stream)
697 {
698 loose_writestream *stream = (loose_writestream *)_stream;
699
700 if (!stream->finished)
701 git_filebuf_cleanup(&stream->fbuf);
702
703 free(stream);
704 }
705
706 static int format_object_header(char *hdr, size_t n, size_t obj_len, git_otype obj_type)
707 {
708 const char *type_str = git_object_type2string(obj_type);
709 int len = snprintf(hdr, n, "%s %"PRIuZ, type_str, obj_len);
710
711 assert(len > 0); /* otherwise snprintf() is broken */
712 assert(((size_t) len) < n); /* otherwise the caller is broken! */
713
714 if (len < 0 || ((size_t) len) >= n)
715 return git__throw(GIT_ERROR, "Failed to format object header. Length is out of bounds");
716 return len+1;
717 }
718
719 int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_backend, size_t length, git_otype type)
720 {
721 loose_backend *backend;
722 loose_writestream *stream;
723
724 char hdr[64], tmp_path[GIT_PATH_MAX];
725 int hdrlen;
726 int error;
727
728 assert(_backend);
729
730 backend = (loose_backend *)_backend;
731 *stream_out = NULL;
732
733 hdrlen = format_object_header(hdr, sizeof(hdr), length, type);
734 if (hdrlen < GIT_SUCCESS)
735 return git__throw(GIT_EOBJCORRUPTED, "Failed to create loose backend stream. Object is corrupted");
736
737 stream = git__calloc(1, sizeof(loose_writestream));
738 if (stream == NULL)
739 return GIT_ENOMEM;
740
741 stream->stream.backend = _backend;
742 stream->stream.read = NULL; /* read only */
743 stream->stream.write = &loose_backend__stream_write;
744 stream->stream.finalize_write = &loose_backend__stream_fwrite;
745 stream->stream.free = &loose_backend__stream_free;
746 stream->stream.mode = GIT_STREAM_WRONLY;
747
748 git__joinpath(tmp_path, backend->objects_dir, "tmp_object");
749
750 error = git_filebuf_open(&stream->fbuf, tmp_path,
751 GIT_FILEBUF_HASH_CONTENTS |
752 GIT_FILEBUF_DEFLATE_CONTENTS |
753 GIT_FILEBUF_TEMPORARY);
754
755 if (error < GIT_SUCCESS) {
756 free(stream);
757 return git__rethrow(error, "Failed to create loose backend stream");
758 }
759
760 error = stream->stream.write((git_odb_stream *)stream, hdr, hdrlen);
761 if (error < GIT_SUCCESS) {
762 git_filebuf_cleanup(&stream->fbuf);
763 free(stream);
764 return git__rethrow(error, "Failed to create loose backend stream");
765 }
766
767 *stream_out = (git_odb_stream *)stream;
768 return GIT_SUCCESS;
769 }
770
771 void loose_backend__free(git_odb_backend *_backend)
772 {
773 loose_backend *backend;
774 assert(_backend);
775 backend = (loose_backend *)_backend;
776
777 free(backend->objects_dir);
778 free(backend);
779 }
780
781 int git_odb_backend_loose(git_odb_backend **backend_out, const char *objects_dir)
782 {
783 loose_backend *backend;
784
785 backend = git__calloc(1, sizeof(loose_backend));
786 if (backend == NULL)
787 return GIT_ENOMEM;
788
789 backend->objects_dir = git__strdup(objects_dir);
790 if (backend->objects_dir == NULL) {
791 free(backend);
792 return GIT_ENOMEM;
793 }
794
795 backend->object_zlib_level = Z_BEST_SPEED;
796 backend->fsync_object_files = 0;
797
798 backend->parent.read = &loose_backend__read;
799 backend->parent.read_prefix = &loose_backend__read_prefix;
800 backend->parent.read_header = &loose_backend__read_header;
801 backend->parent.writestream = &loose_backend__stream;
802 backend->parent.exists = &loose_backend__exists;
803 backend->parent.free = &loose_backend__free;
804
805 *backend_out = (git_odb_backend *)backend;
806 return GIT_SUCCESS;
807 }