2021-03-17 11:04:05 -04:00
|
|
|
/*
|
|
|
|
* mkbootimg/ech.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 a very minimal echfs driver which is much easier to use than echfs-utils
|
2021-03-20 20:58:09 -04:00
|
|
|
* See https://github.com/echfs/echfs
|
2021-03-17 11:04:05 -04:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include "main.h"
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
uint64_t parent_id;
|
|
|
|
uint8_t type;
|
|
|
|
char name[201];
|
|
|
|
uint64_t atime;
|
|
|
|
uint64_t mtime;
|
|
|
|
uint16_t perms;
|
|
|
|
uint16_t owner;
|
|
|
|
uint16_t group;
|
|
|
|
uint64_t ctime;
|
|
|
|
uint64_t payload;
|
|
|
|
uint64_t size;
|
|
|
|
}__attribute__((packed)) ech_entry_t;
|
|
|
|
ech_entry_t *ech_ents = NULL;
|
|
|
|
int ech_numents, ech_maxents;
|
|
|
|
|
|
|
|
uint8_t *ech_data = NULL, ech_uuid[16];
|
|
|
|
uint64_t ech_size;
|
|
|
|
uint64_t ech_numblk;
|
|
|
|
|
2021-03-25 03:30:25 -04:00
|
|
|
/*** mkbootimg interface ***/
|
2021-03-17 11:04:05 -04:00
|
|
|
void ech_open(gpt_t *gpt_entry)
|
|
|
|
{
|
2021-03-19 02:00:08 -04:00
|
|
|
if(gpt_entry) {
|
|
|
|
if((gpt_entry->last - gpt_entry->start) < 1) {
|
|
|
|
fprintf(stderr,"mkbootimg: partition #%d %s\r\n", fs_no, lang[ERR_NOSIZE]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2021-03-17 11:04:05 -04:00
|
|
|
memcpy(ech_uuid, &gpt_entry->guid, 16);
|
|
|
|
ech_numblk = gpt_entry->last - gpt_entry->start + 1;
|
|
|
|
ech_maxents = (ech_numblk * 5 / 100) * 512 / sizeof(ech_entry_t);
|
|
|
|
} else {
|
|
|
|
memcpy(ech_uuid, "INITRD", 6);
|
|
|
|
memset(ech_uuid + 6, 0, 10);
|
|
|
|
ech_numblk = 0;
|
|
|
|
ech_maxents = 0;
|
|
|
|
}
|
|
|
|
ech_numents = 0;
|
|
|
|
ech_size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ech_add(struct stat *st, char *name, unsigned char *content, int size)
|
|
|
|
{
|
|
|
|
uint64_t parent = UINT64_C(0xffffffffffffffff);
|
|
|
|
int i, j;
|
|
|
|
char *end, *fn = strrchr(name, '/');
|
|
|
|
if(!fn) fn = name; else fn++;
|
|
|
|
if(!strcmp(fn, ".") || !strcmp(fn, "..")) return;
|
|
|
|
if(!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode)) return;
|
|
|
|
|
|
|
|
fn = name;
|
|
|
|
end = strchr(name, '/');
|
|
|
|
if(!end) end = name + strlen(name);
|
|
|
|
for(i = 0; i < ech_numents; i++) {
|
|
|
|
if(ech_ents[i].parent_id == parent && !memcmp(ech_ents[i].name, fn, end - fn) && !ech_ents[i].name[end - fn]) {
|
|
|
|
parent = ech_ents[i].payload;
|
|
|
|
fn = end + 1;
|
|
|
|
end = *end ? strchr(fn, '/') : NULL;
|
2021-03-19 02:00:08 -04:00
|
|
|
if(!end) { end = fn + strlen(fn); break; }
|
2021-03-17 11:04:05 -04:00
|
|
|
}
|
|
|
|
}
|
2021-03-19 02:00:08 -04:00
|
|
|
if(ech_numblk && ech_numblk * 512 < ech_size + size) {
|
|
|
|
fprintf(stderr,"mkbootimg: partition #%d %s\r\n", fs_no, lang[ERR_TOOBIG]);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if(ech_maxents && ech_numents + 1 >= ech_maxents) {
|
|
|
|
fprintf(stderr,"mkbootimg: partition #%d %s\r\n", fs_no, lang[ERR_TOOMANY]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2021-03-17 11:04:05 -04:00
|
|
|
ech_ents = (ech_entry_t*)realloc(ech_ents, (ech_numents + 1) * sizeof(ech_entry_t));
|
|
|
|
if(!ech_ents) { fprintf(stderr,"mkbootimg: %s\r\n",lang[ERR_MEM]); exit(1); }
|
|
|
|
memset(&ech_ents[ech_numents], 0, sizeof(ech_entry_t));
|
|
|
|
ech_ents[ech_numents].parent_id = parent;
|
|
|
|
memcpy(ech_ents[ech_numents].name, fn, end - fn);
|
|
|
|
ech_ents[ech_numents].atime = st->st_atime;
|
|
|
|
ech_ents[ech_numents].mtime = st->st_mtime;
|
|
|
|
ech_ents[ech_numents].ctime = st->st_ctime;
|
|
|
|
ech_ents[ech_numents].perms = st->st_mode & 0xFFF;
|
|
|
|
if(S_ISDIR(st->st_mode)) {
|
|
|
|
ech_ents[ech_numents].type = 1;
|
|
|
|
ech_ents[ech_numents].payload = ech_numents + 1;
|
|
|
|
} else {
|
|
|
|
ech_ents[ech_numents].size = size;
|
|
|
|
ech_ents[ech_numents].payload = ech_size / 512;
|
|
|
|
j = (size + 511) & ~511;
|
|
|
|
if(j > 0) {
|
|
|
|
ech_data = (uint8_t*)realloc(ech_data, ech_size + j);
|
|
|
|
if(!ech_ents) { fprintf(stderr,"mkbootimg: %s\r\n",lang[ERR_MEM]); exit(1); }
|
|
|
|
memcpy(ech_data + ech_size, content, size);
|
|
|
|
ech_size += j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ech_numents++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ech_close()
|
|
|
|
{
|
|
|
|
ech_entry_t *ent;
|
|
|
|
uint64_t offs, *ptr, i, j;
|
|
|
|
if(!ech_numblk) {
|
|
|
|
ech_maxents = ech_numents;
|
|
|
|
ech_numblk = 16 + (ech_numents * sizeof(ech_entry_t) + 511 + ech_size) / 512;
|
|
|
|
ech_numblk += (ech_numblk * 8 + 511) / 512;
|
|
|
|
}
|
|
|
|
offs = 16 + ((ech_maxents * sizeof(ech_entry_t) + 511) / 512) + (ech_numblk * 8 + 511) / 512;
|
|
|
|
fs_len = ech_numblk*512;
|
|
|
|
fs_base = realloc(fs_base, fs_len);
|
|
|
|
if(!fs_base) { fprintf(stderr,"mkbootimg: %s\r\n",lang[ERR_MEM]); exit(1); }
|
|
|
|
memset(fs_base, 0, fs_len);
|
|
|
|
/* superblock */
|
|
|
|
memcpy(fs_base + 4, "_ECH_FS_", 8);
|
|
|
|
memcpy(fs_base + 12, &ech_numblk, 8);
|
|
|
|
j = (ech_maxents * sizeof(ech_entry_t) + 511) / 512;
|
|
|
|
memcpy(fs_base + 20, &j, 8);
|
|
|
|
j = 512;
|
|
|
|
memcpy(fs_base + 28, &j, 8);
|
|
|
|
memcpy(fs_base + 40, &ech_uuid, 16);
|
|
|
|
/* allocation table */
|
|
|
|
for(i = 0, ptr = (uint64_t*)(fs_base + 16 * 512); i < offs; i++, ptr++)
|
|
|
|
*ptr = UINT64_C(0xfffffffffffffff0);
|
|
|
|
/* directory entries */
|
|
|
|
ent = (ech_entry_t*)(fs_base + (16 + (ech_numblk * 8 + 511) / 512) * 512);
|
|
|
|
for(i = 0; (int)i < ech_numents; i++, ent++) {
|
|
|
|
memcpy(ent, &ech_ents[i], sizeof(ech_entry_t));
|
|
|
|
if(!ent->type) {
|
|
|
|
if(!ent->size)
|
|
|
|
ent->payload = UINT64_C(0xffffffffffffffff);
|
|
|
|
else {
|
|
|
|
ent->payload += offs;
|
|
|
|
j = ent->payload + 1;
|
|
|
|
while(ech_ents[i].size > 512) {
|
|
|
|
ech_ents[i].size -= 512;
|
|
|
|
*ptr++ = j++;
|
|
|
|
}
|
|
|
|
*ptr++ = UINT64_C(0xffffffffffffffff);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* file data */
|
|
|
|
if(ech_data && ech_size)
|
|
|
|
memcpy(fs_base + offs * 512, ech_data, ech_size);
|
|
|
|
/* free resources */
|
|
|
|
if(ech_ents) { free(ech_ents); ech_ents = NULL; }
|
|
|
|
ech_numents = 0;
|
|
|
|
ech_maxents = 0;
|
|
|
|
if(ech_data) { free(ech_data); ech_data = NULL; }
|
|
|
|
ech_size = 0;
|
|
|
|
ech_numblk = 0;
|
|
|
|
}
|