This is probably a simplification of what I would do. I haven't tested the code or anything so there might be errors. There should obviously be error checking added as well and non-hardcoded filenames:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
unsigned int filesize(int fd)
{
struct stat st;
fstat(fd, &st);
return st.st_size;
}
int main(void)
{
struct fileinfo
{
char *name;
unsigned int size;
};
struct fileinfo sourcefiles[] = { { "file1.bin", 0 }, { "file2.bin", 0 } };
int numfiles = 2;
int fdin, fdout;
char buffer[BUFSIZ];
int bytesread;
int i;
fdout = open("archive.blah", O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR);
// Reserve space for the header
int headerlen = sizeof(short);
for(i = 0;i < numfiles;++i)
headerlen += 1 + strlen(sourcefiles[i].name) + sizeof(unsigned int);
lseek(fdout, headerlen, SEEK_SET);
// Write the contents of the files
for(i = 0;i < numfiles;++i)
{
fdin = open(sourcefiles[i].name, O_RDONLY);
sourcefiles[i].size = filesize(fdin);
while((bytesread = read(fdin, buffer, sizeof(buffer))) > 0)
write(fdout, buffer, bytesread);
close(fdin);
}
// Go back and write the header
lseek(fdout, 0, SEEK_SET);
write(fdout, (short*)&numfiles, sizeof(short));
for(i = 0;i < numfiles;++i)
{
unsigned char namelen = (unsigned char)strlen(sourcefiles[i].name);
write(fdout, &namelen, 1);
write(fdout, sourcefiles[i].name, namelen);
write(fdout, &sourcefiles[i].size, sizeof(unsigned int));
}
close(fdout);
return 0;
}
There's some endian issues to work out, but you get the idea at least.