]>
git.proxmox.com Git - libgit2.git/blob - src/odb.c
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.
34 /** Path to the "objects" directory. */
37 /** Alternate databases to search. */
41 typedef struct { /* object header data */
42 git_otype type
; /* object type */
43 size_t size
; /* object size */
47 const char *str
; /* type name string */
48 int loose
; /* valid loose object type flag */
49 } obj_type_table
[] = {
50 { "", 0 }, /* 0 = GIT_OBJ__EXT1 */
51 { "commit", 1 }, /* 1 = GIT_OBJ_COMMIT */
52 { "tree", 1 }, /* 2 = GIT_OBJ_TREE */
53 { "blob", 1 }, /* 3 = GIT_OBJ_BLOB */
54 { "tag", 1 }, /* 4 = GIT_OBJ_TAG */
55 { "", 0 }, /* 5 = GIT_OBJ__EXT2 */
56 { "OFS_DELTA", 0 }, /* 6 = GIT_OBJ_OFS_DELTA */
57 { "REF_DELTA", 0 } /* 7 = GIT_OBJ_REF_DELTA */
60 const char *git_obj_type_to_string(git_otype type
)
62 if (type
< 0 || type
>= ARRAY_SIZE(obj_type_table
))
64 return obj_type_table
[type
].str
;
67 git_otype
git_obj_string_to_type(const char *str
)
74 for (i
= 0; i
< ARRAY_SIZE(obj_type_table
); i
++)
75 if (!strcmp(str
, obj_type_table
[i
].str
))
81 int git_obj__loose_object_type(git_otype type
)
83 if (type
< 0 || type
>= ARRAY_SIZE(obj_type_table
))
85 return obj_type_table
[type
].loose
;
88 static int format_object_header(char *hdr
, size_t n
, git_obj
*obj
)
90 const char *type_str
= git_obj_type_to_string(obj
->type
);
91 int len
= snprintf(hdr
, n
, "%s %" PRIuPTR
, type_str
, obj
->len
);
93 assert(len
> 0); /* otherwise snprintf() is broken */
94 assert(len
< n
); /* otherwise the caller is broken! */
96 if (len
< 0 || len
>= n
)
101 int git_obj_hash(git_oid
*id
, git_obj
*obj
)
109 if (!git_obj__loose_object_type(obj
->type
))
112 if (!obj
->data
&& obj
->len
!= 0)
115 if ((hdrlen
= format_object_header(hdr
, sizeof(hdr
), obj
)) < 0)
120 vec
[1].data
= obj
->data
;
121 vec
[1].len
= obj
->len
;
123 git_hash_vec(id
, vec
, 2);
128 static int object_file_name(char *name
, size_t n
, char *dir
, const git_oid
*id
)
130 size_t len
= strlen(dir
);
132 /* check length: 43 = 40 hex sha1 chars + 2 * '/' + '\0' */
136 /* the object dir: eg $GIT_DIR/objects */
138 if (name
[len
-1] != '/')
141 /* loose object filename: aa/aaa... (41 bytes) */
142 git_oid_pathfmt(&name
[len
], id
);
148 static int is_zlib_compressed_data(unsigned char *data
)
152 w
= ((unsigned int)(data
[0]) << 8) + data
[1];
153 return data
[0] == 0x78 && !(w
%31);
156 static size_t get_binary_object_header(obj_hdr
*hdr
, gitfo_buf
*obj
)
159 unsigned char *data
= obj
->data
;
160 size_t shift
, size
, used
= 0;
166 hdr
->type
= (c
>> 4) & 7;
171 if (obj
->len
<= used
)
173 if (sizeof(size_t) * 8 <= shift
)
176 size
+= (c
& 0x7f) << shift
;
184 static size_t get_object_header(obj_hdr
*hdr
, unsigned char *data
)
186 char c
, typename
[10];
187 size_t size
, used
= 0;
190 * type name string followed by space.
192 while ((c
= data
[used
]) != ' ') {
193 typename
[used
++] = c
;
194 if (used
>= sizeof(typename
))
200 hdr
->type
= git_obj_string_to_type(typename
);
201 used
++; /* consume the space */
204 * length follows immediately in decimal (without
207 size
= data
[used
++] - '0';
211 while ((c
= data
[used
]) != '\0') {
216 size
= size
* 10 + d
;
222 * the length must be followed by a zero byte
224 if (data
[used
++] != '\0')
230 static void init_stream(z_stream
*s
, void *out
, size_t len
)
232 memset(s
, 0, sizeof(*s
));
237 static void set_stream_input(z_stream
*s
, void *in
, size_t len
)
243 static void set_stream_output(z_stream
*s
, void *out
, size_t len
)
249 static int start_inflate(z_stream
*s
, gitfo_buf
*obj
, void *out
, size_t len
)
251 init_stream(s
, out
, len
);
252 set_stream_input(s
, obj
->data
, obj
->len
);
254 return inflate(s
, 0);
257 static int finish_inflate(z_stream
*s
)
261 while (status
== Z_OK
)
262 status
= inflate(s
, Z_FINISH
);
266 if ((status
!= Z_STREAM_END
) || (s
->avail_in
!= 0))
272 static void *inflate_tail(z_stream
*s
, void *hb
, size_t used
, obj_hdr
*hdr
)
274 unsigned char *buf
, *head
= hb
;
278 * allocate a buffer to hold the inflated data and copy the
279 * initial sequence of inflated data from the tail of the
280 * head buffer, if any.
282 if ((buf
= git__malloc(hdr
->size
+ 1)) == NULL
)
284 tail
= s
->total_out
- used
;
285 if (used
> 0 && tail
> 0) {
286 if (tail
> hdr
->size
)
288 memcpy(buf
, head
+ used
, tail
);
293 * inflate the remainder of the object data, if any
295 if (hdr
->size
>= used
) {
296 set_stream_output(s
, buf
+ used
, hdr
->size
- used
);
297 if (finish_inflate(s
)) {
306 static int inflate_buffer(void *in
, size_t inlen
, void *out
, size_t outlen
)
311 init_stream(&zs
, out
, outlen
);
312 set_stream_input(&zs
, in
, inlen
);
316 while (status
== Z_OK
)
317 status
= inflate(&zs
, Z_FINISH
);
321 if ((status
!= Z_STREAM_END
) || (zs
.total_out
!= outlen
))
324 if (zs
.avail_in
!= 0)
331 * At one point, there was a loose object format that was intended to
332 * mimic the format used in pack-files. This was to allow easy copying
333 * of loose object data into packs. This format is no longer used, but
334 * we must still read it.
336 static int inflate_packlike_loose_disk_obj(git_obj
*out
, gitfo_buf
*obj
)
338 unsigned char *in
, *buf
;
343 * read the object header, which is an (uncompressed)
344 * binary encoding of the object type and size.
346 if ((used
= get_binary_object_header(&hdr
, obj
)) == 0)
349 if (!git_obj__loose_object_type(hdr
.type
))
353 * allocate a buffer and inflate the data into it
355 buf
= git__malloc(hdr
.size
+ 1);
359 in
= ((unsigned char *)obj
->data
) + used
;
360 len
= obj
->len
- used
;
361 if (inflate_buffer(in
, len
, buf
, hdr
.size
)) {
365 buf
[hdr
.size
] = '\0';
369 out
->type
= hdr
.type
;
374 static int inflate_disk_obj(git_obj
*out
, gitfo_buf
*obj
)
376 unsigned char head
[64], *buf
;
383 * check for a pack-like loose object
385 if (!is_zlib_compressed_data(obj
->data
))
386 return inflate_packlike_loose_disk_obj(out
, obj
);
389 * inflate the initial part of the io buffer in order
390 * to parse the object header (type and size).
392 if ((z_status
= start_inflate(&zs
, obj
, head
, sizeof(head
))) < Z_OK
)
395 if ((used
= get_object_header(&hdr
, head
)) == 0)
398 if (!git_obj__loose_object_type(hdr
.type
))
402 * allocate a buffer and inflate the object data into it
403 * (including the initial sequence in the head buffer).
405 if ((buf
= inflate_tail(&zs
, head
, used
, &hdr
)) == NULL
)
407 buf
[hdr
.size
] = '\0';
411 out
->type
= hdr
.type
;
416 static int open_alternates(git_odb
*db
)
420 db
->alternates
= git__malloc(sizeof(*db
->alternates
) * (n
+ 1));
424 db
->alternates
[n
] = NULL
;
428 int git_odb_open(git_odb
**out
, const char *objects_dir
)
430 git_odb
*db
= git__malloc(sizeof(*db
));
434 db
->objects_dir
= git__strdup(objects_dir
);
435 if (!db
->objects_dir
) {
440 db
->alternates
= NULL
;
446 void git_odb_close(git_odb
*db
)
451 if (db
->alternates
) {
453 for (alt
= db
->alternates
; *alt
; alt
++)
455 free(db
->alternates
);
458 free(db
->objects_dir
);
468 if (!git_odb__read_packed(out
, db
, id
))
470 if (!git_odb__read_loose(out
, db
, id
))
472 if (!db
->alternates
&& !open_alternates(db
))
476 return GIT_ENOTFOUND
;
479 int git_odb__read_loose(git_obj
*out
, git_odb
*db
, const git_oid
*id
)
481 char file
[GIT_PATH_MAX
];
482 gitfo_buf obj
= GITFO_BUF_INIT
;
484 assert(out
&& db
&& id
);
488 out
->type
= GIT_OBJ_BAD
;
490 if (object_file_name(file
, sizeof(file
), db
->objects_dir
, id
))
491 return GIT_ENOTFOUND
; /* TODO: error handling */
493 if (gitfo_read_file(&obj
, file
))
494 return GIT_ENOTFOUND
; /* TODO: error handling */
496 if (inflate_disk_obj(out
, &obj
)) {
497 gitfo_free_buf(&obj
);
498 return GIT_ENOTFOUND
; /* TODO: error handling */
501 gitfo_free_buf(&obj
);
506 int git_odb__read_packed(git_obj
*out
, git_odb
*db
, const git_oid
*id
)
508 return GIT_ENOTFOUND
;