static Result action_url_install_open_dst(void* data, u32 index, void* initialReadBlock, u64 size, u32* handle) { url_install_data* installData = (url_install_data*) data; Result res = 0; installData->responseCode = 0; installData->ticket = false; installData->currTitleId = 0; installData->n3dsContinue = false; memset(&installData->ticketInfo, 0, sizeof(installData->ticketInfo)); if(*(u16*) initialReadBlock == 0x0100) { if(!installData->cdnDecided) { ui_view* view = prompt_display("Optional", "Install ticket titles from CDN?", COLOR_TEXT, true, data, NULL, action_url_install_cdn_check_onresponse); if(view != NULL) { svcWaitSynchronization(view->active, U64_MAX); } } installData->ticket = true; installData->ticketInfo.titleId = util_get_ticket_title_id((u8*) initialReadBlock); AM_DeleteTicket(installData->ticketInfo.titleId); res = AM_InstallTicketBegin(handle); } else if(*(u16*) initialReadBlock == 0x2020) { u64 titleId = util_get_cia_title_id((u8*) initialReadBlock); FS_MediaType dest = (titleId & 0x0000801000000002) != 0 ? MEDIATYPE_NAND : MEDIATYPE_SD; bool n3ds = false; if(R_SUCCEEDED(APT_CheckNew3DS(&n3ds)) && !n3ds && ((titleId >> 28) & 0xF) == 2) { ui_view* view = prompt_display("Confirmation", "Title is intended for New 3DS systems.\nContinue?", COLOR_TEXT, true, data, NULL, action_url_install_n3ds_onresponse); if(view != NULL) { svcWaitSynchronization(view->active, U64_MAX); } if(!installData->n3dsContinue) { return R_FBI_WRONG_SYSTEM; } } // Deleting FBI before it reinstalls itself causes issues. if(((titleId >> 8) & 0xFFFFF) != 0xF8001) { AM_DeleteTitle(dest, titleId); AM_DeleteTicket(titleId); if(dest == MEDIATYPE_SD) { AM_QueryAvailableExternalTitleDatabase(NULL); } } if(R_SUCCEEDED(res = AM_StartCiaInstall(dest, handle))) { installData->currTitleId = titleId; } } else {
static int installCia(Handle ciaFile){ Result failed; Handle outputHandle; u64 fileSize; u64 fileOffset = 0; u32 bytesRead; u32 bytesWritten; u8 transferBuffer[FILE_CHUNK_SIZE]; failed = AM_StartCiaInstall(MEDIATYPE_SD, &outputHandle); if(R_FAILED(failed)) return -1; failed = FSFILE_GetSize(ciaFile, &fileSize); if(R_FAILED(failed)) return -1; while(fileOffset < fileSize){ u64 bytesRemaining = fileSize - fileOffset; failed = FSFILE_Read(ciaFile, &bytesRead, fileOffset, transferBuffer, bytesRemaining < FILE_CHUNK_SIZE ? bytesRemaining : FILE_CHUNK_SIZE); if(R_FAILED(failed)){ AM_CancelCIAInstall(outputHandle); return -1; } failed = FSFILE_Write(outputHandle, &bytesWritten, fileOffset, transferBuffer, bytesRead, 0); if(R_FAILED(failed)){ AM_CancelCIAInstall(outputHandle); if(R_DESCRIPTION(failed) == RD_ALREADY_EXISTS) return 1; return -1; } if(bytesWritten != bytesRead){ AM_CancelCIAInstall(outputHandle); return -1; } fileOffset += bytesWritten; } failed = AM_FinishCiaInstall(outputHandle); if(R_FAILED(failed)) return -1; return 1; }
void installCia(const std::u16string& path, FS_MediaType mediaType, std::function<void (const std::u16string& file, u32 percent)> callback) { fs::File ciaFile(path, FS_OPEN_READ), cia; Buffer<u8> buffer(MAX_BUF_SIZE, false); Handle ciaHandle; u32 blockSize; u64 ciaSize, offset = 0; Result res; ciaSize = ciaFile.size(); if((res = AM_StartCiaInstall(mediaType, &ciaHandle))) throw titleException(_FILE_, __LINE__, res, "Failed to start CIA installation!"); cia.setFileHandle(ciaHandle); // Use the handle returned by AM for(u32 i=0; i<=ciaSize / MAX_BUF_SIZE; i++) { blockSize = ((ciaSize - offset<MAX_BUF_SIZE) ? ciaSize - offset : MAX_BUF_SIZE); if(blockSize>0) { try { ciaFile.read(&buffer, blockSize); cia.write(&buffer, blockSize); } catch(fsException& e) { AM_CancelCIAInstall(&ciaHandle); // Abort installation cia.setFileHandle(0); // Reset the handle so it doesn't get closed twice throw; } offset += blockSize; if(callback) callback(path, offset * 100 / ciaSize); } } if((res = AM_FinishCiaInstall(mediaType, &ciaHandle))) throw titleException(_FILE_, __LINE__, res, "installation successfull :)!"); }
AppResult appInstall(MediaType mediaType, FILE* fd, u64 size, std::function<bool(u64 pos, u64 totalSize)> onProgress) { if(!serviceRequire("am")) { return APP_AM_INIT_FAILED; } if(onProgress != NULL) { onProgress(0, size); } Handle ciaHandle; Result startResult = AM_StartCiaInstall(appMediatypeToByte(mediaType), &ciaHandle); if(startResult != 0) { platformSetError(serviceParseError((u32) startResult)); return APP_BEGIN_INSTALL_FAILED; } u32 bufSize = 1024 * 128; // 128KB void* buf = malloc(bufSize); bool cancelled = false; u64 pos = 0; while(platformIsRunning()) { if(onProgress != NULL && !onProgress(pos, size)) { cancelled = true; break; } size_t bytesRead = fread(buf, 1, bufSize, fd); if(bytesRead > 0) { Result writeResult = FSFILE_Write(ciaHandle, NULL, pos, buf, (u32) bytesRead, FS_WRITE_NOFLUSH); if(writeResult != 0) { AM_CancelCIAInstall(&ciaHandle); platformSetError(serviceParseError((u32) writeResult)); return APP_INSTALL_ERROR; } pos += bytesRead; } if((ferror(fd) && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINPROGRESS) || (size != 0 && pos == size)) { break; } } free(buf); if(cancelled) { AM_CancelCIAInstall(&ciaHandle); return APP_OPERATION_CANCELLED; } if(!platformIsRunning()) { AM_CancelCIAInstall(&ciaHandle); return APP_PROCESS_CLOSING; } if(size != 0 && pos != size) { AM_CancelCIAInstall(&ciaHandle); return APP_IO_ERROR; } if(onProgress != NULL) { onProgress(size, size); } Result finishResult = AM_FinishCiaInstall(appMediatypeToByte(mediaType), &ciaHandle); if(finishResult != 0) { platformSetError(serviceParseError((u32) finishResult)); return APP_FINALIZE_INSTALL_FAILED; } return APP_SUCCESS; }
int installTitleFromCIA(const char *path, PrintConsole *con) { Handle CIAIn, CIAOut; u32 bytesread; u32 byteswritten; u64 totalread; int animpos; LOG_INFO("installTitleFromCIA: Installing CIA from %s.", path); CIAIn = openFileHandle(path, FS_OPEN_READ); if(CIAIn == 0) { LOG_ERROR("installTitleFromCIA: Failed to open %s.", path); printf("Failed to open file %s.\n", path); goto error0; } #ifdef ARMED if(R_FAILED(AM_StartCiaInstall(MEDIATYPE_NAND, &CIAOut))) { LOG_ERROR("installTitleFromCIA: AM_StartCiaInstall failed."); printf("Failed to start CIA install.\n"); goto error1; } #endif bytesread = BUFFERSIZE; totalread = 0; while(bytesread == BUFFERSIZE) { printf("%c", anim[animpos]); stepFrame(); con->cursorX--; animpos = (animpos + 1) % 4; if(R_FAILED(FSFILE_Read(CIAIn, &bytesread, totalread, buffer, BUFFERSIZE))) { printf("\nFailed to read %s around %llu!\n", path, totalread); stepFrame(); goto error2; } #ifdef ARMED if(R_FAILED(FSFILE_Write(CIAOut, &byteswritten, totalread, buffer, bytesread, FS_WRITE_FLUSH))) { printf("\nFailed to write %s around %llu!\n", path, totalread); stepFrame(); goto error2; } if(byteswritten < bytesread) { LOG_ERROR("installTitleFromCIA: Incomplete write around %llu.", totalread); printf("\nIncompelete write around %llu!\n", totalread); stepFrame(); goto error2; } #endif totalread += bytesread; } #ifdef ARMED if(R_FAILED(AM_FinishCiaInstall(MEDIATYPE_NAND, &CIAOut))) { LOG_ERROR("installTitleFromCIA: AM_FinishCiaInstall failed."); printf("Failed to finalize CIA install.\n"); goto error2; } #endif closeFileHandle(CIAIn); LOG_INFO("Successfully installed %s.", path); return(0); error2: #ifdef ARMED if(R_FAILED(AM_CancelCIAInstall(&CIAOut))) { printf("Couldn't cancel unsuccessful CIA install.\n"); } #endif error1: closeFileHandle(CIAIn); error0: LOG_ERROR("Failed installing %s.", path); return(-1); }