mirror of
https://gitlab.com/bztsrc/bootboot.git
synced 2023-02-13 20:54:32 -05:00
mkbootimg generating LFN FAT and Minix3 file systems
This commit is contained in:
parent
d7e8e7d9fc
commit
c74b2a0d67
18 changed files with 823 additions and 73 deletions
|
@ -1,7 +1,7 @@
|
|||
TARGET = mkbootimg
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -ansi -pedantic
|
||||
CFLAGS = -Wall -Wextra -ansi -pedantic -g
|
||||
SRCS = $(filter-out bin2h.c data.c,$(wildcard *.c)) data.c
|
||||
|
||||
ifneq ("$(wildcard /bin/*.exe)","")
|
||||
|
|
|
@ -7,7 +7,8 @@ Ez egy minden az egyben, többplatformos, függőség nélküli lemezkép kreál
|
|||
forgatva). Egy lemezkonfigurációt kell megadni neki JSON-ben, és létrehozza az ESP FAT boot partíciót a szükséges betöltő
|
||||
fájlokkal, GPT táblával, PMBR-el, stb. Továbbá képes létrehozni az induló memórialemezképet egy könyvtár tartalmából (jelenleg
|
||||
`cpio`, `tar`, `jamesm` (James Molloy initrdje), `echfs` és az `FS/Z` támogatott, de a kód úgy lett megírva, hogy könnyű legyen
|
||||
bővíteni).
|
||||
bővíteni). Szemben ezzel, könyvtárból generálható partíció `fat` (hosszú fájlnevekkel), `minix` (Minix V3, POSIX
|
||||
jogosultságokkal és eszközfájlokkal), `tar`, `echfs`, `FS/Z` fájlrendszerekhez.
|
||||
|
||||
A kigenerált képet leellenőriztem fdisk-el, valamint a gdisk verify funkciójával. A FAT partíció tesztelve lett fsck.vfat-al
|
||||
és UEFI förmverrel, továbbá Raspberry Pi-n. Az ISO9660-es rész iat-vel (ISO9660 Analyzer Tool) és Linux mounttal lett tesztelve.
|
||||
|
@ -23,7 +24,7 @@ BOOTBOOT mkbootimg utility - bztsrc@gitlab
|
|||
Raspbery Pi Firmware Copyright (c) Broadcom Corp, Raspberry Pi (Trading) Ltd
|
||||
|
||||
Ellenőrzi, hogy az ELF vagy PE futtatható BOOTBOOT kompatíbilis-e, illetve
|
||||
hibrid indító lemez képet generál a hobbi OS-edhez vagy Option ROM képet.
|
||||
hibrid indító lemez képet vagy Option ROM képet generál a hobbi OS-edhez.
|
||||
|
||||
Használat:
|
||||
./mkbootimg check <kernel elf / pe>
|
||||
|
@ -121,22 +122,25 @@ fix "EFI System Partition" névvel. Ugyanezért a `size` méret megadása kötel
|
|||
| size | szám | opcionális, a partíció mérete Megabájtban. Ha nincs megadva, kiszámolja |
|
||||
| file | fájlnév | opcionális, a használandó partíciókép elérési útja |
|
||||
| directory | mappa | opcionális, mappa elérési útja, a tarmalmából fogja generálni a partícióképet |
|
||||
| driver | sztring | opcionális, ha a paríció típusa nem határozná meg egyértelműen a formátumot |
|
||||
| type | sztring | a partíció formátuma. Érvénytelen esetén listázza a lehetőségeket |
|
||||
| name | sztring | UTF-8 partíciónév, korlátozva a 32 és 65535 közötti UNICODE kódpontokra (BMP) |
|
||||
|
||||
Az első elem esetén a `type` lehetséges értékei: `boot` (vagy explicit `fat16` és `fat32`). A parancs igyekszik kényelmesen
|
||||
használni ezeket, ha lehet FAT16-ot választva, helytakarékosság miatt. A boot partíció minimális mérete 16 Megabájt. Bár mind
|
||||
a lemezkép készítő, mind a BOOTBOOT betöltő képes lenne kezelni kissebb méretet, néhány UEFI förmver helytelenül FAT12-nek
|
||||
hiszi, ha túl kevés kluszter van a fájlrendszeren. Ha a partíció mérete meghaladja a 128 Megabájtot, akkor automatikusan
|
||||
FAT32-t választ. Ha nem használsz `iso9660`-t, akkor kissebb méretű is lehet, de legalább 33 Megabájt (ez a FAT32 minimális
|
||||
mérete). Ugyanakkor `iso9660` használata esetén garantálni kell, hogy minden kluszter 2048 bájtos címen kezdődjön, amit
|
||||
4 szektor per kluszterrel a legegyszerűbb elérni. Itt is ugyanaz a probléma merül fel, mind a lemezkép készítő, mind a
|
||||
BOOTBOOT betöltők képesek lennének kevessebb kluszterrel is használni a FAT32-t, de néhány UEFI förmver nem, és hibásan
|
||||
FAT16-nak látná. Hogy ezt elkerüljük a minimális kluszterszámmal, az ISO9960 és FAT32 együttes használata esetén a
|
||||
partíció minimális mérete 128 Megabájt (128\*1024\*1024/512/4 = 65536, ami pont eggyel több, mint ami még 16 bitbe belefér).
|
||||
Az első elem esetén a `type` lehetséges értékei: `boot` (vagy explicit `fat16` és `fat32`). Csak 8+3 fájlneveket generál.
|
||||
A parancs igyekszik kényelmesen kezelni ezt, ha lehet FAT16-ot választva, helytakarékosság miatt. A boot partíció
|
||||
minimális mérete 16 Megabájt. Bár mind a lemezkép készítő, mind a BOOTBOOT betöltő képes lenne kezelni kissebb méretet,
|
||||
néhány UEFI förmver helytelenül FAT12-nek hiszi, ha túl kevés kluszter van a fájlrendszeren. Ha a partíció mérete meghaladja
|
||||
a 128 Megabájtot, akkor automatikusan FAT32-t választ. Ha nem használsz `iso9660`-t, akkor kissebb méretű is lehet, de
|
||||
legalább 33 Megabájt (ez a FAT32 minimális mérete). Ugyanakkor `iso9660` használata esetén garantálni kell, hogy minden
|
||||
kluszter 2048 bájtos címen kezdődjön, amit 4 szektor per kluszterrel a legegyszerűbb elérni. Itt is ugyanaz a probléma merül
|
||||
fel, mind a lemezkép készítő, mind a BOOTBOOT betöltők képesek lennének kevessebb kluszterrel is használni a FAT32-t, de
|
||||
néhány UEFI förmver nem, és hibásan FAT16-nak látná. Hogy ezt elkerüljük a minimális kluszterszámmal, az ISO9960 és FAT32
|
||||
együttes használata esetén a partíció minimális mérete 128 Megabájt (128\*1024\*1024/512/4 = 65536, ami pont eggyel több,
|
||||
mint ami még 16 bitbe belefér).
|
||||
|
||||
A többi (a másodiktól kezdve) bejegyzés esetén a `type` vagy egy GUID, vagy egy az előre definiált aliaszok közül. Érvénytelen
|
||||
sztring esetén a parancs listázza az összes lehetséges értéket.
|
||||
A többi (a másodiktól kezdve) bejegyzés esetén a `type` vagy egy GUID, vagy egy az előre definiált aliaszok közül. Itt a
|
||||
`fat` meghajtó csakis a kluszterek száma alapján dönt, hogy FAT16 vagy FAT32 legyen-e, és hosszú fájlneveket is generál.
|
||||
Érvénytelen sztring esetén a parancs listázza az összes lehetséges értéket.
|
||||
|
||||
Példa:
|
||||
```
|
||||
|
@ -167,10 +171,12 @@ akkor a kölönbséget nullákkal tölti fel. A partíció mérete mindig `align
|
|||
a partíciók 1 Megabájtos címekre lesznek igazítva. Az első bejegyzés esetén csak a `size` használható, a `file` nem.
|
||||
Alternatívaként esetleg használható a `directory` a `file` helyett, amennyiben a `type`-nál megadott típushoz van
|
||||
fájlrendszer meghajtó implementálva. Ekkor a megadott mappa tartalmából generálódik a partíció tartalma. Mivel nem feltétlenül
|
||||
van egy-az-egyhez megfeleltetés a fájlrendszer típus és a partíció típus között, ezért használható a `typeguid` az utóbbi
|
||||
explicit megadására. Erre csak a `directory` direktíva használata esetén lehet szükség. Példa:
|
||||
van egy-az-egyhez megfeleltetés a partíció típus és a fájlrendszer típus között, ezért használható a `driver` az utóbbi
|
||||
explicit megadására. Erre csak a `directory` direktíva használata esetén lehet szükség. Példák:
|
||||
```
|
||||
{ "type": "FS/Z", "typeguid": "5A2F534F-8664-5346-2F5A-000075737200", "size": 32, "name": "MyOS usr", "directory": "myusr" },
|
||||
{ "type": "5A2F534F-8664-5346-2F5A-000075737200", "driver": "FS/Z", "size": 32, "name": "usr", "directory": "myusr" },
|
||||
{ "type": "Linux home", "driver": "minix", "size": 32, "name": "home", "directory": "myhome" },
|
||||
{ "type": "Microsoft basic data", "driver": "fat", "size": 32, "name": "data", "directory": "mydata" },
|
||||
```
|
||||
|
||||
Végezetül a `name` egy sima UTF-8 sztring, a partíció neve. Maximális hossza 35 karakter. Az első partíciónál nem használható.
|
||||
|
@ -187,17 +193,20 @@ void somefs_add(struct stat *st, char *name, int pathlen, unsigned char *content
|
|||
void somefs_close();
|
||||
```
|
||||
|
||||
Az első akkor hívódik, amikor egy új fájlrendszert kell létrehozni. Itt a `gpt_entry` mutató NULL, ha memórialemezkép kreáláshoz
|
||||
hívódik a meghajtó. Ahogy a megadott mappát rekurzívan bejárja, minden almappa és fájl esetén meghívódik az "add". Ez hozzá
|
||||
kell adja a fájlt vagy mappát a fájlrendszer képéhez. Az `st` a stat struktúra, `name` a fájl neve teljes elérési úttal,
|
||||
Az első, az "open" akkor hívódik, amikor egy új fájlrendszert kell létrehozni. Itt a `gpt_entry` mutató NULL, ha memórialemezkép
|
||||
kreáláshoz hívódik a meghajtó. Ahogy a megadott mappát rekurzívan bejárja, minden almappa és fájl esetén meghívódik az "add". Ez
|
||||
hozzá kell adja a fájlt vagy mappát a fájlrendszer képéhez. Az `st` a stat struktúra, `name` a fájl neve teljes elérési úttal,
|
||||
a `content` és a `size` pedig a fájl tartalma, illetve szimbolikus hivatkozások esetén a mutatott elérési út. Végezetül amikor a
|
||||
bejárásnak vége, a close hívódik meg, hogy lezárja és véglegesítse a lemezképet. Ezek közül csak az "add" a kötelező, a másik
|
||||
bejárásnak vége, a "close" hívódik meg, hogy lezárja és véglegesítse a lemezképet. Ezek közül csak az "add" a kötelező, a másik
|
||||
kettő opcionális.
|
||||
|
||||
Ezek a funkciók elérnek két globális változót, az `fs_base`-t és `fs_len`-t, amik a lemezkép memóriabeli bufferét jelölik.
|
||||
Ezek a funkciók elérnek két globális változót, az `fs_base`-t és `fs_len`-t, amik a lemezkép memóriabeli bufferét jelölik
|
||||
(ebből következik, hogy a partíciók mérete pár gigabájt lehet, amennyi szabad memória van a gépedben). Ha hibát kell jelenteni,
|
||||
az `fs_no` változó tartalmazza annak a partíciónak a számát, amihez a meghajtó éppen generál.
|
||||
|
||||
Ezen függvények hiányában, a fájlrendszer továbbra is használható a partíciók `type` mezőjében, de ekkor csak a GPT bejegyzést
|
||||
hozza létre, magát a partíció tartalmát nem.
|
||||
hozza létre, magát a partíció tartalmát nem. A `driver` mezőben csak olyan fájlrendszer típus adható meg, ami rendelkezik ezekkel
|
||||
a funkciókkal.
|
||||
|
||||
A beépített binárisok naprakészen tartása
|
||||
-----------------------------------------
|
||||
|
|
|
@ -6,7 +6,9 @@ See [BOOTBOOT Protocol](https://gitlab.com/bztsrc/bootboot) for common details.
|
|||
This is an all-in-one, multiplatform, dependency-free disk image creator tool. You pass a disk configuration to it in a very
|
||||
flexible JSON, and it generates ESP FAT boot partition with the required loader files, GPT partitioning table, PMBR, etc. It
|
||||
also creates an initrd from a directory (currently `cpio`, `tar`, `jamesm` (James Molloy's initrd), `echfs` and `FS/Z`
|
||||
supported, but the code is written in a way that it is easily expandable).
|
||||
supported, but the code is written in a way that it is easily expandable). In contrast, partitions can be generated from
|
||||
directories for `fat` (with long file names), `minix` (Minix V3 with POSIX permissions and device files), `tar`, `echfs`,
|
||||
`FS/Z` filesystems.
|
||||
|
||||
The generated image was tested with fdisk, and with the verify function of gdisk. The FAT partition was tested with fsck.vfat
|
||||
and with TianoCore UEFI firmware and on Raspberry Pi. The ISO9660 part tested with iat (ISO9660 Analyzer Tool) and Linux mount.
|
||||
|
@ -22,7 +24,7 @@ BOOTBOOT mkbootimg utility - bztsrc@gitlab
|
|||
Raspbery Pi Firmware Copyright (c) Broadcom Corp, Raspberry Pi (Trading) Ltd
|
||||
|
||||
Validates ELF or PE executables for being BOOTBOOT compatible, otherwise
|
||||
creates a bootable hybrid image for your hobby OS or Option ROM image.
|
||||
creates a bootable hybrid image or Option ROM image for your hobby OS.
|
||||
|
||||
Usage:
|
||||
./mkbootimg check <kernel elf / pe>
|
||||
|
@ -120,21 +122,23 @@ for the first (boot) partition.
|
|||
| size | integer | optional, the size of the partition in Megabytes. If not given, it is calculated |
|
||||
| file | filename | optional, path to a partition image to be used |
|
||||
| directory | folder | optional, path to a folder, its contents will be used to generate the partition |
|
||||
| driver | string | optional, in case type can't specify the format without a doubt |
|
||||
| type | string | format of the partition. When invalid value given, it lists the options |
|
||||
| name | string | UTF-8 partition names, limited to UNICODE code points 32 to 65535 (BMP) |
|
||||
|
||||
For the first entry, valid values for `type` are: `boot` (or explicit `fat16` and `fat32`). The utility handles these
|
||||
comfortably, it tries to use FAT16 if possible to save storage space. There's a minimal size for the boot partition,
|
||||
16 Megabytes. Although both the image creator and BOOTBOOT is capable of handling smaller sizes, some UEFI firmware
|
||||
incorrectly assumes FAT12 when there are too few clusters on the file system. If the partition size is bigger than
|
||||
128 Megabytes, then it automatically switches to FAT32. If you don't use `iso9660`, then you can also set FAT32 for
|
||||
smaller images, but at least 33 Megabytes (that's a hard lower limit for FAT32). With `iso9660`, each cluster must
|
||||
For the first entry, valid values for `type` are: `boot` (or explicit `fat16` and `fat32`). Generates only 8+3 file names.
|
||||
The utility handles this comfortably, it tries to use FAT16 if possible to save storage space. There's a minimal size
|
||||
for the boot partition, 16 Megabytes. Although both the image creator and BOOTBOOT is capable of handling smaller sizes,
|
||||
some UEFI firmware incorrectly assumes FAT12 when there are too few clusters on the file system. If the partition size is
|
||||
bigger than 128 Megabytes, then it automatically switches to FAT32. If you don't use `iso9660`, then you can also set FAT32
|
||||
for smaller images, but at least 33 Megabytes (that's a hard lower limit for FAT32). With `iso9660`, each cluster must
|
||||
be 2048 bytes aligned, which is achieved by 4 sectors per cluster. The same problem applies here, both the image
|
||||
creator and the BOOTBOOT loader capable of handling FAT32 with smaller cluster numbers, but some UEFI firmware don't,
|
||||
and falsely assumes FAT16. To guarantee the minimum number of clusters, with ISO9660 and FAT32 the boot partition's
|
||||
minimum size is 128 Megabytes (128\*1024\*1024/512/4 = 65536, just one larger than what fits in 16 bits).
|
||||
|
||||
For the other entries (starting from the second), `type` is either a GUID or one of a pre-defined file system aliases.
|
||||
Here `fat` will decide between FAT16 and FAT32 based on the number of clusters, and it can generate long file names.
|
||||
With an invalid string, the utility will list all possible values.
|
||||
|
||||
Example:
|
||||
|
@ -164,12 +168,14 @@ If `file` given, then the partition is filled with data from that file. If `size
|
|||
the file's size, then the file's size will be the partition's size. If both given, and `size` is larger, then the
|
||||
difference is filled up with zeros. Partition sizes will always be multiple of `align` Kilobytes. Using 1024
|
||||
as alignment gives you 1 Megabyte aligned partitions. For the first entry, only `size` is valid, `file` isn't.
|
||||
Alternatively to `file`, you might also able to use `directory` to generate the partition image from the contents
|
||||
Alternatively to `file`, you might also be able to use `directory` to generate the partition image from the contents
|
||||
of a directory. This option is only available if the file system driver is implemented for `type`. Because there might
|
||||
be no one-to-one relation between file system types and partition types, you can use `typeguid` to explicily set the
|
||||
be no one-to-one relation between partition types and file system types, you can use `driver` to explicily set the
|
||||
latter. This is only relevant when the `directory` directive is used. For example:
|
||||
```
|
||||
{ "type": "FS/Z", "typeguid": "5A2F534F-8664-5346-2F5A-000075737200", "size": 32, "name": "MyOS usr", "directory": "myusr" },
|
||||
{ "type": "5A2F534F-8664-5346-2F5A-000075737200", "driver": "FS/Z", "size": 32, "name": "usr", "directory": "myusr" },
|
||||
{ "type": "Linux home", "driver": "minix", "size": 32, "name": "home", "directory": "myhome" },
|
||||
{ "type": "Microsoft basic data", "driver": "fat", "size": 32, "name": "data", "directory": "mydata" },
|
||||
```
|
||||
|
||||
Finally, `name` is just an UTF-8 string, name of the partition. Maximum length is 35 characters. Not valid for the first entry.
|
||||
|
@ -177,7 +183,7 @@ Finally, `name` is just an UTF-8 string, name of the partition. Maximum length i
|
|||
Adding More File Systems
|
||||
------------------------
|
||||
|
||||
These are listed in the fs registry, in the file `fs.h`. You can freely add new types. For file systems that you
|
||||
Types are listed in the fs registry, in the file `fs.h`. You can freely add new file system types. For file systems that you
|
||||
want to use for generating partition images or initrd as well, you must implement three functions, like:
|
||||
|
||||
```
|
||||
|
@ -186,17 +192,18 @@ void somefs_add(struct stat *st, char *name, unsigned char *content, int size);
|
|||
void somefs_close();
|
||||
```
|
||||
|
||||
The first is called whenever a new file system is to be created. The `gpt_entry` is NULL when called for initrd creation.
|
||||
As the given directory is recursively parsed, for each directory entry an "add" call is made. This should add the file or
|
||||
directory to the file system image. Here `st` is the stat struct for the file, `name` is the filename with full path,
|
||||
The first, the "open" is called whenever a new file system is to be created. The `gpt_entry` is NULL when called for initrd
|
||||
creation. As the given directory is recursively parsed, for each directory entry an "add" call is made. This should add the
|
||||
file or directory to the file system image. Here `st` is the stat struct for the file, `name` is the filename with full path,
|
||||
`content` and `size` are the file's content, or in case of a symbolic link, the pointed path. Finally when the parsing is
|
||||
done, the close function is called to finalize the image. Only the "add" function is mandatory, the other two are optional.
|
||||
done, the "close" function is called to finalize the image. Only the "add" function is mandatory, the other two are optional.
|
||||
|
||||
These functions can use two global variables, `fs_base` and `fs_len` which holds the buffer for the filesystem image
|
||||
in memory.
|
||||
in memory (this implies that partitions are limited to few gigabytes, depending how much RAM you have). In case they want
|
||||
to report error, `fs_no` is the number of the partition the driver is generating for.
|
||||
|
||||
In lack of these functions, the file system still can be used in the partition's `type` field, but then only the GPT entry
|
||||
will be created, not the content of the partition.
|
||||
will be created, not the content of the partition. The `driver` field only accepts file system types which have these functions.
|
||||
|
||||
Keeping the built-in binaries up-to-date
|
||||
----------------------------------------
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
void cpio_open(gpt_t *gpt_entry)
|
||||
{
|
||||
(void)gpt_entry;
|
||||
if(gpt_entry) { fprintf(stderr,"mkbootimg: partition #%d %s cpio.\r\n", fs_no, lang[ERR_INITRDTYPE]); exit(1); }
|
||||
}
|
||||
|
||||
void cpio_add(struct stat *st, char *name, unsigned char *content, int size)
|
||||
|
|
|
@ -52,8 +52,11 @@ uint64_t ech_numblk;
|
|||
|
||||
void ech_open(gpt_t *gpt_entry)
|
||||
{
|
||||
if(gpt) {
|
||||
if((gpt_entry->last - gpt_entry->start) < 1) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_NOSIZE]); exit(1); }
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
@ -84,10 +87,17 @@ void ech_add(struct stat *st, char *name, unsigned char *content, int size)
|
|||
parent = ech_ents[i].payload;
|
||||
fn = end + 1;
|
||||
end = *end ? strchr(fn, '/') : NULL;
|
||||
if(!end) { end = fn + strlen(name); break; }
|
||||
if(!end) { end = fn + strlen(fn); break; }
|
||||
}
|
||||
}
|
||||
if(ech_maxents && ech_numents + 1 >= ech_maxents) { fprintf(stderr,"mkbootimg: %s\r\n",lang[ERR_TOOMANY]); exit(1); }
|
||||
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);
|
||||
}
|
||||
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));
|
||||
|
|
302
mkbootimg/fat.c
Normal file
302
mkbootimg/fat.c
Normal file
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
* mkbootimg/fat.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 normal (non-ESP) FAT16/32 file system driver with long filename support
|
||||
*
|
||||
*/
|
||||
#include "main.h"
|
||||
|
||||
#define SECTOR_PER_CLUSTER 1
|
||||
|
||||
struct tm *fat_ts;
|
||||
int fat_nextcluster, fat_bpc, fat_spf, fat_lfncnt, fat_numclu;
|
||||
unsigned char *fat_rootdir, *fat_data, fat_lfn[769];
|
||||
uint16_t *fat_fat16_1, *fat_fat16_2;
|
||||
uint32_t *fat_fat32_1, *fat_fat32_2;
|
||||
|
||||
unsigned char *fat_newclu(int parent)
|
||||
{
|
||||
int clu;
|
||||
if(fat_fat16_1) {
|
||||
while(parent != fat_nextcluster && fat_fat16_1[parent] && fat_fat16_1[parent] != 0xFFFF)
|
||||
parent = fat_fat16_1[parent];
|
||||
fat_fat16_1[parent] = fat_fat16_2[parent] = fat_nextcluster;
|
||||
fat_fat16_1[fat_nextcluster] = fat_fat16_2[fat_nextcluster] = 0xFFFF;
|
||||
} else {
|
||||
while(parent != fat_nextcluster && fat_fat32_1[parent] && fat_fat32_1[parent] != 0xFFFFFFF)
|
||||
parent = fat_fat32_1[parent];
|
||||
fat_fat32_1[parent] = fat_fat32_2[parent] = fat_nextcluster;
|
||||
fat_fat32_1[fat_nextcluster] = fat_fat32_2[fat_nextcluster] = 0xFFFFFFF;
|
||||
}
|
||||
clu = fat_nextcluster++;
|
||||
if(fat_nextcluster >= fat_numclu) { fprintf(stderr,"mkbootimg: partition #%d %s\r\n", fs_no, lang[ERR_TOOBIG]); exit(1); }
|
||||
return fat_data + clu * fat_bpc;
|
||||
}
|
||||
|
||||
unsigned char *fat_readlfn(unsigned char *dir, int *clu, int *size, int parent)
|
||||
{
|
||||
uint16_t uc2[256], *u;
|
||||
unsigned char *s, *d;
|
||||
int i, n;
|
||||
memset(fat_lfn, 0, sizeof(fat_lfn));
|
||||
if(!dir[0]) return dir;
|
||||
while(dir[0] == '.') dir += 32;
|
||||
fat_lfncnt++;
|
||||
if(parent != 2 && !((uint64_t)(dir - fs_base) & (fat_bpc - 1))) {
|
||||
if(fat_fat16_1) {
|
||||
parent = fat_fat16_1[parent];
|
||||
if(!parent || parent == 0xFFFF) return NULL;
|
||||
} else {
|
||||
parent = fat_fat32_1[parent];
|
||||
if(!parent || parent == 0xFFFFFFF) return NULL;
|
||||
}
|
||||
dir = fat_data + parent * fat_bpc;
|
||||
}
|
||||
if(dir[0xB] != 0xF) {
|
||||
for(s = dir, d = fat_lfn; *s && *s != ' ' && i < 8; i++)
|
||||
*d++ = *s++;
|
||||
if(dir[8] && dir[8] != ' ') {
|
||||
*d++ = '.';
|
||||
for(s = dir + 8; *s != ' ' && i < 3; i++)
|
||||
*d++ = *s++;
|
||||
}
|
||||
} else {
|
||||
memset(uc2, 0, sizeof(uc2));
|
||||
n = dir[0] & 0x3F;
|
||||
u = uc2 + (n - 1) * 13;
|
||||
while(n--) {
|
||||
for(i = 0; i < 5; i++)
|
||||
u[i] = dir[i*2+2] << 8 | dir[i*2+1];
|
||||
for(i = 0; i < 6; i++)
|
||||
u[i+5] = dir[i*2+0xF] << 8 | dir[i*2+0xE];
|
||||
u[11] = dir[0x1D] << 8 | dir[0x1C];
|
||||
u[12] = dir[0x1F] << 8 | dir[0x1E];
|
||||
u -= 13;
|
||||
dir += 32;
|
||||
if(!((uint64_t)(dir - fs_base) & (fat_bpc - 1))) {
|
||||
if(fat_fat16_1) {
|
||||
parent = fat_fat16_1[parent];
|
||||
if(!parent || parent == 0xFFFF) return NULL;
|
||||
} else {
|
||||
parent = fat_fat32_1[parent];
|
||||
if(!parent || parent == 0xFFFFFFF) return NULL;
|
||||
}
|
||||
dir = fat_data + parent * fat_bpc;
|
||||
}
|
||||
}
|
||||
for(d = fat_lfn, u = uc2; *u; u++)
|
||||
if(*u < 0x80) {
|
||||
*d++ = *u;
|
||||
} else if(*u < 0x800) {
|
||||
*d++ = ((*u>>6)&0x1F)|0xC0;
|
||||
*d++ = (*u&0x3F)|0x80;
|
||||
} else {
|
||||
*d++ = ((*u>>12)&0x0F)|0xE0;
|
||||
*d++ = ((*u>>6)&0x3F)|0x80;
|
||||
*d++ = (*u&0x3F)|0x80;
|
||||
}
|
||||
}
|
||||
*clu = (dir[0x15] << 24) | (dir[0x14] << 16) | (dir[0x1B] << 8) | dir[0x1A];
|
||||
*size = (dir[0x1F] << 24) | (dir[0x1E] << 16) | (dir[0x1D] << 8) | dir[0x1C];
|
||||
return dir + 32;
|
||||
}
|
||||
|
||||
unsigned char *fat_writelfn(unsigned char *dir, char *name, int type, int size, int parent, int clu)
|
||||
{
|
||||
uint16_t uc2[256], *u;
|
||||
unsigned char *s, c = 0, sfn[12];
|
||||
int i, n;
|
||||
if(name[0] == '.') {
|
||||
memset(dir, ' ', 11);
|
||||
memcpy(dir, name, strlen(name));
|
||||
} else {
|
||||
memset(uc2, 0, sizeof(uc2));
|
||||
for(n = 0, u = uc2, s = (unsigned char*)name; *s; n++, u++) {
|
||||
if((*s & 128) != 0) {
|
||||
if((*s & 32) == 0) { *u = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); s += 2; } else
|
||||
if((*s & 16) == 0) { *u = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); s += 3; }
|
||||
else { fprintf(stderr,"mkbootimg: partition #%d %s '%s'\r\n", fs_no, lang[ERR_WRITE], name); exit(1); }
|
||||
} else
|
||||
*u = *s++;
|
||||
}
|
||||
/* don't convert "Microsoft" to "MICROS~1 ", that's patented... */
|
||||
sprintf((char*)sfn, "~%07xLFN", fat_lfncnt++);
|
||||
for(i = 0; i < 11; i++)
|
||||
c = (((c & 1) << 7) | ((c & 0xfe) >> 1)) + sfn[i];
|
||||
n = (n + 12) / 13;
|
||||
u = uc2 + (n - 1) * 13;
|
||||
i = 0x40;
|
||||
while(n--) {
|
||||
if(parent > 2 && !((uint64_t)(dir - fs_base) & (fat_bpc - 1)))
|
||||
dir = fat_newclu(parent);
|
||||
dir[0] = i | (n + 1);
|
||||
dir[11] = 0xF;
|
||||
dir[0xD] = c;
|
||||
memcpy(dir + 1, (unsigned char*)u, 10);
|
||||
memcpy(dir + 14, (unsigned char*)u + 10, 12);
|
||||
memcpy(dir + 28, (unsigned char*)u + 22, 4);
|
||||
i = 0;
|
||||
u -= 13;
|
||||
dir += 32;
|
||||
}
|
||||
if(parent > 2 && !((uint64_t)(dir - fs_base) & (fat_bpc - 1)))
|
||||
dir = fat_newclu(parent);
|
||||
memcpy(dir, sfn, 11);
|
||||
}
|
||||
if(type) {
|
||||
dir[0xB] = 0x10;
|
||||
} else {
|
||||
dir[0x1C] = size & 0xFF; dir[0x1D] = (size >> 8) & 0xFF;
|
||||
dir[0x1E] = (size >> 16) & 0xFF; dir[0x1F] = (size >> 24) & 0xFF;
|
||||
}
|
||||
if(!clu) clu = fat_nextcluster;
|
||||
if(clu < 3) clu = 0;
|
||||
dir[0x1A] = clu & 0xFF; dir[0x1B] = (clu >> 8) & 0xFF;
|
||||
dir[0x14] = (clu >> 16) & 0xFF; dir[0x15] = (clu >> 24) & 0xFF;
|
||||
i = (fat_ts->tm_hour << 11) | (fat_ts->tm_min << 5) | (fat_ts->tm_sec/2);
|
||||
dir[0xE] = dir[0x16] = i & 0xFF; dir[0xF] = dir[0x17] = (i >> 8) & 0xFF;
|
||||
i = ((fat_ts->tm_year+1900-1980) << 9) | ((fat_ts->tm_mon+1) << 5) | (fat_ts->tm_mday);
|
||||
return dir + 32;
|
||||
}
|
||||
|
||||
void fat_open(gpt_t *gpt_entry)
|
||||
{
|
||||
int i;
|
||||
if(!gpt_entry) { fprintf(stderr,"mkbootimg: %s fat.\r\n", lang[ERR_BADINITRDTYPE]); exit(1); }
|
||||
fat_numclu = (gpt_entry->last - gpt_entry->start + 1) / SECTOR_PER_CLUSTER;
|
||||
if(fat_numclu < 4085) { fprintf(stderr,"mkbootimg: partition #%d %s\r\n", fs_no, lang[ERR_NOSIZE]); exit(1); }
|
||||
/* "format" the partition to either FAT16 or FAT32 */
|
||||
fs_len = fat_numclu * 512 * SECTOR_PER_CLUSTER;
|
||||
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);
|
||||
memcpy(fs_base + 3, "MSWIN4.1", 8);
|
||||
fs_base[0xC] = 2; fs_base[0x10] = 2; fs_base[0x15] = 0xF8; fs_base[0x1FE] = 0x55; fs_base[0x1FF] = 0xAA;
|
||||
fs_base[0x18] = 0x20; fs_base[0x1A] = 0x40;
|
||||
memcpy(fs_base + 0x1C, &gpt_entry->start, 4);
|
||||
if(fat_numclu > 65535)
|
||||
memcpy(fs_base + 0x20, &fat_numclu, 4);
|
||||
else
|
||||
memcpy(fs_base + 0x13, &fat_numclu, 2);
|
||||
if(fat_numclu < 65525) {
|
||||
/* FAT16 */
|
||||
fat_spf = (fat_numclu*2 + 511) / 512;
|
||||
fs_base[0xD] = SECTOR_PER_CLUSTER; fs_base[0xE] = 4; fs_base[0x12] = 2;
|
||||
fs_base[0x16] = fat_spf & 0xFF; fs_base[0x17] = (fat_spf >> 8) & 0xFF;
|
||||
fs_base[0x24] = 0x80; fs_base[0x26] = 0x29;
|
||||
memcpy(fs_base + 0x27, &gpt_entry->guid, 4);
|
||||
memcpy(fs_base + 0x2B, "NO NAME FAT16 ", 19);
|
||||
fat_bpc = fs_base[0xD] * 512;
|
||||
fat_rootdir = fs_base + (fat_spf*fs_base[0x10]+fs_base[0xE]) * 512;
|
||||
fat_data = fat_rootdir + ((((fs_base[0x12]<<8)|fs_base[0x11])*32 - 2*fat_bpc) & ~(fat_bpc-1));
|
||||
fat_fat16_1 = (uint16_t*)(&fs_base[fs_base[0xE] * 512]);
|
||||
fat_fat16_2 = (uint16_t*)(&fs_base[(fs_base[0xE]+fat_spf) * 512]);
|
||||
fat_fat16_1[0] = fat_fat16_2[0] = 0xFFF8; fat_fat16_1[1] = fat_fat16_2[1] = 0xFFFF;
|
||||
fat_fat32_1 = fat_fat32_2 = NULL;
|
||||
} else {
|
||||
/* FAT32 */
|
||||
fat_spf = (fat_numclu*4) / 512 - 8;
|
||||
fs_base[0xD] = SECTOR_PER_CLUSTER; fs_base[0xE] = 8;
|
||||
fs_base[0x24] = fat_spf & 0xFF; fs_base[0x25] = (fat_spf >> 8) & 0xFF;
|
||||
fs_base[0x26] = (fat_spf >> 16) & 0xFF; fs_base[0x27] = (fat_spf >> 24) & 0xFF;
|
||||
fs_base[0x2C] = 2; fs_base[0x30] = 1; fs_base[0x32] = 6; fs_base[0x40] = 0x80; fs_base[0x42] = 0x29;
|
||||
memcpy(fs_base + 0x43, &gpt_entry->guid, 4);
|
||||
memcpy(fs_base + 0x47, "NO NAME FAT32 ", 19);
|
||||
memcpy(fs_base + 0x200, "RRaA", 4); memcpy(fs_base + 0x3E4, "rrAa", 4);
|
||||
for(i = 0; i < 8; i++) fs_base[0x3E8 + i] = 0xFF;
|
||||
fs_base[0x3FE] = 0x55; fs_base[0x3FF] = 0xAA;
|
||||
fat_bpc = fs_base[0xD] * 512;
|
||||
fat_rootdir = fs_base + (fat_spf*fs_base[0x10]+fs_base[0xE]) * 512;
|
||||
fat_data = fat_rootdir - 2*fat_bpc;
|
||||
fat_fat32_1 = (uint32_t*)(&fs_base[fs_base[0xE] * 512]);
|
||||
fat_fat32_2 = (uint32_t*)(&fs_base[(fs_base[0xE]+fat_spf) * 512]);
|
||||
fat_fat32_1[0] = fat_fat32_2[0] = fat_fat32_1[2] = fat_fat32_2[2] = 0x0FFFFFF8;
|
||||
fat_fat32_1[1] = fat_fat32_2[1] = 0x0FFFFFFF;
|
||||
fat_fat16_1 = fat_fat16_2 = NULL;
|
||||
}
|
||||
fat_nextcluster = 3;
|
||||
}
|
||||
|
||||
void fat_add(struct stat *st, char *name, unsigned char *content, int size)
|
||||
{
|
||||
int parent = 2, clu, i;
|
||||
unsigned char *dir = fat_rootdir;
|
||||
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;
|
||||
fat_ts = gmtime(&st->st_mtime);
|
||||
fn = name;
|
||||
end = strchr(name, '/');
|
||||
if(!end) end = name + strlen(name);
|
||||
fat_lfncnt = 1;
|
||||
do {
|
||||
dir = fat_readlfn(dir, &clu, &size, parent);
|
||||
if(!dir) return;
|
||||
if(!memcmp(fat_lfn, fn, end - fn) && !fat_lfn[end - fn]) {
|
||||
fat_lfncnt = 1;
|
||||
parent = clu;
|
||||
dir = fat_data + parent * fat_bpc + 64;
|
||||
fn = end + 1;
|
||||
end = *end ? strchr(fn, '/') : NULL;
|
||||
if(!end) { end = fn + strlen(fn); break; }
|
||||
}
|
||||
} while(dir[0]);
|
||||
dir = fat_writelfn(dir, fn, S_ISDIR(st->st_mode), size, parent, 0);
|
||||
if(S_ISDIR(st->st_mode)) {
|
||||
dir = fat_newclu(fat_nextcluster);
|
||||
dir = fat_writelfn(dir, ".", 1, 0, 2, fat_nextcluster - 1);
|
||||
dir = fat_writelfn(dir, "..", 1, 0, 2, parent);
|
||||
} else if(content && size > 0) {
|
||||
if(fat_nextcluster * fat_bpc + size >= fs_len) {
|
||||
fprintf(stderr,"mkbootimg: partition #%d %s\r\n", fs_no, lang[ERR_TOOBIG]);
|
||||
exit(1);
|
||||
}
|
||||
memcpy(fat_data + fat_nextcluster * fat_bpc, content, size);
|
||||
for(i = 0; i < ((size + fat_bpc-1) & ~(fat_bpc-1)); i += fat_bpc, fat_nextcluster++) {
|
||||
if(fat_fat16_1) fat_fat16_1[fat_nextcluster] = fat_fat16_2[fat_nextcluster] = fat_nextcluster+1;
|
||||
else fat_fat32_1[fat_nextcluster] = fat_fat32_2[fat_nextcluster] = fat_nextcluster+1;
|
||||
}
|
||||
if(fat_fat16_1) fat_fat16_1[fat_nextcluster-1] = fat_fat16_2[fat_nextcluster-1] = 0xFFFF;
|
||||
else fat_fat32_1[fat_nextcluster-1] = fat_fat32_2[fat_nextcluster-1] = 0xFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
void fat_close()
|
||||
{
|
||||
int i;
|
||||
if(!fs_base || fs_len < 512) return;
|
||||
if(fat_fat32_1) {
|
||||
fat_nextcluster -= 2;
|
||||
i = ((fs_len - (fat_spf*fs_base[0x10]+fs_base[0xE]) * 512)/fat_bpc) - fat_nextcluster;
|
||||
fs_base[0x3E8] = i & 0xFF; fs_base[0x3E9] = (i >> 8) & 0xFF;
|
||||
fs_base[0x3EA] = (i >> 16) & 0xFF; fs_base[0x3EB] = (i >> 24) & 0xFF;
|
||||
fs_base[0x3EC] = fat_nextcluster & 0xFF; fs_base[0x3ED] = (fat_nextcluster >> 8) & 0xFF;
|
||||
fs_base[0x3EE] = (fat_nextcluster >> 16) & 0xFF; fs_base[0x3EF] = (fat_nextcluster >> 24) & 0xFF;
|
||||
/* copy backup boot sectors */
|
||||
memcpy(fs_base + (fs_base[0x32]*512), fs_base, 1024);
|
||||
}
|
||||
}
|
|
@ -44,17 +44,28 @@ void ech_open(gpt_t *gpt_entry);
|
|||
void ech_add(struct stat *st, char *name, unsigned char *content, int size);
|
||||
void ech_close();
|
||||
|
||||
void mnx_open(gpt_t *gpt_entry);
|
||||
void mnx_add(struct stat *st, char *name, unsigned char *content, int size);
|
||||
void mnx_close();
|
||||
|
||||
void fat_open(gpt_t *gpt_entry);
|
||||
void fat_add(struct stat *st, char *name, unsigned char *content, int size);
|
||||
void fat_close();
|
||||
|
||||
void jamesm_open(gpt_t *gpt_entry);
|
||||
void jamesm_add(struct stat *st, char *name, unsigned char *content, int size);
|
||||
void jamesm_close();
|
||||
|
||||
/*** specify file system drivers and GPT file system types here ***/
|
||||
/* for simplicity, first list the ones with drivers, and types only afterwards */
|
||||
fsdrv_t fsdrv[] = {
|
||||
{ "jamesm", {0}, jamesm_open, jamesm_add, jamesm_close },
|
||||
{ "cpio", {0}, cpio_open, cpio_add, cpio_close },
|
||||
{ "tar", { 0x65706154, 0x4120, 0x6372, { 0x68,0x69,0x76,0x65,0x20,0x46,0x53,0x20} }, tar_open, tar_add, tar_close },
|
||||
{ "FS/Z", { 0x5A2F534F, 0x0000, 0x5346, { 0x2F,0x5A,0x00,0x00,0x00,0x00,0x00,0x00} }, fsz_open, fsz_add, fsz_close },
|
||||
{ "echfs", { 0x66686365, 0x6973, 0x7673, { 0x65,0x72,0x79,0x6C,0x61,0x6D,0x65,0x00} }, ech_open, ech_add, ech_close },
|
||||
{ "minix", { 0xB7AADF00, 0xDE27, 0x11CA, { 0xA5,0x74,0x56,0x72,0x69,0x6A,0x65,0x55} }, mnx_open, mnx_add, mnx_close },
|
||||
{ "fat", { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7} }, fat_open, fat_add, fat_close },
|
||||
{ "FS/Z", { 0x5A2F534F, 0x0000, 0x5346, { 0x2F,0x5A,0x00,0x00,0x00,0x00,0x00,0x00} }, fsz_open, fsz_add, fsz_close },
|
||||
{ "OS/Z usr (x86_64)", { 0x5A2F534F, 0x8664, 0x5346, { 0x2F,0x5A,0x00,0x00,0x75,0x73,0x72,0x00} }, NULL, NULL, NULL },
|
||||
{ "OS/Z usr (AArch64)", { 0x5A2F534F, 0xAA64, 0x5346, { 0x2F,0x5A,0x00,0x00,0x75,0x73,0x72,0x00} }, NULL, NULL, NULL },
|
||||
{ "OS/Z var", { 0x5A2F534F, 0x0000, 0x5346, { 0x2F,0x5A,0x00,0x00,0x76,0x61,0x72,0x00} }, NULL, NULL, NULL },
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "main.h"
|
||||
#include "fsZ.h"
|
||||
|
||||
int fsz_secsize = FSZ_SECSIZE, fsz_isinitrd = 0;
|
||||
int fsz_secsize = FSZ_SECSIZE, fsz_max = 0;
|
||||
unsigned char fsz_emptysec[FSZ_SECSIZE] = {0};
|
||||
|
||||
/* private functions */
|
||||
|
@ -44,6 +44,10 @@ 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);
|
||||
|
@ -110,7 +114,7 @@ void fsz_link_inode(int inode, char *path, int toinode)
|
|||
}
|
||||
/* 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);
|
||||
fprintf(stderr,"mkbootimg: partition #%d %s: %s\n", fs_no, lang[ERR_TOOMANY], path); exit(1);
|
||||
}
|
||||
hdr->numentries++;
|
||||
in->modifydate=t * 1000000;
|
||||
|
@ -130,6 +134,10 @@ void fsz_add_file(char *name, unsigned char *data, unsigned long int size)
|
|||
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);
|
||||
|
@ -147,7 +155,7 @@ void fsz_add_file(char *name, unsigned char *data, unsigned long int size)
|
|||
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){ 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->flags=FSZ_IN_FLAG_SDINLINE;
|
||||
|
@ -162,7 +170,7 @@ void fsz_add_file(char *name, unsigned char *data, unsigned long int size)
|
|||
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)) {
|
||||
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);
|
||||
|
@ -294,12 +302,12 @@ void fsz_open(gpt_t *gpt_entry)
|
|||
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;
|
||||
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_isinitrd = 1;
|
||||
fsz_max = 0;
|
||||
}
|
||||
memcpy(sb->magic2,FSZ_MAGIC,4);
|
||||
fs_len = fsz_secsize;
|
||||
|
|
|
@ -70,10 +70,6 @@ void gpt_maketable()
|
|||
for(i = 0; fsdrv[i].name; i++)
|
||||
if(fsdrv[i].type.Data1 && !strcmp(tmp, fsdrv[i].name)) { memcpy(&typeguid, &fsdrv[i].type, sizeof(guid_t)); break; }
|
||||
free(tmp);
|
||||
/* override with specific GUID if type was an fsname */
|
||||
sprintf(key, "partitions.%d.%s", np, "typeguid");
|
||||
tmp = json_get(json, key);
|
||||
if(tmp && *tmp) { getguid(tmp, &typeguid); free(tmp); }
|
||||
/* if there's still no type GUID */
|
||||
if(!typeguid.Data1 && !typeguid.Data2 && !typeguid.Data3 && !typeguid.Data4[0]) {
|
||||
fprintf(stderr,"mkbootimg: partition #%d %s. %s:\r\n", np+1, lang[ERR_TYPE], lang[ERR_ACCEPTVALUES]);
|
||||
|
@ -216,6 +212,7 @@ void gpt_maketable()
|
|||
else u[i] = 0;
|
||||
}
|
||||
}
|
||||
free(tmp);
|
||||
p += 128;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
void img_write(char *fn)
|
||||
{
|
||||
FILE *f, *d;
|
||||
int i, n, lastpercent, k;
|
||||
int i, j, n, lastpercent, k;
|
||||
char key[64], *tmp, *dir, *buf;
|
||||
unsigned long int size, pos;
|
||||
size_t s;
|
||||
|
@ -82,9 +82,13 @@ void img_write(char *fn)
|
|||
sprintf(key, "partitions.%d.%s", k, "directory");
|
||||
dir = json_get(json, key);
|
||||
if(dir && *dir) {
|
||||
fs_base = NULL; fs_len = 0;
|
||||
sprintf(key, "partitions.%d.%s", k, "type");
|
||||
fs_base = NULL; fs_len = 0; fs_no = k + 1;
|
||||
sprintf(key, "partitions.%d.%s", k, "driver");
|
||||
tmp = json_get(json, key);
|
||||
if(!tmp || !*tmp) {
|
||||
sprintf(key, "partitions.%d.%s", k, "type");
|
||||
tmp = json_get(json, key);
|
||||
}
|
||||
if(tmp && *tmp) {
|
||||
rd_open = NULL; rd_add = NULL; rd_close = NULL;
|
||||
for(i = 0; fsdrv[i].name && fsdrv[i].add; i++)
|
||||
|
@ -95,6 +99,16 @@ void img_write(char *fn)
|
|||
if(rd_open) (*rd_open)((gpt_t*)(gpt + 1024 + k * 128));
|
||||
parsedir(dir, 0);
|
||||
if(rd_close) (*rd_close)();
|
||||
} else {
|
||||
fprintf(stderr,"mkbootimg: partition #%d %s. %s:\r\n", np+1, lang[ERR_TYPE], lang[ERR_ACCEPTVALUES]);
|
||||
for(i = 0; fsdrv[i].name; i++)
|
||||
if(fsdrv[i].add) {
|
||||
fprintf(stderr," \"%08X-%04X-%04X-%02X%02X-",fsdrv[i].type.Data1,fsdrv[i].type.Data2,
|
||||
fsdrv[i].type.Data3, fsdrv[i].type.Data4[0],fsdrv[i].type.Data4[1]);
|
||||
for(j = 2; j < 8; j++) fprintf(stderr,"%02X",fsdrv[i].type.Data4[j]);
|
||||
fprintf(stderr,"\" / \"%s\"\r\n",fsdrv[i].name);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
free(dir);
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
void jamesm_open(gpt_t *gpt_entry)
|
||||
{
|
||||
(void)gpt_entry;
|
||||
if(gpt_entry) { fprintf(stderr,"mkbootimg: partition #%d %s jamesm.\r\n", fs_no, lang[ERR_INITRDTYPE]); exit(1); }
|
||||
fs_len = 4 + 64 * 73;
|
||||
fs_base = realloc(fs_base, fs_len);
|
||||
if(!fs_base) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_MEM]); exit(1); }
|
||||
|
|
|
@ -42,6 +42,7 @@ char *dict[NUMLANGS][NUMTEXTS + 1] = {
|
|||
"initrd not specified in json",
|
||||
"initrd type not specified in json",
|
||||
"invalid initrd type",
|
||||
"initrd-only type",
|
||||
"Accepted values",
|
||||
"unable to read BOOTBOOT configuration from",
|
||||
"BOOTBOOT configuration file is bigger than 4095 bytes",
|
||||
|
@ -71,7 +72,7 @@ char *dict[NUMLANGS][NUMTEXTS + 1] = {
|
|||
"must use valid static addresses",
|
||||
"valid dynamic addresses",
|
||||
"Validates ELF or PE executables for being BOOTBOOT compatible, otherwise",
|
||||
"creates a bootable hybrid image for your hobby OS or Option ROM image",
|
||||
"creates a bootable hybrid image or Option ROM image for your hobby OS",
|
||||
"Usage",
|
||||
"configuration json",
|
||||
"output disk image name",
|
||||
|
@ -87,6 +88,7 @@ char *dict[NUMLANGS][NUMTEXTS + 1] = {
|
|||
"initrd nincs megadva a json-ben",
|
||||
"initrd type nincs megadva a json-ben",
|
||||
"érvénytelen initrd type",
|
||||
"csak initrd-nél használható type",
|
||||
"Lehetséges értékek",
|
||||
"nem tudom beolvasni a BOOTBOOT konfigurációt innen",
|
||||
"a BOOTBOOT konfiguráció több, mint 4095 bájt",
|
||||
|
@ -116,7 +118,7 @@ char *dict[NUMLANGS][NUMTEXTS + 1] = {
|
|||
"helyes statikus címeket kell használnia",
|
||||
"érvényes dinamikus címek",
|
||||
"Ellenőrzi, hogy az ELF vagy PE futtatható BOOTBOOT kompatíbilis-e, illetve",
|
||||
"hibrid indító lemez képet generál a hobbi OS-edhez vagy Option ROM képet",
|
||||
"hibrid indító lemez képet vagy Option ROM képet generál a hobbi OS-edhez",
|
||||
"Használat",
|
||||
"konfigurációs json",
|
||||
"kimeneti lemezkép neve",
|
||||
|
@ -132,6 +134,7 @@ char *dict[NUMLANGS][NUMTEXTS + 1] = {
|
|||
"initrd nie jest opisany w pliku json",
|
||||
"typ initrd nie jest opisany w pliku json",
|
||||
"niepoprawny typ initrd",
|
||||
"nie ma poprawnego typu",
|
||||
"Akceptowane wartości",
|
||||
"nie udało się załadować konfiguracji BOOTBOOT z",
|
||||
"plik z konfiguracją BOOTBOOT jest większy niż 4095 bajtów",
|
||||
|
@ -161,7 +164,7 @@ char *dict[NUMLANGS][NUMTEXTS + 1] = {
|
|||
"musi używać poprawnych statycznych adresów",
|
||||
"poprawny dynamiczny adres",
|
||||
"Sprawdza czy plik wykonywalny ELF lub PE jest kompatybilny z BOOTBOOT, w przeciwnym wypadku",
|
||||
"tworzy boot-owalny obraz hybrydoway z twoim hobbistycznym OS lub \"Option ROM image\"",
|
||||
"tworzy boot-owalny obraz hybrydoway lub \"Option ROM image\" z twoim hobbistycznym OS",
|
||||
"Sposoby użytkowania",
|
||||
"plik konfiguracyjny json",
|
||||
"nazwa wyjściowego pliku obrazu dysku",
|
||||
|
|
|
@ -34,6 +34,7 @@ enum {
|
|||
ERR_NOINITRD,
|
||||
ERR_NOINITRDTYPE,
|
||||
ERR_BADINITRDTYPE,
|
||||
ERR_INITRDTYPE,
|
||||
ERR_ACCEPTVALUES,
|
||||
ERR_NOCONF,
|
||||
ERR_BIGCONF,
|
||||
|
|
|
@ -463,13 +463,14 @@ int main(int argc, char **argv)
|
|||
parsekernel(i, data, 0);
|
||||
free(data);
|
||||
skipbytes = strlen(initrd_dir[i]) + 1;
|
||||
fs_base = NULL; fs_len = 0;
|
||||
fs_base = NULL; fs_len = 0; fs_no = 0;
|
||||
if(rd_open) (*rd_open)(NULL);
|
||||
parsedir(initrd_dir[i], 0);
|
||||
if(rd_close) (*rd_close)();
|
||||
initrdcompress();
|
||||
initrd_buf[i] = fs_base;
|
||||
initrd_size[i] = fs_len;
|
||||
free(initrd_dir[i]);
|
||||
} else
|
||||
if(initrd_buf[i]) {
|
||||
fs_base = initrd_buf[i]; fs_len = initrd_size[i];
|
||||
|
@ -519,6 +520,8 @@ int main(int argc, char **argv)
|
|||
free(kernelname);
|
||||
free(initrd_buf[0]);
|
||||
if(initrd_buf[1]) free(initrd_buf[1]);
|
||||
if(initrd_buf[2]) free(initrd_buf[2]);
|
||||
if(config) free(config);
|
||||
free(json);
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -185,8 +185,8 @@ extern time_t t;
|
|||
extern struct tm *ts;
|
||||
extern guid_t diskguid;
|
||||
extern char *json, *config, *kernelname, *initrd_dir[NUMARCH], initrd_arch[NUMARCH];
|
||||
extern int fs_len, initrd_size[NUMARCH], initrd_gzip, boot_size, boot_fat, disk_size, esp_size, esp_bbs, bbp_start, bbp_end;
|
||||
extern int iso9660, skipbytes, np;
|
||||
extern int fs_len, fs_no, initrd_size[NUMARCH], initrd_gzip, boot_size, boot_fat, disk_size, esp_size, esp_bbs;
|
||||
extern int iso9660, skipbytes, np, bbp_start, bbp_end;
|
||||
extern unsigned char *esp, *gpt, gpt2[512], *fs_base, *initrd_buf[NUMARCH];
|
||||
extern unsigned long int tsize, es, esiz, disk_align, gpt_parts[248];
|
||||
extern fsdrv_t fsdrv[];
|
||||
|
|
382
mkbootimg/minix.c
Normal file
382
mkbootimg/minix.c
Normal file
|
@ -0,0 +1,382 @@
|
|||
/*
|
||||
* mkbootimg/minix.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 Minix3 file system driver
|
||||
*
|
||||
*/
|
||||
#include "main.h"
|
||||
|
||||
typedef uint32_t zone_t; /* zone number */
|
||||
typedef uint32_t block_t; /* block number */
|
||||
typedef uint32_t bit_t; /* bit number in a bit map */
|
||||
typedef uint32_t bitchunk_t; /* collection of bits in a bitmap */
|
||||
|
||||
#define DEFAULT_BLOCK_SIZE 4096
|
||||
#define SUPER_V3 0x4d5a /* magic # for V3 file systems */
|
||||
#define MFS_DIRSIZ 60
|
||||
#define NR_DZONES 7 /* # direct zone numbers in a V2 inode */
|
||||
#define NR_TZONES 10 /* total # zone numbers in a V2 inode */
|
||||
#define NR_DIR_ENTRIES (int)(DEFAULT_BLOCK_SIZE/sizeof(direct_t)) /* # dir entries/blk */
|
||||
#define INDIRECTS (int)(DEFAULT_BLOCK_SIZE/sizeof(zone_t)) /* # zones/indir block */
|
||||
#define FS_BITMAP_CHUNKS (int)(DEFAULT_BLOCK_SIZE/sizeof(bitchunk_t)) /*# map chunks/blk*/
|
||||
#define FS_BITCHUNK_BITS (sizeof(bitchunk_t) * 8)
|
||||
#define FS_BITS_PER_BLOCK (FS_BITMAP_CHUNKS * FS_BITCHUNK_BITS)
|
||||
|
||||
typedef struct {
|
||||
uint32_t s_ninodes; /* # usable inodes on the minor device */
|
||||
uint16_t s_nzones; /* total device size, including bit maps etc */
|
||||
int16_t s_imap_blocks; /* # of blocks used by inode bit map */
|
||||
int16_t s_zmap_blocks; /* # of blocks used by zone bit map */
|
||||
uint16_t s_firstdatazone_old; /* number of first data zone (small) */
|
||||
uint16_t s_log_zone_size; /* log2 of blocks/zone */
|
||||
uint16_t s_flags; /* FS state flags */
|
||||
int32_t s_max_size; /* maximum file size on this device */
|
||||
uint32_t s_zones; /* number of zones (replaces s_nzones in V2) */
|
||||
int16_t s_magic; /* magic number to recognize super-blocks */
|
||||
/* The following items are valid on disk only for V3 and above */
|
||||
int16_t s_pad2; /* try to avoid compiler-dependent padding */
|
||||
/* The block size in bytes. Minimum MIN_BLOCK SIZE. SECTOR_SIZE multiple.*/
|
||||
uint16_t s_block_size; /* block size in bytes. */
|
||||
int8_t s_disk_version; /* filesystem format sub-version */
|
||||
} __attribute__((packed)) superblock_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t d_ino;
|
||||
char d_name[MFS_DIRSIZ];
|
||||
} __attribute__((packed)) direct_t;
|
||||
|
||||
typedef struct { /* V2/V3 disk inode */
|
||||
uint16_t i_mode; /* file type, protection, etc. */
|
||||
uint16_t i_nlinks; /* how many links to this file. */
|
||||
int16_t i_uid; /* user id of the file's owner. */
|
||||
uint16_t i_gid; /* group number */
|
||||
uint32_t i_size; /* current file size in bytes */
|
||||
uint32_t i_atime; /* when was file data last accessed */
|
||||
uint32_t i_mtime; /* when was file data last changed */
|
||||
uint32_t i_ctime; /* when was inode data last changed */
|
||||
uint32_t i_zone[NR_TZONES]; /* zone nums for direct, ind, and dbl ind */
|
||||
} __attribute__((packed)) inode_t;
|
||||
|
||||
block_t mnx_numblk, mnx_inode_offset, mnx_next_zone, mnx_next_inode, mnx_zone_map, mnx_root_inum;
|
||||
zone_t mnx_zoff;
|
||||
|
||||
/* Insert one bit into the bitmap */
|
||||
void mnx_insert_bit(block_t map, bit_t bit)
|
||||
{
|
||||
int boff, w, s;
|
||||
block_t map_block = map + bit / FS_BITS_PER_BLOCK;
|
||||
boff = bit % FS_BITS_PER_BLOCK;
|
||||
w = boff / FS_BITCHUNK_BITS;
|
||||
s = boff % FS_BITCHUNK_BITS;
|
||||
*((uint32_t*)(fs_base + map_block * DEFAULT_BLOCK_SIZE + w)) |= (1 << s);
|
||||
}
|
||||
|
||||
/* Increment the link count to inode n */
|
||||
void mnx_incr_link(ino_t n)
|
||||
{
|
||||
inode_t *inodes = (inode_t*)(fs_base + mnx_inode_offset * DEFAULT_BLOCK_SIZE + (n-1) * sizeof(inode_t));
|
||||
inodes[0].i_nlinks++;
|
||||
}
|
||||
|
||||
/* Increment the file-size in inode n */
|
||||
void mnx_incr_size(ino_t n, size_t count)
|
||||
{
|
||||
inode_t *inodes = (inode_t*)(fs_base + mnx_inode_offset * DEFAULT_BLOCK_SIZE + (n-1) * sizeof(inode_t));
|
||||
inodes[0].i_size += count;
|
||||
}
|
||||
|
||||
/* allocate an inode */
|
||||
static ino_t mnx_alloc_inode(int mode, int usrid, int grpid)
|
||||
{
|
||||
ino_t num;
|
||||
inode_t *inodes;
|
||||
superblock_t *sup = (superblock_t*)(fs_base + 1024);
|
||||
|
||||
num = mnx_next_inode++;
|
||||
if(num > sup->s_ninodes) {
|
||||
fprintf(stderr,"mkbootimg: partition #%d %s\r\n", fs_no, lang[ERR_TOOMANY]);
|
||||
exit(1);
|
||||
}
|
||||
inodes = (inode_t*)(fs_base + mnx_inode_offset * DEFAULT_BLOCK_SIZE + (num-1) * sizeof(inode_t));
|
||||
inodes[0].i_mode = mode;
|
||||
inodes[0].i_uid = usrid;
|
||||
inodes[0].i_gid = grpid;
|
||||
/* Set the bit in the bit map. */
|
||||
mnx_insert_bit((block_t)2, num);
|
||||
return(num);
|
||||
}
|
||||
|
||||
/* Allocate a new zone */
|
||||
static zone_t mnx_alloc_zone(void)
|
||||
{
|
||||
zone_t z = mnx_next_zone++;
|
||||
mnx_insert_bit(mnx_zone_map, z - mnx_zoff);
|
||||
return z;
|
||||
}
|
||||
|
||||
void mnx_add_zone(ino_t n, zone_t z, size_t bytes, time_t mtime, char *name)
|
||||
{
|
||||
/* Add zone z to inode n. The file has grown by 'bytes' bytes. */
|
||||
int i, j;
|
||||
inode_t *p;
|
||||
zone_t indir, dindir, *blk, *dblk;
|
||||
|
||||
p = (inode_t*)(fs_base + mnx_inode_offset * DEFAULT_BLOCK_SIZE + (n-1) * sizeof(inode_t));
|
||||
p->i_size += bytes;
|
||||
p->i_mtime = mtime;
|
||||
for (i = 0; i < NR_DZONES; i++)
|
||||
if (p->i_zone[i] == 0) {
|
||||
p->i_zone[i] = z;
|
||||
return;
|
||||
}
|
||||
|
||||
/* File has grown beyond a small file. */
|
||||
if (p->i_zone[NR_DZONES] == 0)
|
||||
p->i_zone[NR_DZONES] = mnx_alloc_zone();
|
||||
indir = p->i_zone[NR_DZONES];
|
||||
--indir; /* Compensate for ++indir below */
|
||||
for (i = 0; i < INDIRECTS; i++) {
|
||||
if (i % INDIRECTS == 0)
|
||||
blk = (zone_t*)(fs_base + ++indir * DEFAULT_BLOCK_SIZE);
|
||||
if (blk[i % INDIRECTS] == 0) {
|
||||
blk[i] = z;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* File has grown beyond single indirect; we need a double indirect */
|
||||
if (p->i_zone[NR_DZONES+1] == 0)
|
||||
p->i_zone[NR_DZONES+1] = mnx_alloc_zone();
|
||||
dindir = p->i_zone[NR_DZONES+1];
|
||||
--dindir; /* Compensate for ++indir below */
|
||||
for (j = 0; j < INDIRECTS; j++) {
|
||||
if (j % INDIRECTS == 0)
|
||||
dblk = (zone_t*)(fs_base + ++dindir * DEFAULT_BLOCK_SIZE);
|
||||
if (dblk[j % INDIRECTS] == 0)
|
||||
dblk[j % INDIRECTS] = mnx_alloc_zone();
|
||||
indir = dblk[j % INDIRECTS];
|
||||
--indir; /* Compensate for ++indir below */
|
||||
for (i = 0; i < INDIRECTS; i++) {
|
||||
if (i % INDIRECTS == 0)
|
||||
blk = (zone_t*)(fs_base + ++indir * DEFAULT_BLOCK_SIZE);
|
||||
if (blk[i % INDIRECTS] == 0) {
|
||||
blk[i] = z;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(stderr,"mkbootimg: partition #%d %s: %s\r\n", fs_no, lang[ERR_TOOBIG], name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int mnx_dir_try_enter(zone_t z, ino_t child, char const *name)
|
||||
{
|
||||
direct_t *dir_entry;
|
||||
int i;
|
||||
dir_entry = (direct_t*)(fs_base + z * DEFAULT_BLOCK_SIZE);
|
||||
for (i = 0; i < NR_DIR_ENTRIES; i++)
|
||||
if (!dir_entry[i].d_ino)
|
||||
break;
|
||||
if(i < NR_DIR_ENTRIES) {
|
||||
dir_entry[i].d_ino = child;
|
||||
strncpy(dir_entry[i].d_name, name, MFS_DIRSIZ);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mnx_enter_dir(ino_t parent, char const *name, ino_t child)
|
||||
{
|
||||
/* Enter child in parent directory */
|
||||
/* Works for dir > 1 block and zone > block */
|
||||
unsigned int k;
|
||||
block_t indir;
|
||||
zone_t z;
|
||||
inode_t *ino;
|
||||
zone_t *indirblock;
|
||||
|
||||
/* Obtain the inode structure */
|
||||
ino = (inode_t*)(fs_base + mnx_inode_offset * DEFAULT_BLOCK_SIZE + (parent-1) * sizeof(inode_t));
|
||||
|
||||
for (k = 0; k < NR_DZONES; k++) {
|
||||
z = ino->i_zone[k];
|
||||
if (z == 0) {
|
||||
z = mnx_alloc_zone();
|
||||
ino->i_zone[k] = z;
|
||||
}
|
||||
|
||||
if(mnx_dir_try_enter(z, child, name))
|
||||
return;
|
||||
}
|
||||
|
||||
/* no space in directory using just direct blocks; try indirect */
|
||||
if (ino->i_zone[NR_DZONES] == 0)
|
||||
ino->i_zone[NR_DZONES] = mnx_alloc_zone();
|
||||
|
||||
indir = ino->i_zone[NR_DZONES];
|
||||
--indir; /* Compensate for ++indir below */
|
||||
for(k = 0; k < INDIRECTS; k++) {
|
||||
if (k % INDIRECTS == 0)
|
||||
indirblock = (zone_t*)(fs_base + ++indir * DEFAULT_BLOCK_SIZE);
|
||||
z = indirblock[k % INDIRECTS];
|
||||
if(!z)
|
||||
z = indirblock[k % INDIRECTS] = mnx_alloc_zone();
|
||||
if(mnx_dir_try_enter(z, child, name))
|
||||
return;
|
||||
}
|
||||
fprintf(stderr,"mkbootimg: partition #%d %s: %s\r\n", fs_no, lang[ERR_TOOBIG], name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void mnx_open(gpt_t *gpt_entry)
|
||||
{
|
||||
zone_t z;
|
||||
superblock_t *sup;
|
||||
int i, kb;
|
||||
if(!gpt_entry) { fprintf(stderr,"mkbootimg: %s minix.\r\n", lang[ERR_BADINITRDTYPE]); exit(1); }
|
||||
mnx_numblk = (gpt_entry->last - gpt_entry->start + 1) * 512 / DEFAULT_BLOCK_SIZE;
|
||||
if(mnx_numblk < 8) { fprintf(stderr,"mkbootimg: partition #%d %s\r\n", fs_no, lang[ERR_NOSIZE]); exit(1); }
|
||||
/* "format" the partition to Minix3FS */
|
||||
fs_len = mnx_numblk * DEFAULT_BLOCK_SIZE;
|
||||
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);
|
||||
sup = (superblock_t*)(fs_base + 1024);
|
||||
kb = fs_len / 1024;
|
||||
sup->s_ninodes = kb / 2;
|
||||
if (kb >= 100000) sup->s_ninodes = kb / 4;
|
||||
if (kb >= 1000000) sup->s_ninodes = kb / 6;
|
||||
if (kb >= 10000000) sup->s_ninodes = kb / 8;
|
||||
if (kb >= 100000000) sup->s_ninodes = kb / 10;
|
||||
if (kb >= 1000000000) sup->s_ninodes = kb / 12;
|
||||
sup->s_ninodes += (DEFAULT_BLOCK_SIZE/sizeof(inode_t)) - 1;
|
||||
sup->s_ninodes &= ~((DEFAULT_BLOCK_SIZE/sizeof(inode_t)) - 1);
|
||||
if(sup->s_ninodes < 1) { fprintf(stderr,"mkbootimg: partition #%d %s\r\n", fs_no, lang[ERR_NOSIZE]); exit(1); }
|
||||
sup->s_zones = mnx_numblk;
|
||||
sup->s_imap_blocks = (1 + sup->s_ninodes + DEFAULT_BLOCK_SIZE - 1) / DEFAULT_BLOCK_SIZE;
|
||||
sup->s_zmap_blocks = (mnx_numblk + DEFAULT_BLOCK_SIZE - 1) / DEFAULT_BLOCK_SIZE;
|
||||
mnx_inode_offset = 2 + sup->s_imap_blocks + sup->s_zmap_blocks;
|
||||
sup->s_magic = SUPER_V3;
|
||||
sup->s_block_size = DEFAULT_BLOCK_SIZE;
|
||||
i = NR_DZONES+(DEFAULT_BLOCK_SIZE/sizeof(inode_t))+(DEFAULT_BLOCK_SIZE/sizeof(inode_t))*(DEFAULT_BLOCK_SIZE/sizeof(inode_t));
|
||||
if(INT32_MAX/DEFAULT_BLOCK_SIZE < i)
|
||||
sup->s_max_size = INT32_MAX;
|
||||
else
|
||||
sup->s_max_size = i * DEFAULT_BLOCK_SIZE;
|
||||
mnx_next_zone = mnx_inode_offset + (sup->s_ninodes+(DEFAULT_BLOCK_SIZE/sizeof(inode_t))-1)/(DEFAULT_BLOCK_SIZE/sizeof(inode_t));
|
||||
mnx_zoff = mnx_next_zone - 1;
|
||||
mnx_next_inode = 1;
|
||||
mnx_zone_map = 2 + sup->s_imap_blocks;
|
||||
mnx_insert_bit(mnx_zone_map, 0); /* bit zero must always be allocated */
|
||||
mnx_insert_bit((block_t)2, 0); /* inode zero not used but must be allocated */
|
||||
mnx_root_inum = mnx_alloc_inode(0755, 0, 0);
|
||||
z = mnx_alloc_zone();
|
||||
mnx_add_zone(mnx_root_inum, z, 2 * sizeof(direct_t), t, "rootdir");
|
||||
mnx_enter_dir(mnx_root_inum, ".", mnx_root_inum);
|
||||
mnx_enter_dir(mnx_root_inum, "..", mnx_root_inum);
|
||||
mnx_incr_link(mnx_root_inum);
|
||||
mnx_incr_link(mnx_root_inum);
|
||||
}
|
||||
|
||||
void mnx_add(struct stat *st, char *name, unsigned char *content, int size)
|
||||
{
|
||||
ino_t n, parent = mnx_root_inum;
|
||||
inode_t *ino;
|
||||
zone_t z;
|
||||
direct_t *dir_entry;
|
||||
int i, k;
|
||||
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) && !S_ISLNK(st->st_mode) && !S_ISCHR(st->st_mode) && !S_ISBLK(st->st_mode))
|
||||
return;
|
||||
n = mnx_alloc_inode(st->st_mode, st->st_uid, st->st_gid);
|
||||
/* Enter name in directory and update directory's size. */
|
||||
fn = name;
|
||||
end = strchr(name, '/');
|
||||
if(!end) end = name + strlen(name);
|
||||
i = k = 0;
|
||||
do {
|
||||
/* FIXME: this doesn't handle indirect and double indirect data */
|
||||
ino = (inode_t*)(fs_base + mnx_inode_offset * DEFAULT_BLOCK_SIZE + (parent-1) * sizeof(inode_t));
|
||||
dir_entry = (direct_t*)(fs_base + ino->i_zone[k] * DEFAULT_BLOCK_SIZE);
|
||||
if(!memcmp(dir_entry[i].d_name, fn, end - fn) && !dir_entry[i].d_name[end - fn]) {
|
||||
parent = dir_entry[i].d_ino; i = k = 0;
|
||||
fn = end + 1;
|
||||
end = *end ? strchr(fn, '/') : NULL;
|
||||
if(!end) break;
|
||||
}
|
||||
i++;
|
||||
if(i == NR_DIR_ENTRIES) { i = 0; k++; }
|
||||
if((k * NR_DIR_ENTRIES + i) * sizeof(direct_t) >= ino->i_size) break;
|
||||
} while(1);
|
||||
mnx_enter_dir(parent, fn, n);
|
||||
mnx_incr_size(parent, sizeof(direct_t));
|
||||
|
||||
/* Check to see if file is directory or special. */
|
||||
mnx_incr_link(n);
|
||||
if (S_ISDIR(st->st_mode)) {
|
||||
/* This is a directory. */
|
||||
z = mnx_alloc_zone(); /* zone for new directory */
|
||||
mnx_add_zone(n, z, 2 * sizeof(direct_t), st->st_mtime, name);
|
||||
mnx_enter_dir(n, ".", n);
|
||||
mnx_enter_dir(n, "..", parent);
|
||||
mnx_incr_link(parent);
|
||||
mnx_incr_link(n);
|
||||
} else if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
|
||||
/* Special file. */
|
||||
mnx_add_zone(n, (zone_t)st->st_rdev, st->st_size, st->st_mtime, name);
|
||||
} else if (S_ISLNK(st->st_mode)) {
|
||||
if(size > DEFAULT_BLOCK_SIZE - 1) {
|
||||
fprintf(stderr,"mkbootimg: partition #%d %s: %s\r\n", fs_no, lang[ERR_TOOBIG], name);
|
||||
exit(1);
|
||||
}
|
||||
z = mnx_alloc_zone();
|
||||
memcpy(fs_base + z * DEFAULT_BLOCK_SIZE, content, size + 1);
|
||||
mnx_add_zone(n, z, size, st->st_mtime, name);
|
||||
} else {
|
||||
/* Regular file. Go read it. */
|
||||
while(size) {
|
||||
z = mnx_alloc_zone();
|
||||
memcpy(fs_base + z * DEFAULT_BLOCK_SIZE, content, DEFAULT_BLOCK_SIZE);
|
||||
mnx_add_zone(n, z, size < DEFAULT_BLOCK_SIZE ? size : DEFAULT_BLOCK_SIZE, st->st_mtime, name);
|
||||
if(size > DEFAULT_BLOCK_SIZE) {
|
||||
content += DEFAULT_BLOCK_SIZE;
|
||||
size -= DEFAULT_BLOCK_SIZE;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mnx_close()
|
||||
{
|
||||
FILE *f;
|
||||
if(!fs_base || fs_len < 2048) return;
|
||||
f = fopen("test.bin", "w");
|
||||
fwrite(fs_base, fs_len, 1, f);
|
||||
fclose(f);
|
||||
}
|
|
@ -31,7 +31,10 @@
|
|||
|
||||
void tar_open(gpt_t *gpt_entry)
|
||||
{
|
||||
if(gpt && (gpt_entry->last - gpt_entry->start) < 1) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_NOSIZE]); exit(1); }
|
||||
if(gpt_entry && (gpt_entry->last - gpt_entry->start) < 1) {
|
||||
fprintf(stderr,"mkbootimg: partition #%d %s\r\n", fs_no, lang[ERR_NOSIZE]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void tar_add(struct stat *st, char *name, unsigned char *content, int size)
|
||||
|
|
|
@ -45,7 +45,7 @@ struct tm *ts;
|
|||
guid_t diskguid;
|
||||
char *json = NULL, *config = NULL, *kernelname = NULL, *initrd_dir[NUMARCH] = {0}, *initrd_file[NUMARCH] = {0};
|
||||
char initrd_arch[NUMARCH] = {0};
|
||||
int fs_len, initrd_size[NUMARCH] = {0}, initrd_gzip = 1, boot_size = 0, boot_fat = 16, disk_size = 0;
|
||||
int fs_len, fs_no, initrd_size[NUMARCH] = {0}, initrd_gzip = 1, boot_size = 0, boot_fat = 16, disk_size = 0;
|
||||
int iso9660 = 0, skipbytes = 0;
|
||||
unsigned char *fs_base = NULL, *initrd_buf[NUMARCH] = {0};
|
||||
unsigned long int tsize = 0, es = 0, esiz = 0, disk_align = 0;
|
||||
|
@ -171,8 +171,8 @@ void initrdcompress()
|
|||
memcpy(fs_base + 10 + initrdgz_len - 2, &crc, 4);
|
||||
memcpy(fs_base + 14 + initrdgz_len - 2, &fs_len, 4);
|
||||
fs_len = initrdgz_len - 2 + 18;
|
||||
} else
|
||||
free(initrdgz);
|
||||
}
|
||||
free(initrdgz);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue