]> git.saurik.com Git - apple/hfs.git/blobdiff - CopyHFSMeta/SparseBundle.c
hfs-407.1.3.tar.gz
[apple/hfs.git] / CopyHFSMeta / SparseBundle.c
index 455903eebec2fbf7b7c2e7003a393de4145f0e59..2d966c46744d6997bfd54c677592ad7ab72fa9b0 100644 (file)
@@ -73,19 +73,23 @@ doSparseRead(struct IOWrapper *context, off_t offset, void *buffer, off_t len)
 {
        struct SparseBundleContext *ctx = context->context;
        off_t blockSize = ctx->bandSize;
-       size_t nread = 0;
+       ssize_t nread = 0;
        ssize_t retval = -1;
 
        while (nread < len) {
                off_t bandNum = (offset + nread) / blockSize;   // Which band file to use
                off_t bandOffset = (offset + nread) % blockSize;        // how far to go into the file
-               size_t amount = MIN(len - nread, blockSize - bandOffset);       // How many bytes to write in this band file
-               struct stat sbuf;
+               ssize_t amount = MIN(len - nread, blockSize - bandOffset);      // How many bytes to write in this band file
                char *bandName;
-               ssize_t n;;
+               ssize_t n;
                int fd;
 
-               asprintf(&bandName, "%s/bands/%x", ctx->pathname, bandNum);
+               asprintf(&bandName, "%s/bands/%llx", ctx->pathname, bandNum);
+               if (!bandName) {
+                       warn("Cannot allocate memory for path '%s/bands/%llx'", ctx->pathname, bandNum);
+                       retval = -1;
+                       goto done;
+               }
                fd = open(bandName, O_RDONLY);
                if (fd == -1) {
                        if (errno == ENOENT) {
@@ -100,15 +104,19 @@ doSparseRead(struct IOWrapper *context, off_t offset, void *buffer, off_t len)
                        free(bandName);
                        goto done;
                }
+
                n = pread(fd, (char*)buffer + nread, amount, bandOffset);
                if (n == -1) {
-                       warn("Cannot write to band file %s/band/%x for offset %llu for amount %zu", ctx->pathname, bandNum, offset+nread, amount);
+                       warn("Cannot read from band file %s for offset %llu for amount %zu", bandName, offset+nread, amount);
                        close(fd);
+                       free(bandName);
                        goto done;
                }
                if (n < amount) {       // hit EOF, pad out with zeroes
                        memset(buffer + nread + amount, 0, amount - n);
                }
+               free(bandName);
+               close(fd);
                nread += n;
        }
        retval = nread;
@@ -121,29 +129,38 @@ done:
  * Write a chunk of data to a bundle.
  */
 static ssize_t
-doSparseWrite(IOWrapper_t *context, off_t offset, void *buffer, size_t len)
+doSparseWrite(IOWrapper_t *context, off_t offset, void *buffer, off_t len)
 {
        struct SparseBundleContext *ctx = context->context;
        off_t blockSize = ctx->bandSize;
-       size_t written = 0;
+       ssize_t written = 0;
        ssize_t retval = -1;
 
        while (written < len) {
                off_t bandNum = (offset + written) / blockSize; // Which band file to use
                off_t bandOffset = (offset + written) % blockSize;      // how far to go into the file
                size_t amount = MIN(len - written, blockSize - bandOffset);     // How many bytes to write in this band file
-               char *bandName;
                ssize_t nwritten;
                int fd;
 
                if (ctx->cfd == -1 || ctx->cBandNum != bandNum) {
+                       char *bandName = NULL;
+
                        if (ctx->cfd != -1) {
                                close(ctx->cfd);
+                               ctx->cfd = -1;
                        }
-                       asprintf(&bandName, "%s/bands/%x", ctx->pathname, bandNum);
+                       asprintf(&bandName, "%s/bands/%llx", ctx->pathname, bandNum);
+                       if (!bandName) {
+                               warnx("Cannot allocate memory for band %s/bands/%llx", ctx->pathname, bandNum);
+                               retval = -1;
+                               goto done;
+                       }
+
                        fd = open(bandName, O_WRONLY | O_CREAT, 0666);
                        if (fd == -1) {
                                warn("Cannot open band file %s for offset %llu", bandName, offset + written);
+                               free(bandName);
                                retval = -1;
                                goto done;
                        }
@@ -165,7 +182,7 @@ doSparseWrite(IOWrapper_t *context, off_t offset, void *buffer, size_t len)
                }
                nwritten = pwrite(fd, (char*)buffer + written, amount, bandOffset);
                if (nwritten == -1) {
-                       warn("Cannot write to band file %s/band/%x for offset %llu for amount %zu", ctx->pathname, bandNum, offset+written, amount);
+                       warn("Cannot write to band file %s/band/%llx for offset %llu for amount %zu", ctx->pathname, bandNum, offset+written, amount);
                        close(fd);
                        ctx->cfd = -1;
                        retval = -1;
@@ -188,7 +205,7 @@ done:
 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;
+       const ssize_t bufSize = 1024 * 1024;
        uint8_t *buffer = NULL;
        ssize_t retval = 0;
        off_t total = 0;
@@ -204,7 +221,7 @@ WriteExtentToSparse(struct IOWrapper * context, DeviceInfo_t *devp, off_t start,
        while (total < len) {
                ssize_t nread;
                ssize_t nwritten;
-               size_t amt = MIN(bufSize, len - total);
+               ssize_t amt = MIN(bufSize, len - total);
                nread = UnalignedRead(devp, buffer, amt, start + total);
                if (nread == -1) {
                        warn("Cannot read from device at offset %lld", start + total);
@@ -251,7 +268,7 @@ GetSizesFromPlist(const char *path, size_t *bandSize, off_t *devSize)
        long long tmpLL;
 
 
-       inFileURL = CFURLCreateFromFileSystemRepresentation(NULL, path, strlen(path), FALSE);
+       inFileURL = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *)path, strlen(path), FALSE);
        if (inFileURL == NULL) {
                if (debug) warn("Cannot create url from pathname %s", path);
                goto done;
@@ -398,10 +415,10 @@ struct IOWrapper *
 InitSparseBundle(const char *path, DeviceInfo_t *devp)
 {
        struct SparseBundleContext ctx = { 0 };
-       struct SparseBundleContext *retctx = NULL;
-       IOWrapper_t *retval = NULL;
+       IOWrapper_t *wrapper = NULL;
        struct stat sb;
-       char tmpname[strlen(path) + sizeof("Info.plist") + 2];  // '/' + NUL
+       char *tmpname = NULL;
+       int tmplen;
 
        if (strstr(path, ".sparsebundle") == NULL) {
                asprintf(&ctx.pathname, "%s.sparsebundle", path);
@@ -409,6 +426,10 @@ InitSparseBundle(const char *path, DeviceInfo_t *devp)
                ctx.pathname = strdup(path);
        }
 
+       if (ctx.pathname == NULL) {
+               return NULL;
+       }
+
        if (lstat(ctx.pathname, &sb) == -1) {
                if (errno != ENOENT) {
                        warn("cannot check sparse bundle %s", ctx.pathname);
@@ -422,7 +443,14 @@ InitSparseBundle(const char *path, DeviceInfo_t *devp)
                warnx("sparse bundle object %s is not a directory", ctx.pathname);
                goto done;
        }
-       sprintf(tmpname, "%s/Info.plist", ctx.pathname);
+       /* NB! All names we create inside the bundle directory are shorter
+        * then "Info.plist", we re-use the buffer allocated here for
+        * multiple file names. */
+       tmplen = asprintf(&tmpname, "%s/Info.plist", ctx.pathname);
+       if (tmpname == NULL) {
+               goto done;
+       }
+
        if (stat(tmpname, &sb) != -1) {
                size_t bandSize = 0;
                off_t devSize = 0;
@@ -445,46 +473,64 @@ InitSparseBundle(const char *path, DeviceInfo_t *devp)
                        goto done;
                }
                ctx.bandSize = kBandSize;
-               fprintf(fp, bundlePrototype, kBandSize, devp->size);
-               fclose(fp);
-               sprintf(tmpname, "%s/Info.bckup", ctx.pathname);
-               fp = fopen(tmpname, "w");
-               if (fp) {
-                       fprintf(fp, bundlePrototype, kBandSize, devp->size);
-                       fclose(fp);
+               if (fprintf(fp, bundlePrototype, kBandSize, devp->size) < 0) {
+                       warn("failed to set bundle information in %s", tmpname);
+                       fclose(fp); /* eat error return */
+                       goto done;
+               }
+               if (fclose(fp) != 0) {
+                       warn("failed to update bundle information in %s", tmpname);
+                       goto done;
                }
-               sprintf(tmpname, "%s/bands", ctx.pathname);
-               if (mkdir(tmpname, 0777) == -1) {
+               snprintf(tmpname, tmplen + 1, "%s/Info.bckup", ctx.pathname);
+               if ((int)strlen(tmpname) == tmplen) { /* Only update backup if we get the full path */
+                       /* Failure to create a backup is not fatal */
+                       fp = fopen(tmpname, "w");
+                       if (fp) {
+                               if ((fprintf(fp, bundlePrototype, kBandSize, devp->size) < 0) ||
+                                       (fclose(fp) < 0)) {
+                                       unlink(tmpname);
+                               }
+                       }
+               } else {
+                       warn("Cannot create backup bundle information file in %s", tmpname);
+               }
+               if ((snprintf(tmpname, tmplen + 1, "%s/bands", ctx.pathname) > tmplen) ||
+                       (mkdir(tmpname, 0777) == -1)) {
                        warn("cannot create bands directory in sparse bundle %s", ctx.pathname);
                        goto done;
                }
-               sprintf(tmpname, "%s/token", ctx.pathname);
-               close(open(tmpname, O_CREAT | O_TRUNC, 0666));
-       }
-
-       retval = malloc(sizeof(*retval));
-       if (retval == NULL) {
-               free(retval);
-               retval = NULL;
-               goto done;
+               if (snprintf(tmpname, tmplen + 1, "%s/token", ctx.pathname) <= tmplen) {
+                       close(open(tmpname, O_CREAT | O_TRUNC, 0666));
+               }
        }
-       retctx = malloc(sizeof(*retctx));
-       if (retctx) {
-               *retctx = ctx;
-               retctx->cfd = -1;
 
+       wrapper = malloc(sizeof(*wrapper));
+       if (wrapper) {
+               struct SparseBundleContext *wrapped_ctx;
+
+               wrapped_ctx = malloc(sizeof(*wrapped_ctx));
+               if (wrapped_ctx) {
+                       *wrapped_ctx = ctx;
+                       wrapped_ctx->cfd = -1;
+
+                       wrapper->writer = &WriteExtentToSparse;
+                       wrapper->reader = &doSparseRead;
+                       wrapper->getprog = &GetProgress;
+                       wrapper->setprog = &SetProgress;
+                       wrapper->cleanup = &doCleanup;
+                       wrapper->context = wrapped_ctx;
+               } else {
+                       free(wrapper);
+                       wrapper = NULL;
+               }
        }
-       retval->writer = &WriteExtentToSparse;
-       retval->reader = &doSparseRead;
-       retval->getprog = &GetProgress;
-       retval->setprog = &SetProgress;
-       retval->cleanup = &doCleanup;
-
-       retval->context = retctx;
 done:
-       if (retval == NULL) {
+       if (wrapper == NULL) {
                if (ctx.pathname)
                        free(ctx.pathname);
        }
-       return retval;
+
+       free(tmpname);
+       return wrapper;
 }