void main() { clear_screens(); if(mount_sd() != 0) { draw_loading("Failed to mount SD", "Make sure your SD card can be read correctly"); return; } // This function already correctly draws error messages if (load_firm() != 0) return; if (load_cakes_info("/cakes/patches") != 0) { draw_loading("Failed to read some cakes", "Make sure your cakes are up to date\n and your SD card can be read correctly"); return; } load_config(); // If the L button isn't pressed, autoboot. if (config->autoboot_enabled && *hid_regs ^ 0xFFF ^ key_l) { boot_cfw(); } menu_main(); }
int menu_firms() { char firms[MAX_OPTIONS][_MAX_LFN + 1], dirpath[] = PATH_FIRMWARE_DIR; int pathlen = strlen(dirpath); int count = find_file_pattern(firms, dirpath, pathlen, MAX_OPTIONS, "firmware*.bin"); if (!count) { draw_loading("Failed to load FIRM", "Make sure the encrypted FIRM is\n located in the firmware directory"); return 1; } char *options[count]; for (int x = 0; x <= count; x++) options[x] = firms[x]; int result = draw_menu("Select firmware", 0, count, options); if (result == -1) return 0; memcpy(config->firm_path, firms[result], _MAX_LFN + 1); reload_native_firm(); load_cakes_info(PATH_PATCHES); return 0; }
void main() { clear_screens(); if(mount_sd() != 0) { draw_loading("Failed to mount SD", "Make sure your SD card can be read correctly"); return; } load_config(); // If the L button isn't pressed, autoboot. if (config->autoboot_enabled && *hid_regs ^ 0xFFF ^ key_l) { print("Autobooting..."); if (read_file(firm_loc, PATH_PATCHED_FIRMWARE, FCRAM_SPACING) != 0 || firm_loc->magic != FIRM_MAGIC) { print("Failed to load patched FIRM"); draw_message("Failed to load patched FIRM", "The option to autoboot was selected,\n but no valid FIRM could be found at:\n " PATH_PATCHED_FIRMWARE); } else { if (read_file(memory_loc, PATH_MEMORY, FCRAM_SPACING) != 0) { print("Failed to load memory patches"); draw_message("Failed to load memory patches", "The option to autoboot was selected,\n but no valid memory patches could be found at:\n " PATH_MEMORY); } else { if (config->firm_console == console_n3ds && config->firm_ver > 0x0F) { slot0x11key96_init(); } // boot_firm() requires current_firm->console and current_firm->version. struct firm_signature config_firm = {.console = config->firm_console, .version = config->firm_ver}; current_firm = &config_firm; boot_firm(); } } } if (load_firms() != 0) { if(menu_firms() !=0) return; } print("Loading cakes"); if (load_cakes_info(PATH_PATCHES) != 0) { draw_loading("Failed to read some cakes", "Make sure your cakes are up to date\n and your SD card can be read correctly"); return; } load_config_cakes(); menu_main(); }
int load_cakes_info(const char *dirpath) { FRESULT fr; DIR dir; FILINFO fno; FIL handle; const int pathlen = strlen(dirpath); static char lfn[_MAX_LFN + 1]; fno.lfname = lfn; fno.lfsize = sizeof(lfn); fr = f_opendir(&dir, dirpath); if (fr != FR_OK) goto error; static_assert(MAX_CAKES < 0x100000 / sizeof(struct cake_info), "This function will overflow it's buffer"); while (cake_count < MAX_CAKES) { fr = f_readdir(&dir, &fno); if (fr != FR_OK) { goto error; } else if (fno.fname[0] == 0) { break; } char *fn = *fno.lfname ? fno.lfname : fno.fname; // Build the path string memcpy(cake_list[cake_count].path, dirpath, pathlen); cake_list[cake_count].path[pathlen] = '/'; strncpy(&cake_list[cake_count].path[pathlen + 1], fn, sizeof(cake_list->path) - pathlen - 1); // Recurse into subdirectories if (fno.fattrib & AM_DIR) { // Using the path stored in the current cake. fr = load_cakes_info(cake_list[cake_count].path); if (fr != FR_OK) return fr; continue; } // Make sure the filename ends in .cake if (!memsearch(cake_list[cake_count].path, ".cake", sizeof(cake_list[cake_count].path), 6)) { continue; } // Open the file fr = f_open(&handle, cake_list[cake_count].path, FA_READ); if (fr != FR_OK) goto error; // Get the header unsigned int bytes_read = 0; struct cake_header header; fr = f_read(&handle, &header, sizeof(header), &bytes_read); if (fr != FR_OK) goto error; // Only add patches applicable to the loaded firms struct firm_signature *current = NULL; switch (header.type) { case NATIVE_FIRM: current = current_firm; break; case AGB_FIRM: current = current_agb_firm; break; default: continue; } if (!current || header.firm_ver != current->version || header.console != current->console) { continue; } // Get the patch description const int desc_size = header.patches_offset - sizeof(header); fr = f_read(&handle, cake_list[cake_count].description, desc_size, &bytes_read); if (fr != FR_OK) goto error; fr = f_close(&handle); if (fr != FR_OK) goto error; cake_count++; } f_closedir(&dir); return 0; error: f_close(&handle); f_closedir(&dir); return fr; }