[Feature][ZXW-88]merge P50 version

Only Configure: No
Affected branch: master
Affected module: unknown
Is it affected on both ZXIC and MTK: only ZXIC
Self-test: Yes
Doc Update: No

Change-Id: I34667719d9e0e7e29e8e4368848601cde0a48408
diff --git a/ap/lib/libmtd/mtd.c b/ap/lib/libmtd/mtd.c
new file mode 100755
index 0000000..5754368
--- /dev/null
+++ b/ap/lib/libmtd/mtd.c
@@ -0,0 +1,819 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <mtd/mtd-abi.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include "mtd_api.h"
+
+#define MTD_PATH_LENGTH_MAX (256)
+
+static ssize_t readn(int fd, void *vptr, size_t n);
+static ssize_t writen(int fd, const void *vptr, size_t n);
+
+/*******************************************************************************
+ *                       内部函数/mtd_private.h                                  *
+ *******************************************************************************/
+/**
+ * @brief 从文件描述符读取数据
+ * @param fd                 入参,文件描述符
+ * @param vptr               出参,数据缓冲区
+ * @param n                  入参,内容字节数
+ * @return 成功返回成功读取的字节数,失败返回-1
+ * @retval
+ * @note 封装read接口,读取被打断时会重试直到全部读取成功
+ * @warning
+ */
+static ssize_t readn(int fd, void *vptr, size_t n)
+{
+    size_t nleft;
+    ssize_t nread;
+    char *ptr;
+
+    ptr = vptr;
+    nleft = n;
+    while (nleft > 0)
+    {
+        if ((nread = read(fd, ptr, nleft)) < 0)
+        {
+            if (errno == EINTR)
+            {
+                nread = 0; /* and call read() again */
+            }
+            else
+            {
+                return (-1);
+            }
+        }
+        else if (nread == 0)
+        {
+            break; /* EOF */
+        }
+
+        nleft -= nread;
+        ptr += nread;
+    }
+    return (n - nleft); /* return >= 0 */
+}
+
+/**
+ * @brief 向文件描述符写入数据
+ * @param fd                 入参,文件描述符
+ * @param vptr               入参,数据缓冲区
+ * @param n                  入参,内容字节数
+ * @return 成功返回成功写入的字节数,失败返回-1
+ * @retval
+ * @note 封装write接口,写入被打断时会重试直到全部写入成功
+ * @warning
+ */
+static ssize_t writen(int fd, const void *vptr, size_t n)
+{
+    size_t nleft;
+    ssize_t nwritten;
+    const char *ptr;
+
+    ptr = vptr;
+    nleft = n;
+    while (nleft > 0)
+    {
+        nwritten = write(fd, ptr, nleft);
+        if (nwritten < 0)
+        {
+            if (errno == EINTR)
+            {
+                nwritten = 0; /* call write() again */
+            }
+            else
+            {
+                return (-1); /* error */
+            }
+        }
+        else if (nwritten == 0)
+        {
+            break;
+        }
+
+        nleft -= nwritten;
+        ptr += nwritten;
+    }
+    return (n - nleft); /* return >= 0 */
+}
+
+/*******************************************************************************
+ *                                外部函数定义                                  *
+ *******************************************************************************/
+int mtd_find(const char *i_parti_name, device_type_t device_type, char *o_mtd_path, unsigned int o_mtd_path_len)
+{
+    FILE *fp_mtd = 0;
+    char buf[128];
+    char *line_str;
+
+    if (!o_mtd_path_len)
+    {
+        return -1;
+    }
+
+    fp_mtd = fopen("/proc/mtd", "r+");
+    if (NULL == fp_mtd)
+    {
+        printf("[libmtd]: mtd_find, open file error:%s", strerror(errno));
+        return -1;
+    }
+    // printf("[libmtd]: partition name:%s\n", i_parti_name);
+
+    while (1)
+    {
+        int matches = 0;
+        char mtdname[64] = {0};
+        int mtdnum = 0;
+        unsigned int mtdsize, mtderasesize;
+        memset(buf, 0, sizeof(buf));
+        line_str = fgets(buf, sizeof(buf) - 1, fp_mtd);
+
+        if (NULL == line_str)
+        {
+            printf("[libmtd]: mtd_find, get info from mtd error:%s\n", strerror(errno));
+            fclose(fp_mtd);
+            return -1;
+        }
+        // mtd5: 00100000 00020000 "fotaflag"
+        matches = sscanf(buf, "mtd%d: %x %x \"%63[^\"]",
+                         &mtdnum, &mtdsize, &mtderasesize, mtdname);
+        mtdname[63] = '\0';
+
+        if ((matches == 4) && (strcmp(mtdname, i_parti_name) == 0))
+        {
+            memset(o_mtd_path, 0, o_mtd_path_len);
+            if (device_type == DEVICE_MTD_BLOCK)
+            {
+                snprintf(o_mtd_path, o_mtd_path_len, "/dev/mtdblock%d", mtdnum);
+            }
+            else if (device_type == DEVICE_MTD)
+            {
+                snprintf(o_mtd_path, o_mtd_path_len, "/dev/mtd%d", mtdnum);
+            }
+            else if (device_type == DEVICE_ZFTL)
+            {
+                snprintf(o_mtd_path, o_mtd_path_len, "/dev/zftl%d", mtdnum);
+            }
+            else
+            {
+                printf("[libmtd]: mtd_find, unknown device type %d\n", device_type);
+                fclose(fp_mtd);
+                return -1;
+            }
+            // printf("[libmtd]: o_mtd_path=[%s]\n", o_mtd_path);
+            break;
+        }
+    }
+    fclose(fp_mtd);
+    return 0;
+}
+
+int mtd_get_info(int fd, struct mtd_info_user *info)
+{
+    if (0 != ioctl(fd, MEMGETINFO, info))
+    {
+        printf("[libmtd]: mtd_get_info, get fd(%d) info error, %s\n", fd, strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+int mtd_block_isbad(int fd, off_t offset)
+{
+    int ret = 0;
+    ret = ioctl(fd, MEMGETBADBLOCK, &offset);
+    if (ret > 0)
+    {
+        printf("[libmtd]: mtd_block_isbad, bad block at 0x%lx, ret = %d\n", offset, ret);
+        ret = 1;
+    }
+    else if (ret < 0)
+    {
+        printf("[libmtd]: mtd_block_isbad, ioctl(MEMGETBADBLOCK) error at 0x%lx, %s, ret = %d\n", offset, strerror(errno), ret);
+        ret = -1;
+    }
+    return ret;
+}
+
+int mtd_erase_partition(const char *partition_name)
+{
+    int ret = 0;
+    char mtd_path[MTD_PATH_LENGTH_MAX] = {0};
+    int fd_mtd = -1;
+
+    struct mtd_info_user meminfo = {0};
+    struct erase_info_user64 erase_info = {0};
+
+    if (NULL == partition_name)
+    {
+        return -1;
+    }
+
+    ret = mtd_find(partition_name, DEVICE_MTD, mtd_path, MTD_PATH_LENGTH_MAX);
+    if (ret < 0)
+    {
+        printf("[libmtd]: mtd_erase_partition, mtd_find %s failed\n", partition_name);
+        ret = -1;
+        goto out;
+    }
+    fd_mtd = open(mtd_path, O_RDWR);
+    if (fd_mtd < 0)
+    {
+        printf("[libmtd]: mtd_erase_partition, open %s error, %s\n", partition_name, strerror(errno));
+        return -1;
+    }
+    ret = mtd_get_info(fd_mtd, &meminfo);
+    if (ret < 0)
+    {
+        printf("[libmtd]: mtd_erase_partition, get %s info error, %s\n", partition_name, strerror(errno));
+        ret = -1;
+        goto out;
+    }
+
+    erase_info.length = meminfo.erasesize;
+    for (erase_info.start = 0; erase_info.start < meminfo.size; erase_info.start += meminfo.erasesize)
+    {
+        ret = mtd_block_isbad(fd_mtd, erase_info.start);
+        if (1 == ret)
+        {
+            continue;
+        }
+        else if (-1 == ret)
+        {
+            printf("[libmtd]: mtd_erase_partition, mtd_block_isbad %s error\n", partition_name);
+            goto out;
+        }
+
+        if (0 != ioctl(fd_mtd, MEMERASE64, &erase_info))
+        {
+            printf("[libmtd]: mtd_erase_partition, erasing %s failure at 0x%llx\n", partition_name, erase_info.start);
+            if (ioctl(fd_mtd, MEMSETBADBLOCK, &(erase_info.start)) < 0)
+            {
+                printf("[libmtd]: mtd_erase_partition, mark %s bad block error, %s\n", partition_name, strerror(errno));
+                ret = -1;
+                goto out;
+            }
+            continue;
+        }
+    }
+    ret = 0;
+out:
+    if (fd_mtd >= 0)
+    {
+        close(fd_mtd);
+    }
+    return ret;
+}
+
+int mtd_write_partition(const char *partition_name, const char *image_file)
+{
+    int ret = 0;
+    ssize_t wr_len;
+    char mtd_path[MTD_PATH_LENGTH_MAX] = {0};
+    int fd_mtd = -1;
+    struct mtd_info_user meminfo = {0};
+
+    off_t data_size = 0;
+    off_t index = 0;
+    off_t fd_img_index = 0;
+    int fd_img = -1;
+    char *buf = NULL;
+    struct stat statbuff = {0};
+
+    if (NULL == partition_name || NULL == image_file)
+    {
+        return -1;
+    }
+
+    ret = mtd_find(partition_name, DEVICE_MTD, mtd_path, MTD_PATH_LENGTH_MAX);
+    if (ret < 0)
+    {
+        printf("[libmtd]: mtd_write_partition, mtd_find %s failed\n", partition_name);
+        ret = -1;
+        goto out;
+    }
+    fd_mtd = open(mtd_path, O_RDWR);
+    if (fd_mtd < 0)
+    {
+        printf("[libmtd]: mtd_write_partition, open %s error, %s\n", partition_name, strerror(errno));
+        return -1;
+    }
+    ret = mtd_get_info(fd_mtd, &meminfo);
+    if (ret < 0)
+    {
+        printf("[libmtd]: mtd_write_partition, get %s info error, %s\n", partition_name, strerror(errno));
+        ret = -1;
+        goto out;
+    }
+
+    if (stat(image_file, &statbuff) < 0)
+    {
+        printf("[libmtd]: mtd_write_partition, stat %s failed, %s\n", image_file, strerror(errno));
+        ret = -1;
+        goto out;
+    }
+
+    fd_img = open(image_file, O_RDONLY);
+    if (fd_img < 0)
+    {
+        printf("[libmtd]: mtd_write_partition, open %s failed, %s\n", image_file, strerror(errno));
+        ret = -1;
+        goto out;
+    }
+
+    buf = (char *)malloc(meminfo.erasesize);
+    if (!buf)
+    {
+        printf("[libmtd]: mtd_write_partition, malloc failed\n");
+        ret = -1;
+        goto out;
+    }
+
+    for (index = 0; index < meminfo.size && fd_img_index < statbuff.st_size; index += meminfo.erasesize)
+    {
+        ret = mtd_block_isbad(fd_mtd, index);
+        if (1 == ret)
+        {
+            continue;
+        }
+        else if (-1 == ret)
+        {
+            printf("[libmtd]: mtd_write_partition, mtd_block_isbad %s error,at 0x%llx\n", partition_name, index);
+            goto out;
+        }
+
+        if (lseek(fd_img, fd_img_index, SEEK_SET) < 0)
+        {
+            printf("[libmtd]: mtd_write_partition, lseek %s error = %s!\n", image_file, strerror(errno));
+            ret = -1;
+            goto out;
+        }
+        if (fd_img_index + meminfo.erasesize > statbuff.st_size)
+        {
+            data_size = statbuff.st_size - fd_img_index;
+        }
+        else
+        {
+            data_size = meminfo.erasesize;
+        }
+        wr_len = readn(fd_img, buf, (size_t)data_size);
+        if (wr_len < 0)
+        {
+            printf("[libmtd]: mtd_write_partition, read %s error, %s\n", image_file, strerror(errno));
+            ret = -1;
+            goto out;
+        }
+        fd_img_index += data_size;
+
+        if (lseek(fd_mtd, index, SEEK_SET) < 0)
+        {
+            printf("[libmtd]: mtd_write_partition, lseek %s error = %s!\n", partition_name, strerror(errno));
+            ret = -1;
+            goto out;
+        }
+        wr_len = writen(fd_mtd, buf, (size_t)data_size);
+        if (wr_len < 0)
+        {
+            printf("[libmtd]: mtd_write_partition, write %s error, %s\n", partition_name, strerror(errno));
+            ret = -1;
+            goto out;
+        }
+        memset(buf, 0xFF, meminfo.erasesize);
+    }
+    if (fd_img_index < statbuff.st_size)
+    {
+        printf("[libmtd]: mtd_write_partition, No space left, writelen=0x%lx, filesize=0x%lx\n", fd_img_index, statbuff.st_size);
+        ret = -1;
+        goto out;
+    }
+    ret = 0;
+out:
+    if (fd_mtd >= 0)
+    {
+        close(fd_mtd);
+    }
+
+    if (buf != NULL)
+    {
+        // memset(buf, 0xFF, meminfo.erasesize);
+        free(buf);
+    }
+
+    if (fd_img >= 0)
+    {
+        close(fd_img);
+    }
+
+    return ret;
+}
+
+int mtd_erase_offset(int fd, off_t offset)
+{
+    struct mtd_info_user meminfo = {0};
+    struct erase_info_user64 erase_info = {0};
+
+    if (fd < 0)
+    {
+        printf("[libmtd]: mtd_erase_offset, fd(%d) error\n", fd);
+        return -1;
+    }
+
+    if (0 != mtd_get_info(fd, &meminfo))
+    {
+        printf("[libmtd]: mtd_erase_offset, get fd(%d) info error, %s\n", fd, strerror(errno));
+        return -1;
+    }
+
+    if (0 != (offset % meminfo.erasesize))
+    {
+        printf("[libmtd]: mtd_erase_offset, not at the beginning of a block, erasesize is %d\n", meminfo.erasesize);
+        return -1;
+    }
+
+    erase_info.length = meminfo.erasesize;
+    erase_info.start = offset;
+
+    if (mtd_block_isbad(fd, erase_info.start))
+    {
+        return -1;
+    }
+    if (0 != ioctl(fd, MEMERASE64, &erase_info))
+    {
+        printf("[libmtd]: mtd_erase_offset, erasing failure at 0x%llx\n", erase_info.start);
+        if (ioctl(fd, MEMSETBADBLOCK, &(erase_info.start)) < 0)
+        {
+            printf("[libmtd]: mtd_erase_offset, mark bad block error, %s\n", strerror(errno));
+        }
+        return -1;
+    }
+
+    return 0;
+}
+
+ssize_t mtd_write_offset(int fd, off_t offset, const void *buf, size_t count)
+{
+    ssize_t writen_len;
+    struct mtd_info_user meminfo = {0};
+
+    if (fd < 0)
+    {
+        return -1;
+    }
+
+    if (0 != mtd_get_info(fd, &meminfo))
+    {
+        printf("[libmtd]: mtd_write_offset, get fd(%d) info error, %s\n", fd, strerror(errno));
+        return -1;
+    }
+    if (count <= 0 || count > meminfo.erasesize)
+    {
+        printf("[libmtd]: mtd_write_offset, count(0x%lx), less than 0, or larger than erasesize(0x%x)\n", count, meminfo.erasesize);
+        return -1;
+    }
+    if (0 != (offset % meminfo.erasesize))
+    {
+        printf("[libmtd]: mtd_write_offset, not at the beginning of a block, erasesize is 0x%x\n", meminfo.erasesize);
+        return -1;
+    }
+
+    if (mtd_block_isbad(fd, offset))
+    {
+        return -1;
+    }
+
+    if (lseek(fd, offset, SEEK_SET) < 0)
+    {
+        printf("[libmtd]: mtd_write_offset, lseek error = %s!\n", strerror(errno));
+        return -1;
+    }
+    writen_len = writen(fd, buf, count);
+    if (writen_len != count)
+    {
+        if (-1 == writen_len)
+        {
+            printf("[libmtd]: mtd_write_offset, write error, %s\n", strerror(errno));
+        }
+        return -1;
+    }
+
+    return writen_len;
+}
+
+ssize_t mtd_read_offset(int fd, off_t offset, void *buf, size_t count)
+{
+    ssize_t readn_len;
+    struct mtd_info_user meminfo = {0};
+
+    if (fd < 0)
+    {
+        return -1;
+    }
+
+    if (0 != mtd_get_info(fd, &meminfo))
+    {
+        printf("[libmtd]: mtd_read_offset, get fd(%d) info error, %s\n", fd, strerror(errno));
+        return -1;
+    }
+    if (count <= 0 || count > meminfo.erasesize)
+    {
+        printf("[libmtd]: mtd_read_offset, count(0x%lx), less than 0, or larger than erasesize(0x%x)\n", count, meminfo.erasesize);
+        return -1;
+    }
+    if (0 != (offset % meminfo.erasesize))
+    {
+        printf("[libmtd]: mtd_read_offset, not at the beginning of a block, erasesize is %x\n", meminfo.erasesize);
+        return -1;
+    }
+
+    if (mtd_block_isbad(fd, offset))
+    {
+        return -1;
+    }
+
+    if (lseek(fd, offset, SEEK_SET) < 0)
+    {
+        printf("[libmtd]: mtd_read_offset, lseek error = %s!\n", strerror(errno));
+        return -1;
+    }
+    readn_len = readn(fd, buf, count);
+    if (readn_len != count)
+    {
+        if (-1 == readn_len)
+        {
+            printf("[libmtd]: mtd_read_offset, read error, %s\n", strerror(errno));
+        }
+        return -1;
+    }
+
+    return readn_len;
+}
+
+static int zftl_verify_partition(const char *partition_name, const char *image_file)
+{
+    int ret = 0;
+    ssize_t rd_len;
+    size_t read_size = 4096;
+    char zftl_path[MTD_PATH_LENGTH_MAX] = {0};
+    int fd_zftl = -1;
+    struct mtd_info_user meminfo = {0};
+
+    off_t data_size = 0;
+    off_t index = 0;
+    off_t fd_img_index = 0;
+    int fd_img = -1;
+    char *buf = NULL;
+    char *buf2 = NULL;
+    struct stat statbuff = {0};
+
+    if (NULL == partition_name || NULL == image_file)
+    {
+        return -1;
+    }
+
+    ret = mtd_find(partition_name, DEVICE_ZFTL, zftl_path, MTD_PATH_LENGTH_MAX);
+    if (ret < 0)
+    {
+        printf("[libmtd]: zftl_verify_partition, mtd_find %s failed\n", partition_name);
+        return -1;
+    }
+    fd_zftl = open(zftl_path, O_RDONLY);
+    if (fd_zftl < 0)
+    {
+        printf("[libmtd]: zftl_verify_partition, open %s error, %s\n", partition_name, strerror(errno));
+        return -1;
+    }
+
+    if (stat(image_file, &statbuff) < 0)
+    {
+        printf("[libmtd]: zftl_verify_partition, stat %s failed, %s\n", image_file, strerror(errno));
+        ret = -1;
+        goto out;
+    }
+
+    fd_img = open(image_file, O_RDONLY);
+    if (fd_img < 0)
+    {
+        printf("[libmtd]: zftl_verify_partition, open %s failed, %s\n", image_file, strerror(errno));
+        ret = -1;
+        goto out;
+    }
+
+    buf = (char *)malloc(read_size);
+    if (!buf)
+    {
+        printf("[libmtd]: zftl_verify_partition, malloc failed\n");
+        ret = -1;
+        goto out;
+    }
+    buf2 = (char *)malloc(read_size);
+    if (!buf2)
+    {
+        printf("[libmtd]: zftl_verify_partition, malloc2 failed\n");
+        ret = -1;
+        goto out;
+    }
+
+    for (index = 0; fd_img_index < statbuff.st_size; index += read_size)
+    {
+        //memset(buf, 0xFF, read_size);
+
+        if (fd_img_index + read_size > statbuff.st_size)
+        {
+            data_size = statbuff.st_size - fd_img_index;
+        }
+        else
+        {
+            data_size = read_size;
+        }
+        // data_size = (fd_img_index + read_size > statbuff.st_size) ? (statbuff.st_size - fd_img_index) : (read_size);
+
+        rd_len = readn(fd_img, buf, (size_t)data_size);
+        if (rd_len < 0)
+        {
+            printf("[libmtd]: zftl_verify_partition, read image file %s error, %s\n", image_file, strerror(errno));
+            ret = -1;
+            goto out;
+        }
+        fd_img_index += data_size;
+
+        rd_len = readn(fd_zftl, buf2, (size_t)data_size);
+        if (rd_len < 0)
+        {
+            printf("[libmtd]: zftl_verify_partition, read zftl %s error, %s\n", partition_name, strerror(errno));
+            ret = -1;
+            goto out;
+        }
+
+        if (memcmp(buf, buf2, (size_t)data_size) != 0)
+        {
+            printf("[libmtd]: zftl_verify_partition, data memcmp %s error\n", partition_name);
+            ret = -1;
+            goto out;
+        }
+    }
+
+    ret = 0;
+out:
+    if (fd_zftl >= 0)
+    {
+        //fsync(fd_zftl);
+        close(fd_zftl);
+    }
+
+    if (buf != NULL)
+    {
+        // memset(buf, 0xFF, meminfo.erasesize);
+        free(buf);
+    }
+    if (buf2 != NULL)
+    {
+        // memset(buf, 0xFF, meminfo.erasesize);
+        free(buf2);
+    }
+
+    if (fd_img >= 0)
+    {
+        close(fd_img);
+    }
+    if (ret == 0)
+    {
+        printf("[libmtd]: zftl %s verify sucess\n", partition_name);
+    }
+    else
+    {
+        printf("[libmtd]: zftl %s verify fail\n", partition_name);
+    }
+
+    return ret;
+}
+
+int zftl_write_partition(const char *partition_name, const char *image_file)
+{
+    int ret = 0;
+    ssize_t wr_len;
+    size_t write_size = 4096;
+    char zftl_path[MTD_PATH_LENGTH_MAX] = {0};
+    int fd_zftl = -1;
+    struct mtd_info_user meminfo = {0};
+
+    off_t data_size = 0;
+    off_t index = 0;
+    off_t fd_img_index = 0;
+    int fd_img = -1;
+    char *buf = NULL;
+    struct stat statbuff = {0};
+
+    if (NULL == partition_name || NULL == image_file)
+    {
+        return -1;
+    }
+
+    ret = mtd_find(partition_name, DEVICE_ZFTL, zftl_path, MTD_PATH_LENGTH_MAX);
+    if (ret < 0)
+    {
+        printf("[libmtd]: zftl_write_partition, mtd_find %s failed\n", partition_name);
+        return -1;
+    }
+    fd_zftl = open(zftl_path, O_RDWR);
+    if (fd_zftl < 0)
+    {
+        printf("[libmtd]: zftl_write_partition, open %s error, %s\n", partition_name, strerror(errno));
+        return -1;
+    }
+
+    if (stat(image_file, &statbuff) < 0)
+    {
+        printf("[libmtd]: zftl_write_partition, stat %s failed, %s\n", image_file, strerror(errno));
+        ret = -1;
+        goto out;
+    }
+
+    fd_img = open(image_file, O_RDONLY);
+    if (fd_img < 0)
+    {
+        printf("[libmtd]: zftl_write_partition, open %s failed, %s\n", image_file, strerror(errno));
+        ret = -1;
+        goto out;
+    }
+
+    buf = (char *)malloc(write_size);
+    if (!buf)
+    {
+        printf("[libmtd]: zftl_write_partition, malloc failed\n");
+        ret = -1;
+        goto out;
+    }
+
+    for (index = 0; fd_img_index < statbuff.st_size; index += write_size)
+    {
+        memset(buf, 0xFF, write_size);
+
+        if (fd_img_index + write_size > statbuff.st_size)
+        {
+            data_size = statbuff.st_size - fd_img_index;
+        }
+        else
+        {
+            data_size = write_size;
+        }
+        // data_size = (fd_img_index + write_size > statbuff.st_size) ? (statbuff.st_size - fd_img_index) : (write_size);
+
+        wr_len = readn(fd_img, buf, (size_t)data_size);
+        if (wr_len < 0)
+        {
+            printf("[libmtd]: zftl_write_partition, read %s error, %s\n", image_file, strerror(errno));
+            ret = -1;
+            goto out;
+        }
+        fd_img_index += data_size;
+
+        wr_len = writen(fd_zftl, buf, (size_t)data_size);
+        if (wr_len < 0)
+        {
+            printf("[libmtd]: zftl_write_partition, write %s error, %s\n", partition_name, strerror(errno));
+            ret = -1;
+            goto out;
+        }
+        
+    }
+    if (fd_img_index < statbuff.st_size)
+    {
+        printf("[libmtd]: zftl_write_partition, No space left, writelen=0x%lx, filesize=0x%lx\n", fd_img_index, statbuff.st_size);
+        ret = -1;
+        goto out;
+    }
+    ret = 0;
+out:
+    if (fd_zftl >= 0)
+    {
+        fsync(fd_zftl);
+        close(fd_zftl);
+    }
+
+    if (buf != NULL)
+    {
+        // memset(buf, 0xFF, meminfo.erasesize);
+        free(buf);
+    }
+
+    if (fd_img >= 0)
+    {
+        close(fd_img);
+    }
+
+    if (ret == 0)
+    {
+        //write sucess then do verify
+        ret = zftl_verify_partition(partition_name, image_file);
+    }
+
+    return ret;
+}
\ No newline at end of file