//文件拼接,长度添加和文件扩充工具fattach源码fattach.c -- gliethttp_20080602
//gcc -o fattach fattach.c;strip -s fattach
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#define GLIETHTTP_DEBUG
#undef GLIETHTTP_DEBUG
#define mode_insert 1
#define mode_replace 2
#define mode_pad 3
#define mode_fill 4
typedef struct _inode
{
char *name;
int append;
int append_pos;
int fill;
char fill_char;
int fill_len;
struct _inode *next;
}inode;
inode *new_inode(void)
{
inode *pinode;
pinode = (inode *)malloc(sizeof(*pinode));
memset(pinode, 0, sizeof(*pinode));
return pinode;
}
void free_inode(inode *head)
{
inode *tmp;
do
{
tmp = head->next;
free(head);
head = tmp;
}while(head);
}
#define help_string \
"\
fcat out_name a.bin -a b.bin -r0x10 c.bin -i0x80 d.bin -p0x00_0x10000 e.bin -p0xff_0x10000 f.bin -f0x00_0x1000 g.bin -f0xff_f0x1000 k.bin <-e>\n \
1.将长度插入到文件头\n\
fattach out.bin -a input.bin\n\
2.将长度插入到文件的指定位置,比如第16字节偏移处\n\
fattach out.bin -i0x10 input.bin或者\n\
fattach out.bin -i16 input.bin\n\
3.将长度填入文件的指定位置,比如第8字节偏移处\n\
fattach out.bin -r0x8 input.bin或者\n\
fattach out.bin -r8 input.bin\n\
4.将文件扩大到指定大小,中间填充执行字符,比如将100字节的文件扩大到1M,中间填充0xaa\n\
fattach out.bin -f0xaa_0x100000 input.bin或者\n\
fattach out.bin -f0xaa_1048576 input.bin\n\
5.扩充之后将长度添加到文件结尾,比如将158字节的文件扩大到1k,中间填充0xff,然后将长度加到结尾\n\
fattach out.bin -p0xff_0x1000 input.bin或者\n\
fattach out.bin -p0xff_1024 input.bin\n\
6.将多个文件拼接在一起,第一个文件的长度放在0x10偏移处,第2..以后的文件长度放在文件头部,最后以0xffffffff长度为文件链结尾标志\n\
比如:obm.bin blob.bin gzip_bitmap1.gz gzip_bitmap2.gz gzip_bitmap3.gz gzip_bitmap4.gz几个文件拼接起来\n\
fattach out.bin -r0x10 obm.bin -a blob.bin -a gzip_bitmap1.gz -a gzip_bitmap2.gz -a gzip_bitmap3.gz -a gzip_bitmap4.gz -e\n\
"
void print_help(void)
{
printf(help_string);
}
int do_write(int handle, void *buf, int len)
{
if( write(handle, buf, len) != len )
{
printf("Error:the counts of writing not the same with expected\n");
return -1;
}
return 0;
}
static int no_end = 1;
int main(int argc, char *argv[])
{
inode *pinode,*head;
int file_handle;
int out_handle;
struct stat sbuf;
char *mmap_buf_file;
if(argc > 1)
{
int i;
char *name;
if(argc < 3)
{
name = argv[1];
if(name[0] == '-')
{
switch(name[1])
{
case 'v':
case 'V':
printf("%s %s \n", __DATE__, __TIME__);
goto EXIT_OK;
}
}
print_help();
goto EXIT_OK;
}
head = pinode = new_inode();
for(i = 1;i < argc;i++)
{
name = argv[i];
if(name[0] == '-')
{
switch(name[1])
{
case 'a':
case 'A':
pinode->append = mode_insert;
pinode->append_pos = 0;
continue;
case 'i':
case 'I':
if(pinode->append == 0)pinode->append = mode_insert;
case 'r':
case 'R':
if(pinode->append == 0)pinode->append = mode_replace;
pinode->append_pos = strtol(&name[2],NULL,0);
#if 0
if( (errno == ERANGE) || (errno == EINVAL) )
{
printf("Error %s : %s \n", name, strerror(errno));
goto EXIT_OK1;
}
#endif
continue;
case 'p':
case 'P':
if(pinode->fill == 0)pinode->fill = mode_pad;
case 'f':
case 'F':
if(pinode->fill == 0)pinode->fill = mode_fill;
char tmp[5];
char *src,*dst;
int i;
src = &name[2];
dst = tmp;
for(i = 0;i < 4;i++)
*dst++ = *src++;
*dst = 0;
pinode->fill_char = strtol(tmp,NULL,0);
pinode->fill_len = strtol(&name[7],NULL,0);//-p0xa5_0x1000
continue;
case 'e':
case 'E':
no_end = 0;
continue;
}
}
pinode->name = name;
pinode->next = new_inode();
pinode = pinode->next;
}
if(head->append || head->fill)
{
printf("Error:not find output name\n");
print_help();
goto EXIT_OK1;
}
for(pinode = head->next;pinode->name;pinode = pinode->next)
{
if(strcmp(head->name, pinode->name) == 0)
{
printf("Error:%s : output name should not be the same with input file !\n", head->name);
print_help();
goto EXIT_OK1;
}
#ifdef GLIETHTTP_DEBUG
printf("#%s : %s\n", pinode->append? "true ":"false", pinode->name);
#endif
file_handle = open(pinode->name, O_RDONLY);
if(file_handle < 0)
{
printf("Error:could not open %s : %s\n", pinode->name, strerror(errno));
goto EXIT_OK1;
}
close(file_handle);
}
out_handle = open(head->name, O_RDWR|O_CREAT|O_TRUNC, 0666);
if(out_handle < 0)
{
printf("Error:could not create file : %s : %s \n", head->name, strerror(errno));
goto EXIT_OK1;
}
for(pinode = head->next;pinode->name;pinode = pinode->next)
{
file_handle = open(pinode->name, O_RDONLY);
if (fstat(file_handle, &sbuf) < 0)
{
printf("Error:could not stat %s : %s \n", pinode->name, strerror(errno));
goto EXIT_OK2;
}
mmap_buf_file = (char *)mmap(0, sbuf.st_size,PROT_READ, MAP_SHARED, file_handle, 0);
if(mmap_buf_file == (char*)MAP_FAILED)
{
close(file_handle);
printf("Error:could not mmap %s : %s\n", pinode->name, strerror(errno));
goto EXIT_OK2;
}
if(pinode->append)
{
#ifdef GLIETHTTP_DEBUG
printf("append_pos = %d\n", pinode->append_pos);
#endif
if( (pinode->append_pos > sbuf.st_size) )
{
printf("Error:-m%d outof file size %d\n", pinode->append_pos, sbuf.st_size);
goto EXIT_OK3;
}
if( do_write(out_handle, mmap_buf_file, pinode->append_pos) )
{
goto EXIT_OK3;
}
if( do_write(out_handle, &sbuf.st_size, sizeof(sbuf.st_size)) )
{
goto EXIT_OK3;
}
if(pinode->append == mode_insert)
{
//if( (pinode->append_pos + sizeof(sbuf.st_size) ) < sbuf.st_size )
{
if( do_write(out_handle,
&mmap_buf_file[pinode->append_pos],
sbuf.st_size - pinode->append_pos
)
)
{
goto EXIT_OK3;
}
}
}
else
{
if( (pinode->append_pos + sizeof(sbuf.st_size) ) < sbuf.st_size )
{
if( do_write(out_handle,
&mmap_buf_file[pinode->append_pos] + sizeof(sbuf.st_size),
sbuf.st_size - pinode->append_pos - sizeof(sbuf.st_size)
)
)
{
goto EXIT_OK3;
}
}
}
}
else
if( do_write(out_handle, mmap_buf_file, sbuf.st_size) )
{
goto EXIT_OK3;
}
if(pinode->fill)
{
char *malloc_buf;
int malloc_len;
if(pinode->fill_len > sbuf.st_size)
{
malloc_len = pinode->fill_len - sbuf.st_size;
if(pinode->fill == mode_pad)malloc_len -= sizeof(sbuf.st_size);
malloc_buf = malloc(malloc_len);
memset(malloc_buf, pinode->fill_char, malloc_len);
if( do_write(out_handle, malloc_buf, malloc_len) )
{
free(malloc_buf);
goto EXIT_OK3;
}
free(malloc_buf);
}
if(pinode->fill == mode_pad)
{
//将长度追加到文件尾[gliethttp_20080602]
if( do_write(out_handle, &sbuf.st_size, sizeof(sbuf.st_size)) )
{
goto EXIT_OK3;
}
}
}
munmap((void *)mmap_buf_file, sbuf.st_size);
close(file_handle);
}
//最后追加0xffffffff作为长度域用来标识重复文件链的结尾
if(no_end == 0)
{
long tmp_len = 0xffffffff;
if ( write(out_handle, &tmp_len, sizeof(tmp_len)) != sizeof(tmp_len) )
{
printf("Error:the counts of writing not the same with expected\n");
goto EXIT_OK2;
}
}
close(out_handle);
goto EXIT_OK1;
}
print_help();
goto EXIT_OK;
EXIT_OK3:
munmap((void *)mmap_buf_file, sbuf.st_size);
EXIT_OK2:
close(file_handle);
close(out_handle);
remove(head->name);
EXIT_OK1:
free_inode(head);
EXIT_OK:
return 0;
}
|