15 ({ __typeof(a) __a = (a); __typeof(b) __b = (b); \
16 __a < __b ? __a : __b; })
19 * Get a block from a given input device.
23 GetBlock(DeviceInfo_t
*devp
, off_t offset
, uint8_t *buffer
)
26 off_t baseOffset
= (offset
/ devp
->blockSize
) * devp
->blockSize
;
28 retval
= pread(devp
->fd
, buffer
, devp
->blockSize
, baseOffset
);
29 if (retval
!= devp
->blockSize
) {
30 warn("GetBlock: pread returned %zd", retval
);
32 if (offset
!= baseOffset
) {
33 size_t off
= offset
% devp
->blockSize
;
34 memmove(buffer
, buffer
+ off
, devp
->blockSize
- off
);
42 * Initialize a VolumeObject. Simple function.
46 InitVolumeObject(struct DeviceInfo
*devp
, struct VolumeDescriptor
*vdp
)
48 VolumeObjects_t
*retval
= NULL
;
50 retval
= malloc(sizeof(*retval
));
55 retval
->byteCount
= 0;
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.
74 AddExtent(VolumeObjects_t
*vdp
, off_t start
, off_t length
)
76 return AddExtentForFile(vdp
, start
, length
, 0);
81 AddExtentForFile(VolumeObjects_t
*vdp
, off_t start
, off_t length
, unsigned int fid
)
85 ExtentList_t
**ep
= &vdp
->list
;
87 if (debug
) printf("AddExtent(%p, %lld, %lld) (file id %u)\n", vdp
, start
, length
, fid
);
89 if ((*ep
)->count
< kExtentCount
) {
91 (*ep
)->extents
[indx
].base
= start
;
92 (*ep
)->extents
[indx
].length
= length
;
93 (*ep
)->extents
[indx
].fid
= fid
;
101 *ep
= malloc(sizeof(ExtentList_t
));
103 err(1, "cannot allocate a new ExtentList object");
106 (*ep
)->extents
[0].base
= start
;
107 (*ep
)->extents
[0].length
= length
;
108 (*ep
)->extents
[0].fid
= fid
;
112 vdp
->byteCount
+= length
;
118 // Debugging function
121 PrintVolumeObject(VolumeObjects_t
*vop
)
125 printf("Volume Information\n");
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
);
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
;
139 for (indx
= 0; indx
< exts
->count
; indx
++) {
140 printf("\t\t<%lld, %lld> (file %u)\n", exts
->extents
[indx
].base
, exts
->extents
[indx
].length
, exts
->extents
[indx
].fid
);
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).
154 CopyObjectsToDest(VolumeObjects_t
*vop
, struct IOWrapper
*wrapper
, off_t skip
)
160 wrapper
->cleanup(wrapper
);
162 for (exts
= vop
->list
;
166 for (indx
= 0; indx
< exts
->count
; indx
++) {
167 off_t start
= exts
->extents
[indx
].base
;
168 off_t len
= exts
->extents
[indx
].length
;
170 __block off_t totalWritten
;
174 off_t amt
= MIN(skip
, len
);
179 wrapper
->setprog(wrapper
, total
);
181 printf("* * * Wrote %lld of %lld\n", total
, vop
->byteCount
);
183 printf("%d%%\n", (int)((total
* 100) / vop
->byteCount
));
186 totalWritten
= total
;
190 wrapper
->setprog(wrapper
, totalWritten
);
192 printf("* * Wrote %lld of %lld (%d%%)\n", totalWritten
, vop
->byteCount
, (int)((totalWritten
* 100) / vop
->byteCount
));
194 printf("%d%%\n", (int)((totalWritten
* 100) / vop
->byteCount
));
204 if (wrapper
->writer(wrapper
, vop
->devp
, start
, len
, bp
) == -1) {
207 warnx("Writing extent <%lld, %lld> failed", start
, len
);
211 total
= totalWritten
;
216 wrapper
->setprog(wrapper
, total
);
218 printf("Wrote %lld of %lld\n", total
, vop
->byteCount
);
220 printf("%d%%\n", (int)((total
* 100) / vop
->byteCount
));
227 if (total
== vop
->byteCount
) {
228 wrapper
->setprog(wrapper
, 0); // remove progress