]> git.saurik.com Git - apple/hfs.git/blobdiff - CopyHFSMeta/SparseBundle.c
hfs-366.30.3.tar.gz
[apple/hfs.git] / CopyHFSMeta / SparseBundle.c
index 1ac5a6889f0d3474a7bb4227615ecd0b63793fe5..455903eebec2fbf7b7c2e7003a393de4145f0e59 100644 (file)
@@ -5,6 +5,7 @@
 #include <fcntl.h>
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <err.h>
 #include <errno.h>
+#include <unistd.h>
 #include <sys/stat.h>
 #include <sys/fcntl.h>
 #include <removefile.h>
 #include <sys/stat.h>
 #include <sys/fcntl.h>
 #include <removefile.h>
  * no encryption.
  */
 
  * no encryption.
  */
 
-#define MIN(a, b) \
+#ifndef MIN
+# define MIN(a, b) \
        ({ __typeof(a) __a = (a); __typeof(b) __b = (b); \
                __a < __b ? __a : __b; })
        ({ __typeof(a) __a = (a); __typeof(b) __b = (b); \
                __a < __b ? __a : __b; })
+#endif
 
 /*
  * Context for the sparse bundle routines.  The path name,
 
 /*
  * Context for the sparse bundle routines.  The path name,
@@ -60,20 +63,6 @@ static const char *bundlePrototype =
 "</dict>\n"
        "</plist>\n";
 
 "</dict>\n"
        "</plist>\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
 
 /*
  * 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) {
                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;
                }
                } else {
                        fd = ctx->cfd;
                }
@@ -172,6 +171,8 @@ doSparseWrite(IOWrapper_t *context, off_t offset, void *buffer, size_t len)
                        retval = -1;
                        goto done;
                }
                        retval = -1;
                        goto done;
                }
+               // Sync the data out.
+               fsync(fd);
                written += nwritten;
        }
        retval = written;
                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;
 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);
        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);
        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);
                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 (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);
                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");
 }
 
 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) {
        } else {
                fp = fopen(progFile, "w");
                if (fp) {
-                       sync_volume(ctx->pathname);
                        (void)fprintf(fp, "%llu\n", prog);
                        fclose(fp);
                }
                        (void)fprintf(fp, "%llu\n", prog);
                        fclose(fp);
                }