]>
Commit | Line | Data |
---|---|---|
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 | } |