diff --git a/docs/qrofs.md b/docs/qrofs.md new file mode 100644 index 0000000..12b5a3d --- /dev/null +++ b/docs/qrofs.md @@ -0,0 +1,35 @@ +# QROFS - Quark Read-Only File System + +QROFS is the FS used by Quark's ramdisk VFS + + - Read-only (cannot write/delete/create/rename files) + - Subdirectory support + - File size limit: 2^32 bytes + - File name limit: 255 characters + - File name validation: ASCII only + - File name case sensitivity: case-sensitive + - Maximum files per directory: 255 + +## At a byte level + +NOTE: Everything is stored in little-endian format, unless otherwise noted + +### QROFS directory + +| Bits | Description | +|-|-| +| 8 | Header (`0x02` for directories) | +| 8 | Name length | +| 8*n | The directory name itself - n is the name length | +| 8 | Number of child nodes | +| ? | Child nodes | + +### QROFS file + +| Bits | Description | +|-|-| +| 8 | Header (`0x01` for files) | +| 8 | Name length | +| 8*n | The file name itself - n is the name length | +| 32 | File size | +| 8*n | File data | diff --git a/tools/qrofs-util.py b/tools/qrofs-util.py new file mode 100755 index 0000000..8564089 --- /dev/null +++ b/tools/qrofs-util.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 + +import sys +import os +import struct + +def create(file_name, dir_name): + if not os.path.exists(dir_name): + print(f"ERROR: {dir_name} does not exist") + exit(1) + + out_fd = open(file_name, "wb+") + + def create_file(name, path): + out_fd.write(bytes([0x01])) # file + out_fd.write(bytes([len(name)])) # name length + out_fd.write(name.encode("ascii")) # name + fd = open(path, "rb") + file_content = fd.read() + fd.close() + out_fd.write(struct.pack("I", len(file_content))) # file size + out_fd.write(file_content) # file data + + def create_directory(name, path): + out_fd.write(bytes([0x02])) # directory + out_fd.write(bytes([len(name)])) # name length + out_fd.write(name.encode("ascii")) # name + child_nodes = os.listdir(path) + out_fd.write(bytes([len(child_nodes)])) # child count + for child in child_nodes: + if(os.path.isdir(os.path.join(path, child))): + create_directory(child, os.path.join(path, child)) + else: + create_file(child, os.path.join(path, child)) + + create_directory("", dir_name) # root directory has no name + + out_fd.close() + + +def main(): + if len(sys.argv) <= 1: + print(f"Usage: {sys.argv[0]} ") + print("Commands:") + print(" create | create a QROFS disk image file from a directory") + print(" extract | extract the QROFS disk image file contents into a directory") + elif sys.argv[1] == "create": + if len(sys.argv) != 4: + print("Usage: create ") + else: + create(sys.argv[2], sys.argv[3]) + +if(__name__ == "__main__"): + main()