mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
Update to v1.0.1.
This commit is contained in:
parent
3888e6a54c
commit
a122605b6e
8 changed files with 92 additions and 68 deletions
2
Makefile
2
Makefile
|
@ -33,7 +33,7 @@ include $(DEVKITPRO)/libnx/switch_rules
|
|||
|
||||
VERSION_MAJOR := 1
|
||||
VERSION_MINOR := 0
|
||||
VERSION_MICRO := 0
|
||||
VERSION_MICRO := 1
|
||||
|
||||
APP_TITLE := Game Card Dump Tool
|
||||
APP_AUTHOR := MCMrARM, DarkMatterCore
|
||||
|
|
16
README.md
16
README.md
|
@ -4,7 +4,7 @@ Nintendo Switch Game Card Dump Tool
|
|||
Main features
|
||||
--------------
|
||||
|
||||
* Generates full XCI cartridge dumps (with optional certificate removal). All dumps are padded with 0xFF up to the actual game card size.
|
||||
* Generates full XCI cartridge dumps (with optional certificate removal). All dumps are padded with 0xFF to match the full game card size.
|
||||
* 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).
|
||||
|
@ -21,3 +21,17 @@ Thanks to
|
|||
* Foen, for giving me some pretty good hints about how to use the NCM service.
|
||||
* Yellows8, for helping me fix a silly bug in my implementation of some NCM service IPC calls.
|
||||
* The folks from ReSwitched, for working towards the creation of a good homebrew ecosystem.
|
||||
|
||||
Changelog
|
||||
--------------
|
||||
|
||||
**v1.0.1:**
|
||||
|
||||
* Minor UI fixes and tweaks.
|
||||
* Added some missing Title ID checks in uiLoop().
|
||||
* All calls to uiStatusMsg() are now properly identified.
|
||||
* Increased wait time to 2 seconds when a new gamecard is detected.
|
||||
|
||||
**v1.0.0:**
|
||||
|
||||
Initial release.
|
||||
|
|
|
@ -45,38 +45,33 @@ bool getRootHfs0Header(FsDeviceOperator* fsOperator)
|
|||
Result result;
|
||||
FsStorage gameCardStorage;
|
||||
|
||||
//breaks = 0;
|
||||
//uiClearScreen();
|
||||
|
||||
hfs0_partition_cnt = 0;
|
||||
|
||||
workaroundPartitionZeroAccess(fsOperator);
|
||||
|
||||
if (R_FAILED(result = fsDeviceOperatorGetGameCardHandle(fsOperator, &handle)))
|
||||
{
|
||||
//snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "GetGameCardHandle failed! (0x%08X)", result);
|
||||
//uiDrawString(strbuf, 0, breaks * 8, 255, 0, 0);
|
||||
uiStatusMsg("getRootHfs0Header: GetGameCardHandle failed! (0x%08X)", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (R_FAILED(result = fsOpenGameCardStorage(&gameCardStorage, handle, 0)))
|
||||
{
|
||||
//snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "OpenGameCardStorage failed! (0x%08X)", result);
|
||||
//uiDrawString(strbuf, 0, breaks * 8, 255, 0, 0);
|
||||
uiStatusMsg("getRootHfs0Header: OpenGameCardStorage failed! (0x%08X)", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
char *gamecard_header = (char*)malloc(GAMECARD_HEADER_SIZE);
|
||||
if (!gamecard_header)
|
||||
{
|
||||
uiStatusMsg("getRootHfs0Header: Unable to allocate memory for the gamecard header!");
|
||||
fsStorageClose(&gameCardStorage);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (R_FAILED(result = fsStorageRead(&gameCardStorage, 0, gamecard_header, GAMECARD_HEADER_SIZE)))
|
||||
{
|
||||
//snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "StorageRead failed! (0x%08X)", result);
|
||||
//uiDrawString(strbuf, 0, breaks * 8, 255, 0, 0);
|
||||
uiStatusMsg("getRootHfs0Header: StorageRead failed to read %u-byte chunk from offset 0x%016lX! (0x%08X)", GAMECARD_HEADER_SIZE, 0, result);
|
||||
|
||||
free(gamecard_header);
|
||||
|
||||
|
@ -108,8 +103,7 @@ bool getRootHfs0Header(FsDeviceOperator* fsOperator)
|
|||
gameCardSize = GAMECARD_SIZE_32GiB;
|
||||
break;
|
||||
default:
|
||||
//snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Invalid game card size value: 0x%02X", cardSize);
|
||||
//uiDrawString(strbuf, 0, breaks * 8, 255, 0, 0);
|
||||
uiStatusMsg("getRootHfs0Header: Invalid game card size value: 0x%02X", cardSize);
|
||||
|
||||
free(gamecard_header);
|
||||
|
||||
|
@ -125,19 +119,16 @@ bool getRootHfs0Header(FsDeviceOperator* fsOperator)
|
|||
|
||||
free(gamecard_header);
|
||||
|
||||
/*snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Root HFS0 offset: 0x%016lX", hfs0_offset);
|
||||
uiDrawString(strbuf, 0, breaks * 8, 255, 255, 255);
|
||||
breaks++;
|
||||
/*uiStatusMsg("getRootHfs0Header: Root HFS0 offset: 0x%016lX", hfs0_offset);
|
||||
delay(1);
|
||||
|
||||
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Root HFS0 size: 0x%016lX", hfs0_size);
|
||||
uiDrawString(strbuf, 0, breaks * 8, 255, 255, 255);
|
||||
breaks++;*/
|
||||
uiStatusMsg("getRootHfs0Header: Root HFS0 size: 0x%016lX", hfs0_size);
|
||||
delay(1);*/
|
||||
|
||||
hfs0_header = (char*)malloc(hfs0_size);
|
||||
if (!hfs0_header)
|
||||
{
|
||||
//snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Failed to allocate buffer!");
|
||||
//uiDrawString(strbuf, 0, breaks * 8, 255, 0, 0);
|
||||
uiStatusMsg("getRootHfs0Header: Unable to allocate memory for the root HFS0 header!");
|
||||
|
||||
gameCardSize = 0;
|
||||
memset(gameCardSizeStr, 0, sizeof(gameCardSizeStr));
|
||||
|
@ -151,8 +142,7 @@ bool getRootHfs0Header(FsDeviceOperator* fsOperator)
|
|||
|
||||
if (R_FAILED(result = fsStorageRead(&gameCardStorage, hfs0_offset, hfs0_header, hfs0_size)))
|
||||
{
|
||||
//snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "StorageRead failed! (0x%08X)", result);
|
||||
//uiDrawString(strbuf, 0, breaks * 8, 255, 0, 0);
|
||||
uiStatusMsg("getRootHfs0Header: StorageRead failed to read %u-byte chunk from offset 0x%016lX! (0x%08X)", hfs0_size, hfs0_offset, result);
|
||||
|
||||
gameCardSize = 0;
|
||||
memset(gameCardSizeStr, 0, sizeof(gameCardSizeStr));
|
||||
|
@ -171,8 +161,7 @@ bool getRootHfs0Header(FsDeviceOperator* fsOperator)
|
|||
|
||||
if (magic != HFS0_MAGIC)
|
||||
{
|
||||
//snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Magic word mismatch! 0x%08X != 0x%08X", magic, HFS0_MAGIC);
|
||||
//uiDrawString(strbuf, 0, breaks * 8, 255, 0, 0);
|
||||
uiStatusMsg("getRootHfs0Header: Magic word mismatch! 0x%08X != 0x%08X", magic, HFS0_MAGIC);
|
||||
|
||||
gameCardSize = 0;
|
||||
memset(gameCardSizeStr, 0, sizeof(gameCardSizeStr));
|
||||
|
@ -341,8 +330,6 @@ bool dumpGameCartridge(FsDeviceOperator* fsOperator, bool isFat32, bool dumpCert
|
|||
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Dumping partition #%u...", partition);
|
||||
uiDrawString(strbuf, 0, breaks * 8, 255, 255, 255);
|
||||
|
||||
syncDisplay();
|
||||
|
||||
workaroundPartitionZeroAccess(fsOperator);
|
||||
|
||||
if (R_SUCCEEDED(result = fsDeviceOperatorGetGameCardHandle(fsOperator, &handle)))
|
||||
|
@ -494,8 +481,6 @@ bool dumpGameCartridge(FsDeviceOperator* fsOperator, bool isFat32, bool dumpCert
|
|||
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Writing 0xFF padding...");
|
||||
uiDrawString(strbuf, 0, breaks * 8, 255, 255, 255);
|
||||
|
||||
syncDisplay();
|
||||
|
||||
for(partitionOffset = 0; partitionOffset < paddingSize; partitionOffset += n, fileOffset += n)
|
||||
{
|
||||
if (DUMP_BUFFER_SIZE > (paddingSize - partitionOffset)) n = (paddingSize - partitionOffset);
|
||||
|
@ -946,8 +931,6 @@ bool copyFile(const char* source, const char* dest, bool doSplitting)
|
|||
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Copying \"%s\"...", source);
|
||||
uiDrawString(strbuf, 0, breaks * 8, 255, 255, 255);
|
||||
|
||||
syncDisplay();
|
||||
|
||||
if ((destLen + 1) < NAME_BUF_LEN)
|
||||
{
|
||||
inFile = fopen(source, "rb");
|
||||
|
|
|
@ -50,6 +50,8 @@ int main(int argc, char **argv)
|
|||
{
|
||||
currentFB = gfxGetFramebuffer(¤tFBWidth, ¤tFBHeight);
|
||||
|
||||
uiPrintHeadline();
|
||||
|
||||
gameCardInserted = isGameCardInserted(&fsOperatorInstance);
|
||||
|
||||
if (gameCardInserted)
|
||||
|
@ -57,13 +59,14 @@ int main(int argc, char **argv)
|
|||
if (hfs0_header == NULL)
|
||||
{
|
||||
// Don't access the gamecard immediately to avoid conflicts with the fs-srv, ncm and ns services
|
||||
delay(1);
|
||||
uiPleaseWait();
|
||||
|
||||
getRootHfs0Header(&fsOperatorInstance);
|
||||
|
||||
getGameCardTitleID(&gameCardTitleID);
|
||||
|
||||
getGameCardControlNacp(gameCardTitleID, gameCardName, sizeof(gameCardName), gameCardAuthor, sizeof(gameCardAuthor), gameCardVersion, sizeof(gameCardVersion));
|
||||
|
||||
uiPrintHeadline();
|
||||
uiUpdateStatusMsg();
|
||||
}
|
||||
} else {
|
||||
if (hfs0_header != NULL)
|
||||
|
|
57
source/ui.c
57
source/ui.c
|
@ -49,7 +49,7 @@ static char titlebuf[NAME_BUF_LEN * 2] = {'\0'};
|
|||
static const int maxListElements = 45;
|
||||
|
||||
static char *filenameBuffer = NULL;
|
||||
static char *filenames[FILENAMES_COUNT_MAX];
|
||||
static char *filenames[FILENAME_MAX_CNT];
|
||||
static int filenamesCount = 0;
|
||||
|
||||
static UIState uiState;
|
||||
|
@ -229,7 +229,7 @@ void uiDrawString(const char* string, int x, int y, u8 r, u8 g, u8 b)
|
|||
|
||||
void uiStatusMsg(const char* format, ...)
|
||||
{
|
||||
statusMessageFadeout = 500;
|
||||
statusMessageFadeout = 1000;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(statusMessage, sizeof(statusMessage) / sizeof(statusMessage[0]), format, args);
|
||||
|
@ -238,6 +238,24 @@ void uiStatusMsg(const char* format, ...)
|
|||
//printf("Status message: %s\n", statusMessage);
|
||||
}
|
||||
|
||||
void uiUpdateStatusMsg()
|
||||
{
|
||||
if (!strlen(statusMessage) || !statusMessageFadeout) return;
|
||||
|
||||
int fadeout = (statusMessageFadeout > 255 ? 255 : statusMessageFadeout);
|
||||
uiFill(0, currentFBHeight - 12, currentFBWidth, 8, 50, 50, 50);
|
||||
uiDrawString(statusMessage, 4, currentFBHeight - 12, fadeout, fadeout, fadeout);
|
||||
statusMessageFadeout -= 4;
|
||||
}
|
||||
|
||||
void uiPleaseWait()
|
||||
{
|
||||
breaks = headlineCnt;
|
||||
uiDrawString("Please wait...", 0, breaks * 8, 115, 115, 255);
|
||||
syncDisplay();
|
||||
delay(2);
|
||||
}
|
||||
|
||||
void uiUpdateFreeSpace()
|
||||
{
|
||||
getSdCardFreeSpace(&freeSpace);
|
||||
|
@ -255,7 +273,7 @@ void uiInit()
|
|||
scroll = 0;
|
||||
headlineCnt = 0;
|
||||
|
||||
filenameBuffer = (char*)malloc(FILENAMEBUFFER_SIZE);
|
||||
filenameBuffer = (char*)malloc(FILENAME_BUFFER_SIZE);
|
||||
|
||||
int i, headlineLen = strlen(appHeadline);
|
||||
for(i = 0; i < headlineLen; i++)
|
||||
|
@ -292,11 +310,17 @@ void uiClearScreen()
|
|||
uiFill(0, 0, currentFBWidth, currentFBHeight, 50, 50, 50);
|
||||
}
|
||||
|
||||
void uiPrintHeadline()
|
||||
{
|
||||
uiClearScreen();
|
||||
uiDrawString(appHeadline, 0, 0, 255, 255, 255);
|
||||
}
|
||||
|
||||
static void enterDirectory(const char *path)
|
||||
{
|
||||
snprintf(currentDirectory, sizeof(currentDirectory) / sizeof(currentDirectory[0]), "%s", path);
|
||||
|
||||
filenamesCount = FILENAMES_COUNT_MAX;
|
||||
filenamesCount = FILENAME_MAX_CNT;
|
||||
getDirectoryContents(filenameBuffer, &filenames[0], &filenamesCount, currentDirectory, (!strcmp(currentDirectory, "view:/") && strlen(currentDirectory) == 6));
|
||||
|
||||
cursor = 0;
|
||||
|
@ -307,9 +331,6 @@ UIResult uiLoop(u32 keysDown)
|
|||
{
|
||||
UIResult res = resultNone;
|
||||
|
||||
uiClearScreen();
|
||||
uiDrawString(appHeadline, 0, 0, 255, 255, 255);
|
||||
|
||||
int i;
|
||||
breaks = headlineCnt;
|
||||
|
||||
|
@ -326,7 +347,7 @@ UIResult uiLoop(u32 keysDown)
|
|||
|
||||
if (uiState != stateViewGameCardFsBrowser)
|
||||
{
|
||||
if (gameCardInserted && hfs0_header != NULL && (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT || hfs0_partition_cnt == GAMECARD_TYPE2_PARTITION_CNT))
|
||||
if (gameCardInserted && hfs0_header != NULL && (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT || hfs0_partition_cnt == GAMECARD_TYPE2_PARTITION_CNT) && gameCardTitleID != 0)
|
||||
{
|
||||
uiDrawString("Game Card is inserted!", 0, breaks * 8, 0, 255, 0);
|
||||
breaks += 2;
|
||||
|
@ -372,8 +393,13 @@ UIResult uiLoop(u32 keysDown)
|
|||
{
|
||||
if (hfs0_header != NULL)
|
||||
{
|
||||
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "Error: unknown root HFS0 header partition count! (%u)", hfs0_partition_cnt);
|
||||
uiDrawString(titlebuf, 0, breaks * 8, 255, 0, 0);
|
||||
if (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT || hfs0_partition_cnt == GAMECARD_TYPE2_PARTITION_CNT)
|
||||
{
|
||||
uiDrawString("Error: unable to retrieve the game card Title ID!", 0, breaks * 8, 255, 0, 0);
|
||||
} else {
|
||||
snprintf(titlebuf, sizeof(titlebuf) / sizeof(titlebuf[0]), "Error: unknown root HFS0 header partition count! (%u)", hfs0_partition_cnt);
|
||||
uiDrawString(titlebuf, 0, breaks * 8, 255, 0, 0);
|
||||
}
|
||||
} else {
|
||||
uiDrawString("Error: unable to get root HFS0 header data!", 0, breaks * 8, 255, 0, 0);
|
||||
}
|
||||
|
@ -387,7 +413,7 @@ UIResult uiLoop(u32 keysDown)
|
|||
breaks += 2;
|
||||
}
|
||||
|
||||
if (gameCardInserted && hfs0_header != NULL && (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT || hfs0_partition_cnt == GAMECARD_TYPE2_PARTITION_CNT))
|
||||
if (gameCardInserted && hfs0_header != NULL && (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT || hfs0_partition_cnt == GAMECARD_TYPE2_PARTITION_CNT) && gameCardTitleID != 0)
|
||||
{
|
||||
const char **menu = NULL;
|
||||
int menuItemsCount;
|
||||
|
@ -719,12 +745,7 @@ UIResult uiLoop(u32 keysDown)
|
|||
res = resultShowMainMenu;
|
||||
}
|
||||
|
||||
if (statusMessageFadeout > 0)
|
||||
{
|
||||
int fadeout = (statusMessageFadeout > 255 ? 255 : statusMessageFadeout);
|
||||
uiDrawString(statusMessage, 4, currentFBHeight - 12, fadeout, fadeout, fadeout);
|
||||
statusMessageFadeout -= 4;
|
||||
}
|
||||
|
||||
uiUpdateStatusMsg();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
11
source/ui.h
11
source/ui.h
|
@ -3,8 +3,8 @@
|
|||
#ifndef __UI_H__
|
||||
#define __UI_H__
|
||||
|
||||
#define FILENAMEBUFFER_SIZE (1024 * 32) // 32 KiB
|
||||
#define FILENAMES_COUNT_MAX 2048
|
||||
#define FILENAME_BUFFER_SIZE (1024 * 32) // 32 KiB
|
||||
#define FILENAME_MAX_CNT 2048
|
||||
|
||||
typedef enum {
|
||||
resultNone,
|
||||
|
@ -38,10 +38,14 @@ typedef enum {
|
|||
stateDumpGameCardCertificate
|
||||
} UIState;
|
||||
|
||||
void uiStatusMsg(const char* fmt, ...);
|
||||
void uiFill(int x, int y, int width, int height, u8 r, u8 g, u8 b);
|
||||
void uiDrawString(const char* string, int x, int y, u8 r, u8 g, u8 b);
|
||||
|
||||
void uiStatusMsg(const char* fmt, ...);
|
||||
void uiUpdateStatusMsg();
|
||||
|
||||
void uiPleaseWait();
|
||||
|
||||
void uiUpdateFreeSpace();
|
||||
|
||||
void uiInit();
|
||||
|
@ -51,6 +55,7 @@ void uiSetState(UIState state);
|
|||
UIState uiGetState();
|
||||
|
||||
void uiClearScreen();
|
||||
void uiPrintHeadline();
|
||||
|
||||
UIResult uiLoop(u32 keysDown);
|
||||
|
||||
|
|
|
@ -61,21 +61,21 @@ bool getGameCardTitleID(u64 *titleID)
|
|||
*titleID = appList->meta_record.titleID;
|
||||
success = true;
|
||||
} else {
|
||||
uiStatusMsg("MetaDatabaseListApplication failed! (0x%08x)", result);
|
||||
uiStatusMsg("getGameCardTitleID: MetaDatabaseListApplication failed! (0x%08x)", result);
|
||||
}
|
||||
} else {
|
||||
uiStatusMsg("GetContentMetaDatabase failed! (0x%08x)", result);
|
||||
uiStatusMsg("getGameCardTitleID: GetContentMetaDatabase failed! (0x%08x)", result);
|
||||
}
|
||||
} else {
|
||||
uiStatusMsg("OpenContentMetaDatabase failed! (0x%08x)", result);
|
||||
uiStatusMsg("getGameCardTitleID: OpenContentMetaDatabase failed! (0x%08x)", result);
|
||||
}
|
||||
|
||||
// Seems to cause problems
|
||||
//if (R_FAILED(result = ncmCloseContentMetaDatabase(FsStorageId_GameCard))) uiStatusMsg("CloseContentMetaDatabase failed! (0x%08x)", result);
|
||||
//if (R_FAILED(result = ncmCloseContentMetaDatabase(FsStorageId_GameCard))) uiStatusMsg("getGameCardTitleID: CloseContentMetaDatabase failed! (0x%08x)", result);
|
||||
|
||||
free(appList);
|
||||
} else {
|
||||
uiStatusMsg("Unable to allocate memory for the NCM service operations.");
|
||||
uiStatusMsg("getGameCardTitleID: Unable to allocate memory for the NCM service operations.");
|
||||
}
|
||||
|
||||
return success;
|
||||
|
@ -103,25 +103,23 @@ bool getGameCardControlNacp(u64 titleID, char *nameBuf, int nameBufSize, char *a
|
|||
if (R_SUCCEEDED(result = nacpGetLanguageEntry(&buf->nacp, &langentry)))
|
||||
{
|
||||
strncpy(nameBuf, langentry->name, nameBufSize - 1);
|
||||
|
||||
strncpy(authorBuf, langentry->author, authorBufSize - 1);
|
||||
|
||||
strncpy(versionBuf, buf->nacp.version, versionBufSize - 1);
|
||||
|
||||
success = true;
|
||||
} else {
|
||||
uiStatusMsg("GetLanguageEntry failed! (0x%08x)", result);
|
||||
uiStatusMsg("getGameCardControlNacp: GetLanguageEntry failed! (0x%08x)", result);
|
||||
}
|
||||
} else {
|
||||
uiStatusMsg("Control.nacp buffer size (%u bytes) is too small! Expected: %u bytes", outsize, sizeof(buf->nacp));
|
||||
uiStatusMsg("getGameCardControlNacp: Control.nacp buffer size (%u bytes) is too small! Expected: %u bytes", outsize, sizeof(buf->nacp));
|
||||
}
|
||||
} else {
|
||||
uiStatusMsg("GetApplicationControlData failed! (0x%08x)", result);
|
||||
uiStatusMsg("getGameCardControlNacp: GetApplicationControlData failed! (0x%08x)", result);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
} else {
|
||||
uiStatusMsg("Unable to allocate memory for the NS service operations.");
|
||||
uiStatusMsg("getGameCardControlNacp: Unable to allocate memory for the NS service operations.");
|
||||
}
|
||||
|
||||
return success;
|
||||
|
@ -135,7 +133,7 @@ int getSdCardFreeSpace(u64 *out)
|
|||
rc = statvfs("sdmc:/", &st);
|
||||
if (rc != 0)
|
||||
{
|
||||
uiStatusMsg("Unable to get SD card filesystem stats! statvfs: %d (%s).", errno, strerror(errno));
|
||||
uiStatusMsg("getSdCardFreeSpace: Unable to get SD card filesystem stats! statvfs: %d (%s).", errno, strerror(errno));
|
||||
} else {
|
||||
*out = (u64)(st.f_bsize * st.f_bfree);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include <switch.h>
|
||||
|
||||
#define APP_VERSION "1.0.0"
|
||||
#define APP_VERSION "1.0.1"
|
||||
#define NAME_BUF_LEN 4096
|
||||
|
||||
bool isGameCardInserted(FsDeviceOperator* o);
|
||||
|
|
Loading…
Reference in a new issue