+ * Read the contents section of the open change file, decompress it and return
+ * the raw bytes.
+ *
+ * Returns a malloc()'ed byte buffer that the caller is responsible for
+ * deallocating. Returns NULL if the full contents could not be read, or the
+ * decompression failed, or some other error occurred.
+ */
+ uint8_t *
+ read_contents(int fd, struct offsets *off)
+ {
+ /**
+ * Allocate two buffers: one for compressed data, and one for
+ * decompressed data. The decompressed data buffer is the return value.
+ */
+ uint8_t *compressed;
+ uint8_t *buf;
+ size_t compressed_to_read;
+ ssize_t compressed_read;
+ ZSTD_seekable *zs;
+ size_t result;
+
+ compressed_to_read = off->total - off->contents_off;
+ printf("expecting to read %lu bytes (compressed)\n", compressed_to_read);
+ compressed = calloc(sizeof(uint8_t), compressed_to_read);
+ if (compressed == NULL) {
+ perror("malloc compressed");
+ exit(1);
+ }
+ buf = calloc(sizeof(uint8_t), off->contents_len);
+ if (buf == NULL) {
+ perror("malloc buf");
+ exit(1);
+ }
+
+ /* Read data into compressed */
+ compressed_read = read(fd, compressed, compressed_to_read);
+ if (compressed_read != compressed_to_read) {
+ fprintf(stderr, "error: Expected to read %lu bytes, got %lu\n",
+ compressed_to_read, compressed_read);
+ goto errout;
+ }
+ dump_buf("compressed", compressed, compressed_read);
+
+ zs = ZSTD_seekable_create();
+ if (zs == NULL) {
+ fprintf(stderr, "ZSTD_seekable_create() failed");
+ goto errout;
+ }
+
+ result = ZSTD_seekable_initBuff(zs, compressed, compressed_to_read);
+ if (ZSTD_isError(result)) {
+ fprintf(stderr, "ZSTD_seekable_init() error: %s\n",
+ ZSTD_getErrorName(result));
+ goto outfreezs;
+ }
+
+ result = ZSTD_seekable_decompress(zs, buf, off->contents_len, 0);
+ printf("decompress result: %lu\n", result);
+ if (ZSTD_isError(result)) {
+ fprintf(stderr, "ZSTD_seekable_decompress() error: %s\n",
+ ZSTD_getErrorName(result));
+ goto outfreezs;
+ }
+ if (result != off->contents_len) {
+ fprintf(stderr, "decoded %lu bytes, wanted %lu\n", result, off->contents_len);
+ goto outfreezs;
+ }
+ /** Success! decompressed all that we wanted */
+ dump_buf("contents", buf, off->contents_len);
+
+ ZSTD_seekable_free(zs);
+ goto out;
+
+ outfreezs:
+ ZSTD_seekable_free(zs);
+ errout:
+ free(buf);
+ buf = NULL;
+ out:
+ free(compressed);
+ return buf;
+
+ }
+
+ /**