Horizon nand-dumper Switch
From GameBrew
More actions
| Horizon nand-dumper | |
|---|---|
| General | |
| Author | asdfaaasssdddfff |
| Type | PC Utilities |
| Version | 2018 |
| License | MIT License |
| Last Updated | 2018/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;
}