/* * ===================================================================================== * * Filename: szbtool.c * * Description: 联想手机szb格式的制作工具,部分开源代码(仅提供程序思想); * * Version: 1.0 * Created: 2013年03月25日 01时46分16秒 * Revision: none * Compiler: gcc * * Author: linkscue (scue), * Organization: * * ===================================================================================== */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <time.h> extern char *optarg; extern int optind; extern int opterr; extern int optopt; #define u8 unsigned char #define u32 unsigned int #define u16 unsigned short #define INFOSIZE 256 #define BUFFER_SIZE 1024 typedef struct { /* * 保密信息:szb文件0~12字节 * */ }szb_header_t; typedef struct { /* * 保密信息:szb文件12~256字节 */ }szb_head_t; typedef struct { /* * 保密信息:szb文件的结构体 */ }szb_info; typedef struct{ /* *保密信息:存放image信息的结构体 * */ }szb_images_t; /*获取文件长度*/ long getSize( FILE *fp ) { long int save_pos; /* 保存当前文件指针 */ long size_of_file; /* 保存文件的大小 */ save_pos = ftell( fp ); /* 暂存当前文件指针位置 */ fseek( fp, 0L, SEEK_END ); /* 从文件开始位置移动至文件结尾 */ size_of_file = ftell( fp ); /* 获取文件指针位置 */ fseek( fp, save_pos, SEEK_SET ); /* 还原之前的文件指针位置 */ return( size_of_file ); /* 返回文件大小数值 */ } unsigned int getSzbSum(char *file){ /* *保密信息:获取szb文件校验码 * */ return sum; } /*计算一个文件的CRC校验*/ unsigned int getSum(FILE *fp) { /* *保密信息:获取image文件校验码 * */ return sum; /* 这里的检验和的值是正确的 */ } /* 分解szb函数 */ void splitFile(char *file){ FILE *fd = NULL; FILE *ft = NULL; int i; get_szb_info(file); /* 显示szb文件信息 */ if ( (fd=fopen(file,"rb")) == NULL ) { /* 打开文件进行操作 */ printf ( "Extract szb file, open %s failure!\n", file ); exit(1); } fseek( fd, 0, SEEK_SET ); /* 重新定向文件指针位置 */ u32 imagecount = 0; fseek( fd, 84, SEEK_SET ); /* 略过前边的84字节 */ fscanf( fd,"%4c", &imagecount ); /* 获取镜像文件个数 */ fseek( fd, 168, SEEK_CUR ); /* 总共略过前边的256字节的Header信息 */ szb_images_t images[10]; memset(images,0x00,sizeof(images)); for ( i=0; i < imagecount ; i++ ){ fscanf(fd,"%64c",&images[i].filename); /* 获取得文件名称 */ fscanf(fd,"%32c",&images[i].partname); fscanf(fd,"%4c",&images[i].checksum); fscanf(fd,"%4c",&images[i].timestamp); fscanf(fd,"%4c",&images[i].imageoffset); /* 获取偏移位置 */ fscanf(fd,"%4c",&images[i].imagesize); /* 获取镜像文件的大小 */ fscanf(fd,"%4c",&images[i].eraseflag); fscanf(fd,"%4c",&images[i].writeflag); fscanf(fd,"%136c",&images[i].reserve); } //开始分解数据; int size,n,offset,fp_local,end; unsigned char imagename[32]=""; unsigned char buffer[BUFFER_SIZE]; /* 创建缓冲区 */ strncpy(buffer,"",sizeof(buffer)); /* 清空缓冲区内容 */ for( i=0; i < imagecount ; i++ ){ strncpy(imagename, images[i].filename, sizeof(imagename)); offset=images[i].imageoffset; size=images[i].imagesize; end=(offset+size); if ( size != 0 ) { if ( ( ft=fopen(imagename,"wb") ) == NULL ){ printf("Extract szb file, open %s failure!\n",imagename); } fseek( fd, offset, SEEK_SET); /* 跳转至数据段 */ printf("Extract %s..\n",imagename); while ( fp_local != end ) { n = fread(buffer,1, sizeof(buffer), fd); fwrite(buffer, n, 1, ft); fp_local=ftell(fd); } } } fclose(fd); printf("Extract szb file done!\n"); } /* 在尾部追加二进制文件(cat a >> b) */ void appendFile(char *fp, char *body) { int n=0; FILE *in,*out; u8 buffer[BUFFER_SIZE]; if ( (in = fopen(fp, "rb")) == NULL){ printf ( "Open in file failure!\n" ); exit(1); } if ( (out=fopen( body , "ab")) == NULL ){ printf ( "Open out file failure!\n" ); exit(1); } while (!feof(in)) { n = fread(buffer, 1, BUFFER_SIZE, in); fwrite(buffer, 1, n, out); } fclose(in); fclose(out); } /* 复制一个文件至另一个文件位置 */ //void copyFile(char *from, char *to){ // FILE * outfile, *infile; // infile = fopen(from, "rb"); // outfile = fopen(to, "wb" ); // unsigned char buf[BUFFER_SIZE]; // if( outfile == NULL || infile == NULL ) // { // printf("Copy file failure!"); // exit(1); // } // int rc; // while( (rc = fread(buf,sizeof(unsigned char), BUFFER_SIZE ,infile)) != 0 ) // { // fwrite( buf, sizeof( unsigned char ), rc, outfile ); // } //// sleep(0.1); // fclose(infile); // fclose(outfile); //} /* 合并两个文件至一个文件 (cat a b > c) */ //void mergeFile(char *fp1,char *fp2,char *name){ // FILE *fd1,*fd2,*fp3; // unsigned char buf[BUFFER_SIZE]; // char filename[100]; // strncpy(filename,name,sizeof(filename)); // int rc1,rc2; // fd1 = fopen(fp1,"rb"); // fd2 = fopen(fp2,"rb"); // fp3 = fopen(filename, "wb" ); // while( (rc1 = fread(buf,sizeof(unsigned char), BUFFER_SIZE,fd1)) != 0 ) // { // fwrite( buf, sizeof( unsigned char ), rc1, fp3 ); // } // while( (rc2 = fread(buf,sizeof(unsigned char), BUFFER_SIZE,fd2)) != 0 ) // { // fwrite( buf, sizeof( unsigned char ), rc2, fp3 ); // } // sleep(0.1); // fclose(fd1); // fclose(fd2); // fclose(fp3); //} /* appendImage(szb文件, image文件,文件名称,分区位置,偏移量,索引位置) */ u32 appendImage(char *szb, char *file, char *filename, char *partname, u32 offset, int index){ FILE *fp,*fb; if((fp=fopen(file,"rb")) == NULL){ printf ( "Open %s failure!\n",filename ); exit(1); } szb_images_t image; strncpy(image.filename, filename, sizeof(image.filename)); strncpy(image.partname, partname, sizeof(image.partname)); strncpy(image.reserve, "", sizeof(image.reserve)); time(&image.timestamp); image.imageoffset=offset; image.imagesize=getSize(fp); image.checksum=getSum(fp); image.eraseflag=1; image.writeflag=1; fclose(fp); printf("Adding: %-12sOffset: 0x%08x Checksum: 0x%08x\n",image.partname, image.imageoffset, image.checksum); if ( (fb=fopen(szb, "rb+")) == NULL) { printf(" append %s to szb file, open szb file failure!\n", file); exit(1); } fseek( fb, ( index * INFOSIZE ), SEEK_SET ); /* 移动文件指针的位置 */ fwrite(&image.filename, sizeof(image.filename), 1, fb); /* 向szb文件写入Image的相关信息 */ fwrite(&image.partname, sizeof(image.partname), 1, fb); /* 向szb文件写入Image的相关信息 */ fwrite(&image.checksum, sizeof(image.checksum), 1, fb); /* 向szb文件写入Image的相关信息 */ fwrite(&image.timestamp, sizeof(image.timestamp), 1, fb); /* 向szb文件写入Image的相关信息 */ fwrite(&image.imageoffset, sizeof(image.imageoffset), 1, fb); /* 向szb文件写入Image的相关信息 */ fwrite(&image.imagesize, sizeof(image.imagesize), 1, fb); /* 向szb文件写入Image的相关信息 */ fwrite(&image.eraseflag, sizeof(image.eraseflag), 1, fb); /* 向szb文件写入Image的相关信息 */ fwrite(&image.writeflag, sizeof(image.writeflag), 1, fb); /* 向szb文件写入Image的相关信息 */ fwrite(&image.reserve, sizeof(image.reserve), 1, fb); /* 向szb文件写入Image的相关信息 */ fclose(fb); /* 向szb文件写完Image信息后关闭 */ appendFile(file, szb); /* 向szb文件的尾部添加image数据 */ return (image.imagesize+image.imageoffset); /* 返回一个偏移数据,方便之后的判断 */ } void get_szb_info(char *file){ FILE *fp; int i,count; szb_info info; if ( (fp=fopen(file, "rb")) == NULL ) { /* code */ } fscanf(fp,"%8c",&info.magic); /* *保密信息: 获取szb头部信息 * */ fscanf(fp,"%136c",&info.reserve); u8 magic[]="LmSzBfMt"; if ( strstr(info.magic,magic) == NULL ){ printf ( "This file not in szb format, abort!\n" ); exit(1); } struct tm *ptr; /* 格式化时间输出 */ time_t lt; unsigned int times=info.timestamp; char str[80]; lt=times; ptr=localtime(<); strftime(str,100,"%F%X",ptr); printf ( "\n" ); printf ( "Header:\n" ); printf ( "Checksum:\t0x%08x\n",info.checksum ); printf ( "Size:\t\t0x%08x\n",info.filesize ); printf ( "Author:\t\t%s\n",info.author ); printf ( "Version:\t%s\n",info.version ); printf ( "Times:\t\t%s\n",str ); printf ( "Counts:\t\t0x%x\n",info.imagecount ); count=info.imagecount; szb_images_t images[10]; printf ( "\n" ); printf ( "Images:\n" ); for ( i=0; i < info.imagecount ; i++ ){ fscanf(fp,"%64c",&images[i].filename); fscanf(fp,"%32c",&images[i].partname); fscanf(fp,"%4c",&images[i].checksum); fscanf(fp,"%4c",&images[i].timestamp); fscanf(fp,"%4c",&images[i].imageoffset); fscanf(fp,"%4c",&images[i].imagesize); fscanf(fp,"%4c",&images[i].eraseflag); fscanf(fp,"%4c",&images[i].writeflag); fscanf(fp,"%136c",&images[i].reserve); if ( strlen(images[i].filename) != 0 ){ printf ( "Position: %-10sOffset: 0x%08x Checksum: 0x%08x\n",images[i].partname, images[i].imageoffset, images[i].checksum );} else{ printf ( "Earse: %-10sCaution!\n",images[i].partname); } } printf ( "\n" ); fclose(fp); } /* 显示szbtool作者信息 */ void author_info(){ printf ( "\n" ); printf ( "===============================================================\n" ); printf ( " Welcome to use Lenovo K860/K860i szbtool! \n" ); printf ( "\n" ); printf ( " -- version: 0.14 \n" ); printf ( " -- author: linkscue \n" ); printf ( "===============================================================\n" ); } /* 显示使用帮助 */ void usage(){ printf ( "\n" ); printf ( "---------------------------------------------------------------\n" ); printf ( "usage:\n" ); printf ( "szbtool -b uboot # add uboot.bin\n" ); printf ( "szbtool -k boot # add boot.img\n" ); printf ( "szbtool -r recovery # add recovery.img\n" ); printf ( "szbtool -s system # add system.img\n" ); printf ( "szbtool -c cpimage # add cpimage.img\n" ); printf ( "szbtool -p preload # add preload.img\n" ); printf ( "szbtool -d userdata # add userdata.img\n" ); printf ( "szbtool -e erase # erase data & cache space\n" ); printf ( "szbtool -a author # specify author\n" ); printf ( "szbtool -v version # specify version\n" ); printf ( "szbtool -i szb # szb information\n" ); printf ( "szbtool -x szb # extract szb \n" ); printf ( "szbtool -h # help\n" ); printf ( "---------------------------------------------------------------\n" ); printf ( "e.g. szbtool -k boot.img -s system.img -a scue@Link -v Link.szb\n" ); printf ( "\n" ); } /*主函数*/ int main ( int argc, char *argv[] ) { FILE *fp,*fp1,*fp2,*fd1,*fd2,*sub_image; char *file=NULL; u8 magic[8]; u8 imagename[64]; u8 partname[32]; u8 version[32]; u8 author[32]; u32 filesize; u32 offset=8192; /* 初始的偏移量 */ char opt; /* 获取输入的选项 */ int index=0; /* 判断szb中的分区索引数量 */ int DO_NOTHING=0; /* 依据此变量判断是否执行 */ int ERASE_DATA=0; /* 依据此变量判断是否擦除数据 */ //清空变量 memset(version,0x00,sizeof(version)); memset(imagename,0x00,sizeof(imagename)); memset(partname,0x00,sizeof(partname)); strncpy(author,"scue@Link",sizeof(author)); //显示作者信息 author_info(); //检测输入参数 if(argc == 1) { usage(); /* 显示使用手册 */ exit(0); } //判断选项中是否有版本 int i; char tmp1[32]=""; char tmp2[32]=""; strncpy(tmp2,"-v",sizeof(tmp2)); for (i = 0; i < argc; i++) { strncpy(tmp1,argv[i],sizeof(tmp1)); if ( strcmp(tmp1,tmp2) == 0 ) { strncpy(version,argv[i+1],sizeof(version)); } if ( strcmp(tmp1,"-x") == 0 || strcmp(tmp1,"-i")==0 ) { DO_NOTHING = 1; } } if ( strlen(version) == 0 && DO_NOTHING !=1 ){ printf ( "\n" ); printf ( "Please use -v to specify a version name!\n" ); usage(); exit(1); } if (DO_NOTHING != 1) { /* 当发现有事可做的时候... */ //创建文件 remove(version); /* delete the old szb file */ if ( (fp=fopen(version,"wb+")) == NULL ) { printf ( "Create version file %s failure!\n",version); exit(1); } u8 header_buffer[INFOSIZE*32]; strncpy(header_buffer, "LmSzBfMt", sizeof(header_buffer)); fwrite(header_buffer, sizeof(header_buffer) , 1, fp); /* 向其中写8192字节后退出 */ index++; fclose(fp); } //开始获取选项信息 opterr=0; /* 不显示错误的选项信息 */ while ((opt = getopt(argc, argv, "b:k:r:s:c:p:d:x:i:v:a:e")) != -1) switch (opt) { case 'v': strncpy(version,optarg,sizeof(version)); break; case 'b': file=optarg; strncpy(partname,"bootloader",sizeof(partname)); strncpy(imagename,"uboot.bin",sizeof(imagename)); offset=appendImage(version, file, imagename, partname, offset, index); index++; break; case 'k': file=optarg; strncpy(partname,"boot",sizeof(partname)); strncpy(imagename,"boot.img",sizeof(imagename)); offset=appendImage(version, file, imagename, partname, offset, index); index++; break; case 'r': file=optarg; strncpy(partname,"recovery",sizeof(partname)); strncpy(imagename,"recovery.img",sizeof(imagename)); offset=appendImage(version, file, imagename, partname, offset, index); index++; break; case 's': file=optarg; strncpy(partname,"system",sizeof(partname)); strncpy(imagename,"system.img",sizeof(imagename)); offset=appendImage(version, file, imagename, partname, offset, index); index++; break; case 'c': file=optarg; strncpy(partname,"cpimage",sizeof(partname)); strncpy(imagename,"cpimage.img",sizeof(imagename)); offset=appendImage(version, file, imagename, partname, offset, index); index++; break; case 'p': file=optarg; strncpy(partname,"preload",sizeof(partname)); strncpy(imagename,"preload.img",sizeof(imagename)); offset=appendImage(version, file, imagename, partname, offset, index); index++; break; case 'd': file=optarg; strncpy(partname,"userdata",sizeof(partname)); strncpy(imagename,"userdata.img",sizeof(imagename)); offset=appendImage(version, file, imagename, partname, offset, index); index++; break; case 'e': ERASE_DATA=1; break; case 'a': strncpy(author,optarg,sizeof(author)); break; case 'x': DO_NOTHING=1; file=optarg; splitFile(file); break; case 'i': DO_NOTHING=1; file=optarg; get_szb_info(file); break; default: DO_NOTHING=1; usage(); } argv += optind; //开始执行制作szb文件 if ( DO_NOTHING != 1 ){ //检查是否输入格式名 if ( strlen(version) == 0 ){ DO_NOTHING = 1; printf ( "\n" ); printf ( "Please use -v to specify a version name!\n" ); usage(); exit(1); } // 双清功能 if ( ERASE_DATA == 1) { /* 判断是否有“双清功能” */ u8 erase_data[32]; u8 erase_cache[32]; strncpy(erase_data, "userdata", sizeof(erase_data)); strncpy(erase_cache, "cache", sizeof(erase_data)); if ( (fp=fopen(version, "rb+")) == NULL ) { printf("Add erase features, open file %s failure!\n", version); exit(1); } fseek( fp, (INFOSIZE * index + 64 ), SEEK_SET ); /* erase userdata */ fwrite(erase_data, sizeof(erase_data), 1, fp); index++; fseek( fp, (INFOSIZE * index + 64 ), SEEK_SET ); /* erase cache */ fwrite(erase_cache, sizeof(erase_cache), 1, fp); index++; fclose(fp); } //制作SZB格式文件头部(256-12)部分 szb_head_t head; if ( (fp=fopen(version,"rb+")) ==NULL ){ printf("Calculate file size, open file %s failure!\n", version); exit(1); } head.filesize=getSize(fp); /* get szb file size */ /* * 保密信息:向szb文件写入数据 * */ time(&head.timestamp); /* 写入时间信息 */ /* * 保密信息:向szb文件写入数据 * */ fseek( fp, 12, SEEK_SET ); fwrite(&head,sizeof(szb_head_t),1,fp); /* 写入256-12字节部分 */ fclose(fp); u32 szb_checksum; szb_checksum=getSzbSum(version); if ( (fp=fopen(version,"rb+")) ==NULL ){ printf("Calculate file size, open file %s failure!\n", version); exit(1); } fseek(fp, 8, SEEK_SET); fwrite(&szb_checksum,sizeof(szb_checksum),1,fp); /* 写入总的验证码字节部分 */ fclose(fp); get_szb_info(version); printf ( ">> Congratulations! The Official ROM %s done!\n",version); printf ( "\n" ); } return 0; }