See YAFFS2 for general information about the YAFFS2 file system.
As outlined in the YAFFS2 page, the file system relies on the ‘spare area’ of each flash memory page to store information about what file system chunk that is stored in that page. The YAFFS2 spec does not specify though the exact format of how that data is stored because devices can choose how to use the spare area for other things, such as check sums. Further, there is nothing in the file system that stores how the spare area is organized, so tools must guess.
There are two things that tools must guess:
TSK assumes that all pages are 2048-bytes and spare area is 64-bytes. It knows about several spare area layouts, but does not know all of them. We need to add the ability to pass in the layout details if you have reverse engineered them.
This section contains some of the layouts that TSK detects. As with all docs, the code will likely evolve to more formats than are documented here.
In practice we’ve seen this format the most:
At present we’ve seen these 16 bytes start at offset 0, offset 2, or offset 30. TSK attempts to determine where the fields are by reading in a reasonable number of initialized spare areas and then doing some tests on each possible offset:
These tests could certainly be improved upon.
As described in the previous section, for each object we create a chronologically ordered list of chunks with that object ID. The current version of an object is created by starting at the end of the list and reading backwards, but we can start at any point in the list and read backwards to create an older version of the object. Object IDs tend to get reused frequently, so in addition to multiple versions of the same file we also expect to see old files that have been deleted.
The question is, where do we start these versions? Starting at every chunk in the list would produce way too many files. Even only starting at header chunks seems like it would create more versions than could reasonably be worked with. For now, we base versions around changes in the sequence number and create them as follows:
Obj id Seq num Offset Type Parent Name
000005f9 00001b3c 07229a00 file 00000004 deleted
000005f9 00001b3d 07240d40 file 0000032e im.db-journal
000005f9 00001b3d 07245780 file 0000032e im.db-journal
000005f9 00001b3d 07246800 file 0000032e im.db-journal
000005f9 00001b3d 0724b240 file 00000003 unlinked
000005f9 00001b3d 0724ba80 file 00000004 deleted
Inodes for older versions are created using the object ID and version number. A version number of zero always returns the current version of the object. To avoid name conflicts, non-current versions have their version number and object ID appended to the file name.
r/r 764: pvcodec.txt
r/r * 2360060: pvcodec.txt#764,9
r/r * 2097916: pvcodec.txt#764,8
r/r * 1835772: pvcodec.txt#764,7
We consider a version of an object to be unallocated if it is not the most recent version or if the most recent header block is a deleted block. We consider a chunk to be allocated if it is part of an allocated version of an object. Since each chunk contains the object ID it belongs to, linking chunks with objects to determine their allocated status is fairly simple.
Last modified: 2013-06-17