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

More USB changes.

* usb: copy command ID and block size before moving command data within the USB transfer buffer.

* nsp_dumper_usb: now spans a background thread for the dump process, progress is now displayed, process can now be cancelled by holding B, updated to properly make use of the new usbCancelFileTransfer() behavior.

* usb_gc_dumper: updated to properly make use of the new usbCancelFileTransfer() behavior.

* usb_romfs_dumper: updated to properly make use of the new usbCancelFileTransfer() behavior.

* Updated ns-usbloader patch. Must be used on commit `8771d551a4e6fa2d645e519d504a377e34cbd730`.
This commit is contained in:
Pablo Curiel 2021-02-16 08:22:14 -04:00
parent b6759f764b
commit de076f4908
5 changed files with 515 additions and 151 deletions

View file

@ -30,6 +30,15 @@
#define BLOCK_SIZE 0x800000
typedef struct
{
void *data;
size_t data_written;
size_t total_size;
bool error;
bool transfer_cancelled;
} ThreadSharedData;
static const char *dump_type_strings[] = {
"dump base application",
"dump update",
@ -55,42 +64,30 @@ static options_t options[] = {
static const u32 options_count = MAX_ELEMENTS(options);
static Mutex g_conMutex = 0;
static void consolePrint(const char *text, ...)
{
mutexLock(&g_conMutex);
va_list v;
va_start(v, text);
vfprintf(stdout, text, v);
va_end(v);
consoleUpdate(NULL);
mutexUnlock(&g_conMutex);
}
static void nspDump(TitleInfo *title_info)
static void consoleRefresh(void)
{
if (!title_info || !title_info->content_count || !title_info->content_infos) return;
mutexLock(&g_conMutex);
consoleUpdate(NULL);
mutexUnlock(&g_conMutex);
}
static void dump_thread_func(void *arg)
{
ThreadSharedData *shared_data = (ThreadSharedData*)arg;
consoleClear();
TitleApplicationMetadata *app_metadata = title_info->app_metadata;
printf("%s info:\n\n", title_info->meta_key.type == NcmContentMetaType_Application ? "base application" : \
(title_info->meta_key.type == NcmContentMetaType_Patch ? "update" : "dlc"));
if (app_metadata)
{
printf("name: %s\n", app_metadata->lang_entry.name);
printf("publisher: %s\n", app_metadata->lang_entry.author);
}
printf("source storage: %s\n", title_info->storage_id == NcmStorageId_GameCard ? "gamecard" : (title_info->storage_id == NcmStorageId_BuiltInUser ? "emmc" : "sd card"));
printf("title id: %016lX\n", title_info->meta_key.id);
printf("version: %u (%u.%u.%u-%u.%u)\n", title_info->version.value, title_info->version.major, title_info->version.minor, title_info->version.micro, title_info->version.major_relstep, \
title_info->version.minor_relstep);
printf("content count: %u\n", title_info->content_count);
printf("size: %s\n", title_info->size_str);
printf("______________________________\n\n");
printf("dump options:\n\n");
for(u32 i = 0; i < options_count; i++) printf("%s: %s\n", options[i].str, options[i].val ? "yes" : "no");
printf("______________________________\n\n");
TitleInfo *title_info = NULL;
bool set_download_type = options[0].val;
bool remove_console_data = options[1].val;
@ -99,7 +96,7 @@ static void nspDump(TitleInfo *title_info)
bool patch_sua = options[4].val;
bool patch_screenshot = options[5].val;
bool patch_video_capture = options[6].val;
bool success = false, usb_conn = false;
bool success = false;
u8 *buf = NULL;
char *dump_name = NULL, *path = NULL;
@ -110,13 +107,13 @@ static void nspDump(TitleInfo *title_info)
ContentMetaContext cnmt_ctx = {0};
ProgramInfoContext *program_info_ctx = NULL;
u32 program_idx = 0, program_count = titleGetContentCountByType(title_info, NcmContentType_Program);
u32 program_idx = 0, program_count = 0;
NacpContext *nacp_ctx = NULL;
u32 control_idx = 0, control_count = titleGetContentCountByType(title_info, NcmContentType_Control);
u32 control_idx = 0, control_count = 0;
LegalInfoContext *legal_info_ctx = NULL;
u32 legal_info_idx = 0, legal_info_count = titleGetContentCountByType(title_info, NcmContentType_LegalInformation);
u32 legal_info_idx = 0, legal_info_count = 0;
Ticket tik = {0};
TikCommonBlock *tik_common_block = NULL;
@ -134,6 +131,12 @@ static void nspDump(TitleInfo *title_info)
Sha256Context sha256_ctx = {0};
u8 sha256_hash[SHA256_HASH_SIZE] = {0};
if (!shared_data || !(title_info = (TitleInfo*)shared_data->data) || !title_info->content_count || !title_info->content_infos) goto end;
program_count = titleGetContentCountByType(title_info, NcmContentType_Program);
control_count = titleGetContentCountByType(title_info, NcmContentType_Control);
legal_info_count = titleGetContentCountByType(title_info, NcmContentType_LegalInformation);
/* Allocate memory for the dump process. */
if (!(buf = usbAllocatePageAlignedBuffer(BLOCK_SIZE)))
{
@ -461,31 +464,7 @@ static void nspDump(TitleInfo *title_info)
nsp_size = (nsp_header_size + pfs_file_ctx.fs_size);
consolePrint("nsp header size: 0x%lX | nsp size: 0x%lX\n", nsp_header_size, nsp_size);
consolePrint("waiting for usb connection... ");
time_t start = time(NULL);
while(true)
{
time_t now = time(NULL);
if ((now - start) >= 10) break;
consolePrint("%lu ", now - start);
if ((usb_conn = usbIsReady())) break;
utilsSleep(1);
}
consolePrint("\n");
if (!usb_conn)
{
consolePrint("usb connection failed\n");
goto end;
}
consolePrint("dump process started. please wait...\n");
start = time(NULL);
consolePrint("dump process started, please wait. hold b to cancel.\n");
if (!usbSendFileProperties(nsp_size, path, (u32)nsp_header_size))
{
@ -495,6 +474,9 @@ static void nspDump(TitleInfo *title_info)
nsp_offset += nsp_header_size;
// set nsp size
shared_data->total_size = nsp_size;
// write ncas
for(u32 i = 0; i < title_info->content_count; i++)
{
@ -519,8 +501,14 @@ static void nspDump(TitleInfo *title_info)
goto end;
}
for(u64 offset = 0; offset < cur_nca_ctx->content_size; offset += blksize, nsp_offset += blksize)
for(u64 offset = 0; offset < cur_nca_ctx->content_size; offset += blksize, nsp_offset += blksize, shared_data->data_written += blksize)
{
if (shared_data->transfer_cancelled)
{
usbCancelFileTransfer();
goto end;
}
if ((cur_nca_ctx->content_size - offset) < blksize) blksize = (cur_nca_ctx->content_size - offset);
// read nca chunk
@ -606,6 +594,7 @@ static void nspDump(TitleInfo *title_info)
}
nsp_offset += cnmt_ctx.authoring_tool_xml_size;
shared_data->data_written += cnmt_ctx.authoring_tool_xml_size;
// update cnmt xml pfs entry name
if (!pfsUpdateEntryNameFromFileContext(&pfs_file_ctx, meta_nca_ctx->content_type_ctx_data_idx, meta_nca_ctx->content_id_str))
@ -653,6 +642,7 @@ static void nspDump(TitleInfo *title_info)
}
nsp_offset += icon_ctx->icon_size;
shared_data->data_written += icon_ctx->icon_size;
// update pfs entry name
if (!pfsUpdateEntryNameFromFileContext(&pfs_file_ctx, data_idx++, cur_nca_ctx->content_id_str))
@ -684,6 +674,7 @@ static void nspDump(TitleInfo *title_info)
}
nsp_offset += authoring_tool_xml_size;
shared_data->data_written += authoring_tool_xml_size;
// update pfs entry name
if (!pfsUpdateEntryNameFromFileContext(&pfs_file_ctx, data_idx, cur_nca_ctx->content_id_str))
@ -704,6 +695,7 @@ static void nspDump(TitleInfo *title_info)
}
nsp_offset += tik.size;
shared_data->data_written += tik.size;
// write cert
tmp_name = pfsGetEntryNameByIndexFromFileContext(&pfs_file_ctx, pfs_file_ctx.header.entry_count - 1);
@ -714,6 +706,7 @@ static void nspDump(TitleInfo *title_info)
}
nsp_offset += raw_cert_chain_size;
shared_data->data_written += raw_cert_chain_size;
}
// write new pfs0 header
@ -729,13 +722,14 @@ static void nspDump(TitleInfo *title_info)
goto end;
}
start = (time(NULL) - start);
consolePrint("process successfully completed in %lu seconds!\n", start);
shared_data->data_written += nsp_header_size;
success = true;
end:
if (usb_conn && !success) usbCancelFileTransfer();
consoleRefresh();
if (!success && !shared_data->transfer_cancelled) shared_data->error = true;
pfsFreeFileContext(&pfs_file_ctx);
@ -768,6 +762,146 @@ end:
if (dump_name) free(dump_name);
if (buf) free(buf);
threadExit();
}
static void nspDump(TitleInfo *title_info)
{
if (!title_info) return;
TitleApplicationMetadata *app_metadata = title_info->app_metadata;
ThreadSharedData shared_data = {0};
Thread dump_thread = {0};
time_t start = 0, btn_cancel_start_tmr = 0, btn_cancel_end_tmr = 0;
bool usb_conn = false, btn_cancel_cur_state = false, btn_cancel_prev_state = false;
u64 prev_size = 0;
u8 prev_time = 0, percent = 0;
consoleClear();
consolePrint("%s info:\n\n", title_info->meta_key.type == NcmContentMetaType_Application ? "base application" : \
(title_info->meta_key.type == NcmContentMetaType_Patch ? "update" : "dlc"));
if (app_metadata)
{
consolePrint("name: %s\n", app_metadata->lang_entry.name);
consolePrint("publisher: %s\n", app_metadata->lang_entry.author);
}
consolePrint("source storage: %s\n", title_info->storage_id == NcmStorageId_GameCard ? "gamecard" : (title_info->storage_id == NcmStorageId_BuiltInUser ? "emmc" : "sd card"));
consolePrint("title id: %016lX\n", title_info->meta_key.id);
consolePrint("version: %u (%u.%u.%u-%u.%u)\n", title_info->version.value, title_info->version.major, title_info->version.minor, title_info->version.micro, title_info->version.major_relstep, \
title_info->version.minor_relstep);
consolePrint("content count: %u\n", title_info->content_count);
consolePrint("size: %s\n", title_info->size_str);
consolePrint("______________________________\n\n");
consolePrint("dump options:\n\n");
for(u32 i = 0; i < options_count; i++) consolePrint("%s: %s\n", options[i].str, options[i].val ? "yes" : "no");
consolePrint("______________________________\n\n");
// make sure we have a valid usb session
consolePrint("waiting for usb connection... ");
start = time(NULL);
while(true)
{
time_t now = time(NULL);
if ((now - start) >= 10) break;
consolePrint("%lu ", now - start);
consoleRefresh();
if ((usb_conn = usbIsReady())) break;
utilsSleep(1);
}
consolePrint("\n");
if (!usb_conn)
{
consolePrint("usb connection failed\n");
return;
}
// create dump thread
shared_data.data = title_info;
utilsCreateThread(&dump_thread, dump_thread_func, &shared_data, 2);
while(!shared_data.total_size && !shared_data.error) svcSleepThread(10000000); // 10 ms
if (shared_data.error)
{
utilsJoinThread(&dump_thread);
return;
}
// start dump
start = time(NULL);
while(shared_data.data_written < shared_data.total_size)
{
if (shared_data.error) break;
time_t now = time(NULL);
struct tm *ts = localtime(&now);
size_t size = shared_data.data_written;
utilsScanPads();
btn_cancel_cur_state = (utilsGetButtonsHeld() & HidNpadButton_B);
if (btn_cancel_cur_state && btn_cancel_cur_state != btn_cancel_prev_state)
{
btn_cancel_start_tmr = now;
} else
if (btn_cancel_cur_state && btn_cancel_cur_state == btn_cancel_prev_state)
{
btn_cancel_end_tmr = now;
if ((btn_cancel_end_tmr - btn_cancel_start_tmr) >= 3)
{
shared_data.transfer_cancelled = true;
break;
}
} else {
btn_cancel_start_tmr = btn_cancel_end_tmr = 0;
}
btn_cancel_prev_state = btn_cancel_cur_state;
if (prev_time == ts->tm_sec || prev_size == size) continue;
percent = (u8)((size * 100) / shared_data.total_size);
prev_time = ts->tm_sec;
prev_size = size;
consolePrint("%lu / %lu (%u%%) | Time elapsed: %lu\n", size, shared_data.total_size, percent, (now - start));
consoleRefresh();
}
start = (time(NULL) - start);
consolePrint("\nwaiting for thread to join\n");
utilsJoinThread(&dump_thread);
consolePrint("dump_thread done: %lu\n", time(NULL));
if (shared_data.error)
{
consolePrint("usb transfer error\n");
return;
}
if (shared_data.transfer_cancelled)
{
consolePrint("process cancelled\n");
return;
}
consolePrint("process completed in %lu seconds\n", start);
}
int main(int argc, char *argv[])
@ -780,6 +914,7 @@ int main(int argc, char *argv[])
consoleInit(NULL);
consolePrint("initializing...\n");
consoleRefresh();
if (!utilsInitializeResources())
{
@ -806,6 +941,7 @@ int main(int argc, char *argv[])
}
consolePrint("app metadata succeeded\n");
consoleRefresh();
utilsSleep(1);
@ -813,72 +949,72 @@ int main(int argc, char *argv[])
{
consoleClear();
printf("press b to %s.\n", menu == 0 ? "exit" : "go back");
printf("______________________________\n\n");
consolePrint("press b to %s.\n", menu == 0 ? "exit" : "go back");
consolePrint("______________________________\n\n");
if (menu == 0)
{
printf("title: %u / %u\n", selected_idx + 1, app_count);
printf("selected title: %016lX - %s\n", app_metadata[selected_idx]->title_id, app_metadata[selected_idx]->lang_entry.name);
consolePrint("title: %u / %u\n", selected_idx + 1, app_count);
consolePrint("selected title: %016lX - %s\n", app_metadata[selected_idx]->title_id, app_metadata[selected_idx]->lang_entry.name);
} else {
printf("title info:\n\n");
printf("name: %s\n", app_metadata[title_idx]->lang_entry.name);
printf("publisher: %s\n", app_metadata[title_idx]->lang_entry.author);
printf("title id: %016lX\n", app_metadata[title_idx]->title_id);
consolePrint("title info:\n\n");
consolePrint("name: %s\n", app_metadata[title_idx]->lang_entry.name);
consolePrint("publisher: %s\n", app_metadata[title_idx]->lang_entry.author);
consolePrint("title id: %016lX\n", app_metadata[title_idx]->title_id);
if (menu == 2)
{
printf("______________________________\n\n");
consolePrint("______________________________\n\n");
if (title_info->previous || title_info->next)
{
printf("press zl/l and/or zr/r to change the selected title\n");
printf("title: %u / %u\n", list_idx, list_count);
printf("______________________________\n\n");
consolePrint("press zl/l and/or zr/r to change the selected title\n");
consolePrint("title: %u / %u\n", list_idx, list_count);
consolePrint("______________________________\n\n");
}
printf("selected %s info:\n\n", title_info->meta_key.type == NcmContentMetaType_Application ? "base application" : \
consolePrint("selected %s info:\n\n", title_info->meta_key.type == NcmContentMetaType_Application ? "base application" : \
(title_info->meta_key.type == NcmContentMetaType_Patch ? "update" : "dlc"));
printf("source storage: %s\n", title_info->storage_id == NcmStorageId_GameCard ? "gamecard" : (title_info->storage_id == NcmStorageId_BuiltInUser ? "emmc" : "sd card"));
if (title_info->meta_key.type != NcmContentMetaType_Application) printf("title id: %016lX\n", title_info->meta_key.id);
printf("version: %u (%u.%u.%u-%u.%u)\n", title_info->version.value, title_info->version.major, title_info->version.minor, title_info->version.micro, title_info->version.major_relstep, \
consolePrint("source storage: %s\n", title_info->storage_id == NcmStorageId_GameCard ? "gamecard" : (title_info->storage_id == NcmStorageId_BuiltInUser ? "emmc" : "sd card"));
if (title_info->meta_key.type != NcmContentMetaType_Application) consolePrint("title id: %016lX\n", title_info->meta_key.id);
consolePrint("version: %u (%u.%u.%u-%u.%u)\n", title_info->version.value, title_info->version.major, title_info->version.minor, title_info->version.micro, title_info->version.major_relstep, \
title_info->version.minor_relstep);
printf("content count: %u\n", title_info->content_count);
printf("size: %s\n", title_info->size_str);
consolePrint("content count: %u\n", title_info->content_count);
consolePrint("size: %s\n", title_info->size_str);
}
}
printf("______________________________\n\n");
consolePrint("______________________________\n\n");
u32 max_val = (menu == 0 ? app_count : (menu == 1 ? dump_type_strings_count : (1 + options_count)));
for(u32 i = scroll; i < max_val; i++)
{
if (i >= (scroll + page_size)) break;
printf("%s", i == selected_idx ? " -> " : " ");
consolePrint("%s", i == selected_idx ? " -> " : " ");
if (menu == 0)
{
printf("%016lX - %s\n", app_metadata[i]->title_id, app_metadata[i]->lang_entry.name);
consolePrint("%016lX - %s\n", app_metadata[i]->title_id, app_metadata[i]->lang_entry.name);
} else
if (menu == 1)
{
printf("%s\n", dump_type_strings[i]);
consolePrint("%s\n", dump_type_strings[i]);
} else
if (menu == 2)
{
if (i == 0)
{
printf("start nsp dump\n");
consolePrint("start nsp dump\n");
} else {
printf("%s: < %s >\n", options[i - 1].str, options[i - 1].val ? "yes" : "no");
consolePrint("%s: < %s >\n", options[i - 1].str, options[i - 1].val ? "yes" : "no");
}
}
}
printf("\n");
consolePrint("\n");
consoleUpdate(NULL);
consoleRefresh();
bool gc_update = false;
u64 btn_down = 0, btn_held = 0;
@ -960,7 +1096,6 @@ int main(int argc, char *argv[])
} else
if (menu == 3)
{
consoleClear();
utilsChangeHomeButtonBlockStatus(true);
nspDump(title_info);
utilsChangeHomeButtonBlockStatus(false);
@ -969,6 +1104,7 @@ int main(int argc, char *argv[])
if (error || menu >= 3)
{
consolePrint("press any button to continue\n");
consoleRefresh();
utilsWaitForButtonPress(0);
menu--;
} else {
@ -1043,6 +1179,8 @@ int main(int argc, char *argv[])
}
out2:
consoleRefresh();
if (menu != UINT32_MAX)
{
consolePrint("press any button to exit\n");

View file

@ -563,7 +563,6 @@ static bool sendGameCardImageViaUsb(void)
if ((btn_cancel_end_tmr - btn_cancel_start_tmr) >= 3)
{
mutexLock(&g_fileMutex);
usbCancelFileTransfer();
shared_data.transfer_cancelled = true;
mutexUnlock(&g_fileMutex);
break;
@ -738,6 +737,7 @@ static void write_thread_func(void *arg)
if (shared_data->read_error || shared_data->transfer_cancelled)
{
if (shared_data->transfer_cancelled) usbCancelFileTransfer();
mutexUnlock(&g_fileMutex);
break;
}

View file

@ -181,6 +181,7 @@ static void write_thread_func(void *arg)
if (shared_data->read_error || shared_data->transfer_cancelled)
{
if (shared_data->transfer_cancelled) usbCancelFileTransfer();
mutexUnlock(&g_fileMutex);
break;
}
@ -585,7 +586,6 @@ int main(int argc, char *argv[])
if ((btn_cancel_end_tmr - btn_cancel_start_tmr) >= 3)
{
mutexLock(&g_fileMutex);
usbCancelFileTransfer();
shared_data.transfer_cancelled = true;
mutexUnlock(&g_fileMutex);
break;

View file

@ -1,33 +1,38 @@
diff --git a/src/main/java/nsusbloader/Utilities/nxdumptool/NxdtUsbAbi1.java b/src/main/java/nsusbloader/Utilities/nxdumptool/NxdtUsbAbi1.java
index dd2a1bc..58add89 100644
index dd2a1bc..6c8f79e 100644
--- a/src/main/java/nsusbloader/Utilities/nxdumptool/NxdtUsbAbi1.java
+++ b/src/main/java/nsusbloader/Utilities/nxdumptool/NxdtUsbAbi1.java
@@ -42,7 +42,7 @@ class NxdtUsbAbi1 {
@@ -42,7 +42,6 @@ class NxdtUsbAbi1 {
private final boolean isWindows;
private boolean isWindows10;
- private static final int NXDT_MAX_DIRECTIVE_SIZE = 0x1000;
+ private static final int NXDT_MAX_DIRECTIVE_SIZE = 0x800000;
private static final int NXDT_FILE_CHUNK_SIZE = 0x800000;
private static final int NXDT_FILE_PROPERTIES_MAX_NAME_LENGTH = 0x300;
@@ -51,6 +51,7 @@ class NxdtUsbAbi1 {
@@ -51,7 +50,9 @@ class NxdtUsbAbi1 {
private static final int CMD_HANDSHAKE = 0;
private static final int CMD_SEND_FILE_PROPERTIES = 1;
+ private static final int CMD_SEND_NSP_HEADER = 2;
private static final int CMD_ENDSESSION = 3;
- private static final int CMD_ENDSESSION = 3;
+ private static final int CMD_CANCEL_FILE_TRANSFER = 2;
+ private static final int CMD_SEND_NSP_HEADER = 3;
+ private static final int CMD_ENDSESSION = 4;
// Standard set of possible replies
@@ -79,9 +80,15 @@ class NxdtUsbAbi1 {
private static final byte[] USBSTATUS_SUCCESS = { 0x4e, 0x58, 0x44, 0x54,
@@ -79,9 +80,17 @@ class NxdtUsbAbi1 {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
- private short endpointMaxPacketSize;
+ private short endpointMaxPacketSize = 0;
private static final int NXDT_USB_TIMEOUT = 5000;
+
- private static final int NXDT_USB_TIMEOUT = 5000;
+ private static final int NXDT_USB_CMD_TIMEOUT = 1000;
+ private static final int NXDT_USB_DATA_TIMEOUT = 5000;
+ private static final int USB_BUF_ALIGNMENT = 0x1000;
+
+ private boolean nspTransferMode = false;
+ private long nspSize = 0;
+ private int nspHeaderSize = 0;
@ -36,17 +41,28 @@ index dd2a1bc..58add89 100644
public NxdtUsbAbi1(DeviceHandle handler,
ILogPrinter logPrinter,
@@ -111,6 +118,9 @@ class NxdtUsbAbi1 {
@@ -111,6 +120,9 @@ class NxdtUsbAbi1 {
DeviceInformation deviceInformation = DeviceInformation.build(handlerNS);
NsUsbEndpointDescriptor endpointInDescriptor = deviceInformation.getSimplifiedDefaultEndpointDescriptorIn();
this.endpointMaxPacketSize = endpointInDescriptor.getwMaxPacketSize();
+
+ USBSTATUS_SUCCESS[8] = (byte)(endpointMaxPacketSize & 0xFF);
+ USBSTATUS_SUCCESS[9] = (byte)((endpointMaxPacketSize >> 8) & 0xFF);
+ USBSTATUS_SUCCESS[8] = (byte)(this.endpointMaxPacketSize & 0xFF);
+ USBSTATUS_SUCCESS[9] = (byte)((this.endpointMaxPacketSize >> 8) & 0xFF);
}
private void readLoop(){
@@ -134,6 +144,9 @@ class NxdtUsbAbi1 {
@@ -121,9 +133,7 @@ class NxdtUsbAbi1 {
while (true){
directive = readUsbDirective();
-
- if (isInvalidDirective(directive))
- continue;
+ if (directive == null || directive.length == 0) continue;
command = getLEint(directive, 4);
@@ -134,7 +144,11 @@ class NxdtUsbAbi1 {
case CMD_SEND_FILE_PROPERTIES:
handleSendFileProperties(directive);
break;
@ -54,9 +70,40 @@ index dd2a1bc..58add89 100644
+ handleSendNspHeader(directive);
+ break;
case CMD_ENDSESSION:
+ writeUsb(USBSTATUS_SUCCESS);
logPrinter.print("Session successfully ended.", EMsgType.PASS);
return;
@@ -187,30 +200,52 @@ class NxdtUsbAbi1 {
default:
@@ -153,28 +167,6 @@ class NxdtUsbAbi1 {
}
}
- private boolean isInvalidDirective(byte[] message) throws Exception{
- if (message.length < 0x10){
- writeUsb(USBSTATUS_MALFORMED_REQUEST);
- logPrinter.print("Directive is too small. Only "+message.length+" bytes received.", EMsgType.FAIL);
- return true;
- }
-
- if (! Arrays.equals(Arrays.copyOfRange(message, 0,4), MAGIC_NXDT)){
- writeUsb(USBSTATUS_INVALID_MAGIC);
- logPrinter.print("Invalid 'MAGIC'", EMsgType.FAIL);
- return true;
- }
-
- int payloadSize = getLEint(message, 0x8);
- if (payloadSize + 0x10 != message.length){
- writeUsb(USBSTATUS_MALFORMED_REQUEST);
- logPrinter.print("Invalid directive info block size. "+message.length+" bytes received while "+payloadSize+" expected.", EMsgType.FAIL);
- return true;
- }
- return false;
- }
-
private void performHandshake(byte[] message) throws Exception{
final byte versionMajor = message[0x10];
final byte versionMinor = message[0x11];
@@ -187,30 +179,52 @@ class NxdtUsbAbi1 {
writeUsb(USBSTATUS_UNSUPPORTED_ABI);
throw new Exception("ABI v"+versionABI+" is not supported in current version.");
}
@ -120,7 +167,7 @@ index dd2a1bc..58add89 100644
// If RomFs related
if (isRomFs(filename)) {
if (isWindows)
@@ -225,24 +260,48 @@ class NxdtUsbAbi1 {
@@ -225,30 +239,105 @@ class NxdtUsbAbi1 {
filename = saveToPath + filename;
}
@ -131,12 +178,6 @@ index dd2a1bc..58add89 100644
- logPrinter.print("Not enough space on selected volume. Need: "+fileSize+
- " while available: "+fileToDump.getParentFile().getFreeSpace(), EMsgType.FAIL);
- return;
- }
- // Check if FS is NOT read-only
- if (! (fileToDump.canWrite() || fileToDump.createNewFile()) ){
- writeUsb(USBSTATUS_HOSTIOERROR);
- logPrinter.print("Unable to write into selected volume: "+fileToDump.getAbsolutePath(), EMsgType.FAIL);
- return;
+ File fileToDump;
+
+ if (!this.nspTransferMode || (this.nspTransferMode && this.nspFile == null)) {
@ -175,18 +216,31 @@ index dd2a1bc..58add89 100644
+ } else {
+ fileToDump = this.nspFile;
}
writeUsb(USBSTATUS_SUCCESS);
- if (fileSize == 0)
- // Check if FS is NOT read-only
- if (! (fileToDump.canWrite() || fileToDump.createNewFile()) ){
- writeUsb(USBSTATUS_HOSTIOERROR);
- logPrinter.print("Unable to write into selected volume: "+fileToDump.getAbsolutePath(), EMsgType.FAIL);
+
+ writeUsb(USBSTATUS_SUCCESS);
+
+ if (fileSize == 0 || (this.nspTransferMode && fileSize == this.nspSize))
return;
+
+ if (dumpFile(fileToDump, fileSize)){
+ writeUsb(USBSTATUS_SUCCESS);
+ } else {
+ fileToDump.delete();
}
dumpFile(fileToDump, fileSize);
@@ -251,6 +310,49 @@ class NxdtUsbAbi1 {
}
+ }
+
+ private void handleCancelFileTransfer() throws Exception{
+ resetNspInfo();
writeUsb(USBSTATUS_SUCCESS);
+ logPrinter.print("User cancelled ongoing file transfer.", EMsgType.FAIL);
+ }
- if (fileSize == 0)
+ private void handleSendNspHeader(byte[] message) throws Exception{
+ final int headerSize = getLEint(message, 0x8);
+
@ -194,9 +248,10 @@ index dd2a1bc..58add89 100644
+ writeUsb(USBSTATUS_MALFORMED_REQUEST);
+ logPrinter.print("Received NSP send header request outside of NSP transfer mode!", EMsgType.FAIL);
+ resetNspInfo();
+ return;
return;
+ }
+
- dumpFile(fileToDump, fileSize);
+ if (this.nspRemainingSize > 0) {
+ writeUsb(USBSTATUS_MALFORMED_REQUEST);
+ logPrinter.print("Received NSP send header request without receiving all NSP file entry data!", EMsgType.FAIL);
@ -218,54 +273,225 @@ index dd2a1bc..58add89 100644
+ }
+
+ resetNspInfo();
+
+ writeUsb(USBSTATUS_SUCCESS);
writeUsb(USBSTATUS_SUCCESS);
+ }
+
+ private void resetNspInfo(){
+ this.nspTransferMode = false;
+ this.nspSize = 0;
+ this.nspHeaderSize = 0;
+ this.nspRemainingSize = 0;
+ this.nspFile = null;
+ }
+
private int getLEint(byte[] bytes, int fromOffset){
return ByteBuffer.wrap(bytes, fromOffset, 0x4).order(ByteOrder.LITTLE_ENDIAN).getInt();
}
@@ -279,7 +381,7 @@ class NxdtUsbAbi1 {
// @see https://bugs.openjdk.java.net/browse/JDK-8146538
private void dumpFile(File file, long size) throws Exception{
- FileOutputStream fos = new FileOutputStream(file, true);
+ FileOutputStream fos = new FileOutputStream(file, this.nspTransferMode);
private int getLEint(byte[] bytes, int fromOffset){
@@ -277,9 +366,9 @@ class NxdtUsbAbi1 {
throw new Exception("Unable to create dir(s) for file in "+folderForTheFile);
}
- // @see https://bugs.openjdk.java.net/browse/JDK-8146538
- private void dumpFile(File file, long size) throws Exception{
+ private boolean dumpFile(File file, long size) throws Exception{
FileOutputStream fos = new FileOutputStream(file, true);
+ boolean success = true;
try (BufferedOutputStream bos = new BufferedOutputStream(fos)) {
FileDescriptor fd = fos.getFD();
@@ -296,15 +398,21 @@ class NxdtUsbAbi1 {
@@ -287,31 +376,44 @@ class NxdtUsbAbi1 {
long received = 0;
int bufferSize;
- while (received+NXDT_FILE_CHUNK_SIZE < size) {
- //readBuffer = readUsbFile();
- readBuffer = readUsbFileDebug(NXDT_FILE_CHUNK_SIZE);
+ while((received + NXDT_FILE_CHUNK_SIZE) < size) {
+ readBuffer = readUsb(NXDT_FILE_CHUNK_SIZE, NXDT_USB_DATA_TIMEOUT);
bos.write(readBuffer);
if (isWindows10)
fd.sync();
bufferSize = readBuffer.length;
received += bufferSize;
- logPrinter.updateProgress((double)received / (double)size);
+ if (bufferSize == 0x10 && Arrays.equals(Arrays.copyOfRange(readBuffer, 0, 4), MAGIC_NXDT)) {
+ int cmd = getLEint(readBuffer, 4);
+ if (cmd == CMD_CANCEL_FILE_TRANSFER){
+ handleCancelFileTransfer();
+ success = false;
+ break;
+ }
+ }
+
+ if (!this.nspTransferMode) {
+ logPrinter.updateProgress((double)received / (double)size);
+ } else {
+ this.nspRemainingSize -= bufferSize;
+ logPrinter.updateProgress((double)(this.nspSize - this.nspRemainingSize) / (double)this.nspSize);
+ }
+ }
+ if (success){
+ int lastChunkSize = (int)((size - received) + 1);
+ readBuffer = readUsb(lastChunkSize, NXDT_USB_DATA_TIMEOUT);
+ bos.write(readBuffer);
+ if (isWindows10)
+ fd.sync();
+ this.nspRemainingSize -= lastChunkSize;
}
int lastChunkSize = (int)(size - received) + 1;
readBuffer = readUsbFileDebug(lastChunkSize);
bos.write(readBuffer);
if (isWindows10)
fd.sync();
+ if (this.nspTransferMode) this.nspRemainingSize -= (lastChunkSize - 1);
- int lastChunkSize = (int)(size - received) + 1;
- readBuffer = readUsbFileDebug(lastChunkSize);
- bos.write(readBuffer);
- if (isWindows10)
- fd.sync();
} finally {
- logPrinter.updateProgress(1.0);
+ if (!this.nspTransferMode || (this.nspTransferMode && this.nspRemainingSize == 0)) logPrinter.updateProgress(1.0);
+ if (success && (!this.nspTransferMode || (this.nspTransferMode && this.nspRemainingSize == 0))) logPrinter.updateProgress(1.0);
}
+
+ return success;
}
/* Handle Zero-length terminator
- /* Handle Zero-length terminator
- private boolean isAligned(long size){
- return ((size & (endpointMaxPacketSize - 1)) == 0);
- }
- */
/** Sending any byte array to USB device **/
private void writeUsb(byte[] message) throws Exception{
@@ -322,7 +424,7 @@ class NxdtUsbAbi1 {
if ( parent.isCancelled() )
throw new InterruptedException("Execution interrupted");
- int result = LibUsb.bulkTransfer(handlerNS, (byte) 0x01, writeBuffer, writeBufTransferred, NXDT_USB_TIMEOUT);
+ int result = LibUsb.bulkTransfer(handlerNS, (byte) 0x01, writeBuffer, writeBufTransferred, NXDT_USB_CMD_TIMEOUT);
if (result == LibUsb.SUCCESS) {
if (writeBufTransferred.get() == message.length)
@@ -335,47 +437,61 @@ class NxdtUsbAbi1 {
"\n Returned: " + UsbErrorCodes.getErrCode(result) +
"\n (execution stopped)");
}
+
/**
- * Reading what USB device responded (command).
+ * Reads an USB directive.
* @return byte array if data read successful
* 'null' if read failed
* */
private byte[] readUsbDirective() throws Exception{
- ByteBuffer readBuffer = ByteBuffer.allocateDirect(NXDT_MAX_DIRECTIVE_SIZE);
- // We can limit it to 32 bytes, but there is a non-zero chance to got OVERFLOW from libusb.
- IntBuffer readBufTransferred = IntBuffer.allocate(1);
- int result;
- while (! parent.isCancelled()) {
- result = LibUsb.bulkTransfer(handlerNS, (byte) 0x81, readBuffer, readBufTransferred, 1000); // last one is TIMEOUT. 0 stands for unlimited. Endpoint IN = 0x81
+ byte[] cmd_header = null, payload = null, directive = null;
+ int payloadSize = 0;
- switch (result) {
- case LibUsb.SUCCESS:
- int trans = readBufTransferred.get();
- byte[] receivedBytes = new byte[trans];
- readBuffer.get(receivedBytes);
- return receivedBytes;
- case LibUsb.ERROR_TIMEOUT:
- break;
- default:
- throw new Exception("Data transfer issue [read command]" +
- "\n Returned: " + UsbErrorCodes.getErrCode(result)+
- "\n (execution stopped)");
+ cmd_header = readUsb(0x10, NXDT_USB_CMD_TIMEOUT);
+ if (cmd_header == null || cmd_header.length == 0) return null;
+
+ if (cmd_header.length != 0x10){
+ writeUsb(USBSTATUS_MALFORMED_REQUEST);
+ logPrinter.print("Command header is too small. Only "+cmd_header.length+" bytes received.", EMsgType.FAIL);
+ return null;
+ }
+
+ if (! Arrays.equals(Arrays.copyOfRange(cmd_header, 0, 4), MAGIC_NXDT)){
+ writeUsb(USBSTATUS_INVALID_MAGIC);
+ logPrinter.print("Invalid 'MAGIC'", EMsgType.FAIL);
+ return null;
+ }
+
+ payloadSize = getLEint(cmd_header, 8);
+ if (payloadSize > 0){
+ payload = readUsb(payloadSize + 1, NXDT_USB_CMD_TIMEOUT);
+ if (payload == null || payload.length != payloadSize){
+ writeUsb(USBSTATUS_MALFORMED_REQUEST);
+ logPrinter.print("Command payload size mismatch. Received "+payload.length+" bytes.", EMsgType.FAIL);
+ return null;
}
}
- throw new InterruptedException();
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ outputStream.write(cmd_header);
+ if (payloadSize > 0) outputStream.write(payload);
+ directive = outputStream.toByteArray();
+
+ return directive;
}
+
/**
- * Reading what USB device responded (file).
+ * Reading what USB device responded (command).
* @return byte array if data read successful
* 'null' if read failed
* */
- private byte[] readUsbFile() throws Exception{
- ByteBuffer readBuffer = ByteBuffer.allocateDirect(NXDT_FILE_CHUNK_SIZE);
+ private byte[] readUsb(int length, int timeout) throws Exception{
+ ByteBuffer readBuffer = ByteBuffer.allocateDirect(alignUp(length, USB_BUF_ALIGNMENT));
IntBuffer readBufTransferred = IntBuffer.allocate(1);
int result;
- int countDown = 0;
- while (! parent.isCancelled() && countDown < 5) {
- result = LibUsb.bulkTransfer(handlerNS, (byte) 0x81, readBuffer, readBufTransferred, 1000);
+
+ while (! parent.isCancelled()) {
+ result = LibUsb.bulkTransfer(handlerNS, (byte)0x81, readBuffer, readBufTransferred, timeout); // last one is TIMEOUT. 0 stands for unlimited. Endpoint IN = 0x81
switch (result) {
case LibUsb.SUCCESS:
@@ -384,33 +500,17 @@ class NxdtUsbAbi1 {
readBuffer.get(receivedBytes);
return receivedBytes;
case LibUsb.ERROR_TIMEOUT:
- countDown++;
break;
default:
- throw new Exception("Data transfer issue [read file]" +
+ throw new Exception("Data transfer issue [read]" +
"\n Returned: " + UsbErrorCodes.getErrCode(result)+
"\n (execution stopped)");
}
}
throw new InterruptedException();
}
-
- private byte[] readUsbFileDebug(int chunkSize) throws Exception {
- ByteBuffer readBuffer = ByteBuffer.allocateDirect(chunkSize);
- IntBuffer readBufTransferred = IntBuffer.allocate(1);
- if (parent.isCancelled())
- throw new InterruptedException();
-
- int result = LibUsb.bulkTransfer(handlerNS, (byte) 0x81, readBuffer, readBufTransferred, NXDT_USB_TIMEOUT);
- if (result == LibUsb.SUCCESS) {
- int trans = readBufTransferred.get();
- byte[] receivedBytes = new byte[trans];
- readBuffer.get(receivedBytes);
- return receivedBytes;
- }
- throw new Exception("Data transfer issue [read file]" +
- "\n Returned: " + UsbErrorCodes.getErrCode(result) +
- "\n (execution stopped)");
+ private int alignUp(int value, int alignment){
+ return ((value + (alignment - 1)) & ~(alignment - 1));
}
}
diff --git a/src/main/resources/NSLMain.fxml b/src/main/resources/NSLMain.fxml
index a2d42d6..9114c3d 100644
--- a/src/main/resources/NSLMain.fxml

View file

@ -657,7 +657,7 @@ NX_INLINE void usbPrepareCommandHeader(u32 cmd, u32 cmd_block_size)
static bool usbSendCommand(void)
{
UsbCommandHeader *cmd_header = (UsbCommandHeader*)g_usbTransferBuffer;
size_t cmd_size = (sizeof(UsbCommandHeader) + cmd_header->cmd_block_size);
u32 cmd = cmd_header->cmd, cmd_block_size = cmd_header->cmd_block_size;
UsbStatus *cmd_status = (UsbStatus*)g_usbTransferBuffer;
u32 status = UsbStatusType_Success;
@ -665,7 +665,7 @@ static bool usbSendCommand(void)
/* Log error message only if the USB session has been started, or if thread exit flag hasn't been enabled. */
bool ret = false, zlt_required = false, cmd_block_written = false, log_rw_errors = (g_usbSessionStarted || !g_usbDetectionThreadExitFlag);
if (cmd_size > USB_TRANSFER_BUFFER_SIZE)
if ((sizeof(UsbCommandHeader) + cmd_block_size) > USB_TRANSFER_BUFFER_SIZE)
{
LOGFILE("Invalid command size!");
status = UsbStatusType_InvalidCommandSize;
@ -675,26 +675,26 @@ static bool usbSendCommand(void)
/* Write command header first. */
if (!usbWrite(cmd_header, sizeof(UsbCommandHeader)))
{
if (log_rw_errors) LOGFILE("Failed to write header for type 0x%X command!", cmd_header->cmd);
if (log_rw_errors) LOGFILE("Failed to write header for type 0x%X command!", cmd);
status = UsbStatusType_WriteCommandFailed;
goto end;
}
/* Check if we need to transfer a command block. */
if (cmd_header->cmd_block_size)
if (cmd_block_size)
{
/* Move command block data within the transfer buffer to guarantee we'll work with proper alignment. */
memmove(g_usbTransferBuffer, g_usbTransferBuffer + sizeof(UsbCommandHeader), cmd_block_size);
/* Determine if we'll need to set a Zero Length Termination (ZLT) packet after sending the command block. */
zlt_required = (g_usbSessionStarted && IS_ALIGNED(cmd_header->cmd_block_size, g_usbEndpointMaxPacketSize));
zlt_required = IS_ALIGNED(cmd_block_size, g_usbEndpointMaxPacketSize);
if (zlt_required) usbSetZltPacket(true);
/* Move command block data within the transfer buffer to guarantee we'll work with proper alignment. */
memmove(g_usbTransferBuffer, g_usbTransferBuffer + sizeof(UsbCommandHeader), cmd_header->cmd_block_size);
/* Write command block. */
cmd_block_written = usbWrite(g_usbTransferBuffer, cmd_header->cmd_block_size);
cmd_block_written = usbWrite(g_usbTransferBuffer, cmd_block_size);
if (!cmd_block_written)
{
if (log_rw_errors) LOGFILE("Failed to write command block for type 0x%X command!", cmd_header->cmd);
if (log_rw_errors) LOGFILE("Failed to write command block for type 0x%X command!", cmd);
status = UsbStatusType_WriteCommandFailed;
}
@ -708,7 +708,7 @@ static bool usbSendCommand(void)
/* Read status block. */
if (!usbRead(cmd_status, sizeof(UsbStatus)))
{
if (log_rw_errors) LOGFILE("Failed to read 0x%lX bytes long status block for type 0x%X command!", sizeof(UsbStatus), cmd_header->cmd);
if (log_rw_errors) LOGFILE("Failed to read 0x%lX bytes long status block for type 0x%X command!", sizeof(UsbStatus), cmd);
status = UsbStatusType_ReadStatusFailed;
goto end;
}