diff --git a/Makefile b/Makefile index af13d7d..3966670 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,13 @@ export RELDIR := release # Definitions for initial RAM disk VRAM_OUT := $(OUTDIR)/vram0.tar VRAM_DATA := data -VRAM_FLAGS := --format=v7 --blocking-factor=1 --xform='s/^$(VRAM_DATA)\/\|^resources\///' +VRAM_FLAGS := --make-new --path-limit 99 --size-limit 3145728 + +ifeq ($(OS),Windows_NT) + PY3 := py -3 +else + PY3 := python3 +endif # Definitions for ARM binaries export INCLUDE := -I"$(shell pwd)/common" @@ -62,7 +68,7 @@ release: clean vram0: @mkdir -p "$(OUTDIR)" @echo "Creating $(VRAM_OUT)" - @tar cf $(VRAM_OUT) $(VRAM_FLAGS) $(shell ls -d $(README) $(SPLASH) $(VRAM_DATA)/*) + @$(PY3) utils/add2tar.py $(VRAM_FLAGS) $(VRAM_OUT) $(shell ls -d $(README) $(SPLASH) $(VRAM_DATA)/*) elf: @set -e; for elf in $(ELF); do \ diff --git a/README.md b/README.md index 38cba81..c6062cb 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ You may now run GodMode9 via holding the X Button (or any other button you chose ## How to build this / developer info -Build `GodMode9.firm` via `make firm` (requires [firmtool](https://github.com/TuxSH/firmtool) installed). On macOS, you may have to install [gnu-tar](https://www.gnu.org/software/tar/) first - do so in terminal via `brew install gnu-tar --with-default-names`. +Build `GodMode9.firm` via `make firm`. This requires [firmtool](https://github.com/TuxSH/firmtool), [Python 3.5+](https://www.python.org/downloads/) and [devkitARM](https://sourceforge.net/projects/devkitpro/) installed). You may run `make release` to get a nice, release-ready package of all required files. To build __SafeMode9__ (a bricksafe variant of GodMode9, with limited write permissions) instead of GodMode9, compile with `make FLAVOR=SafeMode9`. To switch screens, compile with `make SWITCH_SCREENS=1`. For additional customization, you may choose the internal font via `make FONT=6X10`, `make FONT=ACORN`, `make FONT=GB` or `make FONT=ORIG`. You may also hardcode the brightness via `make FIXED_BRIGHTNESS=x`, whereas `x` is a value between 0...15. diff --git a/utils/add2tar.py b/utils/add2tar.py new file mode 100755 index 0000000..b8ef961 --- /dev/null +++ b/utils/add2tar.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 + +import argparse +import tarfile +import glob +import os.path +import posixpath +from os import unlink + +# don't add useless files +prefix_to_ignore = ('thumbs.db', 'desktop.ini', '$recycle.bin', '.') + + +class PathTooLongException(Exception): + """Filename is too long to be added to the TAR file.""" + + +class TarTooLargeException(Exception): + """Resulting tar is larger than the given size.""" + + +def tarpack(*, items, out, size_limit=0, path_limit=0, make_new=False): + with tarfile.open(out, 'w' if make_new else 'a', format=tarfile.USTAR_FORMAT, bufsize=tarfile.BLOCKSIZE) as tar: + def addtotar(realpath, tarpath): + if path_limit and len(tarpath) > path_limit: + raise PathTooLongException("path is longer than {} chars ({}): {}".format(path_limit, len(tarpath), tarpath)) + print('add:', tarpath) + info = tarfile.TarInfo(tarpath) + info.size = os.path.getsize(realpath) + with open(realpath, 'rb') as f: + tar.addfile(tarinfo=info, fileobj=f) + + def iterdir(realpath, tarpath): + items = os.listdir(realpath) + if path_limit and len(tarpath) > path_limit: + raise PathTooLongException("path is longer than {} chars ({}): {}".format(path_limit, len(tarpath), tarpath)) + info = tarfile.TarInfo(tarpath) + info.type = tarfile.DIRTYPE + tar.addfile(info) + for path in items: + new_realpath = os.path.join(realpath, path) + if os.path.isdir(new_realpath) and not os.path.basename(path).lower().startswith(prefix_to_ignore): + iterdir(new_realpath, posixpath.join(tarpath, path)) + elif os.path.isfile(new_realpath) and not os.path.basename(path).lower().startswith(prefix_to_ignore): + addtotar(os.path.join(realpath, path), posixpath.join(tarpath, path)) + + for i in items: + if os.path.isdir(i): + iterdir(i, os.path.basename(i)) + elif os.path.isfile(i): + addtotar(i, os.path.basename(i)) + else: + raise FileNotFoundError("couldn't find " + i) + + # tarfile is adding more end blocks when it only needs two + tar.fileobj.seek(0, 2) + tar.fileobj.write(tarfile.NUL * (tarfile.BLOCKSIZE * 2)) + tar.fileobj.close() + tar.closed = True + + tarsize = os.path.getsize(out) + if size_limit and tarsize > size_limit: + raise TarTooLargeException("TAR size is {} bytes is larger than the limit of {} bytes".format(tarsize, size_limit)) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description="Pack files into a TAR file, leaving out extra information.") + parser.add_argument('--make-new', '-n', help="Always create a new TAR file.", action='store_true') + parser.add_argument('--size-limit', '-l', type=int, help="Throw an error when the file size reaches the specified limit.") + parser.add_argument('--path-limit', '-p', type=int, help="Throw an error when a file path is longer than the specified limit.") + parser.add_argument('out', help="Output filename.") + parser.add_argument('items', nargs='+', help="Files and directories to add.") + + a = parser.parse_args() + tarpack(items=a.items, out=a.out, size_limit=a.size_limit, path_limit=a.path_limit, make_new=a.make_new)