#include #include #include #include #include #include #include #include "hfsmeta.h" #include "Data.h" struct HFSDataObject { int64_t offset; int64_t size; }; typedef struct HFSDataObject HFSDataObject; enum { kHFSInfoHeaderVersion = 1, }; #define MIN(a, b) \ ({ __typeof(a) __a = (a); __typeof(b) __b = (b); \ __a < __b ? __a : __b; }) struct HFSInfoHeader { uint32_t version; uint32_t deviceBlockSize; int64_t rawDeviceSize; int32_t size; // Size of header int32_t objectCount; }; static ssize_t WriteExtent(gzFile outf, DeviceInfo_t *devp, off_t start, off_t len) { const size_t bufSize = 1024 * 1024; uint8_t buffer[bufSize]; off_t total = 0; while (total < len) { ssize_t nread; size_t amt = MIN(bufSize, len - total); ssize_t nwritten; nread = pread(devp->fd, buffer, amt, start + total); if (nread == -1) { warn("Cannot read from device at offset %lld", start + total); return -1; } if (nread != amt) { warnx("Tried to read %zu bytes, only read %zd", amt, nread); } nwritten = gzwrite(outf, (char*)buffer, amt); if (nwritten == -1) { warn("tried to gzwrite %zu bytes", amt); return -1; } else if (nwritten != amt) { warnx("tried to gzwrite %zu bytes, only wrote %u", amt, nwritten); total += nwritten; } else total += amt; } return 0; } void WriteGatheredData(const char *pathname, VolumeObjects_t *vop) { int fd; gzFile outf; struct HFSInfoHeader hdr = { 0 }; HFSDataObject *objs = NULL, *op; ExtentList_t *ep; int i; hdr.version = S32(kHFSInfoHeaderVersion); hdr.deviceBlockSize = S32((uint32_t)vop->devp->blockSize); hdr.rawDeviceSize = S64(vop->devp->size); hdr.objectCount = S32(vop->count); hdr.size = S32(sizeof(hdr) + sizeof(HFSDataObject) * vop->count); objs = malloc(sizeof(HFSDataObject) * vop->count); if (objs == NULL) { warn("Unable to allocate space for data objects (%zu bytes)", sizeof(HFSDataObject)* vop->count); goto done; } op = objs; for (ep = vop->list; ep; ep = ep->next) { int i; for (i = 0; i < ep->count; i++) { op->offset = S64(ep->extents[i].base); op->size = S64(ep->extents[i].length); op++; } } fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd == -1) { warn("cannot create gather file %s", pathname); goto done; } outf = gzdopen(fd, "wb"); if (outf == NULL) { warn("Cannot create gz descriptor from file %s", pathname); close(fd); goto done; } gzwrite(outf, &hdr, sizeof(hdr)); gzwrite(outf, objs, sizeof(HFSDataObject) * vop->count); int count = 0; for (ep = vop->list; ep; ep = ep->next) { int i; for (i = 0; i < ep->count; i++) { if (verbose) fprintf(stderr, "Writing extent <%lld, %lld>\n", ep->extents[i].base, ep->extents[i].length); if (WriteExtent(outf, vop->devp, ep->extents[i].base, ep->extents[i].length) == -1) { if (verbose) fprintf(stderr, "\tWrite failed\n"); break; } count++; } } gzclose(outf); if (count != vop->count) fprintf(stderr, "WHOAH! we're short by %zd objects!\n", vop->count - count); done: if (objs) free(objs); return; }