2 d71d75ad 2017-11-05 stsp * Copyright (c) 2017 Stefan Sperling <stsp@openbsd.org>
4 d71d75ad 2017-11-05 stsp * Permission to use, copy, modify, and distribute this software for any
5 d71d75ad 2017-11-05 stsp * purpose with or without fee is hereby granted, provided that the above
6 d71d75ad 2017-11-05 stsp * copyright notice and this permission notice appear in all copies.
8 d71d75ad 2017-11-05 stsp * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 d71d75ad 2017-11-05 stsp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 d71d75ad 2017-11-05 stsp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 d71d75ad 2017-11-05 stsp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 d71d75ad 2017-11-05 stsp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 d71d75ad 2017-11-05 stsp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 d71d75ad 2017-11-05 stsp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 d71d75ad 2017-11-05 stsp #include <stdio.h>
18 ab9a70b2 2017-11-06 stsp #include <stdlib.h>
19 ab9a70b2 2017-11-06 stsp #include <string.h>
20 d71d75ad 2017-11-05 stsp #include <sha1.h>
21 ab9a70b2 2017-11-06 stsp #include <zlib.h>
22 ab9a70b2 2017-11-06 stsp #include <ctype.h>
23 ab9a70b2 2017-11-06 stsp #include <limits.h>
25 ab9a70b2 2017-11-06 stsp #include "got_error.h"
26 d71d75ad 2017-11-05 stsp #include "got_object.h"
27 ab9a70b2 2017-11-06 stsp #include "got_repository.h"
30 ab9a70b2 2017-11-06 stsp #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
33 ab9a70b2 2017-11-06 stsp #ifndef nitems
34 ab9a70b2 2017-11-06 stsp #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
37 ab9a70b2 2017-11-06 stsp #define GOT_OBJ_TAG_COMMIT "commit"
38 ab9a70b2 2017-11-06 stsp #define GOT_OBJ_TAG_TREE "tree"
39 ab9a70b2 2017-11-06 stsp #define GOT_OBJ_TAG_BLOB "blob"
41 d71d75ad 2017-11-05 stsp const char *
42 d71d75ad 2017-11-05 stsp got_object_id_str(struct got_object_id *id, char *buf, size_t size)
44 d71d75ad 2017-11-05 stsp char *p = buf;
45 d71d75ad 2017-11-05 stsp char hex[3];
48 d71d75ad 2017-11-05 stsp if (size < SHA1_DIGEST_STRING_LENGTH)
49 d71d75ad 2017-11-05 stsp return NULL;
51 d71d75ad 2017-11-05 stsp for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
52 d71d75ad 2017-11-05 stsp snprintf(hex, sizeof(hex), "%.2x", id->sha1[i]);
53 d71d75ad 2017-11-05 stsp p[0] = hex[0];
54 d71d75ad 2017-11-05 stsp p[1] = hex[1];
57 d71d75ad 2017-11-05 stsp p[0] = '\0';
62 ab9a70b2 2017-11-06 stsp struct got_zstream_buf {
64 ab9a70b2 2017-11-06 stsp char *inbuf;
65 ab9a70b2 2017-11-06 stsp size_t inlen;
66 ab9a70b2 2017-11-06 stsp char *outbuf;
67 ab9a70b2 2017-11-06 stsp size_t outlen;
69 ab9a70b2 2017-11-06 stsp #define GOT_ZSTREAM_F_HAVE_MORE 0x01
73 ab9a70b2 2017-11-06 stsp inflate_end(struct got_zstream_buf *zb)
75 ab9a70b2 2017-11-06 stsp free(zb->inbuf);
76 ab9a70b2 2017-11-06 stsp free(zb->outbuf);
77 ab9a70b2 2017-11-06 stsp inflateEnd(&zb->z);
80 ab9a70b2 2017-11-06 stsp static const struct got_error *
81 ab9a70b2 2017-11-06 stsp inflate_init(struct got_zstream_buf *zb, size_t bufsize)
83 ab9a70b2 2017-11-06 stsp const struct got_error *err = NULL;
85 ab9a70b2 2017-11-06 stsp memset(zb, 0, sizeof(*zb));
87 ab9a70b2 2017-11-06 stsp zb->z.zalloc = Z_NULL;
88 ab9a70b2 2017-11-06 stsp zb->z.zfree = Z_NULL;
89 ab9a70b2 2017-11-06 stsp if (inflateInit(&zb->z) != Z_OK) {
90 ab9a70b2 2017-11-06 stsp err = got_error(GOT_ERR_IO);
94 ab9a70b2 2017-11-06 stsp zb->inlen = zb->outlen = bufsize;
96 ab9a70b2 2017-11-06 stsp zb->inbuf = calloc(1, zb->inlen);
97 ab9a70b2 2017-11-06 stsp if (zb->inbuf == NULL) {
98 ab9a70b2 2017-11-06 stsp err = got_error(GOT_ERR_NO_MEM);
102 ab9a70b2 2017-11-06 stsp zb->outbuf = calloc(1, zb->outlen);
103 ab9a70b2 2017-11-06 stsp if (zb->outbuf == NULL) {
104 ab9a70b2 2017-11-06 stsp err = got_error(GOT_ERR_NO_MEM);
110 ab9a70b2 2017-11-06 stsp inflate_end(zb);
111 ab9a70b2 2017-11-06 stsp return err;
114 ab9a70b2 2017-11-06 stsp static const struct got_error *
115 ab9a70b2 2017-11-06 stsp inflate_read(struct got_zstream_buf *zb, FILE *f, size_t *outlenp)
117 ab9a70b2 2017-11-06 stsp size_t last_total_out = zb->z.total_out;
118 ab9a70b2 2017-11-06 stsp z_stream *z = &zb->z;
119 ab9a70b2 2017-11-06 stsp int n, ret;
121 ab9a70b2 2017-11-06 stsp z->next_out = zb->outbuf;
122 ab9a70b2 2017-11-06 stsp z->avail_out = zb->outlen;
124 ab9a70b2 2017-11-06 stsp if (z->avail_in == 0 && (zb->flags & GOT_ZSTREAM_F_HAVE_MORE) == 0) {
126 ab9a70b2 2017-11-06 stsp n = fread(zb->inbuf, 1, zb->inlen, f);
127 ab9a70b2 2017-11-06 stsp if (n == 0) {
128 ab9a70b2 2017-11-06 stsp if (ferror(f))
129 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_IO);
130 ab9a70b2 2017-11-06 stsp *outlenp = 0;
131 ab9a70b2 2017-11-06 stsp return NULL;
133 ab9a70b2 2017-11-06 stsp z->next_in = zb->inbuf;
134 ab9a70b2 2017-11-06 stsp z->avail_in = n;
137 ab9a70b2 2017-11-06 stsp ret = inflate(z, Z_SYNC_FLUSH);
138 ab9a70b2 2017-11-06 stsp if (ret == Z_OK) {
139 ab9a70b2 2017-11-06 stsp if (z->avail_out == 0)
140 ab9a70b2 2017-11-06 stsp zb->flags |= GOT_ZSTREAM_F_HAVE_MORE;
142 ab9a70b2 2017-11-06 stsp zb->flags &= ~GOT_ZSTREAM_F_HAVE_MORE;
143 ab9a70b2 2017-11-06 stsp } else if (ret != Z_STREAM_END)
144 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_DECOMPRESSION);
146 ab9a70b2 2017-11-06 stsp *outlenp = z->total_out - last_total_out;
147 ab9a70b2 2017-11-06 stsp return NULL;
150 ab9a70b2 2017-11-06 stsp static const struct got_error *
151 ab9a70b2 2017-11-06 stsp parse_obj_header(struct got_object **obj, char *buf, size_t len)
153 ab9a70b2 2017-11-06 stsp const char *obj_tags[] = {
154 ab9a70b2 2017-11-06 stsp GOT_OBJ_TAG_COMMIT,
155 ab9a70b2 2017-11-06 stsp GOT_OBJ_TAG_TREE,
156 ab9a70b2 2017-11-06 stsp GOT_OBJ_TAG_BLOB
158 ab9a70b2 2017-11-06 stsp const int obj_types[] = {
159 ab9a70b2 2017-11-06 stsp GOT_OBJ_TYPE_COMMIT,
160 ab9a70b2 2017-11-06 stsp GOT_OBJ_TYPE_TREE,
161 ab9a70b2 2017-11-06 stsp GOT_OBJ_TYPE_BLOB,
163 ab9a70b2 2017-11-06 stsp int type = 0;
164 ab9a70b2 2017-11-06 stsp size_t size = 0;
166 ab9a70b2 2017-11-06 stsp char *p = strchr(buf, '\0');
168 ab9a70b2 2017-11-06 stsp if (p == NULL)
169 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_BAD_OBJ_HDR);
171 ab9a70b2 2017-11-06 stsp for (i = 0; i < nitems(obj_tags); i++) {
172 ab9a70b2 2017-11-06 stsp const char *tag = obj_tags[i];
173 ab9a70b2 2017-11-06 stsp const char *errstr;
175 ab9a70b2 2017-11-06 stsp if (strncmp(buf, tag, strlen(tag)) != 0)
178 ab9a70b2 2017-11-06 stsp type = obj_types[i];
179 ab9a70b2 2017-11-06 stsp if (len <= strlen(tag))
180 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_BAD_OBJ_HDR);
181 ab9a70b2 2017-11-06 stsp size = strtonum(buf + strlen(tag), 0, LONG_MAX, &errstr);
182 ab9a70b2 2017-11-06 stsp if (errstr != NULL)
183 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_BAD_OBJ_HDR);
187 ab9a70b2 2017-11-06 stsp if (type == 0)
188 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_BAD_OBJ_HDR);
190 ab9a70b2 2017-11-06 stsp *obj = calloc(1, sizeof(**obj));
191 ab9a70b2 2017-11-06 stsp (*obj)->type = type;
192 ab9a70b2 2017-11-06 stsp (*obj)->size = size;
193 ab9a70b2 2017-11-06 stsp return NULL;
196 ab9a70b2 2017-11-06 stsp static const struct got_error *
197 ab9a70b2 2017-11-06 stsp read_object_header(struct got_object **obj, struct got_repository *repo,
198 ab9a70b2 2017-11-06 stsp const char *path)
200 ab9a70b2 2017-11-06 stsp const struct got_error *err;
202 ab9a70b2 2017-11-06 stsp struct got_zstream_buf zb;
204 ab9a70b2 2017-11-06 stsp size_t outlen;
205 ab9a70b2 2017-11-06 stsp int i, ret;
207 ab9a70b2 2017-11-06 stsp f = fopen(path, "rb");
208 ab9a70b2 2017-11-06 stsp if (f == NULL)
209 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_BAD_PATH);
211 ab9a70b2 2017-11-06 stsp err = inflate_init(&zb, 64);
214 ab9a70b2 2017-11-06 stsp return err;
217 ab9a70b2 2017-11-06 stsp err = inflate_read(&zb, f, &outlen);
221 ab9a70b2 2017-11-06 stsp err = parse_obj_header(obj, zb.outbuf, outlen);
223 ab9a70b2 2017-11-06 stsp inflate_end(&zb);
225 ab9a70b2 2017-11-06 stsp return err;
228 ab9a70b2 2017-11-06 stsp const struct got_error *
229 ab9a70b2 2017-11-06 stsp got_object_open(struct got_object **obj, struct got_repository *repo,
230 ab9a70b2 2017-11-06 stsp struct got_object_id *id)
232 ab9a70b2 2017-11-06 stsp const struct got_error *err = NULL;
233 ab9a70b2 2017-11-06 stsp char *path_objects = got_repo_get_path_objects(repo);
234 ab9a70b2 2017-11-06 stsp char hex[SHA1_DIGEST_STRING_LENGTH];
235 ab9a70b2 2017-11-06 stsp char *path = NULL;
237 ab9a70b2 2017-11-06 stsp if (path_objects == NULL)
238 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_NO_MEM);
240 ab9a70b2 2017-11-06 stsp got_object_id_str(id, hex, sizeof(hex));
242 ab9a70b2 2017-11-06 stsp if (asprintf(&path, "%s/%.2x/%s",
243 ab9a70b2 2017-11-06 stsp path_objects, id->sha1[0], hex + 2) == -1) {
244 ab9a70b2 2017-11-06 stsp err = got_error(GOT_ERR_NO_MEM);
248 ab9a70b2 2017-11-06 stsp err = read_object_header(obj, repo, path);
249 ab9a70b2 2017-11-06 stsp if (err == NULL)
250 ab9a70b2 2017-11-06 stsp memcpy((*obj)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH);
253 ab9a70b2 2017-11-06 stsp free(path);
254 ab9a70b2 2017-11-06 stsp free(path_objects);
255 ab9a70b2 2017-11-06 stsp return err;
259 ab9a70b2 2017-11-06 stsp got_object_close(struct got_object *obj)