Advertisement
Guest User

Untitled

a guest
Jan 18th, 2020
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.69 KB | None | 0 0
  1. #include <malloc.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4.  
  5. #include <3ds.h>
  6.  
  7. #include "action.h"
  8. #include "../resources.h"
  9. #include "../task/uitask.h"
  10. #include "../../core/core.h"
  11.  
  12. typedef struct {
  13. linked_list* items;
  14.  
  15. list_item* targetItem;
  16. file_info* target;
  17.  
  18. linked_list contents;
  19.  
  20. bool delete;
  21.  
  22. volatile bool n3dsContinue;
  23.  
  24. data_op_data installInfo;
  25. } install_cias_data;
  26.  
  27. static void action_install_cias_n3ds_onresponse(ui_view* view, void* data, u32 response) {
  28. ((install_cias_data*) data)->n3dsContinue = response == PROMPT_YES;
  29. }
  30.  
  31. static void action_install_cias_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
  32. install_cias_data* installData = (install_cias_data*) data;
  33.  
  34. u32 curr = installData->installInfo.processed;
  35. if(curr < installData->installInfo.total) {
  36. task_draw_file_info(view, ((list_item*) linked_list_get(&installData->contents, curr))->data, x1, y1, x2, y2);
  37. } else {
  38. task_draw_file_info(view, installData->target, x1, y1, x2, y2);
  39. }
  40. }
  41.  
  42. static Result action_install_cias_is_src_directory(void* data, u32 index, bool* isDirectory) {
  43. *isDirectory = false;
  44. return 0;
  45. }
  46.  
  47. static Result action_install_cias_make_dst_directory(void* data, u32 index) {
  48. return 0;
  49. }
  50.  
  51. static Result action_install_cias_open_src(void* data, u32 index, u32* handle) {
  52. install_cias_data* installData = (install_cias_data*) data;
  53.  
  54. file_info* info = (file_info*) ((list_item*) linked_list_get(&installData->contents, index))->data;
  55.  
  56. Result res = 0;
  57.  
  58. FS_Path* fsPath = fs_make_path_utf8(info->path);
  59. if(fsPath != NULL) {
  60. res = FSUSER_OpenFile(handle, info->archive, *fsPath, FS_OPEN_READ, 0);
  61.  
  62. fs_free_path_utf8(fsPath);
  63. } else {
  64. res = R_APP_OUT_OF_MEMORY;
  65. }
  66.  
  67. return res;
  68. }
  69.  
  70. static Result action_install_cias_close_src(void* data, u32 index, bool succeeded, u32 handle) {
  71. install_cias_data* installData = (install_cias_data*) data;
  72.  
  73. file_info* info = (file_info*) ((list_item*) linked_list_get(&installData->contents, index))->data;
  74.  
  75. Result res = 0;
  76.  
  77. if(R_SUCCEEDED(res = FSFILE_Close(handle)) && installData->delete && succeeded) {
  78. FS_Path* fsPath = fs_make_path_utf8(info->path);
  79. if(fsPath != NULL) {
  80. if(R_SUCCEEDED(FSUSER_DeleteFile(info->archive, *fsPath))) {
  81. linked_list_iter iter;
  82. linked_list_iterate(installData->items, &iter);
  83.  
  84. while(linked_list_iter_has_next(&iter)) {
  85. list_item* item = (list_item*) linked_list_iter_next(&iter);
  86. file_info* currInfo = (file_info*) item->data;
  87.  
  88. if(strncmp(currInfo->path, info->path, FILE_PATH_MAX) == 0) {
  89. linked_list_iter_remove(&iter);
  90. task_free_file(item);
  91. }
  92. }
  93. }
  94.  
  95. fs_free_path_utf8(fsPath);
  96. } else {
  97. res = R_APP_OUT_OF_MEMORY;
  98. }
  99. }
  100.  
  101. return res;
  102. }
  103.  
  104. static Result action_install_cias_get_src_size(void* data, u32 handle, u64* size) {
  105. return FSFILE_GetSize(handle, size);
  106. }
  107.  
  108. static Result action_install_cias_read_src(void* data, u32 handle, u32* bytesRead, void* buffer, u64 offset, u32 size) {
  109. return FSFILE_Read(handle, bytesRead, offset, buffer, size);
  110. }
  111.  
  112. static Result action_install_cias_open_dst(void* data, u32 index, void* initialReadBlock, u64 size, u32* handle) {
  113. install_cias_data* installData = (install_cias_data*) data;
  114.  
  115. installData->n3dsContinue = false;
  116.  
  117. file_info* info = (file_info*) ((list_item*) linked_list_get(&installData->contents, index))->data;
  118.  
  119. FS_MediaType dest = fs_get_title_destination(info->ciaInfo.titleId);
  120.  
  121. bool n3ds = false;
  122. if(R_SUCCEEDED(APT_CheckNew3DS(&n3ds)) && !n3ds && ((info->ciaInfo.titleId >> 28) & 0xF) == 2) {
  123. ui_view* view = prompt_display_yes_no("Confirmation", "Title is intended for New 3DS systems.\nContinue?", COLOR_TEXT, data, action_install_cias_draw_top, action_install_cias_n3ds_onresponse);
  124. if(view != NULL) {
  125. svcWaitSynchronization(view->active, U64_MAX);
  126. }
  127.  
  128. if(!installData->n3dsContinue) {
  129. return R_APP_SKIPPED;
  130. }
  131. }
  132.  
  133. // Deleting FBI before it reinstalls itself causes issues.
  134. u64 currTitleId = 0;
  135. FS_MediaType currMediaType = MEDIATYPE_NAND;
  136.  
  137. if(envIsHomebrew() || R_FAILED(APT_GetAppletInfo((NS_APPID) envGetAptAppId(), &currTitleId, (u8*) &currMediaType, NULL, NULL, NULL)) || info->ciaInfo.titleId != currTitleId || dest != currMediaType) {
  138. AM_DeleteTitle(dest, info->ciaInfo.titleId);
  139. AM_DeleteTicket(info->ciaInfo.titleId);
  140.  
  141. if(dest == MEDIATYPE_SD) {
  142. AM_QueryAvailableExternalTitleDatabase(NULL);
  143. }
  144. }
  145.  
  146. return AM_StartCiaInstall(dest, handle);
  147. }
  148.  
  149. static Result action_install_cias_close_dst(void* data, u32 index, bool succeeded, u32 handle) {
  150. if(succeeded) {
  151. install_cias_data* installData = (install_cias_data*) data;
  152.  
  153. file_info* info = (file_info*) ((list_item*) linked_list_get(&installData->contents, index))->data;
  154.  
  155. Result res = 0;
  156. if(R_SUCCEEDED(res = AM_FinishCiaInstall(handle))) {
  157. http_download_seed(info->ciaInfo.titleId);
  158.  
  159. if((info->ciaInfo.titleId & 0xFFFFFFF) == 0x0000002) {
  160. res = AM_InstallFirm(info->ciaInfo.titleId);
  161. }
  162. }
  163.  
  164. return res;
  165. } else {
  166. return AM_CancelCIAInstall(handle);
  167. }
  168. }
  169.  
  170. static Result action_install_cias_write_dst(void* data, u32 handle, u32* bytesWritten, void* buffer, u64 offset, u32 size) {
  171. return FSFILE_Write(handle, bytesWritten, offset, buffer, size, 0);
  172. }
  173.  
  174. static Result action_install_cias_suspend(void* data, u32 index) {
  175. return 0;
  176. }
  177.  
  178. static Result action_install_cias_restore(void* data, u32 index) {
  179. return 0;
  180. }
  181.  
  182. bool action_install_cias_error(void* data, u32 index, Result res, ui_view** errorView) {
  183. *errorView = error_display_res(data, action_install_cias_draw_top, res, "Failed to install CIA file.");
  184. return true;
  185. }
  186.  
  187. static void action_install_cias_free_data(install_cias_data* data) {
  188. task_clear_files(&data->contents);
  189. linked_list_destroy(&data->contents);
  190.  
  191. if(data->targetItem != NULL) {
  192. task_free_file(data->targetItem);
  193. data->targetItem = NULL;
  194. data->target = NULL;
  195. }
  196.  
  197. free(data);
  198. }
  199.  
  200. static void action_install_cias_update(ui_view* view, void* data, float* progress, char* text) {
  201. install_cias_data* installData = (install_cias_data*) data;
  202.  
  203. if(installData->installInfo.finished) {
  204. if(installData->delete) {
  205. FSUSER_ControlArchive(installData->target->archive, ARCHIVE_ACTION_COMMIT_SAVE_DATA, NULL, 0, NULL, 0);
  206. }
  207.  
  208. ui_pop();
  209. info_destroy(view);
  210.  
  211. if(R_SUCCEEDED(installData->installInfo.result)) {
  212. prompt_display_notify("Success", "Install finished.", COLOR_TEXT, NULL, NULL, NULL);
  213. }
  214.  
  215. action_install_cias_free_data(installData);
  216.  
  217. return;
  218. }
  219.  
  220. if((hidKeysDown() & KEY_B) && !installData->installInfo.finished) {
  221. svcSignalEvent(installData->installInfo.cancelEvent);
  222. }
  223.  
  224. *progress = installData->installInfo.currTotal != 0 ? (float) ((double) installData->installInfo.currProcessed / (double) installData->installInfo.currTotal) : 0;
  225. snprintf(text, PROGRESS_TEXT_MAX, "%lu / %lu\n%.2f %s / %.2f %s\n%.2f %s/s, ETA %s", installData->installInfo.processed, installData->installInfo.total,
  226. ui_get_display_size(installData->installInfo.currProcessed),
  227. ui_get_display_size_units(installData->installInfo.currProcessed),
  228. ui_get_display_size(installData->installInfo.currTotal),
  229. ui_get_display_size_units(installData->installInfo.currTotal),
  230. ui_get_display_size(installData->installInfo.bytesPerSecond),
  231. ui_get_display_size_units(installData->installInfo.bytesPerSecond),
  232. ui_get_display_eta(installData->installInfo.estimatedRemainingSeconds));
  233. }
  234.  
  235. static void action_install_cias_onresponse(ui_view* view, void* data, u32 response) {
  236. install_cias_data* installData = (install_cias_data*) data;
  237.  
  238. if(response == PROMPT_YES) {
  239. Result res = task_data_op(&installData->installInfo);
  240. if(R_SUCCEEDED(res)) {
  241. info_display("Installing CIA(s)", "Press B to cancel.", true, data, action_install_cias_update, action_install_cias_draw_top);
  242. } else {
  243. error_display_res(NULL, NULL, res, "Failed to initiate CIA installation.");
  244.  
  245. action_install_cias_free_data(installData);
  246. }
  247. } else {
  248. action_install_cias_free_data(installData);
  249. }
  250. }
  251.  
  252. typedef struct {
  253. install_cias_data* installData;
  254.  
  255. const char* message;
  256.  
  257. fs_filter_data filterData;
  258. populate_files_data popData;
  259. } install_cias_loading_data;
  260.  
  261. static void action_install_cias_loading_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
  262. action_install_cias_draw_top(view, ((install_cias_loading_data*) data)->installData, x1, y1, x2, y2);
  263. }
  264.  
  265. static void action_install_cias_loading_update(ui_view* view, void* data, float* progress, char* text) {
  266. install_cias_loading_data* loadingData = (install_cias_loading_data*) data;
  267.  
  268. if(loadingData->popData.finished) {
  269. ui_pop();
  270. info_destroy(view);
  271.  
  272. if(R_SUCCEEDED(loadingData->popData.result)) {
  273. loadingData->installData->installInfo.total = linked_list_size(&loadingData->installData->contents);
  274. loadingData->installData->installInfo.processed = loadingData->installData->installInfo.total;
  275.  
  276. prompt_display_yes_no("Confirmation", loadingData->message, COLOR_TEXT, loadingData->installData, action_install_cias_draw_top, action_install_cias_onresponse);
  277. } else {
  278. error_display_res(NULL, NULL, loadingData->popData.result, "Failed to populate CIA list.");
  279.  
  280. action_install_cias_free_data(loadingData->installData);
  281. }
  282.  
  283. free(loadingData);
  284. return;
  285. }
  286.  
  287. if((hidKeysDown() & KEY_B) && !loadingData->popData.finished) {
  288. svcSignalEvent(loadingData->popData.cancelEvent);
  289. }
  290.  
  291. snprintf(text, PROGRESS_TEXT_MAX, "Fetching CIA list...");
  292. }
  293.  
  294. static void action_install_cias_internal(linked_list* items, list_item* selected, bool (*filter)(void* data, const char* name, u32 attributes), void* filterData, const char* message, bool delete) {
  295. install_cias_data* data = (install_cias_data*) calloc(1, sizeof(install_cias_data));
  296. if(data == NULL) {
  297. error_display(NULL, NULL, "Failed to allocate install CIAs data.");
  298.  
  299. return;
  300. }
  301.  
  302. data->items = items;
  303.  
  304. file_info* targetInfo = (file_info*) selected->data;
  305. Result targetCreateRes = task_create_file_item(&data->targetItem, targetInfo->archive, targetInfo->path, targetInfo->attributes, true);
  306. if(R_FAILED(targetCreateRes)) {
  307. error_display_res(NULL, NULL, targetCreateRes, "Failed to create target file item.");
  308.  
  309. action_install_cias_free_data(data);
  310. return;
  311. }
  312.  
  313. data->target = (file_info*) data->targetItem->data;
  314.  
  315. data->delete = delete;
  316.  
  317. data->n3dsContinue = false;
  318.  
  319. data->installInfo.data = data;
  320.  
  321. data->installInfo.op = DATAOP_COPY;
  322.  
  323. data->installInfo.bufferSize = 256 * 1024;
  324. data->installInfo.copyEmpty = false;
  325.  
  326. data->installInfo.isSrcDirectory = action_install_cias_is_src_directory;
  327. data->installInfo.makeDstDirectory = action_install_cias_make_dst_directory;
  328.  
  329. data->installInfo.openSrc = action_install_cias_open_src;
  330. data->installInfo.closeSrc = action_install_cias_close_src;
  331. data->installInfo.getSrcSize = action_install_cias_get_src_size;
  332. data->installInfo.readSrc = action_install_cias_read_src;
  333.  
  334. data->installInfo.openDst = action_install_cias_open_dst;
  335. data->installInfo.closeDst = action_install_cias_close_dst;
  336. data->installInfo.writeDst = action_install_cias_write_dst;
  337.  
  338. data->installInfo.suspend = action_install_cias_suspend;
  339. data->installInfo.restore = action_install_cias_restore;
  340.  
  341. data->installInfo.error = action_install_cias_error;
  342.  
  343. data->installInfo.finished = true;
  344.  
  345. linked_list_init(&data->contents);
  346.  
  347. install_cias_loading_data* loadingData = (install_cias_loading_data*) calloc(1, sizeof(install_cias_loading_data));
  348. if(loadingData == NULL) {
  349. error_display(NULL, NULL, "Failed to allocate loading data.");
  350.  
  351. action_install_cias_free_data(data);
  352. return;
  353. }
  354.  
  355. loadingData->installData = data;
  356. loadingData->message = message;
  357.  
  358. loadingData->filterData.parentFilter = filter;
  359. loadingData->filterData.parentFilterData = filterData;
  360.  
  361. loadingData->popData.items = &data->contents;
  362. loadingData->popData.archive = data->target->archive;
  363. string_copy(loadingData->popData.path, data->target->path, FILE_PATH_MAX);
  364. loadingData->popData.recursive = false;
  365. loadingData->popData.includeBase = !(data->target->attributes & FS_ATTRIBUTE_DIRECTORY);
  366. loadingData->popData.meta = true;
  367. loadingData->popData.filter = fs_filter_cias;
  368. loadingData->popData.filterData = &loadingData->filterData;
  369.  
  370. Result listRes = task_populate_files(&loadingData->popData);
  371. if(R_FAILED(listRes)) {
  372. error_display_res(NULL, NULL, listRes, "Failed to initiate CIA list population.");
  373.  
  374. free(loadingData);
  375. action_install_cias_free_data(data);
  376. return;
  377. }
  378.  
  379. info_display("Loading", "Press B to cancel.", false, loadingData, action_install_cias_loading_update, action_install_cias_loading_draw_top);
  380. }
  381.  
  382. void action_install_cia(linked_list* items, list_item* selected) {
  383. action_install_cias_internal(items, selected, NULL, NULL, "Install the selected CIA?", false);
  384. }
  385.  
  386. void action_install_cia_delete(linked_list* items, list_item* selected) {
  387. action_install_cias_internal(items, selected, NULL, NULL, "Install and delete the selected CIA?", true);
  388. }
  389.  
  390. void action_install_cias(linked_list* items, list_item* selected, bool (*filter)(void* data, const char* name, u32 attributes), void* filterData) {
  391. action_install_cias_internal(items, selected, filter, filterData, "Install all CIAs in the current directory?", false);
  392. }
  393.  
  394. void action_install_cias_delete(linked_list* items, list_item* selected, bool (*filter)(void* data, const char* name, u32 attributes), void* filterData) {
  395. action_install_cias_internal(items, selected, filter, filterData, "Install and delete all CIAs in the current directory?", true);
  396. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement