X-Git-Url: https://git.saurik.com/apple/hfs.git/blobdiff_plain/246784f7dc26d498d36b5dbe514331e0b88c00c2..e962a853db003df4e563927d0171c9a8968454a8:/CopyHFSMeta/SparseBundle.c diff --git a/CopyHFSMeta/SparseBundle.c b/CopyHFSMeta/SparseBundle.c index 1ac5a68..455903e 100644 --- a/CopyHFSMeta/SparseBundle.c +++ b/CopyHFSMeta/SparseBundle.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -22,9 +23,11 @@ * no encryption. */ -#define MIN(a, b) \ +#ifndef MIN +# define MIN(a, b) \ ({ __typeof(a) __a = (a); __typeof(b) __b = (b); \ __a < __b ? __a : __b; }) +#endif /* * Context for the sparse bundle routines. The path name, @@ -60,20 +63,6 @@ static const char *bundlePrototype = "\n" "\n"; -/* - * Do a per-volume sync. We use this just before updating the progress file, so - * that any changes -- data and metadata -- will have made it to disk, without - * causing a sync of every mounted volume. - * - */ - -static void -sync_volume(const char *path) { - int full_sync = FSCTL_SYNC_FULLSYNC | FSCTL_SYNC_WAIT; - - (void)fsctl(path, FSCTL_SYNC_VOLUME, &full_sync, 0); - return; -} /* * Read from a sparse bundle. If the band file doesn't exist, or is shorter than @@ -148,19 +137,29 @@ doSparseWrite(IOWrapper_t *context, off_t offset, void *buffer, size_t len) int fd; if (ctx->cfd == -1 || ctx->cBandNum != bandNum) { - if (ctx->cfd != -1) - close(ctx->cfd); - asprintf(&bandName, "%s/bands/%x", ctx->pathname, bandNum); - fd = open(bandName, O_WRONLY | O_CREAT, 0666); - if (fd == -1) { - warn("Cannot open band file %s for offset %llu", bandName, offset + written); - retval = -1; - goto done; - } - free(bandName); - bandName = NULL; - ctx->cfd = fd; - ctx->cBandNum = bandNum; + if (ctx->cfd != -1) { + close(ctx->cfd); + } + asprintf(&bandName, "%s/bands/%x", ctx->pathname, bandNum); + fd = open(bandName, O_WRONLY | O_CREAT, 0666); + if (fd == -1) { + warn("Cannot open band file %s for offset %llu", bandName, offset + written); + retval = -1; + goto done; + } + /* + * When we create a new band file, we sync the volume + * it's on, so that we can ensure that the band file is present + * on disk. (Otherwise, with a crash, we can end up with the + * data not where we expected.) In this case, however, we probably + * don't need to wait for it -- just start the sync. + */ + fsync_volume_np(fd, 0); + fcntl(fd, F_NOCACHE, 1); + free(bandName); + bandName = NULL; + ctx->cfd = fd; + ctx->cBandNum = bandNum; } else { fd = ctx->cfd; } @@ -172,6 +171,8 @@ doSparseWrite(IOWrapper_t *context, off_t offset, void *buffer, size_t len) retval = -1; goto done; } + // Sync the data out. + fsync(fd); written += nwritten; } retval = written; @@ -188,30 +189,44 @@ static ssize_t WriteExtentToSparse(struct IOWrapper * context, DeviceInfo_t *devp, off_t start, off_t len, void (^bp)(off_t)) { const size_t bufSize = 1024 * 1024; - uint8_t buffer[bufSize]; + uint8_t *buffer = NULL; + ssize_t retval = 0; off_t total = 0; if (debug) printf("Writing extent <%lld, %lld>\n", start, len); + buffer = malloc(bufSize); + if (buffer == NULL) { + warn("%s(%s): Could not allocate %zu bytes for buffer", __FILE__, __FUNCTION__, bufSize); + retval = -1; + goto done; + } + while (total < len) { ssize_t nread; ssize_t nwritten; size_t amt = MIN(bufSize, len - total); - nread = pread(devp->fd, buffer, amt, start + total); + nread = UnalignedRead(devp, buffer, amt, start + total); if (nread == -1) { warn("Cannot read from device at offset %lld", start + total); - return -1; + retval = -1; + break; } if (nread < amt) { warnx("Short read from source device -- got %zd, expected %zd", nread, amt); } nwritten = doSparseWrite(context, start + total, buffer, nread); - if (nwritten == -1) - return -1; + if (nwritten == -1) { + retval = -1; + break; + } bp(nread); total += nread; } if (debug) printf("\twrote %lld\n", total); - return 0; +done: + if (buffer) + free(buffer); + return retval; } static const CFStringRef kBandSizeKey = CFSTR("band-size"); @@ -341,7 +356,6 @@ SetProgress(struct IOWrapper *context, off_t prog) } else { fp = fopen(progFile, "w"); if (fp) { - sync_volume(ctx->pathname); (void)fprintf(fp, "%llu\n", prog); fclose(fp); }