]> git.saurik.com Git - apple/hfs.git/blame - CopyHFSMeta/Gather.c
hfs-195.tar.gz
[apple/hfs.git] / CopyHFSMeta / Gather.c
CommitLineData
a56bdb9d
A
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}