1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-22 18:26:39 +00:00

Update to v1.0.6.

This commit is contained in:
Pablo Curiel 2019-04-23 01:14:57 -04:00
parent edd7eee294
commit d22add43bf
9 changed files with 651 additions and 769 deletions

View file

@ -4,18 +4,18 @@ Nintendo Switch Game Card Dump Tool
Main features
--------------
* Generates XCI cartridge dumps (with optional certificate removal and optional trimming).
* Generates XCI cartridge dumps with optional certificate removal and optional trimming.
* CRC32 checksum calculation for XCI dumps.
* Full XCI dump verification using XML database from nswdb.com (NSWreleases.xml).
* XML database update via libcurl.
* Precise HFS0 raw partition dumping (using the root HFS0 header from the game card).
* Full XCI dump verification using XML database from NSWDB.COM (NSWreleases.xml).
* XML database and in-app update via libcurl.
* Precise HFS0 raw partition dumping, using the root HFS0 header from the game card.
* Partition filesystem data dumping.
* Partition filesystem browser (with manual file dump support).
* Partition filesystem browser with manual file dump support.
* Manual game card certificate dump.
* Free SD card space checks in place.
* File splitting support for all operations, using 2 GiB parts.
* Game card Title ID and Control.nacp retrieval support using NCM and NS services.
* Dump speed and ETA calculation.
* Dump speed, ETA calculation and progress bar.
Thanks to
--------------
@ -31,6 +31,21 @@ Thanks to
Changelog
--------------
**v1.0.6:**
* Updated application codebase in order to make it compatible with the latest devkitA64 and libnx releases.
* Removed some fs-srv service functions from fsext.c/h that have been included in libnx (and fixed the ones that haven't).
* Revamped the GFX code to replace the 8x8 ASCII font with the shared system font, using the pl service and FreeType.
* Enabled (and fixed) the in-app update option. HTTPS compatibility is achieved through the mbedtls portlib.
* Disabled screen dimming and auto sleep.
* Added file counter to partition browser.
* Changed the naming convention for split gamecard dumps to *.xc[part number], in order to make them compatible with SX OS and other tools right away.
* Increased the delay after inserting a new gamecard by 1 second.
* Added a gamecard detection thread to monitor gamecard state changes in a better way. This thread is hooked to a gamecard detection kernel handle retrieved through an IEventNotifier object.
* Replaced partition filesystem mounting through fs-srv service calls with manual HFS0 partition header parsing. This should fix issues when browsing the Logo partition from type 0x02 gamecards.
* Blocked HOME button presses when running as a regular/system application instead of an applet. A warning message will be displayed whenever any operation is started if the application is running as an applet.
* Added detection for bundled FW versions 6.0.0 - 8.0.0.
**v1.0.5:**
* Fixed game card version reading (now using the ncm service instead of retrieving it from the cached Control.nacp).

File diff suppressed because it is too large Load diff

View file

@ -33,6 +33,8 @@
#define GAMECARD_TYPE2_PART_NAMES(x) ((x) == 0 ? "Update" : ((x) == 1 ? "Logo" : ((x) == 2 ? "Normal" : ((x) == 3 ? "Secure" : "Unknown"))))
#define GAMECARD_PARTITION_NAME(x, y) ((x) == GAMECARD_TYPE1_PARTITION_CNT ? GAMECARD_TYPE1_PART_NAMES(y) : ((x) == GAMECARD_TYPE2_PARTITION_CNT ? GAMECARD_TYPE2_PART_NAMES(y) : "Unknown"))
#define HFS0_TO_ISTORAGE_IDX(x, y) ((x) == GAMECARD_TYPE1_PARTITION_CNT ? ((y) < 2 ? 0 : 1) : ((y) < 3 ? 0 : 1))
#define GAMECARD_SIZE_1GiB (u64)0x40000000
#define GAMECARD_SIZE_2GiB (u64)0x80000000
#define GAMECARD_SIZE_4GiB (u64)0x100000000
@ -81,18 +83,12 @@ typedef struct
u8 hashed_region_sha256[0x20];
} PACKED hfs0_entry_table;
void workaroundPartitionZeroAccess(FsDeviceOperator* fsOperator);
bool getRootHfs0Header(FsDeviceOperator* fsOperator);
bool getHsf0PartitionDetails(u32 partition, u64 *out_offset, u64 *out_size);
bool dumpGameCartridge(FsDeviceOperator* fsOperator, bool isFat32, bool dumpCert, bool trimDump, bool calcCrc);
bool dumpRawPartition(FsDeviceOperator* fsOperator, u32 partition, bool doSplitting);
bool openPartitionFs(FsFileSystem* ret, FsDeviceOperator* fsOperator, u32 partition);
bool copyFile(const char* source, const char* dest, bool doSplitting, bool calcEta);
bool copyDirectory(const char* source, const char* dest, bool doSplitting);
void removeDirectory(const char *path);
bool getDirectorySize(const char *path, u64 *out_size);
bool dumpPartitionData(FsDeviceOperator* fsOperator, u32 partition);
bool mountViewPartition(FsDeviceOperator *fsOperator, FsFileSystem *out, u32 partition);
bool getHfs0FileList(FsDeviceOperator* fsOperator, u32 partition);
bool dumpFileFromPartition(FsDeviceOperator* fsOperator, u32 partition, u32 file, char *filename);
bool dumpGameCertificate(FsDeviceOperator *fsOperator);
#endif

