More actions
(Created page with "{{Infobox Switch Homebrews |title=Horizon nand-dumper |image=horizonnanddumperswitch.png |description=Open source horizon nand-dumper. |author=asdfaaasssdddfff |lastupdated=2018/09/15 |type=PC Utilities |version=2018 |license=Mixed |download=https://dlhb.gamebrew.org/switchhomebrews/horizonnanddumperswitch.7z |website=https://gbatemp.net/threads/open-source-horizon-nand-dumper.518095/ |source= |donation= }} {{#seo: |title=Switch Homebrew PC Tools (PC Utilities) - GameBr...") |
No edit summary |
||
Line 1: | Line 1: | ||
{{Infobox Switch Homebrews | {{Infobox Switch Homebrews | ||
|title=Horizon nand-dumper | |title=Horizon nand-dumper | ||
|image= | |image=switch-logo.png | ||
|description=Open source horizon nand-dumper. | |description=Open source horizon nand-dumper. | ||
|author=asdfaaasssdddfff | |author=asdfaaasssdddfff | ||
|lastupdated=2018/09/15 | |lastupdated=2018/09/15 | ||
|type=PC Utilities | |type=PC Utilities | ||
|version=2018 | |version=2018 | ||
|license= | |license=MIT | ||
|download=https://dlhb.gamebrew.org/switchhomebrews/horizonnanddumperswitch.7z | |download=https://dlhb.gamebrew.org/switchhomebrews/horizonnanddumperswitch.7z Source Only | ||
|website=https://gbatemp.net/threads/open-source-horizon-nand-dumper.518095/ | |website=https://gbatemp.net/threads/open-source-horizon-nand-dumper.518095/ | ||
|source= | |source= | ||
|donation= | |donation= | ||
}} | }} | ||
{{# | An open source tool which dumps the nand from horizon, similar to what [[ReiNX_Toolkit_Switch|reinx-toolbox]] does. | ||
It's mostly a direct port of this [https://github.com/reswitched/pegaswitch/blob/master/usefulscripts/DumpBIS.js 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. | ||
<pre> | |||
#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; | |||
} | |||
</pre> | |||
== External links == | == External links == | ||
* | * GBAtemp - https://gbatemp.net/threads/open-source-horizon-nand-dumper.518095/ | ||
Revision as of 01:49, 7 Haziran 2023
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; }