[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/Makefile b/ap/lib/libmtd/Makefile
new file mode 100755
index 0000000..f4fa4c6
--- /dev/null
+++ b/ap/lib/libmtd/Makefile
@@ -0,0 +1,37 @@
+#*******************************************************************************
+# include ZTE library makefile
+#*******************************************************************************
+#include $(COMMON_MK)
+
+##############USER COMIZE BEGIN################
+LIB_STATIC = libmtd.a
+LIB_SHARED = libmtd.so
+
+OBJS = mtd.o
+
+CFLAGS += -g -I.
+# off_t:32 bits -> 64 bits
+CFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+#LDFLAGS += -lpthread
+##############USER COMIZE END##################
+
+CFLAGS += -fPIC
+
+CFLAGS += -I$(zte_app_path)/include
+
+LDFLAGS += -shared
+
+all: $(LIB_STATIC) $(LIB_SHARED)
+
+$(LIB_STATIC) : $(OBJS)
+	$(AR) rcs $(LIB_STATIC) $(OBJS)
+
+$(LIB_SHARED): $(OBJS)
+	$(CC) $(LDFLAGS) -o $@ $^
+
+romfs:
+	$(ROMFSINST) $(LIB_SHARED) /lib/$(LIB_SHARED)
+
+clean:
+	-$(RM) *.a *.o *.so $(LIB_SHARED) $(LIB_STATIC) $(OBJS)
+
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
diff --git a/ap/lib/libmtd/mtd_api.h b/ap/lib/libmtd/mtd_api.h
new file mode 100755
index 0000000..bd95421
--- /dev/null
+++ b/ap/lib/libmtd/mtd_api.h
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * 版权所有 (C)2022, 中兴通讯股份有限公司。
+ *
+ * 文件名称:     pub_flags.h
+ * 文件标识:     pub_flags
+ * 内容摘要:     zx298501芯片平台flags分区规划头文件
+ * 使用方法:
+ *
+ * 修改日期        版本号      修改标记        修改人          修改内容
+ * ------------------------------------------------------------------------------
+ * 2022/09/15      V1.0        Create          周国坡          创建
+ *
+ *******************************************************************************/
+
+#ifndef _MTD_API_H
+#define _MTD_API_H
+
+typedef enum
+{
+    DEVICE_MTD = 0,
+    DEVICE_ZFTL = 1,
+    DEVICE_MTD_BLOCK,
+} device_type_t;
+
+/**
+ * @brief 根据分区名查找分区设备文件路径
+ * @param partition_name      入参,分区名
+ * @param type                入参,设备类型
+ * @param out_mtd_path        出参,设备文件路径缓冲区
+ * @param out_mtd_path_len    入参,out_mtd_path数据缓冲区长度
+ * @return 成功返回0,失败返回-1
+ * @retval
+ * @note
+ * @warning
+ */
+extern int mtd_find(const char *i_parti_name, device_type_t type, char *out_mtd_path, unsigned int out_mtd_path_len);
+
+/**
+ * @brief 根据分区名获取mtd分区信息
+ * @param fd                  入参,mtd分区文件fd
+ * @param info                出参,包括分区大小和擦除块大小
+ * @return 成功返回0,失败返回-1
+ * @retval
+ * @note fd为打开/dev/mtdN设备句柄
+ * @warning
+ */
+extern int mtd_get_info(int fd, struct mtd_info_user *info);
+
+/**
+ * @brief 判断block是否是坏块
+ * @param fd                  入参,mtd分区文件fd
+ * @param offset              入参,mtd分区偏移位置,包含坏块
+ * @return 0表示非坏块,1表示坏块,-1表示失败
+ * @retval
+ * @note fd为打开/dev/mtdN设备句柄
+ * @warning
+ */
+extern int mtd_block_isbad(int fd, off_t offset);
+
+/**
+ * @brief 擦除指定分区
+ * @param partition_name      入参,分区名
+  * @return 成功返回0,失败返回-1
+ * @retval
+ * @note
+ * @warning
+ */
+extern int mtd_erase_partition(const char *partition_name);
+
+/**
+ * @brief 将指定镜像文件写到指定分区
+ * @param partition_name      入参,分区名
+ * @param image_file          入参,指定的镜像文件
+ * @return 成功返回0,失败返回-1
+ * @retval
+ * @note
+ * @warning 先要mtd_erase_partition函数擦除分区
+ */
+extern int mtd_write_partition(const char *partition_name, const char *image_file);
+
+/**
+ * @brief 擦除mtd分区指定位置数据
+ * @param fd                  入参,mtd分区文件fd
+ * @param offset              入参,mtd分区偏移位置,包含坏块
+  * @return 成功返回0,失败返回-1
+ * @retval
+ * @note fd为打开/dev/mtdN设备句柄
+ * @warning 
+ */
+extern int mtd_erase_offset(int fd, off_t offset);
+
+/**
+ * @brief 将数据写到mtd分区指定偏移位置
+ * @param fd                  入参,mtd分区文件fd
+ * @param offset              入参,mtd分区偏移位置
+ * @param buf                 入参,数据缓冲区
+ * @param count               入参,buf数据长度,不超过一个擦除块
+ * @return 成功返回写入数据长度,失败返回-1
+ * @retval
+ * @note fd为打开/dev/mtdN设备句柄
+ * @warning 先要mtd_erase_partition函数擦除分区
+ */
+extern ssize_t mtd_write_offset(int fd, off_t offset, const void *buf, size_t count);
+
+/**
+ * @brief 读取mtd分区指定偏移位置的数据
+ * @param fd                  入参,mtd分区文件fd
+ * @param offset              入参,mtd分区偏移位置
+ * @param buf                 出参,数据缓冲区
+ * @param count               入参,buf数据长度,不超过一个擦除块
+ * @return 成功返回读取数据长度,失败返回-1
+ * @retval
+ * @note fd为打开/dev/mtdN设备句柄
+ * @warning
+ */
+extern ssize_t mtd_read_offset(int fd, off_t offset, void *buf, size_t count);
+
+#endif  /* _MTD_API_H */