]> git.proxmox.com Git - libgit2.git/blob - src/odb_loose.c
oid: Uniformize ncmp methods
[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 "git2/oid.h"
30 #include "fileops.h"
31 #include "hash.h"
32 #include "odb.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 * compare the first ncmp characters of the oids */
496 if (!memcmp(sstate->short_oid + 2,
497 (unsigned char *)pathbuf + sstate->dir_len,
498 sstate->short_oid_len - 2)) {
499
500 if (!sstate->found) {
501 sstate->res_oid[0] = sstate->short_oid[0];
502 sstate->res_oid[1] = sstate->short_oid[1];
503 memcpy(sstate->res_oid+2, pathbuf+sstate->dir_len, GIT_OID_HEXSZ-2);
504 }
505 sstate->found++;
506 }
507 }
508 if (sstate->found > 1)
509 return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Ambiguous sha1 prefix within loose objects");
510
511 return GIT_SUCCESS;
512 }
513
514 /* Locate an object matching a given short oid */
515 static int locate_object_short_oid(char *object_location, git_oid *res_oid, loose_backend *backend, const git_oid *short_oid, unsigned int len)
516 {
517 char *objects_dir = backend->objects_dir;
518 size_t dir_len = strlen(objects_dir);
519 loose_locate_object_state state;
520 int error;
521
522 if (dir_len+43 > GIT_PATH_MAX)
523 return git__throw(GIT_ERROR, "Failed to locate object from short oid. Object path too long");
524
525 strcpy(object_location, objects_dir);
526
527 /* Add a separator if not already there */
528 if (object_location[dir_len-1] != '/')
529 object_location[dir_len++] = '/';
530
531 /* Convert raw oid to hex formatted oid */
532 git_oid_fmt((char *)state.short_oid, short_oid);
533 /* Explore OBJ_DIR/xx/ where xx is the beginning of hex formatted short oid */
534 sprintf(object_location+dir_len, "%.2s/", state.short_oid);
535
536 /* Check that directory exists */
537 if (gitfo_exists(object_location) || gitfo_isdir(object_location))
538 return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found");
539
540 state.dir_len = dir_len+3;
541 state.short_oid_len = len;
542 state.found = 0;
543 /* Explore directory to find a unique object matching short_oid */
544 error = gitfo_dirent(object_location, GIT_PATH_MAX, fn_locate_object_short_oid, &state);
545 if (error) {
546 return git__rethrow(error, "Failed to locate object from short oid");
547 }
548 if (!state.found) {
549 return git__throw(GIT_ENOTFOUND, "Failed to locate object from short oid. Object not found");
550 }
551
552 /* Convert obtained hex formatted oid to raw */
553 error = git_oid_fromstr(res_oid, (char *)state.res_oid);
554 if (error) {
555 return git__rethrow(error, "Failed to locate object from short oid");
556 }
557
558 /* Update the location according to the oid obtained */
559 git_oid_pathfmt(object_location+dir_len, res_oid);
560
561 return GIT_SUCCESS;
562 }
563
564
565
566
567
568
569
570
571
572 /***********************************************************
573 *
574 * LOOSE BACKEND PUBLIC API
575 *
576 * Implement the git_odb_backend API calls
577 *
578 ***********************************************************/
579
580 int loose_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
581 {
582 char object_path[GIT_PATH_MAX];
583 git_rawobj raw;
584 int error;
585
586 assert(backend && oid);
587
588 raw.len = 0;
589 raw.type = GIT_OBJ_BAD;
590
591 if (locate_object(object_path, (loose_backend *)backend, oid) < 0)
592 return git__throw(GIT_ENOTFOUND, "Failed to read loose backend header. Object not found");
593
594 if ((error = read_header_loose(&raw, object_path)) < GIT_SUCCESS)
595 return error;
596
597 *len_p = raw.len;
598 *type_p = raw.type;
599 return GIT_SUCCESS;
600 }
601
602 int loose_backend__read(void **buffer_p, size_t *len_p, git_otype *type_p, git_odb_backend *backend, const git_oid *oid)
603 {
604 char object_path[GIT_PATH_MAX];
605 git_rawobj raw;
606 int error;
607
608 assert(backend && oid);
609
610 if (locate_object(object_path, (loose_backend *)backend, oid) < 0)
611 return git__throw(GIT_ENOTFOUND, "Failed to read loose backend. Object not found");
612
613 if ((error = read_loose(&raw, object_path)) < GIT_SUCCESS)
614 return git__rethrow(error, "Failed to read loose backend");
615
616 *buffer_p = raw.data;
617 *len_p = raw.len;
618 *type_p = raw.type;
619
620 return GIT_SUCCESS;
621 }
622
623 int loose_backend__read_prefix(
624 git_oid *out_oid,
625 void **buffer_p,
626 size_t *len_p,
627 git_otype *type_p,
628 git_odb_backend *backend,
629 const git_oid *short_oid,
630 unsigned int len)
631 {
632 if (len < GIT_OID_MINPREFIXLEN)
633 return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to read loose backend. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN);
634
635 if (len >= GIT_OID_HEXSZ) {
636 /* We can fall back to regular read method */
637 int error = loose_backend__read(buffer_p, len_p, type_p, backend, short_oid);
638 if (error == GIT_SUCCESS)
639 git_oid_cpy(out_oid, short_oid);
640
641 return error;
642 } else {
643 char object_path[GIT_PATH_MAX];
644 git_rawobj raw;
645 int error;
646
647 assert(backend && short_oid);
648
649 if ((error = locate_object_short_oid(object_path, out_oid, (loose_backend *)backend, short_oid, len)) < 0) {
650 return git__rethrow(error, "Failed to read loose backend");
651 }
652
653 if ((error = read_loose(&raw, object_path)) < GIT_SUCCESS)
654 return git__rethrow(error, "Failed to read loose backend");
655
656 *buffer_p = raw.data;
657 *len_p = raw.len;
658 *type_p = raw.type;
659 }
660
661 return GIT_SUCCESS;
662 }
663
664 int loose_backend__exists(git_odb_backend *backend, const git_oid *oid)
665 {
666 char object_path[GIT_PATH_MAX];
667
668 assert(backend && oid);
669
670 return locate_object(object_path, (loose_backend *)backend, oid) == GIT_SUCCESS;
671 }
672
673 int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream)
674 {
675 loose_writestream *stream = (loose_writestream *)_stream;
676 loose_backend *backend = (loose_backend *)_stream->backend;
677
678 int error;
679 char final_path[GIT_PATH_MAX];
680
681 if ((error = git_filebuf_hash(oid, &stream->fbuf)) < GIT_SUCCESS)
682 return git__rethrow(error, "Failed to write loose backend");
683
684 if (object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid))
685 return GIT_ENOMEM;
686
687 if ((error = gitfo_mkdir_2file(final_path)) < GIT_SUCCESS)
688 return git__rethrow(error, "Failed to write loose backend");
689
690 stream->finished = 1;
691 return git_filebuf_commit_at(&stream->fbuf, final_path);
692 }
693
694 int loose_backend__stream_write(git_odb_stream *_stream, const char *data, size_t len)
695 {
696 loose_writestream *stream = (loose_writestream *)_stream;
697 return git_filebuf_write(&stream->fbuf, data, len);
698 }
699
700 void loose_backend__stream_free(git_odb_stream *_stream)
701 {
702 loose_writestream *stream = (loose_writestream *)_stream;
703
704 if (!stream->finished)
705 git_filebuf_cleanup(&stream->fbuf);
706
707 free(stream);
708 }
709
710 static int format_object_header(char *hdr, size_t n, size_t obj_len, git_otype obj_type)
711 {
712 const char *type_str = git_object_type2string(obj_type);
713 int len = snprintf(hdr, n, "%s %"PRIuZ, type_str, obj_len);
714
715 assert(len > 0); /* otherwise snprintf() is broken */
716 assert(((size_t) len) < n); /* otherwise the caller is broken! */
717
718 if (len < 0 || ((size_t) len) >= n)
719 return git__throw(GIT_ERROR, "Failed to format object header. Length is out of bounds");
720 return len+1;
721 }
722
723 int loose_backend__stream(git_odb_stream **stream_out, git_odb_backend *_backend, size_t length, git_otype type)
724 {
725 loose_backend *backend;
726 loose_writestream *stream;
727
728 char hdr[64], tmp_path[GIT_PATH_MAX];
729 int hdrlen;
730 int error;
731
732 assert(_backend);
733
734 backend = (loose_backend *)_backend;
735 *stream_out = NULL;
736
737 hdrlen = format_object_header(hdr, sizeof(hdr), length, type);
738 if (hdrlen < GIT_SUCCESS)
739 return git__throw(GIT_EOBJCORRUPTED, "Failed to create loose backend stream. Object is corrupted");
740
741 stream = git__calloc(1, sizeof(loose_writestream));
742 if (stream == NULL)
743 return GIT_ENOMEM;
744
745 stream->stream.backend = _backend;
746 stream->stream.read = NULL; /* read only */
747 stream->stream.write = &loose_backend__stream_write;
748 stream->stream.finalize_write = &loose_backend__stream_fwrite;
749 stream->stream.free = &loose_backend__stream_free;
750 stream->stream.mode = GIT_STREAM_WRONLY;
751
752 git__joinpath(tmp_path, backend->objects_dir, "tmp_object");
753
754 error = git_filebuf_open(&stream->fbuf, tmp_path,
755 GIT_FILEBUF_HASH_CONTENTS |
756 GIT_FILEBUF_DEFLATE_CONTENTS |
757 GIT_FILEBUF_TEMPORARY);
758
759 if (error < GIT_SUCCESS) {
760 free(stream);
761 return git__rethrow(error, "Failed to create loose backend stream");
762 }
763
764 error = stream->stream.write((git_odb_stream *)stream, hdr, hdrlen);
765 if (error < GIT_SUCCESS) {
766 git_filebuf_cleanup(&stream->fbuf);
767 free(stream);
768 return git__rethrow(error, "Failed to create loose backend stream");
769 }
770
771 *stream_out = (git_odb_stream *)stream;
772 return GIT_SUCCESS;
773 }
774
775 void loose_backend__free(git_odb_backend *_backend)
776 {
777 loose_backend *backend;
778 assert(_backend);
779 backend = (loose_backend *)_backend;
780
781 free(backend->objects_dir);
782 free(backend);
783 }
784
785 int git_odb_backend_loose(git_odb_backend **backend_out, const char *objects_dir)
786 {
787 loose_backend *backend;
788
789 backend = git__calloc(1, sizeof(loose_backend));
790 if (backend == NULL)
791 return GIT_ENOMEM;
792
793 backend->objects_dir = git__strdup(objects_dir);
794 if (backend->objects_dir == NULL) {
795 free(backend);
796 return GIT_ENOMEM;
797 }
798
799 backend->object_zlib_level = Z_BEST_SPEED;
800 backend->fsync_object_files = 0;
801
802 backend->parent.read = &loose_backend__read;
803 backend->parent.read_prefix = &loose_backend__read_prefix;
804 backend->parent.read_header = &loose_backend__read_header;
805 backend->parent.writestream = &loose_backend__stream;
806 backend->parent.exists = &loose_backend__exists;
807 backend->parent.free = &loose_backend__free;
808
809 *backend_out = (git_odb_backend *)backend;
810 return GIT_SUCCESS;
811 }