mirror of
https://gitlab.com/bztsrc/bootboot.git
synced 2023-02-13 20:54:32 -05:00
337 lines
12 KiB
C
337 lines
12 KiB
C
/*
|
|
* mkbootimg/fsZ.c
|
|
*
|
|
* Copyright (C) 2017 - 2020 bzt (bztsrc@gitlab)
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use, copy,
|
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
* of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* This file is part of the BOOTBOOT Protocol package.
|
|
* @brief FS/Z file system driver
|
|
*
|
|
*/
|
|
#include "main.h"
|
|
#include "fsZ.h"
|
|
|
|
int fsz_secsize = FSZ_SECSIZE, fsz_isinitrd = 0;
|
|
unsigned char fsz_emptysec[FSZ_SECSIZE] = {0};
|
|
|
|
/* private functions */
|
|
static int fsz_direntcmp(const void *a, const void *b)
|
|
{
|
|
return strcmp((char *)((FSZ_DirEnt *)a)->name,(char *)((FSZ_DirEnt *)b)->name);
|
|
}
|
|
|
|
int fsz_add_inode(char *filetype, char *mimetype)
|
|
{
|
|
unsigned int i,j=!strcmp(filetype,FSZ_FILETYPE_SYMLINK)||!strcmp(filetype,FSZ_FILETYPE_UNION)?fsz_secsize-1024:36;
|
|
FSZ_Inode *in;
|
|
FSZ_DirEntHeader *hdr;
|
|
fs_base=realloc(fs_base,fs_len+fsz_secsize);
|
|
if(!fs_base) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_MEM]); exit(1); }
|
|
memset(fs_base+fs_len,0,fsz_secsize);
|
|
in=(FSZ_Inode *)(fs_base+fs_len);
|
|
memcpy(in->magic,FSZ_IN_MAGIC,4);
|
|
memcpy((char*)&in->owner,"root",5);
|
|
in->owner.access=FSZ_READ|FSZ_WRITE|FSZ_DELETE|(filetype && (
|
|
!strcmp(filetype,FSZ_FILETYPE_DIR) || !strcmp(filetype,FSZ_FILETYPE_UNION))? FSZ_EXEC : 0);
|
|
if(filetype!=NULL){
|
|
i=strlen(filetype);
|
|
memcpy(in->filetype,filetype,i>4?4:i);
|
|
if(!strcmp(filetype,FSZ_FILETYPE_DIR)){
|
|
hdr=(FSZ_DirEntHeader *)(in->data.small.inlinedata);
|
|
in->sec=fs_len/fsz_secsize;
|
|
in->flags=FSZ_IN_FLAG_INLINE;
|
|
in->size=sizeof(FSZ_DirEntHeader);
|
|
memcpy(in->data.small.inlinedata,FSZ_DIR_MAGIC,4);
|
|
hdr->checksum=crc32_calc((unsigned char*)hdr+sizeof(FSZ_DirEntHeader),hdr->numentries*sizeof(FSZ_DirEnt));
|
|
}
|
|
}
|
|
if(mimetype!=NULL){
|
|
if(!strcmp(filetype,FSZ_FILETYPE_UNION)){
|
|
for(i=1;i<j && !(mimetype[i-1]==0 && mimetype[i]==0);i++);
|
|
i++;
|
|
} else {
|
|
i=strlen(mimetype);
|
|
}
|
|
memcpy(j==36?in->mimetype:in->data.small.inlinedata,mimetype,i>j?j:i);
|
|
if(j!=36)
|
|
in->size=i;
|
|
}
|
|
in->changedate=t * 1000000;
|
|
in->modifydate=t * 1000000;
|
|
in->checksum=crc32_calc(in->filetype,1016);
|
|
fs_len+=fsz_secsize;
|
|
return fs_len/fsz_secsize-1;
|
|
}
|
|
|
|
void fsz_link_inode(int inode, char *path, int toinode)
|
|
{
|
|
unsigned int ns=0,cnt=0;
|
|
FSZ_DirEntHeader *hdr;
|
|
FSZ_DirEnt *ent;
|
|
FSZ_Inode *in, *in2;
|
|
if(toinode==0)
|
|
toinode=((FSZ_SuperBlock *)fs_base)->rootdirfid;
|
|
hdr=(FSZ_DirEntHeader *)(fs_base+toinode*fsz_secsize+1024);
|
|
ent=(FSZ_DirEnt *)hdr; ent++;
|
|
while(path[ns]!='/'&&path[ns]!=0) ns++;
|
|
while(ent->fid!=0 && cnt<(unsigned int)((fsz_secsize-1024)/128-1)) {
|
|
if(!strncmp((char *)(ent->name),path,ns+1)) {
|
|
fsz_link_inode(inode,path+ns+1,ent->fid);
|
|
return;
|
|
}
|
|
ent++; cnt++;
|
|
}
|
|
in=((FSZ_Inode *)(fs_base+toinode*fsz_secsize));
|
|
in2=((FSZ_Inode *)(fs_base+inode*fsz_secsize));
|
|
ent->fid=inode;
|
|
ent->length=strlen(path);
|
|
memcpy(ent->name,path,strlen(path));
|
|
if(!strncmp((char *)(((FSZ_Inode *)(fs_base+inode*fsz_secsize))->filetype),FSZ_FILETYPE_DIR,4)){
|
|
ent->name[ent->length++]='/';
|
|
}
|
|
/* the format can hold 2^127 directory entries, but we only implement directories embedded in inodes here, up to 23 */
|
|
if(hdr->numentries >= (fsz_secsize - 1024 - sizeof(FSZ_DirEntHeader)) / sizeof(FSZ_DirEnt)) {
|
|
fprintf(stderr,"mkbootimg: %s: %s\n",lang[ERR_TOOMANY],path); exit(1);
|
|
}
|
|
hdr->numentries++;
|
|
in->modifydate=t * 1000000;
|
|
in->size+=sizeof(FSZ_DirEnt);
|
|
qsort((char*)hdr+sizeof(FSZ_DirEntHeader), hdr->numentries, sizeof(FSZ_DirEnt), fsz_direntcmp);
|
|
hdr->checksum=crc32_calc((unsigned char*)hdr+sizeof(FSZ_DirEntHeader),hdr->numentries*sizeof(FSZ_DirEnt));
|
|
in->checksum=crc32_calc(in->filetype,1016);
|
|
in2->numlinks++;
|
|
in2->checksum=crc32_calc(in2->filetype,1016);
|
|
}
|
|
|
|
void fsz_add_file(char *name, unsigned char *data, unsigned long int size)
|
|
{
|
|
FSZ_Inode *in;
|
|
unsigned char *ptr;
|
|
long int i,j,k,l,s=((size+fsz_secsize-1)/fsz_secsize)*fsz_secsize;
|
|
int inode=fsz_add_inode(data[0]==0x55 && data[1]==0xAA &&
|
|
data[3]==0xE9 && data[8]=='B' &&
|
|
data[12]=='B'?"boot":"application","octet-stream");
|
|
fs_base=realloc(fs_base,fs_len+fsz_secsize+s);
|
|
if(!fs_base) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_MEM]); exit(1); }
|
|
memset(fs_base+fs_len,0,fsz_secsize);
|
|
in=(FSZ_Inode *)(fs_base+inode*fsz_secsize);
|
|
in->changedate=t * 1000000;
|
|
in->modifydate=t * 1000000;
|
|
in->size=size;
|
|
if(size<=(unsigned long int)fsz_secsize-1024) {
|
|
in->sec=inode;
|
|
in->flags=FSZ_IN_FLAG_INLINE;
|
|
in->numblocks=0;
|
|
memcpy(in->data.small.inlinedata,data,size);
|
|
s=0;
|
|
} else {
|
|
in->sec=fs_len/fsz_secsize;
|
|
if(size>(unsigned long int)fsz_secsize) {
|
|
j=s/fsz_secsize;
|
|
if(j*16>fsz_secsize){ fprintf(stderr,"mkbootimg: %s: %s\n",lang[ERR_TOOBIG],name); exit(1); }
|
|
if(j*16<=fsz_secsize-1024) {
|
|
ptr=(unsigned char*)&in->data.small.inlinedata;
|
|
in->flags=FSZ_IN_FLAG_SDINLINE;
|
|
in->numblocks=0;
|
|
l=0;
|
|
} else {
|
|
ptr=fs_base+size;
|
|
in->flags=FSZ_IN_FLAG_SD;
|
|
in->numblocks=1;
|
|
l=1;
|
|
}
|
|
k=inode+1+l;
|
|
for(i=0;i<j;i++){
|
|
/* no spare blocks allowed in initrd, there we must save a sector full of zeros */
|
|
if(fsz_isinitrd || memcmp(data+i*fsz_secsize,fsz_emptysec,fsz_secsize)) {
|
|
memcpy(ptr,&k,4);
|
|
memcpy(fs_base+size+(i+l)*fsz_secsize,data+i*fsz_secsize,
|
|
(unsigned long int)(i+l)*fsz_secsize>size?size%fsz_secsize:(unsigned long int)fsz_secsize);
|
|
k++;
|
|
in->numblocks++;
|
|
} else {
|
|
s-=fsz_secsize;
|
|
}
|
|
ptr+=16;
|
|
}
|
|
if(in->flags==FSZ_IN_FLAG_SD)
|
|
size+=fsz_secsize;
|
|
} else {
|
|
in->flags=FSZ_IN_FLAG_DIRECT;
|
|
if(memcmp(data,fsz_emptysec,fsz_secsize)) {
|
|
in->numblocks=1;
|
|
memcpy(fs_base+fs_len,data,size);
|
|
} else {
|
|
in->sec=0;
|
|
in->numblocks=0;
|
|
}
|
|
}
|
|
}
|
|
if(!strncmp((char*)data+1,"ELF",3) || !strncmp((char*)data,"OS/Z",4) || !strncmp((char*)data,"CSBC",4) ||
|
|
!strncmp((char*)data,"\000asm",4))
|
|
{memset(in->mimetype,0,36);memcpy(in->mimetype,"executable",10);in->owner.access|=FSZ_EXEC;}
|
|
if(!strcmp(name+strlen(name)-3,".so"))
|
|
{memset(in->mimetype,0,36);memcpy(in->mimetype,"sharedlib",9);}
|
|
else
|
|
if(!strcmp(name+strlen(name)-2,".h")||
|
|
!strcmp(name+strlen(name)-2,".c")||
|
|
!strcmp(name+strlen(name)-3,".md")||
|
|
!strcmp(name+strlen(name)-4,".txt")||
|
|
!strcmp(name+strlen(name)-5,".conf")
|
|
) {memset(in->mimetype,0,36);memcpy(in->mimetype,"plain",5);
|
|
memcpy(in->filetype,"text",4);
|
|
}
|
|
else
|
|
if(!strcmp(name+strlen(name)-3,".sh"))
|
|
{memset(in->mimetype,0,36);memcpy(in->mimetype,"shellscript",11);
|
|
memcpy(in->filetype,"text",4);in->owner.access|=FSZ_EXEC;
|
|
}
|
|
else
|
|
if(!strcmp(name+strlen(name)-4,".htm")||
|
|
!strcmp(name+strlen(name)-5,".html")
|
|
)
|
|
{memset(in->mimetype,0,36);memcpy(in->mimetype,"html",4);
|
|
memcpy(in->filetype,"text",4);
|
|
}
|
|
else
|
|
if(!strcmp(name+strlen(name)-4,".css"))
|
|
{memset(in->mimetype,0,36);memcpy(in->mimetype,"stylesheet",10);
|
|
memcpy(in->filetype,"text",4);
|
|
}
|
|
else
|
|
if(!strcmp(name+strlen(name)-4,".svg"))
|
|
{memset(in->mimetype,0,36);memcpy(in->mimetype,"svg",3);
|
|
memcpy(in->filetype,"imag",4);
|
|
}
|
|
else
|
|
if(!strcmp(name+strlen(name)-4,".gif"))
|
|
{memset(in->mimetype,0,36);memcpy(in->mimetype,"gif",3);
|
|
memcpy(in->filetype,"imag",4);
|
|
}
|
|
else
|
|
if(!strcmp(name+strlen(name)-4,".png"))
|
|
{memset(in->mimetype,0,36);memcpy(in->mimetype,"png",3);
|
|
memcpy(in->filetype,"imag",4);
|
|
}
|
|
else
|
|
if(!strcmp(name+strlen(name)-4,".jpg"))
|
|
{memset(in->mimetype,0,36);memcpy(in->mimetype,"jpeg",4);
|
|
memcpy(in->filetype,"imag",4);
|
|
}
|
|
else
|
|
if(!strcmp(name+strlen(name)-4,".bmp"))
|
|
{memset(in->mimetype,0,36);memcpy(in->mimetype,"bitmap",6);
|
|
memcpy(in->filetype,"imag",4);
|
|
}
|
|
else
|
|
if(!strcmp(name+strlen(name)-4,".sfn"))
|
|
{memset(in->mimetype,0,36);memcpy(in->mimetype,"ssfont",6);
|
|
memcpy(in->filetype,"font",4);
|
|
}
|
|
else
|
|
if(!strcmp(name+strlen(name)-4,".psf"))
|
|
{memset(in->mimetype,0,36);memcpy(in->mimetype,"pc-screen-font",14);
|
|
memcpy(in->filetype,"font",4);
|
|
}
|
|
else
|
|
if(!strcmp(name+strlen(name)-4,".ttf"))
|
|
{memset(in->mimetype,0,36);memcpy(in->mimetype,"sfnt",4);
|
|
memcpy(in->filetype,"font",4);
|
|
}
|
|
else
|
|
if(!strcmp(name+strlen(name)-4,".m3d"))
|
|
{memset(in->mimetype,0,36);memcpy(in->mimetype,"3d-model",8);
|
|
memcpy(in->filetype,data[1]=='d' ? "text" : "mode",4);
|
|
}
|
|
else {
|
|
j=1; for(i=0;i<read_size;i++) if(data[i]<9) { j=0; break; }
|
|
if(j) {
|
|
memset(in->mimetype,0,36);memcpy(in->mimetype,"plain",5);
|
|
memcpy(in->filetype,"text",4);
|
|
}
|
|
}
|
|
in->checksum=crc32_calc(in->filetype,1016);
|
|
fs_len+=s;
|
|
fsz_link_inode(inode,name,0);
|
|
}
|
|
|
|
/*** mkbootimg interface ***/
|
|
void fsz_open(gpt_t *gpt_entry)
|
|
{
|
|
FSZ_SuperBlock *sb;
|
|
fs_base = realloc(fs_base, 2*fsz_secsize);
|
|
if(!fs_base) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_MEM]); exit(1); }
|
|
memset(fs_base,0,2*fsz_secsize);
|
|
sb=(FSZ_SuperBlock *)(fs_base);
|
|
memcpy(sb->magic,FSZ_MAGIC,4);
|
|
memcpy((char*)&sb->owner,"root",4);
|
|
sb->version_major=FSZ_VERSION_MAJOR;
|
|
sb->version_minor=FSZ_VERSION_MINOR;
|
|
sb->raidtype=FSZ_SB_SOFTRAID_NONE;
|
|
sb->logsec=fsz_secsize==2048?0:(fsz_secsize==4096?1:2);
|
|
sb->physec=fsz_secsize/512;
|
|
sb->maxmounts=255;
|
|
sb->currmounts=0;
|
|
sb->createdate=sb->lastchangedate=t * 1000000;
|
|
if(gpt_entry) {
|
|
memcpy(&sb->uuid, (void*)(gpt_entry + 16), sizeof(guid_t));
|
|
sb->numsec = (gpt_entry->last - gpt_entry->start + 1) * 512 / fsz_secsize;
|
|
fsz_isinitrd = 0;
|
|
} else {
|
|
memcpy(&sb->uuid, (void*)&diskguid, sizeof(guid_t));
|
|
sb->uuid[15]--;
|
|
fsz_isinitrd = 1;
|
|
}
|
|
memcpy(sb->magic2,FSZ_MAGIC,4);
|
|
fs_len = fsz_secsize;
|
|
/* don't use sb after this point because add inode will realloc */
|
|
((FSZ_SuperBlock *)(fs_base))->rootdirfid = fsz_add_inode(FSZ_FILETYPE_DIR,FSZ_MIMETYPE_DIR_ROOT);
|
|
((FSZ_Inode*)(fs_base+fsz_secsize))->numlinks++;
|
|
}
|
|
|
|
void fsz_add(struct stat *st, char *name, unsigned char *content, int size)
|
|
{
|
|
int i;
|
|
char *fn = strrchr(name, '/');
|
|
if(!fn) fn = name; else fn++;
|
|
if(!strcmp(fn, ".") || !strcmp(fn, "..")) return;
|
|
if(S_ISDIR(st->st_mode)) {
|
|
i=fsz_add_inode(FSZ_FILETYPE_DIR,NULL);
|
|
fsz_link_inode(i,name,0);
|
|
} else
|
|
if(S_ISREG(st->st_mode)) {
|
|
fsz_add_file(name,content,size);
|
|
} else
|
|
if(S_ISLNK(st->st_mode) && content) {
|
|
i=fsz_add_inode(FSZ_FILETYPE_SYMLINK,(char*)content);
|
|
fsz_link_inode(i,name,0);
|
|
}
|
|
}
|
|
|
|
void fsz_close()
|
|
{
|
|
FSZ_SuperBlock *sb=(FSZ_SuperBlock *)(fs_base);
|
|
if(!sb) return;
|
|
if(!sb->numsec) sb->numsec = fs_len / fsz_secsize;
|
|
sb->freesec = fs_len / fsz_secsize;
|
|
sb->checksum = crc32_calc((unsigned char *)&sb->magic,508);
|
|
}
|