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