Fix for 64-bit platforms.
[cascardo/bootimg.git] / bootimg.c
index 77758c2..7e38e0a 100644 (file)
--- a/bootimg.c
+++ b/bootimg.c
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
+#include <sys/stat.h>
 
-static int dump(int fd, size_t len, int pgsz, char *fname)
+static int dump_or_load(int fd, uint32_t *len, int pgsz, char *fname, int dump)
 {
-       int out;
+       int cfd;
        char *page;
        int i, npages;
        int r;
+       int ifd, ofd;
+       int rem;
        page = malloc(pgsz);
        if (!page)
                return -ENOMEM;
-       out = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0644);
-       if (out < 0)
-               return -errno;
-       npages = (len + pgsz - 1) / pgsz;
+       if (dump)
+               cfd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0644);
+       else
+               cfd = open(fname, O_RDONLY);
+       if (cfd < 0)
+               goto out;
+       if (dump) {
+               ifd = fd;
+               ofd = cfd;
+       } else {
+               struct stat s;
+               r = fstat(cfd, &s);
+               if (r < 0) {
+                       goto out;
+               }
+               *len = s.st_size;
+               ifd = cfd;
+               ofd = fd;
+       }
+       npages = (*len + pgsz - 1) / pgsz;
        for (i = 1; i <= npages; i++) {
                if (i == npages) {
-                       len = len & (pgsz - 1);
-                       if (len > 0) {
-                               r = read(fd, page, len);
-                               if (r != len)
+                       rem = *len & (pgsz - 1);
+                       if (rem > 0) {
+                               r = read(ifd, page, rem);
+                               if (r != rem)
                                        goto out;
-                               r = write(out, page, len);
-                               if (r != len)
+                               r = write(ofd, page, rem);
+                               if (r != rem)
                                        goto out;
+                               /* Write padding */
+                               if (!dump) {
+                                       memset(page, 0, pgsz - rem);
+                                       write(ofd, page, pgsz - rem);
+                               }
                        }
+               } else {
+                       r = read(ifd, page, pgsz);
+                       if (r != pgsz)
+                               goto out;
+                       r = write(ofd, page, pgsz);
+                       if (r != pgsz)
+                               goto out;
                }
-               r = read(fd, page, pgsz);
-               if (r != pgsz)
-                       goto out;
-               r = write(out, page, pgsz);
-               if (r != pgsz)
-                       goto out;
        }
        free(page);
-       close(out);
+       close(cfd);
        return 0;
 out:
        free(page);
-       close(out);
+       close(cfd);
        if (r < 0)
                return -errno;
        return -EINVAL;
 }
 
+static int dump(int fd, uint32_t len, int pgsz, char *fname)
+{
+       return dump_or_load(fd, &len, pgsz, fname, 1);
+}
+
+static int load(int fd, uint32_t *len, int pgsz, char *fname)
+{
+       return dump_or_load(fd, len, pgsz, fname, 0);
+}
+
 int main(int argc, char **argv)
 {
        int fd;
-       uint32_t kernel, initrd, second, pgsz;
+       uint32_t *kernel, *initrd, *second, pgsz;
        char buffer[4096];
        char *p;
        int r;
        off_t offset;
+       int is_load;
        if (argc < 2)
                return 1;
-       fd = open(argv[1], O_RDONLY);
+       if (argc > 2)
+               is_load = 1;
+       if (is_load)
+               fd = open(argv[1], O_RDWR);
+       else
+               fd = open(argv[1], O_RDONLY);
        if (fd < 0) {
                return 2;
        }
@@ -88,27 +129,40 @@ int main(int argc, char **argv)
        if (strncmp(buffer, "ANDROID!", 8)) {
                return 4;
        }
-       kernel = *(uint32_t *) p;
+       kernel = (uint32_t *) p;
        p += 8;
-       initrd = *(uint32_t *) p;
+       initrd = (uint32_t *) p;
        p += 8;
-       second = *(uint32_t *) p;
+       second = (uint32_t *) p;
        p += 12;
        pgsz = *(uint32_t *) p;
        offset = pgsz;
-       if (kernel > 0) {
+       if (!is_load && *kernel > 0) {
+               lseek(fd, offset, SEEK_SET);
+               dump(fd, *kernel, pgsz, "kernel");
+       } else {
                lseek(fd, offset, SEEK_SET);
-               dump(fd, kernel, pgsz, "kernel");
+               load(fd, kernel, pgsz, "kernel");
        }
-       offset += ((kernel + pgsz - 1) / pgsz) * pgsz;
-       if (initrd > 0) {
+       offset += ((*kernel + pgsz - 1) / pgsz) * pgsz;
+       if (!is_load && *initrd > 0) {
+               lseek(fd, offset, SEEK_SET);
+               dump(fd, *initrd, pgsz, "initrd");
+       } else {
                lseek(fd, offset, SEEK_SET);
-               dump(fd, initrd, pgsz, "initrd");
+               load(fd, initrd, pgsz, "initrd");
        }
-       offset += ((initrd + pgsz - 1) / pgsz) * pgsz;
-       if (second > 0) {
+       offset += ((*initrd + pgsz - 1) / pgsz) * pgsz;
+       if (!is_load && *second > 0) {
                lseek(fd, offset, SEEK_SET);
-               dump(fd, second, pgsz, "second");
+               dump(fd, *second, pgsz, "second");
+       } else {
+               /* For now, don't care about using second. */
+               /* The header must be written back, and we may need to
+                * truncate the file. */
+               ftruncate(fd, offset);
+               lseek(fd, 0, SEEK_SET);
+               write(fd, buffer, pgsz);
        }
        close(fd);
        return 0;