Horizon nand-dumper Switch

From GameBrew
Horizon nand-dumper
Switch-logo.png
General
Authorasdfaaasssdddfff
TypePC Utilities
Version2018
LicenseMIT License
Last Updated2018/09/15
Links
Source Only Download
Website

An open source tool which dumps the nand from horizon, similar to what reinx-toolbox does.

It's mostly a direct port of this pegaswitch-script.

It will dump boot0+1, prodinfo and the rawnand to the root of the sdcard, automatically splitting the file if on a fat32-sdcard (source below).

Warning: This may or may not result in a corrupted backup, the author takes no responsibility whatsoever for bricks. If you want a proper backup use hekate which has proper backup-verification.

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/statvfs.h>
#include <unistd.h>
#include <switch.h>

#define MIN(x, y) (((x) < (y)) ? (x) : (y))

/*
This is basically a port of this pegaswitch-script:
https://github.com/reswitched/pegaswitch/blob/master/usefulscripts/DumpBIS.js
*/

int partitionIds[] = {0, 10, 27, 20};
char *partitionNames[] = {"BOOT0", "BOOT1", "PRODINFO", "rawnand"};

#define BufSize 0x500000

long GetAvailableSpace(const char *path)
{
    struct statvfs stat;

    if (statvfs(path, &stat) != 0)
    {
        // error happens, just quits here
        return -1;
    }

    // the available size is f_bsize * f_bavail
    return stat.f_bsize * stat.f_bavail;
}

int dumpPartition(int partitionIndex)
{
    printf("\n%s\n", partitionNames[partitionIndex]);
    int id = partitionIds[partitionIndex];

    char *buffer = malloc(BufSize);

    FsStorage partition;
    fsOpenBisStorage(&partition, id);
    u64 size = 0;
    fsStorageGetSize(&partition, &size);

    if (GetAvailableSpace("/") < size)
    {
        consoleClear();
        fsStorageClose(&partition);
        printf("Not enough space left on the sd!\n");
        while (appletMainLoop())
        {

            hidScanInput();
            u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);

            if (kDown & KEY_PLUS)
                break;

            gfxFlushBuffers();
            gfxSwapBuffers();
        }
        return -1;
    }

    int file_num = 0;

    char filename[100];
    sprintf(filename, "/%s.bin", partitionNames[partitionIndex]);

    FILE *partitionfile = fopen(filename, "wb");

    u64 curPos = 0;

    bool isFat32 = false;

    // dump loop
    while (appletMainLoop())
    {
        u64 readSize = MIN(size - curPos, BufSize);
        if (readSize == 0)
            break;

        fsStorageRead(&partition, curPos, buffer, readSize);

        u64 sucessfullyWriten = fwrite(buffer, 1, readSize, partitionfile);

        curPos += sucessfullyWriten;

        if (sucessfullyWriten < readSize)
        {
            fclose(partitionfile);
            // Filesystem doesn't support big files
            if(!isFat32) {
                char oldFilename[100];
                strcpy(oldFilename, filename);
                sprintf(filename, "/%s_%d.bin", partitionNames[partitionIndex], file_num++);
                rename(oldFilename, filename);
                isFat32 = true;
            }
            sprintf(filename, "/%s_%d.bin", partitionNames[partitionIndex], file_num++);
            partitionfile = fopen(filename, "wb");
        }


        printf("\r%lu/%lu", curPos, size);

        gfxFlushBuffers();
        gfxSwapBuffers();
    }
    fclose(partitionfile);
    fsStorageClose(&partition);
    free(buffer);

    return 0;
}

int main(int argc, char **argv)
{
    gfxInitDefault();
    consoleInit(NULL);

    printf("ATTENTION, DO NOT USE THIS AS YOUR PRIMARY BACKUP!\n");
    printf("I'm serious: I'll not be responsible for any bricks because of this!\n");
    printf("Press + if you want to continue\n");

    while (appletMainLoop())
    {
        hidScanInput();
        u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);

        if (kDown & KEY_PLUS)
            break;

        gfxFlushBuffers();
        gfxSwapBuffers();
    }
    
    consoleClear();

    for (int i = 0; i < (sizeof(partitionIds) / sizeof(int)); i++)
    {
        if(dumpPartition(i) != 0)
            return 0;
    }

    printf("\nDump complete!\nPress + to exit");

    while (appletMainLoop())
    {
        hidScanInput();
        u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);

        if (kDown & KEY_PLUS)
            break;

        gfxFlushBuffers();
        gfxSwapBuffers();
    }

    gfxExit();
    return 0;
}

External links

Advertising: