]> www.infradead.org Git - mtd-utils.git/commitdiff
libmtd: add mtd_write_img
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Mon, 14 Jun 2010 10:25:07 +0000 (13:25 +0300)
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Mon, 14 Jun 2010 10:54:31 +0000 (13:54 +0300)
Add another helper interface which can be used to write an image
to an mtd device.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
ubi-utils/include/libmtd.h
ubi-utils/include/libubi.h
ubi-utils/src/libmtd.c

index c8b44e848c64b40c75f42e461c3d44eb96cda016..dd82b72076977598999c7ba9922a316d928d8038 100644 (file)
@@ -213,6 +213,21 @@ int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
 int mtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
              void *buf, int len);
 
+/**
+ * mtd_write_img - write a file to MTD device.
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: eraseblock to write to
+ * @offs: offset withing the eraseblock to write to
+ * @img_name: the file to write
+ *
+ * This function writes an image @img_name the MTD device defined by @mtd. @eb
+ * and @offs are the starting eraseblock and offset on the MTD device. Returns
+ * %0 in case of success and %-1 in case of failure.
+ */
+int mtd_write_img(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
+                 const char *img_name);
+
 /**
  * mtd_probe_node - test MTD node.
  * @desc: MTD library descriptor
index f029a8d99b4361f6bb3e001e6767069eff366c9a..ffc4be9dcbd776a17ff81a08e7badb6f8bbf79a2 100644 (file)
@@ -43,8 +43,8 @@ typedef void * libubi_t;
  * @dev_num: number to assign to the newly created UBI device
  *           (%UBI_DEV_NUM_AUTO should be used to automatically assign the
  *           number)
- * @mtd_num: MTD device number to attach
- * @dev: path to device node to attach
+ * @mtd_num: MTD device number to attach (used if @dev is %NULL)
+ * @dev: path to MTD device node to attach
  * @vid_hdr_offset: VID header offset (%0 means default offset and this is what
  *                  most of the users want)
  */
index 249fa23b5ae95d68ca410528a4dc26f4764fd349..011327d35a4e4bd42c09dfc027d468140a6000a4 100644 (file)
@@ -981,7 +981,6 @@ int mtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
                errno = EINVAL;
                return -1;
        }
-
        if (offs % mtd->subpage_size) {
                errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
                       offs, mtd->dev_num, mtd->subpage_size);
@@ -1009,6 +1008,109 @@ int mtd_write(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
        return 0;
 }
 
+int mtd_write_img(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
+                 const char *img_name)
+{
+       int tmp, ret, in_fd, len, written = 0;
+       off_t seek;
+       struct stat st;
+       char *buf;
+
+       if (eb < 0 || eb >= mtd->eb_cnt) {
+               errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks",
+                      eb, mtd->dev_num, mtd->eb_cnt);
+               errno = EINVAL;
+               return -1;
+       }
+       if (offs < 0 || offs >= mtd->eb_size) {
+               errmsg("bad offset %d, mtd%d eraseblock size is %d",
+                      offs, mtd->dev_num, mtd->eb_size);
+               errno = EINVAL;
+               return -1;
+       }
+       if (offs % mtd->subpage_size) {
+               errmsg("write offset %d is not aligned to mtd%d min. I/O size %d",
+                      offs, mtd->dev_num, mtd->subpage_size);
+               errno = EINVAL;
+               return -1;
+       }
+
+       in_fd = open(img_name, O_RDONLY);
+       if (in_fd == -1)
+               return sys_errmsg("cannot open %s", img_name);
+
+       if (fstat(in_fd, &st)) {
+               sys_errmsg("cannot stat %s", img_name);
+               goto out_close;
+       }
+
+       len = st.st_size;
+       if (len % mtd->subpage_size) {
+               errmsg("size of \"%s\" is %d byte, which is not aligned to "
+                      "mtd%d min. I/O size %d", img_name, len, mtd->dev_num,
+                      mtd->subpage_size);
+               errno = EINVAL;
+               goto out_close;
+       }
+       tmp = (offs + len + mtd->eb_size - 1) / mtd->eb_size;
+       if (eb + tmp > mtd->eb_cnt) {
+               errmsg("\"%s\" image size is %d bytes, mtd%d size is %d "
+                      "eraseblocks, the image does not fit if we write it "
+                      "starting from eraseblock %d, offset %d",
+                      img_name, len, mtd->dev_num, mtd->eb_cnt, eb, offs);
+               errno = EINVAL;
+               goto out_close;
+       }
+
+       /* Seek to the beginning of the eraseblock */
+       seek = (off_t)eb * mtd->eb_size + offs;
+       if (lseek(fd, seek, SEEK_SET) != seek) {
+               sys_errmsg("cannot seek mtd%d to offset %llu",
+                           mtd->dev_num, (unsigned long long)seek);
+               goto out_close;
+       }
+
+       buf = malloc(mtd->eb_size);
+       if (!buf) {
+               sys_errmsg("cannot allocate %d bytes of memory", mtd->eb_size);
+               goto out_close;
+       }
+
+       while (written < len) {
+               int rd = 0;
+
+               do {
+                       ret = read(in_fd, buf, mtd->eb_size - offs - rd);
+                       if (ret == -1) {
+                               sys_errmsg("cannot read from %s", img_name);
+                               goto out_free;
+                       }
+                       rd += ret;
+               } while (ret && rd < mtd->eb_size - offs);
+
+               ret = write(fd, buf, rd);
+               if (ret != rd) {
+                       sys_errmsg("cannot write %d bytes to mtd%d (eraseblock %d, offset %d)",
+                                  len, mtd->dev_num, eb, offs);
+                       goto out_free;
+               }
+
+               offs = 0;
+               eb += 1;
+               written += rd;
+       }
+
+       free(buf);
+       close(in_fd);
+       return 0;
+
+out_free:
+       free(buf);
+out_close:
+       close(in_fd);
+       return -1;
+}
+
 int mtd_probe_node(libmtd_t desc, const char *node)
 {
        struct stat st;