X-Git-Url: https://git.saurik.com/apple/hfs.git/blobdiff_plain/a56bdb9dd68c843a17a0658b5250e0cc67c22fe8..51e135ce018217de5c809f4ac236ef6b6d87ef97:/CopyHFSMeta/SparseBundle.c diff --git a/CopyHFSMeta/SparseBundle.c b/CopyHFSMeta/SparseBundle.c index e342d47..a7c5668 100644 --- a/CopyHFSMeta/SparseBundle.c +++ b/CopyHFSMeta/SparseBundle.c @@ -5,11 +5,13 @@ #include #include #include +#include #include #include #include #include +#include #include "hfsmeta.h" #include "Sparse.h" @@ -59,6 +61,46 @@ static const char *bundlePrototype = "\n" "\n"; +/* + * Perform a (potentially) unaligned read from a given input device. + */ +static ssize_t +UnalignedRead(DeviceInfo_t *devp, void *buffer, size_t size, off_t offset) +{ + ssize_t nread = -1; + size_t readSize = ((size + devp->blockSize - 1) / devp->blockSize) * devp->blockSize; + off_t baseOffset = (offset / devp->blockSize) * devp->blockSize; + size_t off = offset - baseOffset; + char *tmpbuf = NULL; + + if ((baseOffset == offset) && (readSize == size)) { + /* + * The read is already properly aligned, so call pread. + */ + return pread(devp->fd, buffer, size, offset); + } + + tmpbuf = malloc(readSize); + if (!tmpbuf) { + goto done; + } + + nread = pread(devp->fd, tmpbuf, readSize, baseOffset); + if (nread == -1) { + goto done; + } + + nread -= off; + if (nread > (ssize_t)size) { + nread = size; + } + memcpy(buffer, tmpbuf + off, nread); + +done: + free(tmpbuf); + return nread; +} + /* * Read from a sparse bundle. If the band file doesn't exist, or is shorter than * what we need to get from it, we pad out with 0's. @@ -132,19 +174,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; } @@ -156,7 +208,8 @@ doSparseWrite(IOWrapper_t *context, off_t offset, void *buffer, size_t len) retval = -1; goto done; } - (void)fcntl(fd, F_FULLFSYNC, 0); + // Sync the data out. + fsync(fd); written += nwritten; } retval = written; @@ -173,30 +226,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");