App appGetCiaInfo(const std::string file, MediaType mediaType) { if(!serviceRequire("am")) { return {}; } FS_archive archive = (FS_archive) {ARCH_SDMC, (FS_path) {PATH_EMPTY, 1, (u8*) ""}}; Result archiveResult = FSUSER_OpenArchive(NULL, &archive); if(archiveResult != 0) { platformSetError(serviceParseError((u32) archiveResult)); return {}; } Handle handle = 0; Result openResult = FSUSER_OpenFile(NULL, &handle, archive, FS_makePath(PATH_CHAR, file.c_str()), FS_OPEN_READ, FS_ATTRIBUTE_NONE); if(openResult != 0) { platformSetError(serviceParseError((u32) openResult)); return {}; } TitleList titleInfo; Result infoResult = AM_GetCiaFileInfo(appMediatypeToByte(mediaType), &titleInfo, handle); if(infoResult != 0) { platformSetError(serviceParseError((u32) infoResult)); return {}; } FSFILE_Close(handle); FSUSER_CloseArchive(NULL, &archive); App app; app.titleId = titleInfo.titleID; app.uniqueId = ((u32*) &titleInfo.titleID)[0]; strcpy(app.productCode, "<N/A>"); app.mediaType = mediaType; app.platform = appPlatformFromId(((u16*) &titleInfo.titleID)[3]); app.category = appCategoryFromId(((u16*) &titleInfo.titleID)[2]); app.version = titleInfo.titleVersion; app.size = titleInfo.size; return app; }
Result task_create_file_item(list_item** out, FS_Archive archive, const char* path) { Result res = 0; list_item* item = (list_item*) calloc(1, sizeof(list_item)); if(item != NULL) { file_info* fileInfo = (file_info*) calloc(1, sizeof(file_info)); if(fileInfo != NULL) { fileInfo->archive = archive; util_get_path_file(fileInfo->name, path, FILE_NAME_MAX); fileInfo->attributes = 0; fileInfo->size = 0; fileInfo->isCia = false; fileInfo->isTicket = false; if(util_is_dir(archive, path)) { item->color = COLOR_DIRECTORY; size_t len = strlen(path); if(len > 1 && path[len - 1] != '/') { snprintf(fileInfo->path, FILE_PATH_MAX, "%s/", path); } else { strncpy(fileInfo->path, path, FILE_PATH_MAX); } fileInfo->attributes = FS_ATTRIBUTE_DIRECTORY; } else { item->color = COLOR_FILE; strncpy(fileInfo->path, path, FILE_PATH_MAX); FS_Path* fileFsPath = util_make_path_utf8(fileInfo->path); if(fileFsPath != NULL) { Handle fileHandle; if(R_SUCCEEDED(FSUSER_OpenFile(&fileHandle, archive, *fileFsPath, FS_OPEN_READ, 0))) { FSFILE_GetAttributes(fileHandle, &fileInfo->attributes); FSFILE_GetSize(fileHandle, &fileInfo->size); size_t len = strlen(fileInfo->path); if(len > 4) { if(strcasecmp(&fileInfo->path[len - 4], ".cia") == 0) { AM_TitleEntry titleEntry; if(R_SUCCEEDED(AM_GetCiaFileInfo(MEDIATYPE_SD, &titleEntry, fileHandle))) { fileInfo->isCia = true; fileInfo->ciaInfo.titleId = titleEntry.titleID; fileInfo->ciaInfo.version = titleEntry.version; fileInfo->ciaInfo.installedSize = titleEntry.size; fileInfo->ciaInfo.hasMeta = false; if((titleEntry.titleID & 0x0000801000000002) != 0 && R_SUCCEEDED(AM_GetCiaFileInfo(MEDIATYPE_NAND, &titleEntry, fileHandle))) { fileInfo->ciaInfo.installedSize = titleEntry.size; } SMDH* smdh = (SMDH*) calloc(1, sizeof(SMDH)); if(smdh != NULL) { if(R_SUCCEEDED(util_get_cia_file_smdh(smdh, fileHandle))) { if(smdh->magic[0] == 'S' && smdh->magic[1] == 'M' && smdh->magic[2] == 'D' && smdh->magic[3] == 'H') { u8 systemLanguage = CFG_LANGUAGE_EN; CFGU_GetSystemLanguage(&systemLanguage); fileInfo->ciaInfo.hasMeta = true; utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.shortDescription, smdh->titles[systemLanguage].shortDescription, sizeof(fileInfo->ciaInfo.meta.shortDescription) - 1); utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.longDescription, smdh->titles[systemLanguage].longDescription, sizeof(fileInfo->ciaInfo.meta.longDescription) - 1); utf16_to_utf8((uint8_t*) fileInfo->ciaInfo.meta.publisher, smdh->titles[systemLanguage].publisher, sizeof(fileInfo->ciaInfo.meta.publisher) - 1); fileInfo->ciaInfo.meta.region = smdh->region; fileInfo->ciaInfo.meta.texture = screen_load_texture_tiled_auto(smdh->largeIcon, sizeof(smdh->largeIcon), 48, 48, GPU_RGB565, false); } } free(smdh); } } } else if(strcasecmp(&fileInfo->path[len - 4], ".tik") == 0) { u32 bytesRead = 0; u8 sigType = 0; if(R_SUCCEEDED(FSFILE_Read(fileHandle, &bytesRead, 3, &sigType, sizeof(sigType))) && bytesRead == sizeof(sigType) && sigType <= 5) { static u32 dataOffsets[6] = {0x240, 0x140, 0x80, 0x240, 0x140, 0x80}; static u32 titleIdOffset = 0x9C; u64 titleId = 0; if(R_SUCCEEDED(FSFILE_Read(fileHandle, &bytesRead, dataOffsets[sigType] + titleIdOffset, &titleId, sizeof(titleId))) && bytesRead == sizeof(titleId)) { fileInfo->isTicket = true; fileInfo->ticketInfo.titleId = __builtin_bswap64(titleId); } } } } FSFILE_Close(fileHandle); } util_free_path_utf8(fileFsPath); } } strncpy(item->name, fileInfo->name, LIST_ITEM_NAME_MAX); item->data = fileInfo; *out = item; } else { free(item); res = R_FBI_OUT_OF_MEMORY; } } else { res = R_FBI_OUT_OF_MEMORY; } return res; }
int exec_cia(const char* path, const char** args){ struct stat sBuff; bool fileExists; bool inited; if(path == NULL || path[0] == '\0'){ errno = EINVAL; return -1; } fileExists = stat(path, &sBuff) == 0; if(!fileExists){ errno = ENOENT; return -1; } else if(S_ISDIR(sBuff.st_mode)){ errno = EINVAL;; return -1; } inited = R_SUCCEEDED(amInit()) && R_SUCCEEDED(fsInit()); if(inited){ Result res; AM_TitleEntry ciaInfo; FS_Archive ciaArchive; Handle ciaFile; int ciaInstalled; ciaParam param; int argsLength; //open cia file res = FSUSER_OpenArchive(&ciaArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")); if(R_FAILED(res)) errorAndQuit("Cant open SD FS archive."); res = FSUSER_OpenFile(&ciaFile, ciaArchive, fsMakePath(PATH_ASCII, path + 5/*skip "sdmc:"*/), FS_OPEN_READ, 0); if(R_FAILED(res)) errorAndQuit("Cant open CIA file."); res = AM_GetCiaFileInfo(MEDIATYPE_SD, &ciaInfo, ciaFile); if(R_FAILED(res)) errorAndQuit("Cant get CIA file info."); ciaInstalled = isCiaInstalled(ciaInfo.titleID, ciaInfo.version); if(ciaInstalled == -1){ //error errorAndQuit("Could not read title id list."); } else if(ciaInstalled == 0){ //not installed int error = installCia(ciaFile); if(error == -1) errorAndQuit("Cant install CIA."); } FSFILE_Close(ciaFile); FSUSER_CloseArchive(ciaArchive); param.argc = 0; argsLength = 0; char* argLocation = param.args; while(args[param.argc] != NULL){ strcpy(argLocation, args[param.argc]); argLocation += strlen(args[param.argc]) + 1; argsLength += strlen(args[param.argc]) + 1; param.argc++; } res = APT_PrepareToDoApplicationJump(0, ciaInfo.titleID, 0x1); if(R_FAILED(res)) errorAndQuit("CIA cant run, cant prepare."); res = APT_DoApplicationJump(¶m, sizeof(param.argc) + argsLength, argvHmac); if(R_FAILED(res)) errorAndQuit("CIA cant run, cant jump."); //wait for application jump, for some reason its not instant while(1); } //should never be reached amExit(); fsExit(); errno = ENOTSUP; return -1; }
TitleList *getUpdateCIAs() { Handle dir, CIAFile; FS_DirectoryEntry ent; int ret; int ciafiles; TitleList *updateCIAs; char ciaPath[9 + 16 + 4 + 1]; // /updates/ + 16 hex digits + .cia + \0 LOG_INFO("getUpdateCIAs"); // Run through first and count .cia files. dir = openDirectory(CIAS_PATH); if(dir == 0) { LOG_ERROR("getUpdateCIAs: Failed to open SDMC:" CIAS_PATH ".\n"); printf("Failed to open SDMC:" CIAS_PATH ".\n"); goto error0; } ciafiles = 0; for(;;) { ret = getNextFile(dir, &ent); if(ret < 1) { if(ret == -1) { LOG_ERROR("getUpdateCIAs: Error reading directory."); printf("Error reading directory.\n"); goto error2; } break; } simpleUTF16toASCII((char *)(ent.name)); if(isCIAName((char *)(ent.name)) == 1) { ciafiles++; } } closeDirectory(dir); LOG_VERBOSE("Found %d files.", ciafiles); updateCIAs = initTitleList(ciafiles, 0); // Run through a second time and add CIA info. dir = openDirectory(CIAS_PATH); if(dir == 0) { LOG_ERROR("getUpdateCIAs: Failed to open SDMC:" CIAS_PATH ".\n"); printf("Failed to open SDMC:" CIAS_PATH ".\n"); goto error1; } ciafiles = 0; for(;;) { ret = getNextFile(dir, &ent); if(ret < 1) { if(ret == -1) { LOG_ERROR("getUpdateCIAs: Error reading directory."); printf("Error reading directory.\n"); goto error2; } break; } simpleUTF16toASCII((char *)(ent.name)); if(isCIAName((char *)(ent.name)) == 1) { snprintf(ciaPath, 9 + 16 + 4 + 1, CIAS_PATH "%s", ent.name); CIAFile = openFileHandle(ciaPath, FS_OPEN_READ); if(CIAFile == 0) { LOG_ERROR("getUpdateCIAs: Failed to open %s for read.\n", ciaPath); printf("Failed to open %s for read.\n", ciaPath); goto error2; } if(R_FAILED(AM_GetCiaFileInfo(MEDIATYPE_NAND, updateCIAs->title[ciafiles], CIAFile))) { LOG_ERROR("getUpdateCIAs: Failed to get information on %s.\n", ciaPath); printf("Failed to get information on %s.\n", ciaPath); goto error3; } closeFileHandle(CIAFile); ciafiles++; LOG_VERBOSE("getUpdateCIAs: Added %s.", (char *)(ent.name)); } } closeDirectory(dir); LOG_INFO("getUpdateCIAs: Got CIAs from SD card."); return(updateCIAs); error3: closeFileHandle(CIAFile); error2: closeDirectory(dir); error1: freeTitleList(updateCIAs); error0: LOG_ERROR("getUpdateCIAs: Failed to get CIAs from SD card."); return(NULL); }
bool installTTP(char* path, u8 mediatype) { // Install a TTP file. (needs libzip and installCIA) Result res; FS_Archive archive = {ARCHIVE_SDMC, {PATH_EMPTY, 0, 0}}; FSUSER_OpenArchive(&archive); FSUSER_DeleteDirectoryRecursively(archive, fsMakePath(PATH_ASCII, "/tmp/cias")); FSUSER_CreateDirectory(archive, fsMakePath(PATH_ASCII, "/tmp/cias"), 0); FILE* ttp = fopen(path, "rb"); FILE* tmp = fopen("/tmp/cias/ttp.tmp", "wb"); u32 titlesAmount; AM_GetTitleCount(mediatype, &titlesAmount); u64* titleIDs = malloc(sizeof(u64) * titlesAmount); AM_GetTitleIdList(mediatype, titlesAmount, titleIDs); u32 size; fseek(ttp, 0x19, SEEK_SET); fread(&size, 0x4, 1, ttp); fseek(ttp, 0x1D, SEEK_SET); u32 blockAmount = size / 0x160000; // Finds how many blocks of 4MB you have in the file u32 i; char* block = malloc(0x160000); for (i = 0; i < blockAmount; i++) { fread(block, 1, 0x160000, ttp); fwrite(block, 1, 0x160000, tmp); } if (size % 0x160000 != 0) { fread(block, 1, size-0x160000*blockAmount, ttp); fwrite(block, 1, size-0x160000*blockAmount, tmp); } free(block); fclose(ttp); fclose(tmp); FSUSER_DeleteDirectoryRecursively(archive, fsMakePath(PATH_ASCII, "/tmp/cias")); FSUSER_CreateDirectory(archive, fsMakePath(PATH_ASCII, "/tmp/cias"), 0); Zip *zipHandle = ZipOpen("/tmp/cias/ttp.tmp"); ZipExtract(zipHandle, NULL); ZipClose(zipHandle); Handle ciaDir; FS_Archive fsarchive; u32 actualAmount; FS_DirectoryEntry* entries; FSUSER_DeleteFile(archive, fsMakePath(PATH_ASCII, "/tmp/cias/ttp.tmp")); res = FSUSER_OpenDirectory(&ciaDir, fsarchive, fsMakePath(PATH_ASCII, "/tmp/cias")); if (res != 0) { free(titleIDs); return false; } entries = malloc(256 * sizeof(FS_DirectoryEntry)); res = FSDIR_Read(ciaDir, &actualAmount, 256, entries); if (res != 0) { free(titleIDs); return false; } char* ciaPath; Handle ciaFileHandle; AM_TitleEntry ciaInfo; for (i = 0; i < actualAmount; i++) { ciaPath = malloc(14 + strlen(entries[i].shortName)); strcpy(ciaPath, "/tmp/cias/"); strcat(ciaPath, entries[i].shortName); strcat(ciaPath, ".cia"); FSUSER_OpenFile(&ciaFileHandle, archive, fsMakePath(PATH_ASCII, ciaPath), FS_OPEN_READ, 0); AM_GetCiaFileInfo(mediatype, &ciaInfo, ciaFileHandle); FSFILE_Close(ciaFileHandle); if (ciaInfo.titleID == 0x0004013800000002LL || ciaInfo.titleID == 0x0004013820000002LL) { if (!installCIA(ciaPath, mediatype, titleIDs, entries[i].shortName)) if (!installCIA(ciaPath, mediatype, titleIDs, entries[i].shortName)) // Tries to install the CIA 3 times then give up. If it has to give up, that probably means brick. if (!installCIA(ciaPath, mediatype, titleIDs, entries[i].shortName)) return false; break; } free(ciaPath); } for (i = 0; i < actualAmount; i++) { ciaPath = malloc(14 + strlen(entries[i].shortName)); strcpy(ciaPath, "/tmp/cias/"); strcat(ciaPath, entries[i].shortName); strcat(ciaPath, ".cia"); if (!installCIA(ciaPath, mediatype, titleIDs, entries[i].shortName)) if (!installCIA(ciaPath, mediatype, titleIDs, entries[i].shortName)) // Tries to install the CIA 3 times then give up. If it has to give up, that probably means brick. installCIA(ciaPath, mediatype, titleIDs, entries[i].shortName); free(ciaPath); } FSUSER_DeleteDirectoryRecursively(archive, fsMakePath(PATH_ASCII, "/tmp/cias")); FSUSER_CloseArchive(&archive); free(titleIDs); return true; }