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__private_extern__ 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 */ 44__private_extern__ 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 */ 72__private_extern__ 73int 74AddExtent(VolumeObjects_t *vdp, off_t start, off_t length) 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) 82{ 83 int retval = 0; 84 size_t indx; 85 ExtentList_t **ep = &vdp->list; 86 87 if (debug) printf("AddExtent(%p, %lld, %lld) (file id %u)\n", vdp, start, length, fid); 88 while (*ep) { 89 if ((*ep)->count < kExtentCount) { 90 indx = (*ep)->count; 91 (*ep)->extents[indx].base = start; 92 (*ep)->extents[indx].length = length; 93 (*ep)->extents[indx].fid = fid; 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; 108 (*ep)->extents[0].fid = fid; 109 (*ep)->next = NULL; 110 } 111 vdp->count++; 112 vdp->byteCount += length; 113 114done: 115 return retval; 116} 117 118// Debugging function 119__private_extern__ 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++) { 140 printf("\t\t<%lld, %lld> (file %u)\n", exts->extents[indx].base, exts->extents[indx].length, exts->extents[indx].fid); 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 */ 152__private_extern__ 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} 233