]> git.saurik.com Git - hfs.git/blob - CopyHFSMeta/misc.c
hfs-191.1.tar.gz
[hfs.git] / CopyHFSMeta / misc.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <fcntl.h>
6 #include <errno.h>
7 #include <err.h>
8 #include <errno.h>
9 #include <sys/stat.h>
10 #include <sys/disk.h>
11
12 #include "hfsmeta.h"
13
14 #define MIN(a, b) \
15 ({ __typeof(a) __a = (a); __typeof(b) __b = (b); \
16 __a < __b ? __a : __b; })
17
18 /*
19 * Get a block from a given input device.
20 */
21 ssize_t
22 GetBlock(DeviceInfo_t *devp, off_t offset, uint8_t *buffer)
23 {
24 ssize_t retval = -1;
25 off_t baseOffset = (offset / devp->blockSize) * devp->blockSize;
26
27 retval = pread(devp->fd, buffer, devp->blockSize, baseOffset);
28 if (retval != devp->blockSize) {
29 warn("GetBlock: pread returned %zd", retval);
30 }
31 if (offset != baseOffset) {
32 size_t off = offset % devp->blockSize;
33 memmove(buffer, buffer + off, devp->blockSize - off);
34 }
35 retval = 0;
36 done:
37 return retval;
38 }
39
40 /*
41 * Initialize a VolumeObject. Simple function.
42 */
43 VolumeObjects_t *
44 InitVolumeObject(struct DeviceInfo *devp, struct VolumeDescriptor *vdp)
45 {
46 VolumeObjects_t *retval = NULL;
47
48 retval = malloc(sizeof(*retval));
49 if (retval) {
50 retval->devp = devp;
51 retval->vdp = vdp;
52 retval->count = 0;
53 retval->byteCount = 0;
54 retval->list = NULL;
55 }
56
57 done:
58 return retval;
59 }
60
61 /*
62 * Add an extent (<start, length> pair) to a volume list.
63 * Note that this doesn't try to see if an extent is already
64 * in the list; the presumption is that an fsck_hfs run will
65 * note overlapping extents in that case. It adds the extents
66 * in groups of kExtentCount; the goal here is to minimize the
67 * number of objects we allocate, while still trying to keep
68 * the waste memory allocation low.
69 */
70 int
71 AddExtent(VolumeObjects_t *vdp, off_t start, off_t length)
72 {
73 int retval = 0;
74 size_t indx;
75 ExtentList_t **ep = &vdp->list;
76
77 if (debug) printf("AddExtent(%p, %lld, %lld)\n", vdp, start, length);
78 while (*ep) {
79 if ((*ep)->count < kExtentCount) {
80 indx = (*ep)->count;
81 (*ep)->extents[indx].base = start;
82 (*ep)->extents[indx].length = length;
83 (*ep)->count++;
84 break;
85 } else {
86 ep = &(*ep)->next;
87 }
88 }
89 if (*ep == NULL) {
90 *ep = malloc(sizeof(ExtentList_t));
91 if (*ep == NULL) {
92 err(1, "cannot allocate a new ExtentList object");
93 }
94 (*ep)->count = 1;
95 (*ep)->extents[0].base = start;
96 (*ep)->extents[0].length = length;
97 (*ep)->next = NULL;
98 }
99 vdp->count++;
100 vdp->byteCount += length;
101
102 done:
103 return retval;
104 }
105
106 // Debugging function
107 void
108 PrintVolumeObject(VolumeObjects_t *vop)
109 {
110 ExtentList_t *exts;
111
112 printf("Volume Information\n");
113 if (vop->devp) {
114 printf("\tDevice %s\n", vop->devp->devname);
115 printf("\t\tSize %lld\n", vop->devp->size);
116 printf("\t\tBlock size %d\n", vop->devp->blockSize);
117 printf("\t\tBlock Count %lld\n", vop->devp->blockCount);
118 }
119 printf("\tObject count %zu\n", vop->count);
120 printf("\tByte count %lld\n", vop->byteCount);
121 printf("\tExtent list:\n");
122 for (exts = vop->list;
123 exts;
124 exts = exts->next) {
125 int indx;
126 for (indx = 0; indx < exts->count; indx++) {
127 printf("\t\t<%lld, %lld>\n", exts->extents[indx].base, exts->extents[indx].length);
128 }
129 }
130 return;
131 }
132
133 /*
134 * The main routine: given a Volume descriptor, copy the metadata from it
135 * to the given destination object (a device or sparse bundle). It keeps
136 * track of progress, and also takes an amount to skip (which happens if it's
137 * resuming an earlier, interrupted copy).
138 */
139 int
140 CopyObjectsToDest(VolumeObjects_t *vop, struct IOWrapper *wrapper, off_t skip)
141 {
142 ExtentList_t *exts;
143 off_t total = 0;
144
145 if (skip == 0) {
146 wrapper->cleanup(wrapper);
147 }
148 for (exts = vop->list;
149 exts;
150 exts = exts->next) {
151 int indx;
152 for (indx = 0; indx < exts->count; indx++) {
153 off_t start = exts->extents[indx].base;
154 off_t len = exts->extents[indx].length;
155 if (skip < len) {
156 __block off_t totalWritten;
157 void (^bp)(off_t);
158
159 if (skip) {
160 off_t amt = MIN(skip, len);
161 len -= amt;
162 start += amt;
163 total += amt;
164 skip -= amt;
165 wrapper->setprog(wrapper, total);
166 if (debug)
167 printf("* * * Wrote %lld of %lld\n", total, vop->byteCount);
168 else
169 printf("%d%%\n", (int)((total * 100) / vop->byteCount));
170 fflush(stdout);
171 }
172 totalWritten = total;
173 if (printProgress) {
174 bp = ^(off_t amt) {
175 totalWritten += amt;
176 wrapper->setprog(wrapper, totalWritten);
177 if (debug)
178 printf("* * Wrote %lld of %lld (%d%%)\n", totalWritten, vop->byteCount, (int)((totalWritten * 100) / vop->byteCount));
179 else
180 printf("%d%%\n", (int)((totalWritten * 100) / vop->byteCount));
181 fflush(stdout);
182 return;
183 };
184 } else {
185 bp = ^(off_t amt) {
186 totalWritten += amt;
187 return;
188 };
189 }
190 if (wrapper->writer(wrapper, vop->devp, start, len, bp) == -1) {
191 int t = errno;
192 if (verbose)
193 warnx("Writing extent <%lld, %lld> failed", start, len);
194 errno = t;
195 return -1;
196 }
197 total = totalWritten;
198 } else {
199 skip -= len;
200 total += len;
201 if (printProgress) {
202 wrapper->setprog(wrapper, total);
203 if (debug)
204 printf("Wrote %lld of %lld\n", total, vop->byteCount);
205 else
206 printf("%d%%\n", (int)((total * 100) / vop->byteCount));
207 fflush(stdout);
208 }
209 }
210 }
211 }
212
213 if (total == vop->byteCount) {
214 wrapper->setprog(wrapper, 0); // remove progress
215 }
216
217 return 0;
218 }