]> git.saurik.com Git - apple/hfs.git/blob - CopyHFSMeta/Gather.c
hfs-285.tar.gz
[apple/hfs.git] / CopyHFSMeta / Gather.c
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
12 struct HFSDataObject {
13 int64_t offset;
14 int64_t size;
15 };
16 typedef struct HFSDataObject HFSDataObject;
17
18 enum {
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
27 struct 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
35 static ssize_t
36 WriteExtent(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
67 void
68 WriteGatheredData(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
137 done:
138 if (objs)
139 free(objs);
140 return;
141
142 }