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