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
|
TARGET = mkbootimg
|
||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
CFLAGS = -Wall -Wextra -ansi -pedantic
|
CFLAGS = -Wall -Wextra -ansi -pedantic -g
|
||||||
SRCS = $(filter-out bin2h.c data.c,$(wildcard *.c)) data.c
|
SRCS = $(filter-out bin2h.c data.c,$(wildcard *.c)) data.c
|
||||||
|
|
||||||
ifneq ("$(wildcard /bin/*.exe)","")
|
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ő
|
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
|
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
|
`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
|
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.
|
é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
|
Raspbery Pi Firmware Copyright (c) Broadcom Corp, Raspberry Pi (Trading) Ltd
|
||||||
|
|
||||||
Ellenőrzi, hogy az ELF vagy PE futtatható BOOTBOOT kompatíbilis-e, illetve
|
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:
|
Használat:
|
||||||
./mkbootimg check <kernel elf / pe>
|
./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 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 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) |
|
| 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
|
Az első elem esetén a `type` lehetséges értékei: `boot` (vagy explicit `fat16` és `fat32`). Csak 8+3 fájlneveket generál.
|
||||||
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 parancs igyekszik kényelmesen kezelni ezt, ha lehet FAT16-ot választva, helytakarékosság miatt. A boot partíció
|
||||||
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
|
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,
|
||||||
hiszi, ha túl kevés kluszter van a fájlrendszeren. Ha a partíció mérete meghaladja a 128 Megabájtot, akkor automatikusan
|
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
|
||||||
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
|
a 128 Megabájtot, akkor automatikusan FAT32-t választ. Ha nem használsz `iso9660`-t, akkor kissebb méretű is lehet, de
|
||||||
mérete). Ugyanakkor `iso9660` használata esetén garantálni kell, hogy minden kluszter 2048 bájtos címen kezdődjön, amit
|
legalább 33 Megabájt (ez a FAT32 minimális mérete). Ugyanakkor `iso9660` használata esetén garantálni kell, hogy minden
|
||||||
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
|
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
|
||||||
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
|
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
|
||||||
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
|
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
|
||||||
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).
|
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
|
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
|
||||||
sztring esetén a parancs listázza az összes lehetséges értéket.
|
`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:
|
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.
|
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
|
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
|
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
|
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élda:
|
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ó.
|
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();
|
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
|
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
|
||||||
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á
|
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
|
||||||
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,
|
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
|
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.
|
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
|
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
|
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
|
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
|
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`
|
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
|
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.
|
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
|
Raspbery Pi Firmware Copyright (c) Broadcom Corp, Raspberry Pi (Trading) Ltd
|
||||||
|
|
||||||
Validates ELF or PE executables for being BOOTBOOT compatible, otherwise
|
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:
|
Usage:
|
||||||
./mkbootimg check <kernel elf / pe>
|
./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 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 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) |
|
| 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
|
For the first entry, valid values for `type` are: `boot` (or explicit `fat16` and `fat32`). Generates only 8+3 file names.
|
||||||
comfortably, it tries to use FAT16 if possible to save storage space. There's a minimal size for the boot partition,
|
The utility handles this comfortably, it tries to use FAT16 if possible to save storage space. There's a minimal size
|
||||||
16 Megabytes. Although both the image creator and BOOTBOOT is capable of handling smaller sizes, some UEFI firmware
|
for the boot partition, 16 Megabytes. Although both the image creator and BOOTBOOT is capable of handling smaller sizes,
|
||||||
incorrectly assumes FAT12 when there are too few clusters on the file system. If the partition size is bigger than
|
some UEFI firmware incorrectly assumes FAT12 when there are too few clusters on the file system. If the partition size is
|
||||||
128 Megabytes, then it automatically switches to FAT32. If you don't use `iso9660`, then you can also set FAT32 for
|
bigger than 128 Megabytes, then it automatically switches to FAT32. If you don't use `iso9660`, then you can also set FAT32
|
||||||
smaller images, but at least 33 Megabytes (that's a hard lower limit for FAT32). With `iso9660`, each cluster must
|
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
|
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,
|
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
|
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).
|
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.
|
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.
|
With an invalid string, the utility will list all possible values.
|
||||||
|
|
||||||
Example:
|
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
|
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
|
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.
|
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
|
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:
|
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.
|
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
|
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:
|
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();
|
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.
|
The first, the "open" is called whenever a new file system is to be created. The `gpt_entry` is NULL when called for initrd
|
||||||
As the given directory is recursively parsed, for each directory entry an "add" call is made. This should add the file or
|
creation. As the given directory is recursively parsed, for each directory entry an "add" call is made. This should add the
|
||||||
directory to the file system image. Here `st` is the stat struct for the file, `name` is the filename with full path,
|
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
|
`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
|
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
|
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
|
Keeping the built-in binaries up-to-date
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
void cpio_open(gpt_t *gpt_entry)
|
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)
|
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)
|
void ech_open(gpt_t *gpt_entry)
|
||||||
{
|
{
|
||||||
if(gpt) {
|
if(gpt_entry) {
|
||||||
if((gpt_entry->last - gpt_entry->start) < 1) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_NOSIZE]); exit(1); }
|
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);
|
memcpy(ech_uuid, &gpt_entry->guid, 16);
|
||||||
ech_numblk = gpt_entry->last - gpt_entry->start + 1;
|
ech_numblk = gpt_entry->last - gpt_entry->start + 1;
|
||||||
ech_maxents = (ech_numblk * 5 / 100) * 512 / sizeof(ech_entry_t);
|
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;
|
parent = ech_ents[i].payload;
|
||||||
fn = end + 1;
|
fn = end + 1;
|
||||||
end = *end ? strchr(fn, '/') : NULL;
|
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));
|
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); }
|
if(!ech_ents) { fprintf(stderr,"mkbootimg: %s\r\n",lang[ERR_MEM]); exit(1); }
|
||||||
memset(&ech_ents[ech_numents], 0, sizeof(ech_entry_t));
|
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_add(struct stat *st, char *name, unsigned char *content, int size);
|
||||||
void ech_close();
|
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_open(gpt_t *gpt_entry);
|
||||||
void jamesm_add(struct stat *st, char *name, unsigned char *content, int size);
|
void jamesm_add(struct stat *st, char *name, unsigned char *content, int size);
|
||||||
void jamesm_close();
|
void jamesm_close();
|
||||||
|
|
||||||
/*** specify file system drivers and GPT file system types here ***/
|
/*** 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[] = {
|
fsdrv_t fsdrv[] = {
|
||||||
{ "jamesm", {0}, jamesm_open, jamesm_add, jamesm_close },
|
{ "jamesm", {0}, jamesm_open, jamesm_add, jamesm_close },
|
||||||
{ "cpio", {0}, cpio_open, cpio_add, cpio_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 },
|
{ "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 },
|
{ "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 (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 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 },
|
{ "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 "main.h"
|
||||||
#include "fsZ.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};
|
unsigned char fsz_emptysec[FSZ_SECSIZE] = {0};
|
||||||
|
|
||||||
/* private functions */
|
/* 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;
|
unsigned int i,j=!strcmp(filetype,FSZ_FILETYPE_SYMLINK)||!strcmp(filetype,FSZ_FILETYPE_UNION)?fsz_secsize-1024:36;
|
||||||
FSZ_Inode *in;
|
FSZ_Inode *in;
|
||||||
FSZ_DirEntHeader *hdr;
|
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);
|
fs_base=realloc(fs_base,fs_len+fsz_secsize);
|
||||||
if(!fs_base) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_MEM]); exit(1); }
|
if(!fs_base) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_MEM]); exit(1); }
|
||||||
memset(fs_base+fs_len,0,fsz_secsize);
|
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 */
|
/* 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)) {
|
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++;
|
hdr->numentries++;
|
||||||
in->modifydate=t * 1000000;
|
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 &&
|
int inode=fsz_add_inode(data[0]==0x55 && data[1]==0xAA &&
|
||||||
data[3]==0xE9 && data[8]=='B' &&
|
data[3]==0xE9 && data[8]=='B' &&
|
||||||
data[12]=='B'?"boot":"application","octet-stream");
|
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);
|
fs_base=realloc(fs_base,fs_len+fsz_secsize+s);
|
||||||
if(!fs_base) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_MEM]); exit(1); }
|
if(!fs_base) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_MEM]); exit(1); }
|
||||||
memset(fs_base+fs_len,0,fsz_secsize);
|
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;
|
in->sec=fs_len/fsz_secsize;
|
||||||
if(size>(unsigned long int)fsz_secsize) {
|
if(size>(unsigned long int)fsz_secsize) {
|
||||||
j=s/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) {
|
if(j*16<=fsz_secsize-1024) {
|
||||||
ptr=(unsigned char*)&in->data.small.inlinedata;
|
ptr=(unsigned char*)&in->data.small.inlinedata;
|
||||||
in->flags=FSZ_IN_FLAG_SDINLINE;
|
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;
|
k=inode+1+l;
|
||||||
for(i=0;i<j;i++){
|
for(i=0;i<j;i++){
|
||||||
/* no spare blocks allowed in initrd, there we must save a sector full of zeros */
|
/* 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(ptr,&k,4);
|
||||||
memcpy(fs_base+size+(i+l)*fsz_secsize,data+i*fsz_secsize,
|
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);
|
(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;
|
sb->createdate=sb->lastchangedate=t * 1000000;
|
||||||
if(gpt_entry) {
|
if(gpt_entry) {
|
||||||
memcpy(&sb->uuid, (void*)(gpt_entry + 16), sizeof(guid_t));
|
memcpy(&sb->uuid, (void*)(gpt_entry + 16), sizeof(guid_t));
|
||||||
sb->numsec = (gpt_entry->last - gpt_entry->start + 1) * 512 / fsz_secsize;
|
fsz_max = (gpt_entry->last - gpt_entry->start + 1) * 512;
|
||||||
fsz_isinitrd = 0;
|
sb->numsec = fsz_max / fsz_secsize;
|
||||||
} else {
|
} else {
|
||||||
memcpy(&sb->uuid, (void*)&diskguid, sizeof(guid_t));
|
memcpy(&sb->uuid, (void*)&diskguid, sizeof(guid_t));
|
||||||
sb->uuid[15]--;
|
sb->uuid[15]--;
|
||||||
fsz_isinitrd = 1;
|
fsz_max = 0;
|
||||||
}
|
}
|
||||||
memcpy(sb->magic2,FSZ_MAGIC,4);
|
memcpy(sb->magic2,FSZ_MAGIC,4);
|
||||||
fs_len = fsz_secsize;
|
fs_len = fsz_secsize;
|
||||||
|
|
|
@ -70,10 +70,6 @@ void gpt_maketable()
|
||||||
for(i = 0; fsdrv[i].name; i++)
|
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; }
|
if(fsdrv[i].type.Data1 && !strcmp(tmp, fsdrv[i].name)) { memcpy(&typeguid, &fsdrv[i].type, sizeof(guid_t)); break; }
|
||||||
free(tmp);
|
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 there's still no type GUID */
|
||||||
if(!typeguid.Data1 && !typeguid.Data2 && !typeguid.Data3 && !typeguid.Data4[0]) {
|
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]);
|
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;
|
else u[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(tmp);
|
||||||
p += 128;
|
p += 128;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
void img_write(char *fn)
|
void img_write(char *fn)
|
||||||
{
|
{
|
||||||
FILE *f, *d;
|
FILE *f, *d;
|
||||||
int i, n, lastpercent, k;
|
int i, j, n, lastpercent, k;
|
||||||
char key[64], *tmp, *dir, *buf;
|
char key[64], *tmp, *dir, *buf;
|
||||||
unsigned long int size, pos;
|
unsigned long int size, pos;
|
||||||
size_t s;
|
size_t s;
|
||||||
|
@ -82,9 +82,13 @@ void img_write(char *fn)
|
||||||
sprintf(key, "partitions.%d.%s", k, "directory");
|
sprintf(key, "partitions.%d.%s", k, "directory");
|
||||||
dir = json_get(json, key);
|
dir = json_get(json, key);
|
||||||
if(dir && *dir) {
|
if(dir && *dir) {
|
||||||
fs_base = NULL; fs_len = 0;
|
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");
|
sprintf(key, "partitions.%d.%s", k, "type");
|
||||||
tmp = json_get(json, key);
|
tmp = json_get(json, key);
|
||||||
|
}
|
||||||
if(tmp && *tmp) {
|
if(tmp && *tmp) {
|
||||||
rd_open = NULL; rd_add = NULL; rd_close = NULL;
|
rd_open = NULL; rd_add = NULL; rd_close = NULL;
|
||||||
for(i = 0; fsdrv[i].name && fsdrv[i].add; i++)
|
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));
|
if(rd_open) (*rd_open)((gpt_t*)(gpt + 1024 + k * 128));
|
||||||
parsedir(dir, 0);
|
parsedir(dir, 0);
|
||||||
if(rd_close) (*rd_close)();
|
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);
|
free(dir);
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
void jamesm_open(gpt_t *gpt_entry)
|
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_len = 4 + 64 * 73;
|
||||||
fs_base = realloc(fs_base, fs_len);
|
fs_base = realloc(fs_base, fs_len);
|
||||||
if(!fs_base) { fprintf(stderr,"mkbootimg: %s\r\n", lang[ERR_MEM]); exit(1); }
|
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 not specified in json",
|
||||||
"initrd type not specified in json",
|
"initrd type not specified in json",
|
||||||
"invalid initrd type",
|
"invalid initrd type",
|
||||||
|
"initrd-only type",
|
||||||
"Accepted values",
|
"Accepted values",
|
||||||
"unable to read BOOTBOOT configuration from",
|
"unable to read BOOTBOOT configuration from",
|
||||||
"BOOTBOOT configuration file is bigger than 4095 bytes",
|
"BOOTBOOT configuration file is bigger than 4095 bytes",
|
||||||
|
@ -71,7 +72,7 @@ char *dict[NUMLANGS][NUMTEXTS + 1] = {
|
||||||
"must use valid static addresses",
|
"must use valid static addresses",
|
||||||
"valid dynamic addresses",
|
"valid dynamic addresses",
|
||||||
"Validates ELF or PE executables for being BOOTBOOT compatible, otherwise",
|
"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",
|
"Usage",
|
||||||
"configuration json",
|
"configuration json",
|
||||||
"output disk image name",
|
"output disk image name",
|
||||||
|
@ -87,6 +88,7 @@ char *dict[NUMLANGS][NUMTEXTS + 1] = {
|
||||||
"initrd nincs megadva a json-ben",
|
"initrd nincs megadva a json-ben",
|
||||||
"initrd type nincs megadva a json-ben",
|
"initrd type nincs megadva a json-ben",
|
||||||
"érvénytelen initrd type",
|
"érvénytelen initrd type",
|
||||||
|
"csak initrd-nél használható type",
|
||||||
"Lehetséges értékek",
|
"Lehetséges értékek",
|
||||||
"nem tudom beolvasni a BOOTBOOT konfigurációt innen",
|
"nem tudom beolvasni a BOOTBOOT konfigurációt innen",
|
||||||
"a BOOTBOOT konfiguráció több, mint 4095 bájt",
|
"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",
|
"helyes statikus címeket kell használnia",
|
||||||
"érvényes dinamikus címek",
|
"érvényes dinamikus címek",
|
||||||
"Ellenőrzi, hogy az ELF vagy PE futtatható BOOTBOOT kompatíbilis-e, illetve",
|
"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",
|
"Használat",
|
||||||
"konfigurációs json",
|
"konfigurációs json",
|
||||||
"kimeneti lemezkép neve",
|
"kimeneti lemezkép neve",
|
||||||
|
@ -132,6 +134,7 @@ char *dict[NUMLANGS][NUMTEXTS + 1] = {
|
||||||
"initrd nie jest opisany w pliku json",
|
"initrd nie jest opisany w pliku json",
|
||||||
"typ initrd nie jest opisany w pliku json",
|
"typ initrd nie jest opisany w pliku json",
|
||||||
"niepoprawny typ initrd",
|
"niepoprawny typ initrd",
|
||||||
|
"nie ma poprawnego typu",
|
||||||
"Akceptowane wartości",
|
"Akceptowane wartości",
|
||||||
"nie udało się załadować konfiguracji BOOTBOOT z",
|
"nie udało się załadować konfiguracji BOOTBOOT z",
|
||||||
"plik z konfiguracją BOOTBOOT jest większy niż 4095 bajtów",
|
"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",
|
"musi używać poprawnych statycznych adresów",
|
||||||
"poprawny dynamiczny adres",
|
"poprawny dynamiczny adres",
|
||||||
"Sprawdza czy plik wykonywalny ELF lub PE jest kompatybilny z BOOTBOOT, w przeciwnym wypadku",
|
"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",
|
"Sposoby użytkowania",
|
||||||
"plik konfiguracyjny json",
|
"plik konfiguracyjny json",
|
||||||
"nazwa wyjściowego pliku obrazu dysku",
|
"nazwa wyjściowego pliku obrazu dysku",
|
||||||
|
|
|
@ -34,6 +34,7 @@ enum {
|
||||||
ERR_NOINITRD,
|
ERR_NOINITRD,
|
||||||
ERR_NOINITRDTYPE,
|
ERR_NOINITRDTYPE,
|
||||||
ERR_BADINITRDTYPE,
|
ERR_BADINITRDTYPE,
|
||||||
|
ERR_INITRDTYPE,
|
||||||
ERR_ACCEPTVALUES,
|
ERR_ACCEPTVALUES,
|
||||||
ERR_NOCONF,
|
ERR_NOCONF,
|
||||||
ERR_BIGCONF,
|
ERR_BIGCONF,
|
||||||
|
|
|
@ -463,13 +463,14 @@ int main(int argc, char **argv)
|
||||||
parsekernel(i, data, 0);
|
parsekernel(i, data, 0);
|
||||||
free(data);
|
free(data);
|
||||||
skipbytes = strlen(initrd_dir[i]) + 1;
|
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);
|
if(rd_open) (*rd_open)(NULL);
|
||||||
parsedir(initrd_dir[i], 0);
|
parsedir(initrd_dir[i], 0);
|
||||||
if(rd_close) (*rd_close)();
|
if(rd_close) (*rd_close)();
|
||||||
initrdcompress();
|
initrdcompress();
|
||||||
initrd_buf[i] = fs_base;
|
initrd_buf[i] = fs_base;
|
||||||
initrd_size[i] = fs_len;
|
initrd_size[i] = fs_len;
|
||||||
|
free(initrd_dir[i]);
|
||||||
} else
|
} else
|
||||||
if(initrd_buf[i]) {
|
if(initrd_buf[i]) {
|
||||||
fs_base = initrd_buf[i]; fs_len = initrd_size[i];
|
fs_base = initrd_buf[i]; fs_len = initrd_size[i];
|
||||||
|
@ -519,6 +520,8 @@ int main(int argc, char **argv)
|
||||||
free(kernelname);
|
free(kernelname);
|
||||||
free(initrd_buf[0]);
|
free(initrd_buf[0]);
|
||||||
if(initrd_buf[1]) free(initrd_buf[1]);
|
if(initrd_buf[1]) free(initrd_buf[1]);
|
||||||
|
if(initrd_buf[2]) free(initrd_buf[2]);
|
||||||
|
if(config) free(config);
|
||||||
free(json);
|
free(json);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -185,8 +185,8 @@ extern time_t t;
|
||||||
extern struct tm *ts;
|
extern struct tm *ts;
|
||||||
extern guid_t diskguid;
|
extern guid_t diskguid;
|
||||||
extern char *json, *config, *kernelname, *initrd_dir[NUMARCH], initrd_arch[NUMARCH];
|
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 fs_len, fs_no, initrd_size[NUMARCH], initrd_gzip, boot_size, boot_fat, disk_size, esp_size, esp_bbs;
|
||||||
extern int iso9660, skipbytes, np;
|
extern int iso9660, skipbytes, np, bbp_start, bbp_end;
|
||||||
extern unsigned char *esp, *gpt, gpt2[512], *fs_base, *initrd_buf[NUMARCH];
|
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 unsigned long int tsize, es, esiz, disk_align, gpt_parts[248];
|
||||||
extern fsdrv_t fsdrv[];
|
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)
|
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)
|
void tar_add(struct stat *st, char *name, unsigned char *content, int size)
|
||||||
|
|
|
@ -45,7 +45,7 @@ struct tm *ts;
|
||||||
guid_t diskguid;
|
guid_t diskguid;
|
||||||
char *json = NULL, *config = NULL, *kernelname = NULL, *initrd_dir[NUMARCH] = {0}, *initrd_file[NUMARCH] = {0};
|
char *json = NULL, *config = NULL, *kernelname = NULL, *initrd_dir[NUMARCH] = {0}, *initrd_file[NUMARCH] = {0};
|
||||||
char initrd_arch[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;
|
int iso9660 = 0, skipbytes = 0;
|
||||||
unsigned char *fs_base = NULL, *initrd_buf[NUMARCH] = {0};
|
unsigned char *fs_base = NULL, *initrd_buf[NUMARCH] = {0};
|
||||||
unsigned long int tsize = 0, es = 0, esiz = 0, disk_align = 0;
|
unsigned long int tsize = 0, es = 0, esiz = 0, disk_align = 0;
|
||||||
|
@ -171,7 +171,7 @@ void initrdcompress()
|
||||||
memcpy(fs_base + 10 + initrdgz_len - 2, &crc, 4);
|
memcpy(fs_base + 10 + initrdgz_len - 2, &crc, 4);
|
||||||
memcpy(fs_base + 14 + initrdgz_len - 2, &fs_len, 4);
|
memcpy(fs_base + 14 + initrdgz_len - 2, &fs_len, 4);
|
||||||
fs_len = initrdgz_len - 2 + 18;
|
fs_len = initrdgz_len - 2 + 18;
|
||||||
} else
|
}
|
||||||
free(initrdgz);
|
free(initrdgz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue