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