View file

@ -46,47 +46,6 @@ Result fsOpenGameCardStorage(FsStorage* out, const FsGameCardHandle* handle, u32
return rc;
}
Result fsOpenGameCardFileSystem(FsFileSystem* out, const FsGameCardHandle* handle, u32 partition)
{
IpcCommand c;
ipcInitialize(&c);
struct {
u64 magic;
u64 cmd_id;
u32 handle;
u32 partition;
} *raw;
raw = serviceIpcPrepareHeader(fsGetServiceSession(), &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 31;
raw->handle = handle->value;
raw->partition = partition;
Result rc = serviceIpcDispatch(fsGetServiceSession());
if (R_SUCCEEDED(rc))
{
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;
serviceIpcParse(fsGetServiceSession(), &r, sizeof(*resp));
resp = r.Raw;
rc = resp->result;
if (R_SUCCEEDED(rc)) serviceCreateSubservice(&out->s, fsGetServiceSession(), &r, 0);
}
return rc;
}
Result fsOpenGameCardDetectionEventNotifier(FsEventNotifier* out)
{
IpcCommand c;

View file

@ -8,7 +8,6 @@
// IFileSystemProxy
Result fsOpenGameCardStorage(FsStorage* out, const FsGameCardHandle* handle, u32 partition);
Result fsOpenGameCardFileSystem(FsFileSystem* out, const FsGameCardHandle* handle, u32 partition);
Result fsOpenGameCardDetectionEventNotifier(FsEventNotifier* out);
// IDeviceOperator

View file

@ -57,7 +57,7 @@ int main(int argc, char *argv[])
result = fsOpenGameCardDetectionEventNotifier(&fsGameCardEventNotifier);
if (R_SUCCEEDED(result))
{
/* Retrieve kernel event handle */
/* Retrieve gamecard detection event handle */
result = fsEventNotifierGetEventHandle(&fsGameCardEventNotifier, &fsGameCardEventHandle);
if (R_SUCCEEDED(result))
{
@ -161,7 +161,7 @@ int main(int argc, char *argv[])
ret = -9;
}
/* Close kernel event */
/* Close gamecard detection kernel event */
eventClose(&fsGameCardKernelEvent);
} else {
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Failed to retrieve gamecard detection event handle! (0x%08X)", result);
@ -171,7 +171,7 @@ int main(int argc, char *argv[])
ret = -8;
}
/* Close gamecard event notifier */
/* Close gamecard detection event notifier */
fsEventNotifierClose(&fsGameCardEventNotifier);
} else {
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Failed to open gamecard detection event notifier! (0x%08X)", result);

View file

@ -19,6 +19,8 @@
extern FsDeviceOperator fsOperatorInstance;
extern AppletType programAppletType;
extern bool gameCardInserted;
extern char gameCardSizeStr[32], trimmedCardSizeStr[32];
@ -27,14 +29,16 @@ extern char *hfs0_header;
extern u64 hfs0_offset, hfs0_size;
extern u32 hfs0_partition_cnt;
extern char *partitionHfs0Header;
extern u64 partitionHfs0HeaderOffset, partitionHfs0HeaderSize;
extern u32 partitionHfs0FileCount, partitionHfs0StrTableSize;
extern u64 gameCardTitleID;
extern u32 gameCardVersion;
extern char gameCardName[0x201], fixedGameCardName[0x201], gameCardAuthor[0x101], gameCardVersionStr[64];
extern char gameCardUpdateVersionStr[128];
extern char currentDirectory[NAME_BUF_LEN];
extern char *filenameBuffer;
extern char *filenames[FILENAME_MAX_CNT];
extern int filenamesCount;
@ -54,19 +58,16 @@ int scroll = 0;
int breaks = 0;
int font_height = 0;
static u32 selectedPartitionIndex;
static u32 selectedFileIndex;
static bool highlight = false;
static bool isFat32 = false, dumpCert = false, trimDump = false, calcCrc = true;
static u32 selectedOption;
static FsFileSystem fs;
static char statusMessage[2048] = {'\0'};
static int statusMessageFadeout = 0;
static char fileCopyPath[NAME_BUF_LEN * 2] = {'\0'};
static int headlineCnt = 0;
u64 freeSpace = 0;
@ -272,19 +273,18 @@ void uiUpdateStatusMsg()
{
if (!strlen(statusMessage) || !statusMessageFadeout) return;
uiFill(0, FB_HEIGHT - (font_height * 2), FB_WIDTH, font_height * 2, BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
if ((statusMessageFadeout - 4) > BG_COLOR_RGB)
{
uiFill(0, FB_HEIGHT - (font_height * 2), FB_WIDTH, font_height * 2, BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
int fadeout = (statusMessageFadeout > 255 ? 255 : statusMessageFadeout);
uiDrawString(statusMessage, 0, FB_HEIGHT - (font_height * 2), fadeout, fadeout, fadeout);
uiRefreshDisplay();
statusMessageFadeout -= 4;
} else {
uiFill(0, FB_HEIGHT - (font_height * 2), FB_WIDTH, font_height * 2, BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
statusMessageFadeout = 0;
}
uiRefreshDisplay();
}
void uiPleaseWait()
@ -411,6 +411,12 @@ int uiInit()
/* Disable screen dimming and auto sleep */
appletSetMediaPlaybackState(true);
/* Get applet type */
programAppletType = appletGetAppletType();
/* Block HOME menu button presses if we're running as a regular application or a system application */
if (programAppletType == AppletType_Application || programAppletType == AppletType_SystemApplication) appletBeginBlockingHomeButton(0);
/* Clear screen */
uiClearScreen();
@ -419,6 +425,9 @@ int uiInit()
void uiDeinit()
{
/* Unblock HOME menu button presses if we're running as a regular application or a system application */
if (programAppletType == AppletType_Application || programAppletType == AppletType_SystemApplication) appletEndBlockingHomeButton();
/* Enable screen dimming and auto sleep */
appletSetMediaPlaybackState(false);
@ -459,6 +468,7 @@ UIResult uiProcess()
int menuItemsCount = 0;
u32 keysDown;
u32 keysHeld;
uiPrintHeadline();
loadGameCardInfo();
@ -588,11 +598,7 @@ UIResult uiProcess()
menu = (const char**)filenames;
menuItemsCount = filenamesCount;
uiDrawString((hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? viewGameCardFsType1MenuItems[selectedOption] : viewGameCardFsType2MenuItems[selectedOption]), 0, breaks * font_height, 115, 115, 255);
breaks += 2;
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "Current directory: %s", currentDirectory);
uiDrawString(titlebuf, 0, breaks * font_height, 255, 255, 255);
uiDrawString((hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? viewGameCardFsType1MenuItems[selectedPartitionIndex] : viewGameCardFsType2MenuItems[selectedPartitionIndex]), 0, breaks * font_height, 115, 115, 255);
breaks += 2;
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "File count: %d | Current file: %d", menuItemsCount, cursor + 1);
@ -677,18 +683,10 @@ UIResult uiProcess()
hidScanInput();
keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
keysHeld = hidKeysHeld(CONTROLLER_P1_AUTO);
// Exit
if (keysDown & KEY_PLUS)
{
if (uiState == stateViewGameCardFsBrowser)
{
fsdevUnmountDevice("view");
fsFsClose(&fs);
}
res = resultExit;
}
if (keysDown & KEY_PLUS) res = resultExit;
// Process key inputs only if the UI state hasn't been changed
if (res == resultNone)
@ -698,11 +696,7 @@ UIResult uiProcess()
if (uiState == stateXciDumpMenu)
{
// Select
if ((keysDown & KEY_A) && cursor == 0)
{
selectedOption = (u32)cursor;
res = resultDumpXci;
}
if ((keysDown & KEY_A) && cursor == 0) res = resultDumpXci;
// Back
if (keysDown & KEY_B) res = resultShowMainMenu;
@ -752,10 +746,10 @@ UIResult uiProcess()
}
// Go up
if (keysDown & KEY_UP) scrollAmount = -1;
if ((keysDown & KEY_DUP) || (keysHeld & KEY_LSTICK_UP) || (keysHeld & KEY_RSTICK_UP)) scrollAmount = -1;
// Go down
if (keysDown & KEY_DOWN) scrollAmount = 1;
if ((keysDown & KEY_DDOWN) || (keysHeld & KEY_LSTICK_DOWN) || (keysHeld & KEY_RSTICK_DOWN)) scrollAmount = 1;
} else {
// Select
if (keysDown & KEY_A)
@ -791,48 +785,27 @@ UIResult uiProcess()
} else
if (uiState == stateRawPartitionDumpMenu)
{
selectedOption = (u32)cursor;
// Save selected partition index
selectedPartitionIndex = (u32)cursor;
res = resultDumpRawPartition;
} else
if (uiState == statePartitionDataDumpMenu)
{
selectedOption = (u32)cursor;
// Save selected partition index
selectedPartitionIndex = (u32)cursor;
res = resultDumpPartitionData;
} else
if (uiState == stateViewGameCardFsMenu)
{
selectedOption = (u32)cursor;
// Save selected partition index
selectedPartitionIndex = (u32)cursor;
res = resultShowViewGameCardFsGetList;
} else
if (uiState == stateViewGameCardFsBrowser)
{
char *selectedPath = (char*)malloc(strlen(currentDirectory) + 1 + strlen(filenames[cursor]) + 2);
memset(selectedPath, 0, strlen(currentDirectory) + 1 + strlen(filenames[cursor]) + 2);
if (strlen(filenames[cursor]) == 2 && !strcmp(filenames[cursor], ".."))
{
for(i = (strlen(currentDirectory) - 1); i >= 0; i--)
{
if (currentDirectory[i] == '/')
{
strncpy(selectedPath, currentDirectory, i);
selectedPath[i] = '\0';
break;
}
}
} else {
snprintf(selectedPath, strlen(currentDirectory) + 1 + strlen(filenames[cursor]) + 2, "%s/%s", currentDirectory, filenames[cursor]);
}
if (isDirectory(selectedPath))
{
enterDirectory(selectedPath);
} else {
snprintf(fileCopyPath, sizeof(fileCopyPath) / sizeof(fileCopyPath[0]), "%s", selectedPath);
res = resultViewGameCardFsBrowserCopyFile;
}
free(selectedPath);
// Save selected file index
selectedFileIndex = (u32)cursor;
res = resultViewGameCardFsBrowserCopyFile;
}
}
@ -845,40 +818,24 @@ UIResult uiProcess()
} else
if (uiState == stateViewGameCardFsBrowser)
{
if (!strcmp(currentDirectory, "view:/") && strlen(currentDirectory) == 6)
{
fsdevUnmountDevice("view");
fsFsClose(&fs);
res = resultShowViewGameCardFsMenu;
} else {
char *selectedPath = (char*)malloc(strlen(currentDirectory) + 1);
memset(selectedPath, 0, strlen(currentDirectory) + 1);
for(i = (strlen(currentDirectory) - 1); i >= 0; i--)
{
if (currentDirectory[i] == '/')
{
strncpy(selectedPath, currentDirectory, i);
selectedPath[i] = '\0';
break;
}
}
if (isDirectory(selectedPath)) enterDirectory(selectedPath);
free(selectedPath);
}
free(partitionHfs0Header);
partitionHfs0Header = NULL;
partitionHfs0HeaderOffset = 0;
partitionHfs0HeaderSize = 0;
partitionHfs0FileCount = 0;
partitionHfs0StrTableSize = 0;
res = resultShowViewGameCardFsMenu;
}
}
// Go up
if (keysDown & KEY_UP) scrollAmount = -1;
if (keysDown & KEY_LEFT) scrollAmount = -5;
if ((keysDown & KEY_DUP) || (keysHeld & KEY_LSTICK_UP) || (keysHeld & KEY_RSTICK_UP)) scrollAmount = -1;
if ((keysDown & KEY_DLEFT) || (keysHeld & KEY_LSTICK_LEFT) || (keysHeld & KEY_RSTICK_LEFT)) scrollAmount = -5;
// Go down
if (keysDown & KEY_DOWN) scrollAmount = 1;
if (keysDown & KEY_RIGHT) scrollAmount = 5;
if ((keysDown & KEY_DDOWN) || (keysHeld & KEY_LSTICK_DOWN) || (keysHeld & KEY_RSTICK_DOWN)) scrollAmount = 1;
if ((keysDown & KEY_DRIGHT) || (keysHeld & KEY_LSTICK_RIGHT) || (keysHeld & KEY_RSTICK_RIGHT)) scrollAmount = 5;
}
// Calculate scroll only if the UI state hasn't been changed
@ -930,6 +887,8 @@ UIResult uiProcess()
uiDrawString(titlebuf, 0, breaks * font_height, 115, 115, 255);
breaks += 2;
uiRefreshDisplay();
dumpGameCartridge(&fsOperatorInstance, isFat32, dumpCert, trimDump, calcCrc);
waitForButtonPress();
@ -939,11 +898,13 @@ UIResult uiProcess()
} else
if (uiState == stateDumpRawPartition)
{
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "Raw %s", (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? partitionDumpType1MenuItems[selectedOption] : partitionDumpType2MenuItems[selectedOption]));
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "Raw %s", (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? partitionDumpType1MenuItems[selectedPartitionIndex] : partitionDumpType2MenuItems[selectedPartitionIndex]));
uiDrawString(titlebuf, 0, breaks * font_height, 115, 115, 255);
breaks += 2;
dumpRawPartition(&fsOperatorInstance, selectedOption, true);
uiRefreshDisplay();
dumpRawPartition(&fsOperatorInstance, selectedPartitionIndex, true);
waitForButtonPress();
@ -952,11 +913,13 @@ UIResult uiProcess()
} else
if (uiState == stateDumpPartitionData)
{
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "Data %s", (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? partitionDumpType1MenuItems[selectedOption] : partitionDumpType2MenuItems[selectedOption]));
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "Data %s", (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? partitionDumpType1MenuItems[selectedPartitionIndex] : partitionDumpType2MenuItems[selectedPartitionIndex]));
uiDrawString(titlebuf, 0, breaks * font_height, 115, 115, 255);
breaks += 2;
dumpPartitionData(&fsOperatorInstance, selectedOption);
uiRefreshDisplay();
dumpPartitionData(&fsOperatorInstance, selectedPartitionIndex);
waitForButtonPress();
@ -965,13 +928,15 @@ UIResult uiProcess()
} else
if (uiState == stateViewGameCardFsGetList)
{
uiDrawString((hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? viewGameCardFsType1MenuItems[selectedOption] : viewGameCardFsType1MenuItems[selectedOption]), 0, breaks * font_height, 115, 115, 255);
uiDrawString((hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? viewGameCardFsType1MenuItems[selectedPartitionIndex] : viewGameCardFsType2MenuItems[selectedPartitionIndex]), 0, breaks * font_height, 115, 115, 255);
breaks += 2;
if (mountViewPartition(&fsOperatorInstance, &fs, selectedOption))
uiRefreshDisplay();
if (getHfs0FileList(&fsOperatorInstance, selectedPartitionIndex))
{
enterDirectory("view:/");
cursor = 0;
scroll = 0;
res = resultShowViewGameCardFsBrowser;
} else {
breaks += 2;
@ -981,45 +946,13 @@ UIResult uiProcess()
} else
if (uiState == stateViewGameCardFsBrowserCopyFile)
{
uiDrawString("Manual File Dump", 0, breaks * font_height, 115, 115, 255);
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "Manual File Dump: %s (Partition %u [%s])", filenames[selectedFileIndex], selectedPartitionIndex, GAMECARD_PARTITION_NAME(hfs0_partition_cnt, selectedPartitionIndex));
uiDrawString(titlebuf, 0, breaks * font_height, 115, 115, 255);
breaks += 2;
FILE *inFile = fopen(fileCopyPath, "rb");
if (inFile)
{
fseek(inFile, 0L, SEEK_END);
u64 input_filesize = ftell(inFile);
fclose(inFile);
if (input_filesize <= freeSpace)
{
char destCopyPath[NAME_BUF_LEN] = {'\0'};
for(i = (strlen(fileCopyPath) - 1); i >= 0; i--)
{
if (fileCopyPath[i] == '/')
{
snprintf(destCopyPath, sizeof(destCopyPath) / sizeof(destCopyPath[0]), "sdmc:/%s v%u (%016lX) - Partition %u (%s)", fixedGameCardName, gameCardVersion, gameCardTitleID, selectedOption, GAMECARD_PARTITION_NAME(hfs0_partition_cnt, selectedOption));
mkdir(destCopyPath, 0744);
snprintf(destCopyPath, sizeof(destCopyPath) / sizeof(destCopyPath[0]), "sdmc:/%s v%u (%016lX) - Partition %u (%s)/%.*s", fixedGameCardName, gameCardVersion, gameCardTitleID, selectedOption, GAMECARD_PARTITION_NAME(hfs0_partition_cnt, selectedOption), (int)(strlen(fileCopyPath) - i), fileCopyPath + i + 1);
break;
}
}
uiDrawString("Hold B to cancel.", 0, breaks * font_height, 255, 255, 255);
breaks += 2;
uiDrawString("Do not press the HOME button. Doing so could corrupt the SD card filesystem.", 0, breaks * font_height, 255, 0, 0);
breaks += 2;
copyFile(fileCopyPath, destCopyPath, true, true);
} else {
uiDrawString("Error: not enough free space available in the SD card.", 0, breaks * font_height, 255, 0, 0);
}
} else {
uiDrawString("Error: unable to get input file size.", 0, breaks * font_height, 255, 0, 0);
}
uiRefreshDisplay();
dumpFileFromPartition(&fsOperatorInstance, selectedPartitionIndex, selectedFileIndex, filenames[selectedFileIndex]);
breaks += 2;

View file

@ -4,6 +4,7 @@
#include <errno.h>
#include <math.h>
#include <dirent.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
@ -53,8 +54,6 @@ static char *result_buf = NULL;
static size_t result_sz = 0;
static size_t result_written = 0;
char currentDirectory[NAME_BUF_LEN] = {'\0'};
char *filenameBuffer = NULL;
char *filenames[FILENAME_MAX_CNT];
int filenamesCount = 0;
@ -65,6 +64,8 @@ Handle fsGameCardEventHandle;
Event fsGameCardKernelEvent;
UEvent exitEvent;
AppletType programAppletType;
bool gameCardInserted;
u64 gameCardSize = 0, trimmedCardSize = 0;
@ -75,7 +76,8 @@ u64 hfs0_offset = 0, hfs0_size = 0;
u32 hfs0_partition_cnt = 0;
char *partitionHfs0Header = NULL;
u64 partitionHfs0HeaderSize = 0;
u64 partitionHfs0HeaderOffset = 0, partitionHfs0HeaderSize = 0;
u32 partitionHfs0FileCount = 0, partitionHfs0StrTableSize = 0;
u64 gameCardTitleID = 0;
u32 gameCardVersion = 0;
@ -287,7 +289,10 @@ void loadGameCardInfo()
{
free(partitionHfs0Header);
partitionHfs0Header = NULL;
partitionHfs0HeaderOffset = 0;
partitionHfs0HeaderSize = 0;
partitionHfs0FileCount = 0;
partitionHfs0StrTableSize = 0;
}
gameCardTitleID = 0;
@ -379,76 +384,44 @@ void waitForButtonPress()
{
hidScanInput();
u32 keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
if (keysDown && !(keysDown & KEY_TOUCH)) break;
if (keysDown && !((keysDown & KEY_TOUCH) || (keysDown & KEY_LSTICK_LEFT) || (keysDown & KEY_LSTICK_RIGHT) || (keysDown & KEY_LSTICK_UP) || (keysDown & KEY_LSTICK_DOWN) || \
(keysDown & KEY_RSTICK_LEFT) || (keysDown & KEY_RSTICK_RIGHT) || (keysDown & KEY_RSTICK_UP) || (keysDown & KEY_RSTICK_DOWN))) break;
}
}
bool isDirectory(char *path)
void addStringToFilenameBuffer(const char *string, char **nextFilename)
{
DIR* dir = opendir(path);
if (!dir) return false;
closedir(dir);
return true;
}
void addString(char **filenames, int *filenamesCount, char **nextFilename, const char *string)
{
filenames[(*filenamesCount)++] = *nextFilename;
filenames[filenamesCount++] = *nextFilename;
strcpy(*nextFilename, string);
*nextFilename += strlen(string) + 1;
*nextFilename += (strlen(string) + 1);
}
static int sortAlpha(const void* a, const void* b)
void removeDirectory(const char *path)
{
return strcasecmp(*((const char**)a), *((const char**)b));
}
void getDirectoryContents(char *filenameBuffer, char **filenames, int *filenamesCount, const char *directory, bool skipParent)
{
struct dirent *ent;
int i, maxFilenamesCount = *filenamesCount;
char *nextFilename = filenameBuffer;
struct dirent* ent;
char cur_path[NAME_BUF_LEN] = {'\0'};
char *slash = (char*)malloc(strlen(directory) + 2);
memset(slash, 0, strlen(directory) + 2);
snprintf(slash, strlen(directory) + 2, "%s/", directory);
*filenamesCount = 0;
if (!skipParent) addString(filenames, filenamesCount, &nextFilename, "..");
DIR* dir = opendir(slash);
DIR *dir = opendir(path);
if (dir)
{
for(i = 0; i < maxFilenamesCount; i++)
while ((ent = readdir(dir)) != NULL)
{
ent = readdir(dir);
if (!ent) break;
if ((strlen(ent->d_name) == 1 && !strcmp(ent->d_name, ".")) || (strlen(ent->d_name) == 2 && !strcmp(ent->d_name, ".."))) continue;
addString(filenames, filenamesCount, &nextFilename, ent->d_name);
snprintf(cur_path, sizeof(cur_path) / sizeof(cur_path[0]), "%s/%s", path, ent->d_name);
if (ent->d_type == DT_DIR)
{
removeDirectory(cur_path);
} else {
remove(cur_path);
}
}
closedir(dir);
rmdir(path);
}
free(slash);
// ".." should stay at the top
qsort(filenames + 1, (*filenamesCount) - 1, sizeof(char*), &sortAlpha);
}
void enterDirectory(const char *path)
{
snprintf(currentDirectory, sizeof(currentDirectory) / sizeof(currentDirectory[0]), "%s", path);
filenamesCount = FILENAME_MAX_CNT;
getDirectoryContents(filenameBuffer, &filenames[0], &filenamesCount, currentDirectory, (!strcmp(currentDirectory, "view:/") && strlen(currentDirectory) == 6));
cursor = 0;
scroll = 0;
}
bool parseNSWDBRelease(xmlDocPtr doc, xmlNodePtr cur, u32 crc)
@ -672,7 +645,13 @@ void updateNSWDBXml()
{
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Downloading XML database from \"%s\", please wait...", nswReleasesXmlUrl);
uiDrawString(strbuf, 0, breaks * font_height, 255, 255, 255);
breaks++;
breaks += 2;
if (programAppletType != AppletType_Application && programAppletType != AppletType_SystemApplication)
{
uiDrawString("Do not press the HOME button. Doing so could corrupt the SD card filesystem.", 0, breaks * font_height, 255, 0, 0);
breaks += 2;
}
uiRefreshDisplay();
@ -930,6 +909,12 @@ void updateApplication()
uiDrawString("Please wait...", 0, breaks * font_height, 255, 255, 255);
breaks += 2;
if (programAppletType != AppletType_Application && programAppletType != AppletType_SystemApplication)
{
uiDrawString("Do not press the HOME button. Doing so could corrupt the SD card filesystem.", 0, breaks * font_height, 255, 0, 0);
breaks += 2;
}
uiRefreshDisplay();
gcDumpToolNro = fopen(gcDumpToolTmpPath, "wb");

View file

@ -26,12 +26,8 @@ void fsGameCardDetectionThreadFunc(void *arg);
void delay(u8 seconds);
bool getGameCardTitleIDAndVersion(u64 *titleID, u32 *version);
void convertTitleVersionToDecimal(u32 version, char *versionBuf, int versionBufSize);
bool getGameCardControlNacp(u64 titleID, char *nameBuf, int nameBufSize, char *authorBuf, int authorBufSize);
void removeIllegalCharacters(char *name);
void strtrim(char *str);
@ -44,13 +40,9 @@ void convertSize(u64 size, char *out, int bufsize);
void waitForButtonPress();
bool isDirectory(char *path);
void addStringToFilenameBuffer(const char *string, char **nextFilename);
void addString(char **filenames, int *filenamesCount, char **nextFilename, const char *string);
void getDirectoryContents(char *filenameBuffer, char **filenames, int *filenamesCount, const char *directory, bool skipParent);
void enterDirectory(const char *path);
void removeDirectory(const char *path);
void gameCardDumpNSWDBCheck(u32 crc);