1#include <stdio.h> 2#include <stdlib.h> 3#include <unistd.h> 4#include <fcntl.h> 5#include <err.h> 6#include <errno.h> 7#include <zlib.h> 8 9#include "hfsmeta.h" 10#include "Data.h" 11 12struct HFSDataObject { 13 int64_t offset; 14 int64_t size; 15}; 16typedef struct HFSDataObject HFSDataObject; 17 18enum { 19 kHFSInfoHeaderVersion = 1, 20}; 21 22 23#define MIN(a, b) \ 24 ({ __typeof(a) __a = (a); __typeof(b) __b = (b); \ 25 __a < __b ? __a : __b; }) 26 27struct HFSInfoHeader { 28 uint32_t version; 29 uint32_t deviceBlockSize; 30 int64_t rawDeviceSize; 31 int32_t size; // Size of header 32 int32_t objectCount; 33}; 34 35static ssize_t 36WriteExtent(gzFile outf, DeviceInfo_t *devp, off_t start, off_t len) 37{ 38 const size_t bufSize = 1024 * 1024; 39 uint8_t buffer[bufSize]; 40 off_t total = 0; 41 42 while (total < len) { 43 ssize_t nread; 44 size_t amt = MIN(bufSize, len - total); 45 ssize_t nwritten; 46 nread = pread(devp->fd, buffer, amt, start + total); 47 if (nread == -1) { 48 warn("Cannot read from device at offset %lld", start + total); 49 return -1; 50 } 51 if (nread != amt) { 52 warnx("Tried to read %zu bytes, only read %zd", amt, nread); 53 } 54 nwritten = gzwrite(outf, (char*)buffer, amt); 55 if (nwritten == -1) { 56 warn("tried to gzwrite %zu bytes", amt); 57 return -1; 58 } else if (nwritten != amt) { 59 warnx("tried to gzwrite %zu bytes, only wrote %u", amt, nwritten); 60 total += nwritten; 61 } else 62 total += amt; 63 } 64 return 0; 65} 66 67void 68WriteGatheredData(const char *pathname, VolumeObjects_t *vop) 69{ 70 int fd; 71 gzFile outf; 72 struct HFSInfoHeader hdr = { 0 }; 73 HFSDataObject *objs = NULL, *op; 74 ExtentList_t *ep; 75 int i; 76 77 hdr.version = S32(kHFSInfoHeaderVersion); 78 hdr.deviceBlockSize = S32((uint32_t)vop->devp->blockSize); 79 hdr.rawDeviceSize = S64(vop->devp->size); 80 hdr.objectCount = S32(vop->count); 81 hdr.size = S32(sizeof(hdr) + sizeof(HFSDataObject) * vop->count); 82 83 objs = malloc(sizeof(HFSDataObject) * vop->count); 84 if (objs == NULL) { 85 warn("Unable to allocate space for data objects (%zu bytes)", sizeof(HFSDataObject)* vop->count); 86 goto done; 87 } 88 89 op = objs; 90 for (ep = vop->list; 91 ep; 92 ep = ep->next) { 93 int i; 94 for (i = 0; i < ep->count; i++) { 95 op->offset = S64(ep->extents[i].base); 96 op->size = S64(ep->extents[i].length); 97 op++; 98 } 99 } 100 101 fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC, 0666); 102 if (fd == -1) { 103 warn("cannot create gather file %s", pathname); 104 goto done; 105 } 106 outf = gzdopen(fd, "wb"); 107 if (outf == NULL) { 108 warn("Cannot create gz descriptor from file %s", pathname); 109 close(fd); 110 goto done; 111 } 112 113 gzwrite(outf, &hdr, sizeof(hdr)); 114 gzwrite(outf, objs, sizeof(HFSDataObject) * vop->count); 115 116 int count = 0; 117 for (ep = vop->list; 118 ep; 119 ep = ep->next) { 120 int i; 121 for (i = 0; i < ep->count; i++) { 122 if (verbose) 123 fprintf(stderr, "Writing extent <%lld, %lld>\n", ep->extents[i].base, ep->extents[i].length); 124 if (WriteExtent(outf, vop->devp, ep->extents[i].base, ep->extents[i].length) == -1) { 125 if (verbose) 126 fprintf(stderr, "\tWrite failed\n"); 127 break; 128 } 129 count++; 130 } 131 } 132 gzclose(outf); 133 if (count != vop->count) 134 fprintf(stderr, "WHOAH! we're short by %zd objects!\n", vop->count - count); 135 136 137done: 138 if (objs) 139 free(objs); 140 return; 141 142} 143