You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
295 lines
9.6 KiB
295 lines
9.6 KiB
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <time.h>
|
|
#include "updater/sparse.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
#define EMMC_BLKSIZE_SHIFT (9)
|
|
#define SZ_1M_SHIFT (20)
|
|
#define BUFFER_SIZE (32*1024)
|
|
#define DEBUG_FOR_SPARESE_EXT4 (0)
|
|
|
|
#define DEBUG_PRINTF_EXT4INFO (1)
|
|
|
|
static const int CHUNK_TYPE_FILL_SHIFT = 4;
|
|
|
|
/******************************************************************************/
|
|
static void print_header_info(sparse_header_t *header)
|
|
{
|
|
#if DEBUG_PRINTF_EXT4INFO
|
|
fprintf(stderr, "sparse header info:\n");
|
|
fprintf(stderr, " magic: 0x%x\n",header->magic);
|
|
fprintf(stderr, " major_version: 0x%x\n",header->major_version);
|
|
fprintf(stderr, " minor_version: 0x%x\n",header->minor_version);
|
|
fprintf(stderr, " file_hdr_sz: %d\n",header->file_hdr_sz);
|
|
fprintf(stderr, " chunk_hdr_sz: %d\n",header->chunk_hdr_sz);
|
|
fprintf(stderr, " blk_sz: %d\n",header->blk_sz);
|
|
fprintf(stderr, " total_blks: %d\n",header->total_blks);
|
|
fprintf(stderr, " total_chunks: %d\n",header->total_chunks);
|
|
fprintf(stderr, " image_checksum: %d\n",header->image_checksum);
|
|
#endif
|
|
}
|
|
|
|
/******************************************************************************/
|
|
static void print_chunk_info(chunk_header_t *chunk)
|
|
{
|
|
#if DEBUG_PRINTF_EXT4INFO
|
|
fprintf(stderr, "chunk header info:\n");
|
|
fprintf(stderr, " chunk_type: 0x%x\n",chunk->chunk_type);
|
|
fprintf(stderr, " chunk_sz: %d\n",chunk->chunk_sz);
|
|
fprintf(stderr, " total_sz: %d\n",chunk->total_sz);
|
|
#endif
|
|
}
|
|
|
|
int fseek_64(FILE *stream, int64_t offset, int origin) {
|
|
if (feof(stream)) {
|
|
rewind(stream);
|
|
} else {
|
|
setbuf(stream, NULL);
|
|
}
|
|
int fd = fileno(stream);
|
|
if (lseek64(fd, offset, origin) == -1) {
|
|
return errno;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int write_ext4sp(const char *filename,const char *partition) {
|
|
U32 i = 0;
|
|
//U32 num = 0;
|
|
U64 dense_len = 0;
|
|
U64 unsparse_len = 0;
|
|
U64 show_point = 0;
|
|
U64 show_point_after = 0;
|
|
//U64 img_size = 0;
|
|
U64 chunk_len = 0;
|
|
S64 temp_len = 0;
|
|
U64 img_offset = 0;
|
|
U64 ext4usp_offset = 0;
|
|
U32 count = 0;
|
|
chunk_header_t chunk;
|
|
sparse_header_t header;
|
|
int ret = -1;
|
|
uint32_t *fillBuf = NULL;
|
|
uint32_t fillVal = 0;
|
|
int j = 0;
|
|
|
|
char readbuf[32*1024];
|
|
size_t readsize,writesize;
|
|
|
|
FILE *fdata = fopen(filename,"rb");
|
|
if (fdata == NULL) {
|
|
fprintf(stderr,"Can't open %s:%s\n",filename,strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
FILE *fext4 = fopen(partition,"wb");
|
|
if (fext4 == NULL) {
|
|
fprintf(stderr,"Can't open %s:%s\n",partition,strerror(errno));
|
|
goto error;
|
|
}
|
|
|
|
img_offset = 0;
|
|
ext4usp_offset = 0;
|
|
|
|
readsize = fread(&header,1,sizeof(header),fdata);
|
|
if (readsize != sizeof(header)) {
|
|
fprintf(stderr, " sparse_header read fail: %d\n ",ferror(fdata));
|
|
goto error;
|
|
}
|
|
|
|
img_offset += header.file_hdr_sz; // just jump to the first chunk
|
|
|
|
print_header_info((sparse_header_t *)&header);
|
|
|
|
if (!IS_SPARSE(((sparse_header_t *)&header))) {
|
|
fprintf(stderr,"the %s is not sparse ext4 fs\n",filename);
|
|
goto error;
|
|
}
|
|
|
|
if (header.blk_sz & ((1 << EMMC_BLKSIZE_SHIFT) - 1)) {
|
|
fprintf(stderr,"image blk size %d is not aligned to 512Byte.\n",
|
|
header.blk_sz);
|
|
goto error;
|
|
}
|
|
|
|
dense_len = 0;
|
|
unsparse_len = 0;
|
|
|
|
for (i = 0; i < header.total_chunks ; i++) {
|
|
ret = fseek_64(fdata,img_offset,SEEK_SET);
|
|
if (ret != 0) {
|
|
printf("line is %d, ret is %d, %s\n",__LINE__,ret,strerror(errno));
|
|
goto error;
|
|
}
|
|
readsize = fread(&chunk,1,sizeof(chunk),fdata);
|
|
if (readsize != sizeof(chunk)) {
|
|
fprintf(stderr, " chunk_header read fail: %d\n ",ferror(fdata));
|
|
goto error;
|
|
}
|
|
img_offset += header.chunk_hdr_sz; // just jump to chunk_data or the next chunk header if the chunk is don't care
|
|
print_chunk_info((chunk_header_t *)&chunk);
|
|
|
|
switch (chunk.chunk_type) {
|
|
case CHUNK_TYPE_RAW:
|
|
chunk_len = chunk.chunk_sz * header.blk_sz;
|
|
if (chunk.total_sz
|
|
!= (chunk_len + header.chunk_hdr_sz)) {
|
|
fprintf(stderr, "chunk.total_sz is not right\n");
|
|
print_chunk_info((chunk_header_t *)&chunk);
|
|
goto error;
|
|
}
|
|
|
|
|
|
temp_len = chunk_len;
|
|
while (temp_len > 0) {
|
|
count = temp_len;
|
|
if (count > BUFFER_SIZE) {
|
|
count = BUFFER_SIZE;
|
|
}
|
|
memset(readbuf,0x00,sizeof(readbuf));
|
|
ret = fseek_64(fdata,img_offset,SEEK_SET);
|
|
if (ret != 0) {
|
|
printf("line is %d,ret is %d, %s\n",__LINE__,ret,strerror(errno));
|
|
goto error;
|
|
}
|
|
readsize = fread(readbuf,1,count,fdata);
|
|
if (readsize != count) {
|
|
fprintf(stderr," read chunk_data failure at img_offset =0x%llx: %d\n",img_offset,ferror(fdata));
|
|
goto error;
|
|
}
|
|
writesize = fwrite(readbuf,1,count,fext4);
|
|
if (writesize != count) {
|
|
fprintf(stderr, "write chunk_data failure %d\n ",ferror(fext4));
|
|
goto error;
|
|
}
|
|
img_offset += count;
|
|
temp_len -= count;
|
|
ext4usp_offset += count;
|
|
unsparse_len += count;
|
|
dense_len += count;
|
|
|
|
show_point = (dense_len >> SZ_1M_SHIFT);
|
|
if ( show_point != show_point_after) {
|
|
fflush(fext4);
|
|
fsync(fileno(fext4));
|
|
show_point_after = show_point;
|
|
fprintf(stderr, ". ");
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case CHUNK_TYPE_DONT_CARE:
|
|
chunk_len = chunk.chunk_sz * header.blk_sz;
|
|
if (chunk.total_sz
|
|
!= header.chunk_hdr_sz) {
|
|
fprintf(stderr ,"chunk.total_sz is not right\n");
|
|
print_chunk_info((chunk_header_t *)&chunk);
|
|
goto error;
|
|
}
|
|
|
|
temp_len = chunk_len;
|
|
while (temp_len > 0) {
|
|
count = temp_len;
|
|
if (count > BUFFER_SIZE) {
|
|
count = BUFFER_SIZE;
|
|
}
|
|
#if DEBUG_FOR_SPARESE_EXT4
|
|
memset(readbuf,0x00,sizeof(readbuf));
|
|
writesize = fwrite(readbuf,1,count,fext4);
|
|
if (writesize != count) {
|
|
fprintf(stderr, "write chunk_data failure %d\n ",ferror(fext4));
|
|
goto error;
|
|
}
|
|
#else
|
|
ret = fseek_64(fext4,count,SEEK_CUR);
|
|
if (ret != 0) {
|
|
fprintf(stderr, "\nunspare_len=0x%llx,ext4usp_offset=0x%llx\n",unsparse_len,ext4usp_offset);
|
|
printf("line is %d, ret is %d, %s\n",__LINE__,ret,strerror(errno));
|
|
goto error;
|
|
}
|
|
#endif
|
|
temp_len -= count;
|
|
ext4usp_offset += count;
|
|
}
|
|
|
|
#if DEBUG_PRINTF_EXT4INFO
|
|
fprintf(stderr, "\nunspare_len=0x%llx,ext4usp_offset=0x%llx\n",unsparse_len,ext4usp_offset);
|
|
#endif
|
|
|
|
unsparse_len += chunk_len;
|
|
|
|
break;
|
|
case CHUNK_TYPE_FILL:
|
|
chunk_len = chunk.chunk_sz * header.blk_sz;
|
|
if (chunk.total_sz
|
|
!= sizeof(uint32_t) + header.chunk_hdr_sz) {
|
|
fprintf(stderr ,"chunk.total_sz is not right\n");
|
|
print_chunk_info((chunk_header_t *)&chunk);
|
|
goto error;
|
|
}
|
|
|
|
fillBuf = (uint32_t *)malloc(header.blk_sz);
|
|
if (!fillBuf) {
|
|
printf("Malloc failed for: CHUNK_TYPE_FILL.\n");
|
|
goto error;
|
|
}
|
|
|
|
ret = fseek_64(fdata,img_offset,SEEK_SET);
|
|
if (ret != 0) {
|
|
printf("line is %d,ret is %d, %s\n",__LINE__,ret,strerror(errno));
|
|
goto error;
|
|
}
|
|
readsize = fread(&fillVal,sizeof(fillVal),1,fdata);
|
|
if (readsize != 1) {
|
|
fprintf(stderr," read chunk_fill_data failure at img_offset =0x%llx: %d\n",img_offset,ferror(fdata));
|
|
goto error;
|
|
}
|
|
for (j = 0; j < (header.blk_sz / sizeof(fillVal)); j++) {
|
|
fillBuf[j] = fillVal;
|
|
}
|
|
|
|
for (j = 0; j < chunk.chunk_sz; j++) {
|
|
writesize = fwrite(fillBuf,sizeof(fillVal),header.blk_sz / sizeof(fillVal),fext4);
|
|
if (writesize != header.blk_sz / sizeof(fillVal)) {
|
|
fprintf(stderr, "write chunk_fill_data failure %d\n ",ferror(fext4));
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
ext4usp_offset += chunk_len;
|
|
unsparse_len += chunk_len;
|
|
img_offset = img_offset + CHUNK_TYPE_FILL_SHIFT;
|
|
free(fillBuf);
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
fclose(fdata);
|
|
fflush(fext4);
|
|
fsync(fileno(fext4));
|
|
fclose(fext4);
|
|
fprintf(stderr, "\ndense_len= 0x%llx:%lldMB, unsparse_len =0x%llx:%lldMB\n",dense_len,dense_len >> SZ_1M_SHIFT,unsparse_len,(unsparse_len >> SZ_1M_SHIFT));
|
|
|
|
return 0;
|
|
error:
|
|
fclose(fdata);
|
|
fclose(fext4);
|
|
return -1;
|
|
}
|