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.
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.)
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.
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.
27 #include "git2/zlib.h"
28 #include "git2/object.h"
32 #include "delta-apply.h"
35 #include "git2/odb_backend.h"
36 #include "git2/types.h"
38 typedef struct { /* object header data */
39 git_otype type
; /* object type */
40 size_t size
; /* object size */
44 git_odb_stream stream
;
49 typedef struct loose_backend
{
50 git_odb_backend parent
;
52 int object_zlib_level
; /** loose object zlib compression level. */
53 int fsync_object_files
; /** loose object file fsync flag. */
58 /***********************************************************
60 * MISCELANEOUS HELPER FUNCTIONS
62 ***********************************************************/
64 static size_t object_file_name(char *name
, size_t n
, char *dir
, const git_oid
*id
)
66 size_t len
= strlen(dir
);
68 /* check length: 43 = 40 hex sha1 chars + 2 * '/' + '\0' */
72 /* the object dir: eg $GIT_DIR/objects */
74 if (name
[len
-1] != '/')
77 /* loose object filename: aa/aaa... (41 bytes) */
78 git_oid_pathfmt(&name
[len
], id
);
85 static size_t get_binary_object_header(obj_hdr
*hdr
, gitfo_buf
*obj
)
88 unsigned char *data
= obj
->data
;
89 size_t shift
, size
, used
= 0;
95 hdr
->type
= (c
>> 4) & 7;
100 if (obj
->len
<= used
)
102 if (sizeof(size_t) * 8 <= shift
)
105 size
+= (c
& 0x7f) << shift
;
113 static size_t get_object_header(obj_hdr
*hdr
, unsigned char *data
)
115 char c
, typename
[10];
116 size_t size
, used
= 0;
119 * type name string followed by space.
121 while ((c
= data
[used
]) != ' ') {
122 typename
[used
++] = c
;
123 if (used
>= sizeof(typename
))
129 hdr
->type
= git_object_string2type(typename
);
130 used
++; /* consume the space */
133 * length follows immediately in decimal (without
136 size
= data
[used
++] - '0';
140 while ((c
= data
[used
]) != '\0') {
145 size
= size
* 10 + d
;
151 * the length must be followed by a zero byte
153 if (data
[used
++] != '\0')
161 /***********************************************************
163 * ZLIB RELATED FUNCTIONS
165 ***********************************************************/
167 static void init_stream(z_stream
*s
, void *out
, size_t len
)
169 memset(s
, 0, sizeof(*s
));
174 static void set_stream_input(z_stream
*s
, void *in
, size_t len
)
180 static void set_stream_output(z_stream
*s
, void *out
, size_t len
)
187 static int start_inflate(z_stream
*s
, gitfo_buf
*obj
, void *out
, size_t len
)
191 init_stream(s
, out
, len
);
192 set_stream_input(s
, obj
->data
, obj
->len
);
194 if ((status
= inflateInit(s
)) < Z_OK
)
197 return inflate(s
, 0);
200 static int finish_inflate(z_stream
*s
)
204 while (status
== Z_OK
)
205 status
= inflate(s
, Z_FINISH
);
209 if ((status
!= Z_STREAM_END
) || (s
->avail_in
!= 0))
215 static int is_zlib_compressed_data(unsigned char *data
)
219 w
= ((unsigned int)(data
[0]) << 8) + data
[1];
220 return data
[0] == 0x78 && !(w
% 31);
223 static int inflate_buffer(void *in
, size_t inlen
, void *out
, size_t outlen
)
228 memset(&zs
, 0x0, sizeof(zs
));
231 zs
.avail_out
= outlen
;
236 if (inflateInit(&zs
) < Z_OK
)
239 while (status
== Z_OK
)
240 status
= inflate(&zs
, Z_FINISH
);
244 if ((status
!= Z_STREAM_END
) /*|| (zs.avail_in != 0) */)
247 if (zs
.total_out
!= outlen
)
253 static void *inflate_tail(z_stream
*s
, void *hb
, size_t used
, obj_hdr
*hdr
)
255 unsigned char *buf
, *head
= hb
;
259 * allocate a buffer to hold the inflated data and copy the
260 * initial sequence of inflated data from the tail of the
261 * head buffer, if any.
263 if ((buf
= git__malloc(hdr
->size
+ 1)) == NULL
) {
267 tail
= s
->total_out
- used
;
268 if (used
> 0 && tail
> 0) {
269 if (tail
> hdr
->size
)
271 memcpy(buf
, head
+ used
, tail
);
276 * inflate the remainder of the object data, if any
278 if (hdr
->size
< used
)
281 set_stream_output(s
, buf
+ used
, hdr
->size
- used
);
282 if (finish_inflate(s
)) {
292 * At one point, there was a loose object format that was intended to
293 * mimic the format used in pack-files. This was to allow easy copying
294 * of loose object data into packs. This format is no longer used, but
295 * we must still read it.
297 static int inflate_packlike_loose_disk_obj(git_rawobj
*out
, gitfo_buf
*obj
)
299 unsigned char *in
, *buf
;
304 * read the object header, which is an (uncompressed)
305 * binary encoding of the object type and size.
307 if ((used
= get_binary_object_header(&hdr
, obj
)) == 0)
310 if (!git_object_typeisloose(hdr
.type
))
314 * allocate a buffer and inflate the data into it
316 buf
= git__malloc(hdr
.size
+ 1);
320 in
= ((unsigned char *)obj
->data
) + used
;
321 len
= obj
->len
- used
;
322 if (inflate_buffer(in
, len
, buf
, hdr
.size
)) {
326 buf
[hdr
.size
] = '\0';
330 out
->type
= hdr
.type
;
335 static int inflate_disk_obj(git_rawobj
*out
, gitfo_buf
*obj
)
337 unsigned char head
[64], *buf
;
344 * check for a pack-like loose object
346 if (!is_zlib_compressed_data(obj
->data
))
347 return inflate_packlike_loose_disk_obj(out
, obj
);
350 * inflate the initial part of the io buffer in order
351 * to parse the object header (type and size).
353 if ((z_status
= start_inflate(&zs
, obj
, head
, sizeof(head
))) < Z_OK
)
356 if ((used
= get_object_header(&hdr
, head
)) == 0)
359 if (!git_object_typeisloose(hdr
.type
))
363 * allocate a buffer and inflate the object data into it
364 * (including the initial sequence in the head buffer).
366 if ((buf
= inflate_tail(&zs
, head
, used
, &hdr
)) == NULL
)
368 buf
[hdr
.size
] = '\0';
372 out
->type
= hdr
.type
;
382 /***********************************************************
384 * ODB OBJECT READING & WRITING
386 * Backend for the public API; read headers and full objects
387 * from the ODB. Write raw data to the ODB.
389 ***********************************************************/
391 static int read_loose(git_rawobj
*out
, const char *loc
)
394 gitfo_buf obj
= GITFO_BUF_INIT
;
400 out
->type
= GIT_OBJ_BAD
;
402 if (gitfo_read_file(&obj
, loc
) < 0)
403 return GIT_ENOTFOUND
;
405 error
= inflate_disk_obj(out
, &obj
);
406 gitfo_free_buf(&obj
);
411 static int read_header_loose(git_rawobj
*out
, const char *loc
)
413 int error
= GIT_SUCCESS
, z_return
= Z_ERRNO
, read_bytes
;
417 unsigned char raw_buffer
[16], inflated_buffer
[64];
423 if ((fd
= gitfo_open(loc
, O_RDONLY
)) < 0)
424 return GIT_ENOTFOUND
;
426 init_stream(&zs
, inflated_buffer
, sizeof(inflated_buffer
));
428 if (inflateInit(&zs
) < Z_OK
) {
434 if ((read_bytes
= read(fd
, raw_buffer
, sizeof(raw_buffer
))) > 0) {
435 set_stream_input(&zs
, raw_buffer
, read_bytes
);
436 z_return
= inflate(&zs
, 0);
438 z_return
= Z_STREAM_END
;
441 } while (z_return
== Z_OK
);
443 if ((z_return
!= Z_STREAM_END
&& z_return
!= Z_BUF_ERROR
)
444 || get_object_header(&header_obj
, inflated_buffer
) == 0
445 || git_object_typeisloose(header_obj
.type
) == 0) {
446 error
= GIT_EOBJCORRUPTED
;
450 out
->len
= header_obj
.size
;
451 out
->type
= header_obj
.type
;
459 static int locate_object(char *object_location
, loose_backend
*backend
, const git_oid
*oid
)
461 object_file_name(object_location
, GIT_PATH_MAX
, backend
->objects_dir
, oid
);
462 return gitfo_exists(object_location
);
473 /***********************************************************
475 * LOOSE BACKEND PUBLIC API
477 * Implement the git_odb_backend API calls
479 ***********************************************************/
481 int loose_backend__read_header(size_t *len_p
, git_otype
*type_p
, git_odb_backend
*backend
, const git_oid
*oid
)
483 char object_path
[GIT_PATH_MAX
];
487 assert(backend
&& oid
);
489 if (locate_object(object_path
, (loose_backend
*)backend
, oid
) < 0)
490 return GIT_ENOTFOUND
;
492 if ((error
= read_header_loose(&raw
, object_path
)) < GIT_SUCCESS
)
500 int loose_backend__read(void **buffer_p
, size_t *len_p
, git_otype
*type_p
, git_odb_backend
*backend
, const git_oid
*oid
)
502 char object_path
[GIT_PATH_MAX
];
506 assert(backend
&& oid
);
508 if (locate_object(object_path
, (loose_backend
*)backend
, oid
) < 0)
509 return GIT_ENOTFOUND
;
511 if ((error
= read_loose(&raw
, object_path
)) < GIT_SUCCESS
)
514 *buffer_p
= raw
.data
;
521 int loose_backend__exists(git_odb_backend
*backend
, const git_oid
*oid
)
523 char object_path
[GIT_PATH_MAX
];
525 assert(backend
&& oid
);
527 return locate_object(object_path
, (loose_backend
*)backend
, oid
) == GIT_SUCCESS
;
530 int loose_backend__stream_fwrite(git_oid
*oid
, git_odb_stream
*_stream
)
532 loose_writestream
*stream
= (loose_writestream
*)_stream
;
533 loose_backend
*backend
= (loose_backend
*)_stream
->backend
;
536 char final_path
[GIT_PATH_MAX
];
538 if ((error
= git_filebuf_hash(oid
, &stream
->fbuf
)) < GIT_SUCCESS
)
541 if (object_file_name(final_path
, sizeof(final_path
), backend
->objects_dir
, oid
))
544 if ((error
= gitfo_mkdir_2file(final_path
)) < GIT_SUCCESS
)
547 stream
->finished
= 1;
548 return git_filebuf_commit_at(&stream
->fbuf
, final_path
);
551 int loose_backend__stream_write(git_odb_stream
*_stream
, const char *data
, size_t len
)
553 loose_writestream
*stream
= (loose_writestream
*)_stream
;
554 return git_filebuf_write(&stream
->fbuf
, data
, len
);
557 void loose_backend__stream_free(git_odb_stream
*_stream
)
559 loose_writestream
*stream
= (loose_writestream
*)_stream
;
561 if (!stream
->finished
)
562 git_filebuf_cleanup(&stream
->fbuf
);
567 static int format_object_header(char *hdr
, size_t n
, size_t obj_len
, git_otype obj_type
)
569 const char *type_str
= git_object_type2string(obj_type
);
570 int len
= snprintf(hdr
, n
, "%s %"PRIuZ
, type_str
, obj_len
);
572 assert(len
> 0); /* otherwise snprintf() is broken */
573 assert(((size_t) len
) < n
); /* otherwise the caller is broken! */
575 if (len
< 0 || ((size_t) len
) >= n
)
580 int loose_backend__stream(git_odb_stream
**stream_out
, git_odb_backend
*_backend
, size_t length
, git_otype type
)
582 loose_backend
*backend
;
583 loose_writestream
*stream
;
585 char hdr
[64], tmp_path
[GIT_PATH_MAX
];
591 backend
= (loose_backend
*)_backend
;
594 hdrlen
= format_object_header(hdr
, sizeof(hdr
), length
, type
);
595 if (hdrlen
< GIT_SUCCESS
)
596 return GIT_EOBJCORRUPTED
;
598 stream
= git__calloc(1, sizeof(loose_writestream
));
602 stream
->stream
.backend
= _backend
;
603 stream
->stream
.read
= NULL
; /* read only */
604 stream
->stream
.write
= &loose_backend__stream_write
;
605 stream
->stream
.finalize_write
= &loose_backend__stream_fwrite
;
606 stream
->stream
.free
= &loose_backend__stream_free
;
607 stream
->stream
.mode
= GIT_STREAM_WRONLY
;
609 git__joinpath(tmp_path
, backend
->objects_dir
, "tmp_object");
611 error
= git_filebuf_open(&stream
->fbuf
, tmp_path
,
612 GIT_FILEBUF_HASH_CONTENTS
|
613 GIT_FILEBUF_DEFLATE_CONTENTS
|
614 GIT_FILEBUF_TEMPORARY
);
616 if (error
< GIT_SUCCESS
) {
621 error
= stream
->stream
.write((git_odb_stream
*)stream
, hdr
, hdrlen
);
622 if (error
< GIT_SUCCESS
) {
623 git_filebuf_cleanup(&stream
->fbuf
);
628 *stream_out
= (git_odb_stream
*)stream
;
632 void loose_backend__free(git_odb_backend
*_backend
)
634 loose_backend
*backend
;
636 backend
= (loose_backend
*)_backend
;
638 free(backend
->objects_dir
);
642 int git_odb_backend_loose(git_odb_backend
**backend_out
, const char *objects_dir
)
644 loose_backend
*backend
;
646 backend
= git__calloc(1, sizeof(loose_backend
));
650 backend
->objects_dir
= git__strdup(objects_dir
);
651 if (backend
->objects_dir
== NULL
) {
656 backend
->object_zlib_level
= Z_BEST_SPEED
;
657 backend
->fsync_object_files
= 0;
659 backend
->parent
.read
= &loose_backend__read
;
660 backend
->parent
.read_header
= &loose_backend__read_header
;
661 backend
->parent
.writestream
= &loose_backend__stream
;
662 backend
->parent
.exists
= &loose_backend__exists
;
663 backend
->parent
.free
= &loose_backend__free
;
665 *backend_out
= (git_odb_backend
*)backend
;