Skip to content

Instantly share code, notes, and snippets.

@rw-r-r-0644
Created March 30, 2021 18:00
Show Gist options
  • Save rw-r-r-0644/f0a7e556ce42b6e7dcd82026626c8bd5 to your computer and use it in GitHub Desktop.
Save rw-r-r-0644/f0a7e556ce42b6e7dcd82026626c8bd5 to your computer and use it in GitHub Desktop.
ISFS_LoadSuperblock RE
ISFS_Superblock *ISFS_LoadSuperblock(ISFS *isfs)
{
if ((isfs->initState & 2) == 0)
return;
if ((isfs->initState & 0x44) == 0x44)
return NULL;
int latestVersion = 0;
u32 maxGeneration = 0xffffffff;
while (true)
{
int latestSuperblock = -1;
int latestGeneration = 0;
/* Try to load the latest ISFS superblock */
if (ISFS_InitSizeProperties(isfs, FALSE) != 0)
return NULL;
int latestSuperblock = ISFS_FindLatestSuperblock(isfs, FALSE, 0, maxGeneration, 0, &generation, &isfsVersion);
if (latestSuperblock >= 0)
{
isfs->initState &= ~0x20;
latestVersion = isfsVersion;
latestGeneration = generation;
isfs->nextSuperBlock = (latestSuperblock + 1) & ((1 << isfs->superblockCountLog2) - 1U);
}
/* Try to load the latest compat ISFS superblock */
if (ISFS_InitSizeProperties(isfs, TRUE) != 0)
return NULL;
int latestComparSuperblock =
ISFS_FindLatestSuperblock(isfs, TRUE, latestGeneration, maxGeneration, 0, &generation, &isfsVersion);
if (latestComparSuperblock >= 0)
{
isfs->initState |= 0x20;
latestVersion = isfsVersion;
latestGeneration = generation;
isfs->nextSuperBlock = (latestComparSuperblock + 1) & ((1 << isfs->superblockCountLog2) - 1U);
latestSuperblock = latestComparSuperblock;
}
/* Setup size properties according to the current ISFS version */
int rc = ISFS_InitSizeProperties(isfs, (isfs->initState & 0x20) ? TRUE : FALSE);
if ((rc != 0) || (latestSuperblock < 0))
return NULL;
/* This is a simplification of the many __divdi3 calls.
* Results should match, but the code differs
* (isfs->nandBlockSize is also involded, although its value can be simplified away)
*/
u32 clustersPerSuperblock = 1 << (isfs->metadataSizeLog2 - isfs->superblockCountLog2 - 0xe);
u32 dataClusters = (isfs->unkZero2 + isfs->dataAreaSize >> 0xe);
u32 superblockClusterIndex = dataClusters + latestSuperblock * clustersPerSuperblock;
u32 superblockClusterCount = 1 << (isfs->metadataSizeLog2 - isfs->superblockCountLog2 - 0xe);
/* HMAC seed */
*(u32 *)(isfs->field_0x44040 + 0x10) = superblockClusterIndex;
rc = ISFS_ReadCluster(isfs, superblockClusterIndex & 0xffff, superblockClusterCount, 2,
(int)isfs->field_0x44040, &isfs->superblock, NULL);
/* read successfull */
if (rc == 0)
break;
/* one of the two copies of the hmac hash did not match */
if (rc == -0x80471)
{
needsRepair = true;
break:
}
maxGeneration = latestGeneration;
}
if (latestVersion != 0)
{
isfs->initState |= 8;
return NULL;
}
else
isfs->initState &= ~8;
if (!isfs)
return NULL;
isfs->initState |= 4;
if (needsRepair)
ISFS_WriteSuperblock(isfs);
return &isfs->superblock;
}
int ISFS_InitSizeProperties(ISFS *isfs, BOOL isCompat)
{
isfs->unkZero2 = isfs->unkZero1;
isfs->superblockCountLog2 = (isCompat) ? 4 : 6;
if (isfs->nandSizeBytes == 0x4000000)
isfs->metadataSizeLog2 = isfs->superblockCountLog2 + 0xe;
else if ((isfs->nandSizeBytes == 0x8000000) || (isfs->nandSizeBytes == 0x10000000))
isfs->metadataSizeLog2 = isfs->superblockCountLog2 + 0x10;
else if ((isfs->nandSizeBytes == 0x20000000) || (isfs->nandSizeBytes == 0x40000000))
isfs->metadataSizeLog2 = isfs->superblockCountLog2 + 0x12;
else
return -0x80480;
u32 sizeOfSuperblock = 1 << (isfs->metadataSizeLog2 - isfs->superblockCountLog2);
if (sizeOfSuperblock > 0x40000)
return -0x80480;
isfs->dataAreaSize = (isfs->nandSizeBytes - isfs->unkZero2) - (1 << isfs->metadataSizeLog2);
isfs->initState = isfs->initState | 0x40;
return 0;
}
u32 ISFS_FindLatestSuperblock(ISFS *isfs, BOOL isCompat, u32 minGeneration, u32 maxGeneration, u32 unkFieldCheck,
u32 *outGeneration, u32 *outIsfsVersion)
{
*outGeneration = 0;
*outIsfsVersion = 0;
int lastValidSuperblock = -1;
for (u32 superblockIndex = 0; superblockIndex < (1 << isfs->superblockCountLog2); superblockIndex++)
{
/* This is a simplification of the many __divdi3 calls.
* Results should match, but the code differs
* (isfs->nandBlockSize is also involded, although its value can be simplified away)
*/
u32 clustersPerSuperblock = 1 << (isfs->metadataSizeLog2 - isfs->superblockCountLog2 - 0xe);
u32 dataClusters = (isfs->unkZero2 + isfs->dataAreaSize >> 0xe);
u32 superblockClusterIndex = dataClusters + superblockIndex * clustersPerSuperblock;
int rc = ISFS_ReadCluster(isfs, superblockClusterIndex, 1, 0, 0, &isfs->superblock, NULL);
if ((rc != 0) && (rc != -0x80471))
continue;
u32 isfsVersion;
if (!isCompat && ((isfs->super.magic & 0xffffff0f) == 0x53465301))
isfsVersion = ((isfs->super.magic >> 4) == 2) ? 0 : 1;
else if (isfs->super.magic == 0x53464653)
isfsVersion = 0;
else
continue;
if (unkFieldCheck > (isfs->super.unkFieldCheck + 1))
continue;
if (unkFieldCheck > isfs->super.unkFieldCheck)
isfs->super.unkFieldCheck = unkFieldCheck;
if (isfs->super.generation < minGeneration)
continue;
if (isfs->super.generation >= maxGeneration)
continue;
if (isfs->super.generation < *outGeneration)
continue;
*outGeneration = isfs->super.generation;
*outIsfsVersion = isfsVersion;
lastValidSuperblock = superblockIndex;
}
return lastValidSuperblock;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment