commit - 82708eb352bd8956dd7b2679c9b9f11015c45c6b
commit + 0a0a30486325aded3095a281a9238a8dcc9b16a7
blob - 398a3f922562de268369987a6e63de7130ec0fc9
blob + fbfadeadba8f2824dfcfeb5129b026e607a5e8cb
--- include/got_error.h
+++ include/got_error.h
/*
- * Copyright (c) 2017 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#define GOT_ERR_OBJ_TYPE 0x0011
#define GOT_ERR_BAD_OBJ_DATA 0x0012
#define GOT_ERR_FILE_OPEN 0x0013
+#define GOT_ERR_BAD_PACKIDX 0x0014
static const struct got_error {
int code;
{ GOT_ERR_OBJ_TYPE, "wrong type of object" },
{ GOT_ERR_BAD_OBJ_DATA, "bad object data" },
{ GOT_ERR_FILE_OPEN, "could not open file" },
+ { GOT_ERR_BAD_PACKIDX, "bad pack index file" },
};
const struct got_error * got_error(int code);
blob - 99603fc59a8b31bc6eed774cb39cc2a0f9a8074c
blob + 4d508b318d7934d6ae1c48eeb2d580a8f6e8b80a
--- lib/pack.h
+++ lib/pack.h
/*
- * Copyright (c) 2017 Stefan Sperling <stsp@openbsd.org>
+ * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
u_int8_t sha1[SHA1_DIGEST_LENGTH];
} __attribute__((__packed__));
-struct got_pack_idx_trailer {
+struct got_packidx_trailer {
u_int8_t pack_file_sha1[SHA1_DIGEST_LENGTH];
u_int8_t pack_idx_sha1[SHA1_DIGEST_LENGTH];
} __attribute__((__packed__));
* total number of objects in the pack file. All pointer variables
* below point to tables with a corresponding number of entries.
*/
- uint32_t fanout_table[0xff]; /* values are big endian */
+ uint32_t fanout_table[0xff + 1]; /* values are big endian */
/* Sorted SHA1 checksums for each object in the pack file. */
struct got_pack_obj_id *sorted_ids;
/* Large offsets table is empty for pack files < 2 GB. */
uint64_t *large_offsets; /* values are big endian */
- struct got_pack_idx_trailer trailer;
+ struct got_packidx_trailer trailer;
};
struct got_packfile_hdr {
struct got_packfile_obj_data {
union {
- struct got_packfile_object_data;
- struct got_packfile_object_data_ref_delta;
- struct got_packfile_object_data_offset_delta;
+ struct got_packfile_object_data data;
+ struct got_packfile_object_data_ref_delta ref_delta;
+ struct got_packfile_object_data_offset_delta offset_delta;
} __attribute__((__packed__));
} __attribute__((__packed__));
+
+const struct got_error *got_packidx_open(struct got_packidx_v2_hdr **,
+ const char *);
+void got_packidx_close(struct got_packidx_v2_hdr *);
blob - /dev/null
blob + 8267925e9c7305afcae3675d6c0a2935ed7cad33 (mode 644)
--- /dev/null
+++ lib/pack.c
+/*
+ * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <sha1.h>
+#include <endian.h>
+
+#include "got_error.h"
+#include "pack.h"
+
+static const struct got_error *
+verify_fanout_table(uint32_t *fanout_table)
+{
+ int i;
+
+ for (i = 0; i < 0xff - 1; i++) {
+ if (fanout_table[i] > fanout_table[i + 1])
+ return got_error(GOT_ERR_BAD_PACKIDX);
+ }
+
+ return NULL;
+}
+
+const struct got_error *
+get_packfile_size(size_t *size, const char *path_idx)
+{
+ struct stat sb;
+ char *path_pack;
+ char base_path[PATH_MAX];
+ char *dot;
+
+ if (strlcpy(base_path, path_idx, PATH_MAX) > PATH_MAX)
+ return got_error(GOT_ERR_NO_SPACE);
+
+ dot = strrchr(base_path, '.');
+ if (dot == NULL)
+ return got_error(GOT_ERR_BAD_PATH);
+ *dot = '\0';
+ if (asprintf(&path_pack, "%s.pack", base_path) == -1)
+ return got_error(GOT_ERR_NO_MEM);
+
+ if (stat(path_pack, &sb) != 0) {
+ free(path_pack);
+ return got_error(GOT_ERR_IO);
+
+ }
+
+ free(path_pack);
+ *size = sb.st_size;
+ return 0;
+}
+
+const struct got_error *
+got_packidx_open(struct got_packidx_v2_hdr **packidx, const char *path)
+{
+ struct got_packidx_v2_hdr *p;
+ FILE *f;
+ const struct got_error *err = NULL;
+ size_t n, nobj, packfile_size;
+
+ f = fopen(path, "rb");
+ if (f == NULL)
+ return got_error(GOT_ERR_BAD_PATH);
+
+ err = get_packfile_size(&packfile_size, path);
+ if (err)
+ return err;
+
+ p = calloc(1, sizeof(*p));
+ if (p == NULL) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+
+ n = fread(&p->magic, sizeof(p->magic), 1, f);
+ if (n != 1) {
+ err = got_error(ferror(f) ? GOT_ERR_IO : GOT_ERR_BAD_PACKIDX);
+ goto done;
+ }
+
+ if (betoh32(p->magic) != GOT_PACKIDX_V2_MAGIC) {
+ err = got_error(GOT_ERR_BAD_PACKIDX);
+ goto done;
+ }
+
+ n = fread(&p->version, sizeof(p->version), 1, f);
+ if (n != 1) {
+ err = got_error(ferror(f) ? GOT_ERR_IO : GOT_ERR_BAD_PACKIDX);
+ goto done;
+ }
+
+ if (betoh32(p->version) != GOT_PACKIDX_VERSION) {
+ err = got_error(GOT_ERR_BAD_PACKIDX);
+ goto done;
+ }
+
+ n = fread(&p->fanout_table, sizeof(p->fanout_table), 1, f);
+ if (n != 1) {
+ err = got_error(ferror(f) ? GOT_ERR_IO : GOT_ERR_BAD_PACKIDX);
+ goto done;
+ }
+
+ err = verify_fanout_table(p->fanout_table);
+ if (err)
+ goto done;
+
+ nobj = betoh32(p->fanout_table[0xff]);
+
+ p->sorted_ids = calloc(nobj, sizeof(*p->sorted_ids));
+ if (p->sorted_ids == NULL) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+
+ n = fread(p->sorted_ids, sizeof(*p->sorted_ids), nobj, f);
+ if (n != nobj) {
+ err = got_error(ferror(f) ? GOT_ERR_IO : GOT_ERR_BAD_PACKIDX);
+ goto done;
+ }
+
+ p->offsets = calloc(nobj, sizeof(*p->offsets));
+ if (p->offsets == NULL) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+
+ n = fread(p->offsets, sizeof(*p->offsets), nobj, f);
+ if (n != nobj) {
+ err = got_error(ferror(f) ? GOT_ERR_IO : GOT_ERR_BAD_PACKIDX);
+ goto done;
+ }
+
+ p->crc32 = calloc(nobj, sizeof(*p->crc32));
+ if (p->crc32 == NULL) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+
+ n = fread(p->crc32, sizeof(*p->crc32), nobj, f);
+ if (n != nobj) {
+ err = got_error(ferror(f) ? GOT_ERR_IO : GOT_ERR_BAD_PACKIDX);
+ goto done;
+ }
+
+ /* Large file offsets are contained only in files > 2GB. */
+ if (packfile_size < 0x80000000)
+ goto checksum;
+
+ p->large_offsets = calloc(nobj, sizeof(*p->large_offsets));
+ if (p->large_offsets == NULL) {
+ err = got_error(GOT_ERR_NO_MEM);
+ goto done;
+ }
+
+ n = fread(p->large_offsets, sizeof(*p->large_offsets), nobj, f);
+ if (n != nobj) {
+ err = got_error(ferror(f) ? GOT_ERR_IO : GOT_ERR_BAD_PACKIDX);
+ goto done;
+ }
+
+checksum:
+
+ n = fread(&p->trailer, sizeof(p->trailer), 1, f);
+ if (n != 1) {
+ err = got_error(ferror(f) ? GOT_ERR_IO : GOT_ERR_BAD_PACKIDX);
+ goto done;
+ }
+
+ /* TODO verify checksum */
+
+done:
+ fclose(f);
+ if (err)
+ got_packidx_close(p);
+ else
+ *packidx = p;
+ return err;
+}
+
+void
+got_packidx_close(struct got_packidx_v2_hdr *packidx)
+{
+ free(packidx->sorted_ids);
+ free(packidx->offsets);
+ free(packidx->crc32);
+ free(packidx->large_offsets);
+ free(packidx);
+}
blob - /dev/null
blob + 829b06d7cb1532e0343af4928d7ce406f568369b (mode 644)
--- /dev/null
+++ regress/packfiles/Makefile
+.PATH:${.CURDIR}/../../lib
+
+PROG = packfile_test
+SRCS = error.c pack.c packfile_test.c
+
+CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib
+LDADD =
+DEBUG = -O0 -g
+
+NOMAN = yes
+
+.include <bsd.regress.mk>
blob - /dev/null
blob + fbe9c7437fe13d12c10a9584e75e2894a0943d46 (mode 644)
--- /dev/null
+++ regress/packfiles/packfile_test.c
+/*
+ * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sha1.h>
+#include <zlib.h>
+
+#include "got_error.h"
+#include "pack.h"
+
+#define RUN_TEST(expr, name) \
+ if (!(expr)) { printf("test %s failed", (name)); failure = 1; }
+
+#define GOT_REPO_PATH "../../../"
+
+static int
+packfile_read_idx(const char *repo_path)
+{
+ const struct got_error *err;
+ struct got_packidx_v2_hdr *packidx;
+ const char *pack_checksum = "5414c35e56c54294d2515863832bf46ad0e321d7";
+ const char *pack_prefix = ".git/objects/pack/pack";
+ char *fullpath;
+ int ret = 1;
+
+ if (asprintf(&fullpath, "%s/%s-%s.idx", repo_path, pack_prefix,
+ pack_checksum) == -1)
+ return 0;
+
+ err = got_packidx_open(&packidx, fullpath);
+ if (err) {
+ printf("got_packidx_open: %s\n", err->msg);
+ ret = 0;
+ }
+
+ got_packidx_close(packidx);
+ free(fullpath);
+ return ret;
+}
+
+int
+main(int argc, const char *argv[])
+{
+ int failure = 0;
+ const char *repo_path;
+
+ if (argc == 1)
+ repo_path = GOT_REPO_PATH;
+ else if (argc == 2)
+ repo_path = argv[1];
+ else {
+ fprintf(stderr, "usage: repository_test [REPO_PATH]\n");
+ return 1;
+ }
+
+ RUN_TEST(packfile_read_idx(repo_path), "packfile_read_idx");
+
+ return failure ? 1 : 0;
+}