Skip to content

Commit a2f8540

Browse files
committed
fix(yaffs): implement a better heuristics for yaffsv1 detection.
We now read the spare according to YAFFSv1 default page and spare size. We then check if this spare contains information for the first chunk, that is an chunk_id of 0, an object_id of 1 and a serial of 0.
1 parent 4de06bb commit a2f8540

File tree

1 file changed

+41
-8
lines changed

1 file changed

+41
-8
lines changed

unblob/handlers/filesystem/yaffs.py

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@
2525

2626
logger = get_logger()
2727

28-
# YAFFS1 images always have a first entry as a directory entry with an empty name
29-
# this is how it's done in mkyaffsimage:
30-
# write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL);
31-
YAFFS1_FIRST_ENTRY = b"\xff\xff\x00\x00\x00\x00\x00\x00"
32-
3328
SPARE_START_BIG_ENDIAN_ECC = b"\x00\x00\x10\x00"
3429
SPARE_START_BIG_ENDIAN_NO_ECC = b"\xFF\xFF\x00\x00\x10\x00"
3530
SPARE_START_LITTLE_ENDIAN_ECC = b"\x00\x10\x00\x00"
@@ -41,6 +36,8 @@
4136

4237
VALID_PAGE_SIZES = [512, 1024, 2048, 4096, 8192, 16384]
4338
VALID_SPARE_SIZES = [16, 32, 64, 128, 256, 512]
39+
YAFFS1_PAGE_SIZE = 512
40+
YAFFS1_SPARE_SIZE = 16
4441

4542
C_DEFINITIONS = """
4643
struct yaffs1_obj_hdr {
@@ -653,8 +650,8 @@ def __init__(self, file: File, config: Optional[YAFFSConfig] = None):
653650
# is the same size as a NAND flash page (ie. 512 bytes + 16 byte spare).
654651
# In the future we might decide to allow for different chunk sizes.
655652
config = YAFFSConfig(
656-
page_size=512,
657-
spare_size=16,
653+
page_size=YAFFS1_PAGE_SIZE,
654+
spare_size=YAFFS1_SPARE_SIZE,
658655
endianness=get_endian_multi(file, BIG_ENDIAN_MAGICS),
659656
ecc=False,
660657
)
@@ -723,8 +720,44 @@ def get_chunks(self, object_id: int) -> Iterable[YAFFS1Chunk]:
723720
yield max(chunks, key=lambda chunk: ((chunk.serial + 1) & 3))
724721

725722

723+
def is_yaffs_v1(file: File, start_offset: int) -> bool:
724+
struct_parser = StructParser(C_DEFINITIONS)
725+
file.seek(start_offset, io.SEEK_SET)
726+
if file[0:4] == b"\x03\x00\x00\x00" or file[0:4] == b"\x01\x00\x00\x00":
727+
endian = Endian.LITTLE
728+
else:
729+
endian = Endian.BIG
730+
file.seek(start_offset + YAFFS1_PAGE_SIZE, io.SEEK_SET)
731+
spare = file.read(YAFFS1_SPARE_SIZE)
732+
733+
yaffs_sparse = struct_parser.parse("yaffs_spare_t", spare, endian)
734+
735+
yaffs_packed_tags = struct_parser.parse(
736+
"yaffs1_packed_tags_t",
737+
bytes(
738+
[
739+
yaffs_sparse.tag_b0,
740+
yaffs_sparse.tag_b1,
741+
yaffs_sparse.tag_b2,
742+
yaffs_sparse.tag_b3,
743+
yaffs_sparse.tag_b4,
744+
yaffs_sparse.tag_b5,
745+
yaffs_sparse.tag_b6,
746+
yaffs_sparse.tag_b7,
747+
]
748+
),
749+
endian,
750+
)
751+
file.seek(start_offset, io.SEEK_SET)
752+
return (
753+
yaffs_packed_tags.chunk_id == 0
754+
and yaffs_packed_tags.serial == 0
755+
and yaffs_packed_tags.object_id == 1
756+
)
757+
758+
726759
def instantiate_parser(file: File, start_offset: int = 0) -> YAFFSParser:
727-
if file[start_offset + 8 : start_offset + 16] == YAFFS1_FIRST_ENTRY:
760+
if is_yaffs_v1(file, start_offset):
728761
return YAFFS1Parser(file)
729762
return YAFFS2Parser(file)
730763

0 commit comments

Comments
 (0)