[Feature][ZXW-130]merge P50U02 version

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

Change-Id: I4f29ec5bb7c59385f23738d2b7ca84e67c100f69
diff --git a/ap/lib/libcpnv/Makefile b/ap/lib/libcpnv/Makefile
index 88990b8..489cb8c 100755
--- a/ap/lib/libcpnv/Makefile
+++ b/ap/lib/libcpnv/Makefile
@@ -9,14 +9,19 @@
 
 OBJS = cpnv.o
 
+ifeq ($(USE_NVRO_BACKUP),yes)
+OBJS += nvro.o mtd.o file.o
+endif
+
 CFLAGS += -g -Werror=implicit-function-declaration
 #LDFLAGS += -lpthread
 ##############USER COMIZE END##################
 
 CFLAGS += -I$(APP_DIR)/include
 #CFLAGS += -I$(TOPDIR)/pub/project/$(CHIP_NAME)/include/nv
-CFLAGS += -I$(LINUX_DIR)/include
+#CFLAGS += -I$(LINUX_DIR)/include
 CFLAGS += -I$(zte_lib_path)/libnvram
+CFLAGS += -I$(zte_lib_path)/libssl/install/include
 CFLAGS += -fPIC
 LDFLAGS += -shared
 
diff --git a/ap/lib/libcpnv/file.c b/ap/lib/libcpnv/file.c
new file mode 100755
index 0000000..939ce20
--- /dev/null
+++ b/ap/lib/libcpnv/file.c
@@ -0,0 +1,157 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#define  FAST_FUNC
+
+ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count)
+{
+	ssize_t n;
+
+	for (;;) {
+		n = read(fd, buf, count);
+		if (n >= 0 || errno != EINTR)
+			break;
+		/* Some callers set errno=0, are upset when they see EINTR.
+		 * Returning EINTR is wrong since we retry read(),
+		 * the "error" was transient.
+		 */
+		errno = 0;
+		/* repeat the read() */
+	}
+
+	return n;
+}
+
+/*
+ * Read all of the supplied buffer from a file.
+ * This does multiple reads as necessary.
+ * Returns the amount read, or -1 on an error.
+ * A short read is returned on an end of file.
+ */
+ssize_t FAST_FUNC full_read(int fd, void *buf, size_t len)
+{
+	ssize_t cc;
+	ssize_t total;
+
+	total = 0;
+
+	while (len) {
+		cc = safe_read(fd, buf, len);
+
+		if (cc < 0) {
+			if (total) {
+				/* we already have some! */
+				/* user can do another read to know the error code */
+				return total;
+			}
+			return cc; /* read() returns -1 on failure. */
+		}
+		if (cc == 0)
+			break;
+		buf = ((char *)buf) + cc;
+		total += cc;
+		len -= cc;
+	}
+
+	return total;
+}
+
+ssize_t FAST_FUNC read_close(int fd, void *buf, size_t size)
+{
+	/*int e;*/
+	size = full_read(fd, buf, size);
+	/*e = errno;*/
+	close(fd);
+	/*errno = e;*/
+	return size;
+}
+
+ssize_t FAST_FUNC open_read_close(const char *filename, void *buf, size_t size)
+{
+#ifdef ZXIC_WIN
+	int fd = open(filename, O_RDONLY | O_BINARY);
+#else
+	int fd = open(filename, O_RDONLY);
+#endif
+	if (fd < 0)
+		return fd;
+	return read_close(fd, buf, size);
+}
+
+ssize_t FAST_FUNC safe_write(int fd, const void *buf, size_t count)
+{
+	ssize_t n;
+
+	for (;;) {
+		n = write(fd, buf, count);
+		if (n >= 0 || errno != EINTR)
+			break;
+		/* Some callers set errno=0, are upset when they see EINTR.
+		 * Returning EINTR is wrong since we retry write(),
+		 * the "error" was transient.
+		 */
+		errno = 0;
+		/* repeat the write() */
+	}
+
+	return n;
+}
+
+ssize_t FAST_FUNC full_write(int fd, const void *buf, size_t len)
+{
+	ssize_t cc;
+	ssize_t total;
+
+	total = 0;
+
+	while (len) {
+		cc = safe_write(fd, buf, len);
+
+		if (cc < 0) {
+			if (total) {
+				/* we already wrote some! */
+				/* user can do another write to know the error code */
+				return total;
+			}
+			return cc;  /* write() returns -1 on failure. */
+		}
+
+		total += cc;
+		buf = ((const char *)buf) + cc;
+		len -= cc;
+	}
+
+	return total;
+}
+
+ssize_t FAST_FUNC open_write_close(const char *filename, void *buf, size_t size)
+{
+	ssize_t ret;
+#ifdef ZXIC_WIN
+	int fd_to = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0640);
+#else
+	int fd_to = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_SYNC, 0640);
+#endif
+
+	if(fd_to < 0)
+		return -1;
+	
+	ret = full_write(fd_to, buf, size);
+	fsync(fd_to);
+	close(fd_to);
+
+	return ret;
+}
diff --git a/ap/lib/libcpnv/mtd.c b/ap/lib/libcpnv/mtd.c
new file mode 100755
index 0000000..61be26d
--- /dev/null
+++ b/ap/lib/libcpnv/mtd.c
@@ -0,0 +1,129 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/vfs.h>
+
+
+#include <mtd/mtd-abi.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include "mtd.h"
+
+
+int mtd_find(const char *i_parti_name, char *o_mtd_path, device_type_t device_type, unsigned int o_mtd_path_len)
+{
+	FILE *fd_mtd = 0;
+	char buf[128];
+	char *line_str;
+
+	if (!o_mtd_path_len)
+		return -1;
+
+	fd_mtd = fopen("/proc/mtd", "r+");
+	if (NULL == fd_mtd) {
+		printf("fs_check open file error:%s", strerror(errno));
+		//sc_debug_info_record(MODULE_ID_AP_FS_CHECK, "fs_check open file error:%s", strerror(errno));
+		goto error0;
+	}
+	//printf("fs_check 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, 0x00, sizeof(buf));
+		line_str = fgets(buf, sizeof(buf), fd_mtd);
+
+		if (NULL == line_str) {
+			printf("fs_check get info from mtd error:%s\n", strerror(errno));
+			//sc_debug_info_record(MODULE_ID_AP_FS_CHECK, "fs_check get info from mtd error:%s\n", strerror(errno));
+			goto error1;
+		}
+		//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, 0x00, 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("fs_check unknown device type %d\n", device_type);
+				//sc_debug_info_record(MODULE_ID_AP_FS_CHECK, "fs_check unknown device type %d\n", device_type);
+				goto error1;
+			}
+			//printf("fs_check o_mtd_path=[%s]\n", o_mtd_path);
+			break;
+		}
+
+	}
+	fclose(fd_mtd);
+	return 0;
+
+error1:
+	fclose(fd_mtd);
+error0:
+	return -1;
+}
+
+int mtd_erase_partition(const char* partition_name)
+{
+	int ret = 0;
+	char mtd_path[MAX_PATH] = {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, mtd_path, DEVICE_MTD, MAX_PATH);
+	if (ret < 0) {
+		printf("fs_check mtd_find %s failed\n", partition_name);
+		//sc_debug_info_record(MODULE_ID_AP_FS_CHECK, "fs_check mtd_find %s failed\n", partition_name);
+		ret = -1;
+		goto out;
+	}
+	fd_mtd = open(mtd_path, O_RDWR);
+	if (fd_mtd < 0) {
+		printf("fs_check open %s error, %s\n", partition_name, strerror(errno));
+		//sc_debug_info_record(MODULE_ID_AP_FS_CHECK, "fs_check open %s error, %s\n", partition_name, strerror(errno));
+		ret = -1;
+		goto out;
+	}
+	if (ioctl(fd_mtd, MEMGETINFO, &meminfo) != 0) {
+		printf("fs_check get %s info error, %s\n", partition_name, strerror(errno));
+		//sc_debug_info_record(MODULE_ID_AP_FS_CHECK, "fs_check 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) {
+		if (ioctl(fd_mtd, MEMGETBADBLOCK, &(erase_info.start)) > 0) {
+			printf("fs_check mtd, not erasing bad block at 0x%llx\n", erase_info.start);
+			continue;
+		}
+		if (ioctl(fd_mtd, MEMERASE64, &erase_info) < 0) {
+			printf("fs_check mtd, erasing failure at 0x%llx\n", erase_info.start);
+		}
+	}
+	ret = 0;
+out:
+	if (fd_mtd >= 0) {
+		close(fd_mtd);
+	}
+	return ret;
+}
diff --git a/ap/lib/libcpnv/mtd.h b/ap/lib/libcpnv/mtd.h
new file mode 100755
index 0000000..a517ad0
--- /dev/null
+++ b/ap/lib/libcpnv/mtd.h
@@ -0,0 +1,16 @@
+#ifndef __CPNV_MTD_H
+#define __CPNV_MTD_H
+
+typedef enum {
+	DEVICE_MTD = 0,
+	DEVICE_ZFTL = 1,
+	DEVICE_MTD_BLOCK,
+} device_type_t;
+
+#define MAX_PATH 					(256)
+
+
+extern int mtd_find(const char *i_parti_name, char *o_mtd_path, device_type_t device_type, unsigned int o_mtd_path_len);
+extern int mtd_erase_partition(const char* partition_name);
+
+#endif
diff --git a/ap/lib/libcpnv/nvro.c b/ap/lib/libcpnv/nvro.c
new file mode 100755
index 0000000..0e5880c
--- /dev/null
+++ b/ap/lib/libcpnv/nvro.c
@@ -0,0 +1,338 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "openssl/md5.h"
+#include "mtd.h"
+#include "libcpnv.h"
+#include "cfg_api.h"
+#include "flags_api.h"
+#include "zxicbasic_api.h"
+
+
+/*******************************************************************************
+* 功能描述:     copyfile
+* 参数说明:     
+*   (传入参数)  to:目标文件
+*   (传入参数)  from:源文件
+* 返 回 值:     0表示成功,负值失败
+* 其它说明:     
+*******************************************************************************/
+static int copyfile(const char *from, const char *to)
+{
+    int fd_to;
+    int fd_from;
+    char buf[4096];
+    ssize_t nread;
+    int ret = -1;
+
+    fd_from = open(from, O_RDONLY);
+    if (fd_from < 0)
+        return -2;
+
+    fd_to = open(to, O_RDWR | O_CREAT | O_TRUNC | O_SYNC, 0640);
+    if (fd_to < 0) {
+        ret = -3;
+        goto out_error;
+    }
+
+    while (1)
+    {
+        char *out_ptr;
+        ssize_t nwritten;
+
+        nread = read(fd_from, buf, sizeof(buf));
+        if (nread == 0)
+        {
+            break; /* read file done*/
+        }
+        else
+        {
+            if (nread < 0 )
+            {
+                if (errno == EINTR || errno == EAGAIN)
+                {
+                    continue;
+                }
+                else
+                {
+                    ret = -4;
+                    goto out_error;
+                }
+            }
+        }
+
+        out_ptr = buf;
+        do
+        {
+            nwritten = write(fd_to, out_ptr, nread);
+            if (nwritten > 0)
+            {
+                nread -= nwritten;
+                out_ptr += nwritten;
+            }
+            else
+            {
+                if (nwritten < 0)
+                {
+                    if (errno == EINTR || errno == EAGAIN)
+                    {
+                        continue;
+                    }
+                    else
+                    {
+                        ret = -5;
+                        goto out_error;
+                    }
+                }
+            }
+        } while (nread > 0);
+    }
+
+    ret = fsync(fd_to);
+	if (ret < 0) {
+		printf("Sync Failed:%s, file path:%s", strerror(errno), to);
+		goto out_error;
+	}
+	
+    if (close(fd_to) < 0)
+    {
+        fd_to = -1;
+        ret = -6;
+        goto out_error;
+    }
+    close(fd_from);
+
+    /* Success! */
+    return 0;
+
+out_error:
+    printf("copyfile %s to %s error:%d\n", from, to, ret);
+    close(fd_from);
+    if (fd_to >= 0)
+        close(fd_to);
+
+    return ret;
+}
+
+int nvrofs2_mount(int rw)
+{
+    if (rw)
+        return zxic_system("/bin/mount -t jffs2 -o rw,sync mtd:nvrofs2 /mnt/nvrofs2");
+    else
+        return zxic_system("/bin/mount -t jffs2 -o ro mtd:nvrofs2 /mnt/nvrofs2");
+}
+int nvrofs2_umount(void)
+{
+    return zxic_system("/bin/umount -f -l /mnt/nvrofs2");
+}
+
+unsigned char *bin2hex(const unsigned char *old, const size_t oldlen)
+{
+    unsigned char *result = (unsigned char *)malloc(oldlen * 2 + 1);
+    size_t i, j;
+    int b = 0;
+
+    for (i = j = 0; i < oldlen; i++)
+    {
+        b = old[i] >> 4;
+        result[j++] = (char)(87 + b + (((b - 10) >> 31) & -39));
+        b = old[i] & 0xf;
+        result[j++] = (char)(87 + b + (((b - 10) >> 31) & -39));
+    }
+    result[j] = '\0';
+    return result;
+}
+
+int calc_file_hash(const char *file_in, unsigned char *hash_value)
+{
+    MD5_CTX ctx;
+    unsigned char *buf;
+    int offset;
+    int fd;
+    ssize_t len;
+    
+    fd = open(file_in, O_RDONLY);
+    if (fd < 0)
+        return -1;
+    buf = malloc(4096);
+    if (buf == NULL)
+        return -1;
+    MD5_Init(&ctx);
+    do
+    {
+        len = full_read(fd, buf, 4096);
+        MD5_Update(&ctx, buf, len);
+        if (len < 4096)
+            break;
+    } while(1);
+
+    MD5_Final(hash_value, &ctx);
+    free(buf);
+    return 0;
+}
+
+int file_hash(const char *file_in, const char *file_hash)
+{
+    unsigned char hash_value[16] = {0};
+    unsigned char *hash_str;
+    int ret;
+    ssize_t ret_s;
+
+    ret = calc_file_hash(file_in, hash_value);
+    if (ret < 0)
+        return -1;
+    hash_str = bin2hex(hash_value, 16);
+    ret_s = open_write_close(file_hash, hash_str, 32);
+    free(hash_str);
+    if (ret_s != 32)
+        return -1;
+    return 0;
+}
+int file_hash_check(const char *file_in, const char *file_hash)
+{
+    unsigned char hash_value[16] = {0};
+    unsigned char *hash_str;
+    unsigned char  hash_str2[33] = {0};
+    int ret;
+    ssize_t ret_s;
+
+    ret = calc_file_hash(file_in, hash_value);
+    if (ret < 0)
+        return -1;
+    hash_str = bin2hex(hash_value, 16);
+    memset(hash_str2, 0, sizeof(hash_str2));
+    ret_s = open_read_close(file_hash, hash_str2, 32);
+    if (ret_s != 32)
+        return -1;
+    if (strcmp(hash_str, hash_str2) == 0)
+    {
+        return 0;
+    }
+    return -1;
+}
+
+unsigned int cpnv_NvroBackup(void)
+{
+    char mtd_path[MAX_PATH] = {0};
+    int ret;
+
+    ret = mtd_find("nvrofs2", mtd_path, DEVICE_MTD_BLOCK, MAX_PATH);
+    if (ret < 0)
+    {
+        printf("[error]cpnv can not find nvrofs2\n");
+        return CPNV_ERROR;
+    }
+    ret = mtd_erase_partition("nvrofs2");
+    if (ret != 0)
+    {
+        printf("[error]cpnv erase nvrofs2\n");
+        return CPNV_ERROR;
+    }
+    
+    nvrofs2_umount();
+    ret = nvrofs2_mount(1);
+    if (ret != 0)
+    {
+        printf("[error]cpnv nvrofs2_mount\n");
+        return CPNV_ERROR;
+    }
+    ret = copyfile("/mnt/nvrofs/nvroall.bin", "/mnt/nvrofs2/nvroall.bin");
+    if (ret != 0)
+    {
+        printf("[error]cpnv nvrofs2 copyfile\n");
+        goto out_err;
+    }
+    ret = file_hash("/mnt/nvrofs2/nvroall.bin", "/mnt/nvrofs2/nvroall.bin.hash");
+    if (ret != 0)
+    {
+        printf("[error]cpnv file_hash\n");
+        goto out_err;
+    }
+    ret = nvrofs2_umount();
+    if (ret < 0)
+    {
+        printf("[error]cpnv nvrofs2_umount\n");
+        return CPNV_ERROR;
+    }
+
+    ret = flags_set_nvroflag(NVRO_BACKED_UP);
+    if (ret != 0)
+    {
+        printf("[error]cpnv NVRO_BACKED_UP\n");
+        return CPNV_ERROR;
+    }
+    return CPNV_OK;
+
+out_err:
+    nvrofs2_umount();
+
+    return CPNV_ERROR;
+}
+
+unsigned int cpnv_NvroRestore(void)
+{
+    int ret;
+    unsigned int ret_u;
+    unsigned int nvro_flag;
+
+    nvro_flag = flags_get_nvroflag();
+    if (nvro_flag != NVRO_RESTORING)
+    {
+        printf("[error]cpnv_NvroRestore nvro flag error\n");
+        return CPNV_ERROR;
+    }
+    nvrofs2_umount();
+    ret = nvrofs2_mount(0);
+    if (ret != 0)
+    {
+        printf("[error]cpnv nvrofs2_mount\n");
+        return CPNV_ERROR;
+    }
+    ret = file_hash_check("/mnt/nvrofs2/nvroall.bin", "/mnt/nvrofs2/nvroall.bin.hash");
+    if (ret != 0)
+    {
+        printf("[error]cpnv file_hash_check\n");
+        goto out_err;
+    }
+    ret_u = cpnv_ChangeFsPartitionAttr(FS_NVROFS, 1);
+    if (ret_u != CPNV_OK)
+    {
+        printf("[error]cpnv nvrofs Attr 1\n");
+        goto out_err;
+    }
+    ret = copyfile("/mnt/nvrofs2/nvroall.bin", "/mnt/nvrofs/nvroall.bin");
+    if (ret != 0)
+    {
+        printf("[error]cpnv nvrofs2 restore copyfile\n");
+        goto out_err;
+    }
+	ret_u = cpnv_ChangeFsPartitionAttr(FS_NVROFS, 0);
+    if (ret_u != CPNV_OK)
+    {
+        printf("[error]cpnv nvrofs Attr 0\n");
+        goto out_err;
+    }
+    ret = nvrofs2_umount();
+    if (ret < 0)
+    {
+        printf("[error]cpnv nvrofs2_umount\n");
+        return CPNV_ERROR;
+    }
+    ret = flags_set_nvroflag(NVRO_BACKED_UP);
+    if (ret != 0)
+    {
+        printf("[error]cpnv_NvroRestore set NVRO_BACKED_UP\n");
+        return CPNV_ERROR;
+    }
+    return CPNV_OK;
+
+out_err:
+    nvrofs2_umount();
+
+    return CPNV_ERROR;
+}
diff --git a/ap/lib/libcpnv/zxicbasic_api.h b/ap/lib/libcpnv/zxicbasic_api.h
new file mode 100755
index 0000000..60b6824
--- /dev/null
+++ b/ap/lib/libcpnv/zxicbasic_api.h
@@ -0,0 +1,13 @@
+
+#ifndef __ZXICBASIC_API_H
+#define __ZXICBASIC_API_H
+
+extern ssize_t  safe_read(int fd, void *buf, size_t count);
+extern ssize_t  full_read(int fd, void *buf, size_t len);
+extern ssize_t  read_close(int fd, void *buf, size_t size);
+extern ssize_t  open_read_close(const char *filename, void *buf, size_t size);
+extern ssize_t  safe_write(int fd, const void *buf, size_t count);
+extern ssize_t  full_write(int fd, const void *buf, size_t len);
+extern ssize_t  open_write_close(const char *filename, void *buf, size_t size);
+
+#endif
\ No newline at end of file