Commit 52a7447583292df7a622b4c0d4d462c55554739c

Stefan Sperling 2018-12-24T16:46:13

implement got_fileindex_read() - not yet tested

diff --git a/include/got_error.h b/include/got_error.h
index 217a29f..e7d37e6 100644
--- a/include/got_error.h
+++ b/include/got_error.h
@@ -64,6 +64,9 @@
 #define GOT_ERR_EXPECTED	48 /* for use in regress tests only */
 #define GOT_ERR_CANCELLED	49
 #define GOT_ERR_NO_TREE_ENTRY	50
+#define GOT_ERR_FILEIDX_SIG	51
+#define GOT_ERR_FILEIDX_VER	52
+#define GOT_ERR_FILEIDX_CSUM	53
 
 static const struct got_error {
 	int code;
@@ -116,6 +119,9 @@ static const struct got_error {
 	{ GOT_ERR_EXPECTED,	"expected an error but have no error" },
 	{ GOT_ERR_CANCELLED,	"operation in progress has been cancelled" },
 	{ GOT_ERR_NO_TREE_ENTRY,"no such entry found in tree" },
+	{ GOT_ERR_FILEIDX_SIG,	"bad file index signature" },
+	{ GOT_ERR_FILEIDX_VER,	"unknown file index format version" },
+	{ GOT_ERR_FILEIDX_CSUM,	"bad file index checksum" },
 };
 
 /*
diff --git a/lib/fileindex.c b/lib/fileindex.c
index 6511dec..ccd3f58 100644
--- a/lib/fileindex.c
+++ b/lib/fileindex.c
@@ -265,3 +265,197 @@ got_fileindex_write(struct got_fileindex *fileindex, FILE *outfile)
 
 	return NULL;
 }
+
+static const struct got_error *
+read_fileindex_val64(uint64_t *val, SHA1_CTX *ctx, FILE *infile)
+{
+	uint8_t buf[sizeof(uint64_t)];
+	size_t n;
+
+	n = fread(buf, 1, sizeof(buf), infile);
+	if (n != sizeof(buf))
+		return got_ferror(infile, GOT_ERR_IO);
+	SHA1Update(ctx, buf, sizeof(buf));
+	memcpy(val, buf, sizeof(*val));
+	*val = htobe64(*val);
+	return NULL;
+}
+
+static const struct got_error *
+read_fileindex_val32(uint32_t *val, SHA1_CTX *ctx, FILE *infile)
+{
+	uint8_t buf[sizeof(uint32_t)];
+	size_t n;
+
+	n = fread(buf, 1, sizeof(buf), infile);
+	if (n != sizeof(buf))
+		return got_ferror(infile, GOT_ERR_IO);
+	SHA1Update(ctx, buf, sizeof(buf));
+	memcpy(val, buf, sizeof(*val));
+	*val = htobe32(*val);
+	return NULL;
+}
+
+static const struct got_error *
+read_fileindex_val16(uint16_t *val, SHA1_CTX *ctx, FILE *infile)
+{
+	uint8_t buf[sizeof(uint16_t)];
+	size_t n;
+
+	n = fread(buf, 1, sizeof(buf), infile);
+	if (n != sizeof(buf))
+		return got_ferror(infile, GOT_ERR_IO);
+	SHA1Update(ctx, buf, sizeof(buf));
+	memcpy(val, buf, sizeof(*val));
+	*val = htobe16(*val);
+	return NULL;
+}
+
+static const struct got_error *
+read_fileindex_path(char **path, SHA1_CTX *ctx, FILE *infile)
+{
+	const struct got_error *err = NULL;
+	uint8_t buf[8];
+	size_t n, len = 0, totlen = sizeof(buf);
+
+	*path = malloc(totlen);
+	if (*path == NULL)
+		return got_error_from_errno();
+
+	do {
+		n = fread(buf, 1, sizeof(buf), infile);
+		if (n != sizeof(buf))
+			return got_ferror(infile, GOT_ERR_IO);
+		if (len + sizeof(buf) > totlen) {
+			char *p = reallocarray(*path, totlen + sizeof(buf), 1);
+			if (p == NULL) {
+				err = got_error_from_errno();
+				break;
+			}
+			totlen += sizeof(buf);
+			*path = p;
+		}
+		SHA1Update(ctx, buf, sizeof(buf));
+		memcpy(*path + len, buf, sizeof(buf));
+		len += sizeof(buf);
+	} while (strchr(buf, '\0') == NULL);
+
+	if (err) {
+		free(*path);
+		*path = NULL;
+	}
+	return err;
+}
+
+static const struct got_error *
+read_fileindex_entry(struct got_fileindex_entry **entryp, SHA1_CTX *ctx,
+    FILE *infile)
+{
+	const struct got_error *err;
+	struct got_fileindex_entry *entry;
+	size_t n;
+
+	*entryp = NULL;
+
+	entry = calloc(1, sizeof(*entry));
+	if (entry == NULL)
+		return got_error_from_errno();
+
+	err = read_fileindex_val64(&entry->ctime_sec, ctx, infile);
+	if (err)
+		goto done;
+	err = read_fileindex_val64(&entry->ctime_nsec, ctx, infile);
+	if (err)
+		goto done;
+	err = read_fileindex_val64(&entry->mtime_sec, ctx, infile);
+	if (err)
+		goto done;
+	err = read_fileindex_val64(&entry->mtime_nsec, ctx, infile);
+	if (err)
+		goto done;
+
+	err = read_fileindex_val32(&entry->uid, ctx, infile);
+	if (err)
+		goto done;
+	err = read_fileindex_val32(&entry->gid, ctx, infile);
+	if (err)
+		goto done;
+	err = read_fileindex_val32(&entry->size, ctx, infile);
+	if (err)
+		goto done;
+
+	err = read_fileindex_val16(&entry->mode, ctx, infile);
+	if (err)
+		goto done;
+
+	n = fread(entry->blob_sha1, 1, SHA1_DIGEST_LENGTH, infile);
+	if (n != SHA1_DIGEST_LENGTH) {
+		err = got_ferror(infile, GOT_ERR_IO);
+		goto done;
+	}
+	SHA1Update(ctx, entry->blob_sha1, SHA1_DIGEST_LENGTH);
+
+	err = read_fileindex_val32(&entry->flags, ctx, infile);
+	if (err)
+		goto done;
+
+	err = read_fileindex_path(&entry->path, ctx, infile);
+done:
+	if (err)
+		free(entry);
+	else
+		*entryp = entry;
+	return err;
+}
+
+const struct got_error *
+got_fileindex_read(struct got_fileindex *fileindex, FILE *infile)
+{
+	const struct got_error *err = NULL;
+	struct got_fileindex_hdr hdr;
+	SHA1_CTX ctx;
+	struct got_fileindex_entry *entry;
+	uint8_t sha1_expected[SHA1_DIGEST_LENGTH];
+	uint8_t sha1[SHA1_DIGEST_LENGTH];
+	size_t n;
+	const size_t len = sizeof(hdr.signature) + sizeof(hdr.version) +
+	    sizeof(hdr.nentries);
+	uint8_t buf[len];
+	int i;
+
+	SHA1Init(&ctx);
+
+	n = fread(buf, 1, len, infile);
+	if (n != len)
+		return got_ferror(infile, GOT_ERR_IO);
+
+	SHA1Update(&ctx, buf, len);
+
+	memcpy(&hdr, buf, len);
+	hdr.signature = htobe32(hdr.signature);
+	hdr.version = htobe32(hdr.version);
+	hdr.nentries = htobe32(hdr.nentries);
+
+	if (hdr.signature != GOT_FILE_INDEX_SIGNATURE)
+		return got_error(GOT_ERR_FILEIDX_SIG);
+	if (hdr.version != GOT_FILE_INDEX_VERSION)
+		return got_error(GOT_ERR_FILEIDX_VER);
+
+	for (i = 0; i < hdr.nentries; i++) {
+		err = read_fileindex_entry(&entry, &ctx, infile);
+		if (err)
+			return err;
+		err = got_fileindex_entry_add(fileindex, entry);
+		if (err)
+			return err;
+	}
+
+	n = fread(sha1_expected, 1, sizeof(sha1_expected), infile);
+	if (n != sizeof(sha1_expected))
+		return got_ferror(infile, GOT_ERR_IO);
+	SHA1Final(sha1, &ctx);
+	if (memcmp(sha1, sha1_expected, SHA1_DIGEST_LENGTH) != 0)
+		return got_error(GOT_ERR_FILEIDX_CSUM);
+
+	return NULL;
+}
diff --git a/lib/got_lib_fileindex.h b/lib/got_lib_fileindex.h
index 018f4f2..d2a28dc 100644
--- a/lib/got_lib_fileindex.h
+++ b/lib/got_lib_fileindex.h
@@ -90,3 +90,4 @@ void got_fileindex_close(struct got_fileindex *);
 const struct got_error *got_fileindex_write(struct got_fileindex *, FILE *);
 const struct got_error *got_fileindex_entry_add(struct got_fileindex *,
     struct got_fileindex_entry *);
+const struct got_error *got_fileindex_read(struct got_fileindex *, FILE *);