fsZ.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /*
  2. * mkbootimg/fsZ.c
  3. *
  4. * Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * This file is part of the BOOTBOOT Protocol package.
  27. * @brief FS/Z file system driver
  28. *
  29. */
  30. #include "main.h"
  31. #include "fsZ.h"
  32. int fsz_secsize = FSZ_SECSIZE, fsz_max = 0;
  33. unsigned char fsz_emptysec[FSZ_SECSIZE] = {0};
  34. /* private functions */
  35. static int fsz_direntcmp(const void *a, const void *b)
  36. {
  37. return strcmp((char *)((FSZ_DirEnt *)a)->name,(char *)((FSZ_DirEnt *)b)->name);
  38. }
  39. int fsz_add_inode(char *filetype, char *mimetype)
  40. {
  41. unsigned int i,j=!strcmp(filetype,FSZ_FILETYPE_SYMLINK)||!strcmp(filetype,FSZ_FILETYPE_UNION)?fsz_secsize-1024:36;
  42. FSZ_Inode *in;
  43. FSZ_DirEntHeader *hdr;
  44. if(fsz_max && fs_len+fsz_secsize > fsz_max) {
  45. fprintf(stderr,"mkbootimg: partition #%d %s\n", fs_no, lang[ERR_TOOBIG]);
  46. exit(1);
  47. }
  48. fs_base=realloc(fs_base,fs_len+fsz_secsize);
  49. if(!fs_base) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_MEM]); exit(1); }
  50. memset(fs_base+fs_len,0,fsz_secsize);
  51. in=(FSZ_Inode *)(fs_base+fs_len);
  52. memcpy(in->magic,FSZ_IN_MAGIC,4);
  53. memcpy((char*)&in->owner,"root",5);
  54. in->owner.access=FSZ_READ|FSZ_WRITE|FSZ_DELETE|(filetype && (
  55. !strcmp(filetype,FSZ_FILETYPE_DIR) || !strcmp(filetype,FSZ_FILETYPE_UNION))? FSZ_EXEC : 0);
  56. if(filetype!=NULL){
  57. i=strlen(filetype);
  58. memcpy(in->filetype,filetype,i>4?4:i);
  59. if(!strcmp(filetype,FSZ_FILETYPE_DIR)){
  60. hdr=(FSZ_DirEntHeader *)(in->data.small.inlinedata);
  61. in->sec=hdr->fid=fs_len/fsz_secsize;
  62. in->flags=0;
  63. in->size=sizeof(FSZ_DirEntHeader);
  64. memcpy(in->data.small.inlinedata,FSZ_DIR_MAGIC,4);
  65. hdr->checksum=crc32_calc((unsigned char*)hdr + 16, in->size - 16);
  66. }
  67. }
  68. if(mimetype!=NULL){
  69. if(!strcmp(filetype,FSZ_FILETYPE_UNION)){
  70. for(i=1;i<j && !(mimetype[i-1]==0 && mimetype[i]==0);i++);
  71. i++;
  72. } else {
  73. i=strlen(mimetype);
  74. }
  75. memcpy(j==36?in->mimetype:in->data.small.inlinedata,mimetype,i>j?j:i);
  76. if(j!=36)
  77. in->size=i;
  78. }
  79. in->changedate=in->createdate=t * 1000000;
  80. in->modifydate=t * 1000000;
  81. in->checksum=crc32_calc(in->filetype,1016);
  82. fs_len+=fsz_secsize;
  83. return fs_len/fsz_secsize-1;
  84. }
  85. void fsz_link_inode(int inode, char *path, int toinode)
  86. {
  87. unsigned int ns=0,cnt=0,l=strlen(path);
  88. FSZ_DirEntHeader *hdr;
  89. FSZ_DirEnt *ent;
  90. FSZ_Inode *in, *in2;
  91. if(toinode==0)
  92. toinode=((FSZ_SuperBlock *)fs_base)->rootdirfid;
  93. hdr=(FSZ_DirEntHeader *)(fs_base+toinode*fsz_secsize+1024);
  94. ent=(FSZ_DirEnt *)hdr; ent++;
  95. while(path[ns]!='/'&&path[ns]!=0) ns++;
  96. while(ent->fid!=0 && cnt<(unsigned int)((fsz_secsize-1024)/128-1)) {
  97. if(!strncmp((char *)(ent->name),path,ns+1)) {
  98. fsz_link_inode(inode,path+ns+1,ent->fid);
  99. return;
  100. }
  101. ent++; cnt++;
  102. }
  103. in=((FSZ_Inode *)(fs_base+toinode*fsz_secsize));
  104. in2=((FSZ_Inode *)(fs_base+inode*fsz_secsize));
  105. ent->fid=inode;
  106. if(l > 110) l = 110;
  107. memcpy(ent->name,path,l);
  108. if(!strncmp((char *)(((FSZ_Inode *)(fs_base+inode*fsz_secsize))->filetype),FSZ_FILETYPE_DIR,4)){
  109. ent->name[l]='/';
  110. }
  111. /* the format can hold 2^127 directory entries, but we only implement directories embedded in inodes here, up to 23 */
  112. if(hdr->numentries >= (fsz_secsize - 1024 - sizeof(FSZ_DirEntHeader)) / sizeof(FSZ_DirEnt)) {
  113. fprintf(stderr,"mkbootimg: partition #%d %s: %s\n", fs_no, lang[ERR_TOOMANY], path); exit(1);
  114. }
  115. hdr->numentries++;
  116. in->modifydate=t * 1000000;
  117. in->size+=sizeof(FSZ_DirEnt);
  118. qsort((char*)hdr+sizeof(FSZ_DirEntHeader), hdr->numentries, sizeof(FSZ_DirEnt), fsz_direntcmp);
  119. hdr->checksum=crc32_calc((unsigned char*)hdr + 16, in->size - 16);
  120. in->checksum=crc32_calc(in->filetype,1016);
  121. in2->numlinks++;
  122. in2->checksum=crc32_calc(in2->filetype,1016);
  123. }
  124. void fsz_add_file(char *name, unsigned char *data, unsigned long int size)
  125. {
  126. FSZ_Inode *in;
  127. unsigned char *ptr;
  128. long int i,j,k,l,s=((size+fsz_secsize-1)/fsz_secsize)*fsz_secsize;
  129. int inode=fsz_add_inode(data[0]==0x55 && data[1]==0xAA &&
  130. data[3]==0xE9 && data[8]=='B' &&
  131. data[12]=='B'?"boot":"application","octet-stream");
  132. if(fsz_max && fs_len+fsz_secsize+s > fsz_max) {
  133. fprintf(stderr,"mkbootimg: partition #%d %s: %s\n", fs_no, lang[ERR_TOOBIG], name);
  134. exit(1);
  135. }
  136. fs_base=realloc(fs_base,fs_len+fsz_secsize+s);
  137. if(!fs_base) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_MEM]); exit(1); }
  138. memset(fs_base+fs_len,0,fsz_secsize);
  139. in=(FSZ_Inode *)(fs_base+inode*fsz_secsize);
  140. in->changedate=t * 1000000;
  141. in->modifydate=t * 1000000;
  142. in->sec=inode+1;
  143. in->size=size;
  144. if(size<=(unsigned long int)fsz_secsize-1024) {
  145. in->sec=inode;
  146. in->flags=0;
  147. in->numblocks=0;
  148. memcpy(in->data.small.inlinedata,data,size);
  149. s=0;
  150. } else {
  151. in->sec=fs_len/fsz_secsize;
  152. if(size>(unsigned long int)fsz_secsize) {
  153. j=s/fsz_secsize;
  154. if(j*16>fsz_secsize){ fprintf(stderr,"mkbootimg: partition #%d %s: %s\n", fs_no, lang[ERR_TOOBIG], name); exit(1); }
  155. if(j*16<=fsz_secsize-1024) {
  156. ptr=(unsigned char*)&in->data.small.inlinedata;
  157. in->sec=inode;
  158. in->flags=1;
  159. in->numblocks=0;
  160. l=0;
  161. } else {
  162. ptr=fs_base+size;
  163. in->flags=1;
  164. in->numblocks=1;
  165. l=1;
  166. }
  167. k=inode+1+l;
  168. for(i=0;i<j;i++){
  169. /* no spare blocks allowed in initrd, there we must save a sector full of zeros */
  170. if(!fsz_max || memcmp(data+i*fsz_secsize,fsz_emptysec,fsz_secsize)) {
  171. memcpy(ptr,&k,4);
  172. memcpy(fs_base+size+(i+l)*fsz_secsize,data+i*fsz_secsize,
  173. (unsigned long int)(i+l)*fsz_secsize>size?size%fsz_secsize:(unsigned long int)fsz_secsize);
  174. k++;
  175. in->numblocks++;
  176. } else {
  177. s-=fsz_secsize;
  178. }
  179. ptr+=16;
  180. }
  181. if(in->flags==1)
  182. size+=fsz_secsize;
  183. } else {
  184. in->flags=0;
  185. if(memcmp(data,fsz_emptysec,fsz_secsize)) {
  186. in->numblocks=1;
  187. memcpy(fs_base+fs_len,data,size);
  188. } else {
  189. in->sec=0;
  190. in->numblocks=0;
  191. }
  192. }
  193. }
  194. if(!strncmp((char*)data+1,"ELF",3) || !strncmp((char*)data,"OS/Z",4) || !strncmp((char*)data,"CSBC",4) ||
  195. !strncmp((char*)data,"\000asm",4))
  196. {memset(in->mimetype,0,36);memcpy(in->mimetype,"executable",10);in->owner.access|=FSZ_EXEC;}
  197. if(!strcmp(name+strlen(name)-3,".so"))
  198. {memset(in->mimetype,0,36);memcpy(in->mimetype,"sharedlib",9);}
  199. else
  200. if(!strcmp(name+strlen(name)-2,".h")||
  201. !strcmp(name+strlen(name)-2,".c")||
  202. !strcmp(name+strlen(name)-3,".md")||
  203. !strcmp(name+strlen(name)-4,".txt")||
  204. !strcmp(name+strlen(name)-5,".conf")
  205. ) {memset(in->mimetype,0,36);memcpy(in->mimetype,"plain",5);
  206. memcpy(in->filetype,"text",4);
  207. }
  208. else
  209. if(!strcmp(name+strlen(name)-3,".sh"))
  210. {memset(in->mimetype,0,36);memcpy(in->mimetype,"shellscript",11);
  211. memcpy(in->filetype,"text",4);in->owner.access|=FSZ_EXEC;
  212. }
  213. else
  214. if(!strcmp(name+strlen(name)-4,".htm")||
  215. !strcmp(name+strlen(name)-5,".html")
  216. )
  217. {memset(in->mimetype,0,36);memcpy(in->mimetype,"html",4);
  218. memcpy(in->filetype,"text",4);
  219. }
  220. else
  221. if(!strcmp(name+strlen(name)-4,".css"))
  222. {memset(in->mimetype,0,36);memcpy(in->mimetype,"stylesheet",10);
  223. memcpy(in->filetype,"text",4);
  224. }
  225. else
  226. if(!strcmp(name+strlen(name)-4,".svg"))
  227. {memset(in->mimetype,0,36);memcpy(in->mimetype,"svg",3);
  228. memcpy(in->filetype,"imag",4);
  229. }
  230. else
  231. if(!strcmp(name+strlen(name)-4,".gif"))
  232. {memset(in->mimetype,0,36);memcpy(in->mimetype,"gif",3);
  233. memcpy(in->filetype,"imag",4);
  234. }
  235. else
  236. if(!strcmp(name+strlen(name)-4,".png"))
  237. {memset(in->mimetype,0,36);memcpy(in->mimetype,"png",3);
  238. memcpy(in->filetype,"imag",4);
  239. }
  240. else
  241. if(!strcmp(name+strlen(name)-4,".jpg"))
  242. {memset(in->mimetype,0,36);memcpy(in->mimetype,"jpeg",4);
  243. memcpy(in->filetype,"imag",4);
  244. }
  245. else
  246. if(!strcmp(name+strlen(name)-4,".bmp"))
  247. {memset(in->mimetype,0,36);memcpy(in->mimetype,"bitmap",6);
  248. memcpy(in->filetype,"imag",4);
  249. }
  250. else
  251. if(!strcmp(name+strlen(name)-4,".sfn"))
  252. {memset(in->mimetype,0,36);memcpy(in->mimetype,"ssfont",6);
  253. memcpy(in->filetype,"font",4);
  254. }
  255. else
  256. if(!strcmp(name+strlen(name)-4,".psf"))
  257. {memset(in->mimetype,0,36);memcpy(in->mimetype,"pc-screen-font",14);
  258. memcpy(in->filetype,"font",4);
  259. }
  260. else
  261. if(!strcmp(name+strlen(name)-4,".ttf"))
  262. {memset(in->mimetype,0,36);memcpy(in->mimetype,"sfnt",4);
  263. memcpy(in->filetype,"font",4);
  264. }
  265. else
  266. if(!strcmp(name+strlen(name)-4,".m3d"))
  267. {memset(in->mimetype,0,36);memcpy(in->mimetype,"3d-model",8);
  268. memcpy(in->filetype,data[1]=='d' ? "text" : "mode",4);
  269. }
  270. else {
  271. j=1; for(i=0;i<read_size;i++) if(data[i]<9) { j=0; break; }
  272. if(j) {
  273. memset(in->mimetype,0,36);memcpy(in->mimetype,"plain",5);
  274. memcpy(in->filetype,"text",4);
  275. }
  276. }
  277. in->checksum=crc32_calc(in->filetype,1016);
  278. fs_len+=s;
  279. fsz_link_inode(inode,name,0);
  280. }
  281. /*** mkbootimg interface ***/
  282. void fsz_open(gpt_t *gpt_entry)
  283. {
  284. FSZ_SuperBlock *sb;
  285. fs_base = realloc(fs_base, 2*fsz_secsize);
  286. if(!fs_base) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_MEM]); exit(1); }
  287. memset(fs_base,0,2*fsz_secsize);
  288. sb=(FSZ_SuperBlock *)(fs_base);
  289. memcpy(sb->magic,FSZ_MAGIC,4);
  290. sb->version_major=FSZ_VERSION_MAJOR;
  291. sb->version_minor=FSZ_VERSION_MINOR;
  292. sb->logsec=fsz_secsize==2048?0:(fsz_secsize==4096?1:2);
  293. sb->maxmounts=255;
  294. sb->currmounts=0;
  295. sb->createdate=sb->lastmountdate=sb->lastumountdate=t * 1000000;
  296. if(gpt_entry) {
  297. memcpy(&sb->uuid, &gpt_entry->guid, 16);
  298. fsz_max = (gpt_entry->last - gpt_entry->start + 1) * 512;
  299. sb->numsec = fsz_max / fsz_secsize;
  300. } else {
  301. memcpy(&sb->uuid, (void*)&diskguid, sizeof(guid_t));
  302. sb->uuid[15]--;
  303. fsz_max = 0;
  304. }
  305. memcpy(sb->magic2,FSZ_MAGIC,4);
  306. fs_len = fsz_secsize;
  307. /* don't use sb after this point because add inode will realloc */
  308. ((FSZ_SuperBlock *)(fs_base))->rootdirfid = fsz_add_inode(FSZ_FILETYPE_DIR,FSZ_MIMETYPE_DIR_ROOT);
  309. ((FSZ_Inode*)(fs_base+fsz_secsize))->numlinks++;
  310. }
  311. void fsz_add(struct stat *st, char *name, unsigned char *content, int size)
  312. {
  313. int i;
  314. char *fn = strrchr(name, '/');
  315. if(!fn) fn = name; else fn++;
  316. if(!strcmp(fn, ".") || !strcmp(fn, "..")) return;
  317. if(S_ISDIR(st->st_mode)) {
  318. i=fsz_add_inode(FSZ_FILETYPE_DIR,NULL);
  319. fsz_link_inode(i,name,0);
  320. } else
  321. if(S_ISREG(st->st_mode)) {
  322. fsz_add_file(name,content,size);
  323. } else
  324. if(S_ISLNK(st->st_mode) && content) {
  325. i=fsz_add_inode(FSZ_FILETYPE_SYMLINK,(char*)content);
  326. fsz_link_inode(i,name,0);
  327. }
  328. }
  329. void fsz_close()
  330. {
  331. FSZ_SuperBlock *sb=(FSZ_SuperBlock *)(fs_base);
  332. if(!sb) return;
  333. if(!sb->numsec) sb->numsec = fs_len / fsz_secsize;
  334. sb->freesec = fs_len / fsz_secsize;
  335. sb->checksum = crc32_calc((unsigned char *)&sb->magic,508);
  336. }