123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- /*
- * mkbootimg/fsZ.c
- *
- * Copyright (C) 2017 - 2021 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_max = 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;
- if(fsz_max && fs_len+fsz_secsize > fsz_max) {
- fprintf(stderr,"mkbootimg: partition #%d %s\n", fs_no, lang[ERR_TOOBIG]);
- exit(1);
- }
- 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=hdr->fid=fs_len/fsz_secsize;
- in->flags=0;
- in->size=sizeof(FSZ_DirEntHeader);
- memcpy(in->data.small.inlinedata,FSZ_DIR_MAGIC,4);
- hdr->checksum=crc32_calc((unsigned char*)hdr + 16, in->size - 16);
- }
- }
- 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=in->createdate=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,l=strlen(path);
- 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;
- if(l > 110) l = 110;
- memcpy(ent->name,path,l);
- if(!strncmp((char *)(((FSZ_Inode *)(fs_base+inode*fsz_secsize))->filetype),FSZ_FILETYPE_DIR,4)){
- ent->name[l]='/';
- }
- /* 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: partition #%d %s: %s\n", fs_no, 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 + 16, in->size - 16);
- 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");
- if(fsz_max && fs_len+fsz_secsize+s > fsz_max) {
- fprintf(stderr,"mkbootimg: partition #%d %s: %s\n", fs_no, lang[ERR_TOOBIG], name);
- exit(1);
- }
- 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->sec=inode+1;
- in->size=size;
- if(size<=(unsigned long int)fsz_secsize-1024) {
- in->sec=inode;
- in->flags=0;
- 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: partition #%d %s: %s\n", fs_no, lang[ERR_TOOBIG], name); exit(1); }
- if(j*16<=fsz_secsize-1024) {
- ptr=(unsigned char*)&in->data.small.inlinedata;
- in->sec=inode;
- in->flags=1;
- in->numblocks=0;
- l=0;
- } else {
- ptr=fs_base+size;
- in->flags=1;
- 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_max || 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==1)
- size+=fsz_secsize;
- } else {
- in->flags=0;
- 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);
- sb->version_major=FSZ_VERSION_MAJOR;
- sb->version_minor=FSZ_VERSION_MINOR;
- sb->logsec=fsz_secsize==2048?0:(fsz_secsize==4096?1:2);
- sb->maxmounts=255;
- sb->currmounts=0;
- sb->createdate=sb->lastmountdate=sb->lastumountdate=t * 1000000;
- if(gpt_entry) {
- memcpy(&sb->uuid, &gpt_entry->guid, 16);
- fsz_max = (gpt_entry->last - gpt_entry->start + 1) * 512;
- sb->numsec = fsz_max / fsz_secsize;
- } else {
- memcpy(&sb->uuid, (void*)&diskguid, sizeof(guid_t));
- sb->uuid[15]--;
- fsz_max = 0;
- }
- 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);
- }
|