Clean up file handling.

This commit is contained in:
Steven Smith 2016-06-02 14:46:19 -07:00
parent a20a389cd9
commit 8583d62ec3
19 changed files with 246 additions and 163 deletions

View File

@ -4,7 +4,8 @@
#include <3ds.h>
#include "clipboard.h"
#include "../task/task.h"
#include "util.h"
#include "../ui/section/task/task.h"
static bool clipboard_has = false;
static bool clipboard_contents_only;
@ -28,30 +29,29 @@ bool clipboard_is_contents_only() {
return clipboard_contents_only;
}
Result clipboard_set_contents(FS_ArchiveID archiveId, FS_Path* archivePath, const char* path, bool contentsOnly) {
Result clipboard_set_contents(FS_Archive archive, const char* path, bool contentsOnly) {
clipboard_clear();
Result res = 0;
if(R_SUCCEEDED(res = util_ref_archive(archive))) {
clipboard_has = true;
clipboard_contents_only = contentsOnly;
clipboard_archive = archive;
strncpy(clipboard_path, path, FILE_PATH_MAX);
Result res = 0;
if(R_FAILED(res = FSUSER_OpenArchive(&clipboard_archive, archiveId, *archivePath))) {
clipboard_clear();
}
return res;
}
void clipboard_clear() {
if(clipboard_archive != 0) {
util_close_archive(clipboard_archive);
}
clipboard_has = false;
clipboard_contents_only = false;
memset(clipboard_path, '\0', FILE_PATH_MAX);
if(clipboard_archive != 0) {
FSUSER_CloseArchive(clipboard_archive);
clipboard_archive = 0;
}
memset(clipboard_path, '\0', FILE_PATH_MAX);
}

View File

@ -1,12 +1,10 @@
#pragma once
#include <stdbool.h>
typedef struct file_info_s file_info;
bool clipboard_has_contents();
FS_Archive clipboard_get_archive();
char* clipboard_get_path();
bool clipboard_is_contents_only();
Result clipboard_set_contents(FS_ArchiveID archiveId, FS_Path* archivePath, const char* path, bool contentsOnly);
Result clipboard_set_contents(FS_Archive archive, const char* path, bool contentsOnly);
void clipboard_clear();

View File

@ -9,6 +9,7 @@
#include "../ui/error.h"
#include "../ui/list.h"
#include "../ui/section/task/task.h"
#include "linkedlist.h"
extern void cleanup();
@ -361,6 +362,14 @@ int util_compare_file_infos(const void** p1, const void** p2) {
list_item* info1 = *(list_item**) p1;
list_item* info2 = *(list_item**) p2;
bool info1Base = strncmp(info1->name, "<current directory>", LIST_ITEM_NAME_MAX) == 0 || strncmp(info1->name, "<current file>", LIST_ITEM_NAME_MAX) == 0;
bool info2Base = strncmp(info2->name, "<current directory>", LIST_ITEM_NAME_MAX) == 0 || strncmp(info2->name, "<current file>", LIST_ITEM_NAME_MAX) == 0;
if(info1Base && !info2Base) {
return -1;
} else if(!info1Base && info2Base) {
return 1;
} else {
file_info* f1 = (file_info*) info1->data;
file_info* f2 = (file_info*) info2->data;
@ -369,16 +378,95 @@ int util_compare_file_infos(const void** p1, const void** p2) {
} else if(!f1->isDirectory && f2->isDirectory) {
return 1;
} else {
return strcasecmp(f1->name, f2->name);
return strncasecmp(f1->name, f2->name, FILE_NAME_MAX);
}
}
}
static const char* path3dsx = NULL;
static const char* path_3dsx = NULL;
const char* util_get_3dsx_path() {
return path3dsx;
return path_3dsx;
}
void util_set_3dsx_path(const char* path) {
path3dsx = path;
path_3dsx = path;
}
typedef struct {
FS_Archive archive;
u32 refs;
} archive_ref;
static linked_list opened_archives;
static Result util_add_archive_ref(FS_Archive archive) {
Result res = 0;
archive_ref* ref = (archive_ref*) calloc(1, sizeof(archive_ref));
if(ref != NULL) {
ref->archive = archive;
ref->refs = 1;
linked_list_add(&opened_archives, ref);
} else {
res = R_FBI_OUT_OF_MEMORY;
}
return res;
}
Result util_open_archive(FS_Archive* archive, FS_ArchiveID id, FS_Path path) {
if(archive == NULL) {
return R_FBI_INVALID_ARGUMENT;
}
Result res = 0;
FS_Archive arch = 0;
if(R_SUCCEEDED(res = FSUSER_OpenArchive(&arch, id, path))) {
if(R_SUCCEEDED(res = util_add_archive_ref(arch))) {
*archive = arch;
} else {
FSUSER_CloseArchive(arch);
}
}
return res;
}
Result util_ref_archive(FS_Archive archive) {
linked_list_iter iter;
linked_list_iterate(&opened_archives, &iter);
while(linked_list_iter_has_next(&iter)) {
archive_ref* ref = (archive_ref*) linked_list_iter_next(&iter);
if(ref->archive == archive) {
ref->refs++;
return 0;
}
}
return util_add_archive_ref(archive);
}
Result util_close_archive(FS_Archive archive) {
linked_list_iter iter;
linked_list_iterate(&opened_archives, &iter);
while(linked_list_iter_has_next(&iter)) {
archive_ref* ref = (archive_ref*) linked_list_iter_next(&iter);
if(ref->archive == archive) {
ref->refs--;
if(ref->refs == 0) {
linked_list_iter_remove(&iter);
free(ref);
} else {
return 0;
}
}
}
return FSUSER_CloseArchive(archive);
}

View File

@ -66,3 +66,7 @@ int util_compare_file_infos(const void** p1, const void** p2);
const char* util_get_3dsx_path();
void util_set_3dsx_path(const char* path);
Result util_open_archive(FS_Archive* archive, FS_ArchiveID id, FS_Path path);
Result util_ref_archive(FS_Archive archive);
Result util_close_archive(FS_Archive archive);

View File

@ -2,12 +2,12 @@
#include <3ds.h>
#include "core/clipboard.h"
#include "core/screen.h"
#include "core/util.h"
#include "svchax/svchax.h"
#include "ui/mainmenu.h"
#include "ui/ui.h"
#include "ui/section/action/clipboard.h"
#include "ui/section/task/task.h"
static void* soc_buffer;

View File

@ -22,10 +22,10 @@ typedef struct {
linked_list contents;
data_op_data deleteInfo;
} delete_contents_data;
} delete_data;
static void action_delete_contents_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
delete_contents_data* deleteData = (delete_contents_data*) data;
static void action_delete_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2) {
delete_data* deleteData = (delete_data*) data;
u32 curr = deleteData->deleteInfo.processed;
if(curr < deleteData->deleteInfo.total) {
@ -35,8 +35,8 @@ static void action_delete_contents_draw_top(ui_view* view, void* data, float x1,
}
}
static Result action_delete_contents_delete(void* data, u32 index) {
delete_contents_data* deleteData = (delete_contents_data*) data;
static Result action_delete_delete(void* data, u32 index) {
delete_data* deleteData = (delete_data*) data;
Result res = 0;
@ -56,9 +56,6 @@ static Result action_delete_contents_delete(void* data, u32 index) {
}
if(R_SUCCEEDED(res)) {
deleteData->target->containsCias = false;
deleteData->target->containsTickets = false;
linked_list_iter iter;
linked_list_iterate(deleteData->items, &iter);
@ -69,10 +66,6 @@ static Result action_delete_contents_delete(void* data, u32 index) {
if(strncmp(currInfo->path, info->path, FILE_PATH_MAX) == 0) {
linked_list_iter_remove(&iter);
task_free_file(item);
} else if(currInfo->isCia) {
deleteData->target->containsCias = true;
} else if(currInfo->isTicket) {
deleteData->target->containsTickets = true;
}
}
}
@ -80,23 +73,23 @@ static Result action_delete_contents_delete(void* data, u32 index) {
return res;
}
static Result action_delete_contents_suspend(void* data, u32 index) {
static Result action_delete_suspend(void* data, u32 index) {
return 0;
}
static Result action_delete_contents_restore(void* data, u32 index) {
static Result action_delete_restore(void* data, u32 index) {
return 0;
}
static bool action_delete_contents_error(void* data, u32 index, Result res) {
delete_contents_data* deleteData = (delete_contents_data*) data;
static bool action_delete_error(void* data, u32 index, Result res) {
delete_data* deleteData = (delete_data*) data;
if(res == R_FBI_CANCELLED) {
prompt_display("Failure", "Delete cancelled.", COLOR_TEXT, false, NULL, NULL, NULL);
return false;
} else {
volatile bool dismissed = false;
error_display_res(&dismissed, data, action_delete_contents_draw_top, res, "Failed to delete content.");
error_display_res(&dismissed, data, action_delete_draw_top, res, "Failed to delete content.");
while(!dismissed) {
svcSleepThread(1000000);
@ -106,14 +99,14 @@ static bool action_delete_contents_error(void* data, u32 index, Result res) {
return index < deleteData->deleteInfo.total - 1;
}
static void action_delete_contents_free_data(delete_contents_data* data) {
static void action_delete_free_data(delete_data* data) {
task_clear_files(&data->contents);
linked_list_destroy(&data->contents);
free(data);
}
static void action_delete_contents_update(ui_view* view, void* data, float* progress, char* text) {
delete_contents_data* deleteData = (delete_contents_data*) data;
static void action_delete_update(ui_view* view, void* data, float* progress, char* text) {
delete_data* deleteData = (delete_data*) data;
if(deleteData->deleteInfo.finished) {
FSUSER_ControlArchive(deleteData->target->archive, ARCHIVE_ACTION_COMMIT_SAVE_DATA, NULL, 0, NULL, 0);
@ -125,7 +118,7 @@ static void action_delete_contents_update(ui_view* view, void* data, float* prog
prompt_display("Success", "Deleted.", COLOR_TEXT, false, NULL, NULL, NULL);
}
action_delete_contents_free_data(deleteData);
action_delete_free_data(deleteData);
return;
}
@ -138,25 +131,25 @@ static void action_delete_contents_update(ui_view* view, void* data, float* prog
snprintf(text, PROGRESS_TEXT_MAX, "%lu / %lu", deleteData->deleteInfo.processed, deleteData->deleteInfo.total);
}
static void action_delete_contents_onresponse(ui_view* view, void* data, bool response) {
delete_contents_data* deleteData = (delete_contents_data*) data;
static void action_delete_onresponse(ui_view* view, void* data, bool response) {
delete_data* deleteData = (delete_data*) data;
if(response) {
Result res = task_data_op(&deleteData->deleteInfo);
if(R_SUCCEEDED(res)) {
info_display("Deleting", "Press B to cancel.", true, data, action_delete_contents_update, action_delete_contents_draw_top);
info_display("Deleting", "Press B to cancel.", true, data, action_delete_update, action_delete_draw_top);
} else {
error_display_res(NULL, deleteData->target, ui_draw_file_info, res, "Failed to initiate delete operation.");
action_delete_contents_free_data(deleteData);
action_delete_free_data(deleteData);
}
} else {
action_delete_contents_free_data(deleteData);
action_delete_free_data(deleteData);
}
}
static void action_delete_contents_internal(linked_list* items, list_item* selected, const char* message, bool recursive, bool includeBase, bool ciasOnly, bool ticketsOnly) {
delete_contents_data* data = (delete_contents_data*) calloc(1, sizeof(delete_contents_data));
static void action_delete_internal(linked_list* items, list_item* selected, const char* message, bool recursive, bool includeBase, bool ciasOnly, bool ticketsOnly) {
delete_data* data = (delete_data*) calloc(1, sizeof(delete_data));
if(data == NULL) {
error_display(NULL, NULL, NULL, "Failed to allocate delete data.");
@ -170,12 +163,12 @@ static void action_delete_contents_internal(linked_list* items, list_item* selec
data->deleteInfo.op = DATAOP_DELETE;
data->deleteInfo.delete = action_delete_contents_delete;
data->deleteInfo.delete = action_delete_delete;
data->deleteInfo.suspend = action_delete_contents_suspend;
data->deleteInfo.restore = action_delete_contents_restore;
data->deleteInfo.suspend = action_delete_suspend;
data->deleteInfo.restore = action_delete_restore;
data->deleteInfo.error = action_delete_contents_error;
data->deleteInfo.error = action_delete_error;
data->deleteInfo.finished = false;
@ -183,7 +176,8 @@ static void action_delete_contents_internal(linked_list* items, list_item* selec
populate_files_data popData;
popData.items = &data->contents;
popData.base = data->target;
popData.archive = data->target->archive;
strncpy(popData.path, data->target->path, FILE_PATH_MAX);
popData.recursive = recursive;
popData.includeBase = includeBase;
popData.filter = ciasOnly ? util_filter_cias : ticketsOnly ? util_filter_tickets : NULL;
@ -193,7 +187,7 @@ static void action_delete_contents_internal(linked_list* items, list_item* selec
if(R_FAILED(listRes)) {
error_display_res(NULL, NULL, NULL, listRes, "Failed to initiate content list population.");
action_delete_contents_free_data(data);
action_delete_free_data(data);
return;
}
@ -204,32 +198,32 @@ static void action_delete_contents_internal(linked_list* items, list_item* selec
if(R_FAILED(popData.result)) {
error_display_res(NULL, NULL, NULL, popData.result, "Failed to populate content list.");
action_delete_contents_free_data(data);
action_delete_free_data(data);
return;
}
data->deleteInfo.total = linked_list_size(&data->contents);
data->deleteInfo.processed = data->deleteInfo.total;
prompt_display("Confirmation", message, COLOR_TEXT, true, data, action_delete_contents_draw_top, action_delete_contents_onresponse);
prompt_display("Confirmation", message, COLOR_TEXT, true, data, action_delete_draw_top, action_delete_onresponse);
}
void action_delete_file(linked_list* items, list_item* selected) {
action_delete_contents_internal(items, selected, "Delete the selected file?", false, true, false, false);
action_delete_internal(items, selected, "Delete the selected file?", false, true, false, false);
}
void action_delete_dir(linked_list* items, list_item* selected) {
action_delete_contents_internal(items, selected, "Delete the current directory?", true, true, false, false);
action_delete_internal(items, selected, "Delete the current directory?", true, true, false, false);
}
void action_delete_dir_contents(linked_list* items, list_item* selected) {
action_delete_contents_internal(items, selected, "Delete all contents of the current directory?", true, false, false, false);
action_delete_internal(items, selected, "Delete all contents of the current directory?", true, false, false, false);
}
void action_delete_dir_cias(linked_list* items, list_item* selected) {
action_delete_contents_internal(items, selected, "Delete all CIAs in the current directory?", false, false, true, false);
action_delete_internal(items, selected, "Delete all CIAs in the current directory?", false, false, true, false);
}
void action_delete_dir_tickets(linked_list* items, list_item* selected) {
action_delete_contents_internal(items, selected, "Delete all tickets in the current directory?", false, false, false, true);
action_delete_internal(items, selected, "Delete all tickets in the current directory?", false, false, false, true);
}

View File

@ -46,10 +46,11 @@ static Result action_delete_pending_titles_delete(void* data, u32 index) {
while(linked_list_iter_has_next(&iter)) {
list_item* currItem = (list_item*) linked_list_iter_next(&iter);
pending_title_info* currInfo = (pending_title_info*) currItem->data;
if(strncmp(currItem->name, item->name, LIST_ITEM_NAME_MAX) == 0) {
if(currInfo->titleId == info->titleId && currInfo->mediaType == info->mediaType) {
linked_list_iter_remove(&iter);
task_free_file(currItem);
task_free_pending_title(currItem);
}
}
}

View File

@ -78,9 +78,6 @@ static Result action_install_cias_close_src(void* data, u32 index, bool succeede
FS_Path* fsPath = util_make_path_utf8(info->path);
if(fsPath != NULL) {
if(R_SUCCEEDED(FSUSER_DeleteFile(info->archive, *fsPath))) {
installData->target->containsCias = false;
installData->target->containsTickets = false;
linked_list_iter iter;
linked_list_iterate(installData->items, &iter);
@ -91,10 +88,6 @@ static Result action_install_cias_close_src(void* data, u32 index, bool succeede
if(strncmp(currInfo->path, info->path, FILE_PATH_MAX) == 0) {
linked_list_iter_remove(&iter);
task_free_file(item);
} else if(currInfo->isCia) {
installData->target->containsCias = true;
} else if(currInfo->isTicket) {
installData->target->containsTickets = true;
}
}
}
@ -303,7 +296,8 @@ static void action_install_cias_internal(linked_list* items, list_item* selected
populate_files_data popData;
popData.items = &data->contents;
popData.base = data->target;
popData.archive = data->target->archive;
strncpy(popData.path, data->target->path, FILE_PATH_MAX);
popData.recursive = false;
popData.includeBase = !data->target->isDirectory;
popData.filter = util_filter_cias;

View File

@ -77,9 +77,6 @@ static Result action_install_tickets_close_src(void* data, u32 index, bool succe
FS_Path* fsPath = util_make_path_utf8(info->path);
if(fsPath != NULL) {
if(R_SUCCEEDED(FSUSER_DeleteFile(info->archive, *fsPath))) {
installData->target->containsCias = false;
installData->target->containsTickets = false;
linked_list_iter iter;
linked_list_iterate(installData->items, &iter);
@ -90,10 +87,6 @@ static Result action_install_tickets_close_src(void* data, u32 index, bool succe
if(strncmp(currInfo->path, info->path, FILE_PATH_MAX) == 0) {
linked_list_iter_remove(&iter);
task_free_file(item);
} else if(currInfo->isCia) {
installData->target->containsCias = true;
} else if(currInfo->isTicket) {
installData->target->containsTickets = true;
}
}
}
@ -280,7 +273,8 @@ static void action_install_tickets_internal(linked_list* items, list_item* selec
populate_files_data popData;
popData.items = &data->contents;
popData.base = data->target;
popData.archive = data->target->archive;
strncpy(popData.path, data->target->path, FILE_PATH_MAX);
popData.recursive = false;
popData.includeBase = !data->target->isDirectory;
popData.filter = util_filter_tickets;

View File

@ -5,13 +5,13 @@
#include <3ds.h>
#include "action.h"
#include "clipboard.h"
#include "../task/task.h"
#include "../../error.h"
#include "../../info.h"
#include "../../list.h"
#include "../../prompt.h"
#include "../../ui.h"
#include "../../../core/clipboard.h"
#include "../../../core/linkedlist.h"
#include "../../../core/screen.h"
#include "../../../core/util.h"
@ -74,7 +74,14 @@ static Result action_paste_files_make_dst_directory(void* data, u32 index) {
char parentPath[FILE_PATH_MAX];
util_get_parent_path(parentPath, dstPath, FILE_PATH_MAX);
if(strncmp(parentPath, pasteData->target->path, FILE_PATH_MAX) == 0) {
char baseDstPath[FILE_PATH_MAX];
if(pasteData->target->isDirectory) {
strncpy(baseDstPath, pasteData->target->path, FILE_PATH_MAX);
} else {
util_get_parent_path(baseDstPath, pasteData->target->path, FILE_PATH_MAX);
}
if(strncmp(parentPath, baseDstPath, FILE_PATH_MAX) == 0) {
list_item* dstItem = NULL;
if(R_SUCCEEDED(res) && R_SUCCEEDED(task_create_file_item(&dstItem, pasteData->target->archive, dstPath))) {
linked_list_add(pasteData->items, dstItem);
@ -152,18 +159,17 @@ static Result action_paste_files_close_dst(void* data, u32 index, bool succeeded
char parentPath[FILE_PATH_MAX];
util_get_parent_path(parentPath, dstPath, FILE_PATH_MAX);
if(strncmp(parentPath, pasteData->target->path, FILE_PATH_MAX) == 0) {
char baseDstPath[FILE_PATH_MAX];
if(pasteData->target->isDirectory) {
strncpy(baseDstPath, pasteData->target->path, FILE_PATH_MAX);
} else {
util_get_parent_path(baseDstPath, pasteData->target->path, FILE_PATH_MAX);
}
if(strncmp(parentPath, baseDstPath, FILE_PATH_MAX) == 0) {
list_item* dstItem = NULL;
if(R_SUCCEEDED(task_create_file_item(&dstItem, pasteData->target->archive, dstPath))) {
linked_list_add(pasteData->items, dstItem);
file_info* dstInfo = (file_info*) dstItem->data;
if(dstInfo->isCia) {
pasteData->target->containsCias = true;
} else if(dstInfo->isTicket) {
pasteData->target->containsTickets = true;
}
}
}
}
@ -316,7 +322,8 @@ void action_paste_contents(linked_list* items, list_item* selected) {
populate_files_data popData;
popData.items = &data->contents;
popData.base = (file_info*) clipboardItem->data;
popData.archive = ((file_info*) clipboardItem->data)->archive;
strncpy(popData.path, ((file_info*) clipboardItem->data)->path, FILE_PATH_MAX);
popData.recursive = true;
popData.includeBase = !clipboard_is_contents_only() || !util_is_dir(clipboard_get_archive(), clipboard_get_path());
popData.filter = NULL;

View File

@ -59,7 +59,10 @@ static void action_rename_kbd_finished(void* data, char* input) {
}
if(R_SUCCEEDED(res)) {
if(strncmp(renameData->target->name, "<current directory>", LIST_ITEM_NAME_MAX) != 0 && strncmp(renameData->target->name, "<current file>", LIST_ITEM_NAME_MAX) != 0) {
strncpy(renameData->target->name, input, LIST_ITEM_NAME_MAX);
}
strncpy(targetInfo->name, input, FILE_NAME_MAX);
strncpy(targetInfo->path, dstPath, FILE_PATH_MAX);
@ -88,5 +91,5 @@ void action_rename(linked_list* items, list_item* selected) {
data->items = items;
data->target = selected;
kbd_display("Enter New Name", data->target->name, data, NULL, action_rename_kbd_finished, action_rename_kbd_canceled);
kbd_display("Enter New Name", ((file_info*) selected->data)->name, data, NULL, action_rename_kbd_finished, action_rename_kbd_canceled);
}

View File

@ -6,12 +6,12 @@
#include "section.h"
#include "action/action.h"
#include "action/clipboard.h"
#include "task/task.h"
#include "../error.h"
#include "../list.h"
#include "../prompt.h"
#include "../ui.h"
#include "../../core/clipboard.h"
#include "../../core/linkedlist.h"
#include "../../core/screen.h"
#include "../../core/util.h"
@ -28,10 +28,10 @@ static list_item install_and_delete_cia = {"Install and delete CIA", COLOR_TEXT,
static list_item install_ticket = {"Install ticket", COLOR_TEXT, action_install_ticket};
static list_item install_and_delete_ticket = {"Install and delete ticket", COLOR_TEXT, action_install_ticket_delete};
static list_item new_folder = {"New folder", COLOR_TEXT, action_new_folder};
static list_item delete_dir = {"Delete", COLOR_TEXT, action_delete_dir};
static list_item delete_all_contents = {"Delete all contents", COLOR_TEXT, action_delete_dir_contents};
static list_item copy_all_contents = {"Copy all contents", COLOR_TEXT, NULL};
static list_item new_folder = {"New folder", COLOR_TEXT, action_new_folder};
static list_item install_all_cias = {"Install all CIAs", COLOR_TEXT, action_install_cias};
static list_item install_and_delete_all_cias = {"Install and delete all CIAs", COLOR_TEXT, action_install_cias_delete};
@ -57,13 +57,15 @@ typedef struct {
bool showTickets;
char currDir[FILE_PATH_MAX];
list_item* dirItem;
} files_data;
typedef struct {
linked_list* items;
list_item* selected;
files_data* parent;
bool containsCias;
bool containsTickets;
} files_action_data;
static void files_action_draw_top(ui_view* view, void* data, float x1, float y1, float x2, float y2, list_item* selected) {
@ -92,7 +94,7 @@ static void files_action_update(ui_view* view, void* data, linked_list* items, l
file_info* info = (file_info*) actionData->selected->data;
Result res = 0;
if(R_SUCCEEDED(res = clipboard_set_contents(actionData->parent->archiveId, &actionData->parent->archivePath, info->path, selected == &copy_all_contents))) {
if(R_SUCCEEDED(res = clipboard_set_contents(actionData->parent->archive, info->path, selected == &copy_all_contents))) {
prompt_display("Success", selected == &copy_all_contents ? "Current directory contents copied to clipboard." : info->isDirectory ? "Current directory copied to clipboard." : "File copied to clipboard.", COLOR_TEXT, false, info, ui_draw_file_info, NULL);
} else {
error_display_res(NULL, info, ui_draw_file_info, res, "Failed to copy to clipboard.");
@ -110,24 +112,24 @@ static void files_action_update(ui_view* view, void* data, linked_list* items, l
file_info* info = (file_info*) actionData->selected->data;
if(info->isDirectory) {
if(info->containsCias) {
if(actionData->containsCias) {
linked_list_add(items, &install_all_cias);
linked_list_add(items, &install_and_delete_all_cias);
linked_list_add(items, &delete_all_cias);
}
if(info->containsTickets) {
if(actionData->containsTickets) {
linked_list_add(items, &install_all_tickets);
linked_list_add(items, &install_and_delete_all_tickets);
linked_list_add(items, &delete_all_tickets);
}
linked_list_add(items, &new_folder);
linked_list_add(items, &delete_all_contents);
linked_list_add(items, &copy_all_contents);
linked_list_add(items, &delete_dir);
linked_list_add(items, &new_folder);
} else {
if(info->isCia) {
linked_list_add(items, &install_cia);
@ -160,6 +162,22 @@ static void files_action_open(linked_list* items, list_item* selected, files_dat
data->selected = selected;
data->parent = parent;
data->containsCias = false;
data->containsTickets = false;
linked_list_iter iter;
linked_list_iterate(data->items, &iter);
while(linked_list_iter_has_next(&iter)) {
file_info* info = (file_info*) ((list_item*) linked_list_iter_next(&iter))->data;
if(info->isCia) {
data->containsCias = true;
} else if(info->isTicket) {
data->containsTickets = true;
}
}
list_display(((file_info*) selected->data)->isDirectory ? "Directory Action" : "File Action", "A: Select, B: Return", data, files_action_update, files_action_draw_top);
}
@ -228,19 +246,11 @@ static void files_repopulate(files_data* listData, linked_list* items) {
}
}
if(listData->dirItem != NULL) {
task_free_file(listData->dirItem);
listData->dirItem = NULL;
}
Result res = 0;
if(R_SUCCEEDED(res = task_create_file_item(&listData->dirItem, listData->archive, listData->currDir))) {
listData->populateData.items = items;
listData->populateData.base = (file_info*) listData->dirItem->data;
res = task_populate_files(&listData->populateData);
}
listData->populateData.archive = listData->archive;
strncpy(listData->populateData.path, listData->currDir, FILE_PATH_MAX);
Result res = task_populate_files(&listData->populateData);
if(R_FAILED(res)) {
error_display_res(NULL, NULL, NULL, res, "Failed to initiate file list population.");
}
@ -262,13 +272,8 @@ static void files_free_data(files_data* data) {
}
}
if(data->dirItem != NULL) {
task_free_file(data->dirItem);
data->dirItem = NULL;
}
if(data->archive != 0) {
FSUSER_CloseArchive(data->archive);
util_close_archive(data->archive);
data->archive = 0;
}
@ -283,9 +288,12 @@ static void files_free_data(files_data* data) {
static void files_update(ui_view* view, void* data, linked_list* items, list_item* selected, bool selectedTouched) {
files_data* listData = (files_data*) data;
if(listData->populated) {
// Detect whether the current directory was renamed by an action.
if(listData->populated && listData->dirItem != NULL && strncmp(listData->currDir, ((file_info*) listData->dirItem->data)->path, FILE_PATH_MAX) != 0) {
strncpy(listData->currDir, ((file_info*) listData->dirItem->data)->path, FILE_PATH_MAX);
list_item* currDirItem = linked_list_get(items, 0);
if(currDirItem != NULL && strncmp(listData->currDir, ((file_info*) currDirItem->data)->path, FILE_PATH_MAX) != 0) {
strncpy(listData->currDir, ((file_info*) currDirItem->data)->path, FILE_PATH_MAX);
}
}
while(!util_is_dir(listData->archive, listData->currDir)) {
@ -318,15 +326,10 @@ static void files_update(ui_view* view, void* data, linked_list* items, list_ite
return;
}
if((hidKeysDown() & KEY_Y) && listData->dirItem != NULL) {
files_action_open(items, listData->dirItem, listData);
return;
}
if(selected != NULL && selected->data != NULL && (selectedTouched || (hidKeysDown() & KEY_A))) {
file_info* fileInfo = (file_info*) selected->data;
if(fileInfo->isDirectory) {
if(fileInfo->isDirectory && strncmp(selected->name, "<current directory>", LIST_ITEM_NAME_MAX) != 0) {
files_navigate(listData, items, fileInfo->path);
} else {
files_action_open(items, selected, listData);
@ -376,7 +379,7 @@ void files_open(FS_ArchiveID archiveId, FS_Path archivePath) {
}
data->populateData.recursive = false;
data->populateData.includeBase = false;
data->populateData.includeBase = true;
data->populateData.filter = files_filter;
data->populateData.filterData = data;
@ -409,17 +412,16 @@ void files_open(FS_ArchiveID archiveId, FS_Path archivePath) {
}
snprintf(data->currDir, FILE_PATH_MAX, "/");
data->dirItem = NULL;
Result res = 0;
if(R_FAILED(res = FSUSER_OpenArchive(&data->archive, archiveId, archivePath))) {
if(R_FAILED(res = util_open_archive(&data->archive, archiveId, archivePath))) {
error_display_res(NULL, NULL, NULL, res, "Failed to open file listing archive.");
files_free_data(data);
return;
}
list_display("Files", "A: Select, B: Back, X: Refresh, Y: Dir, Select: Filter", data, files_update, files_draw_top);
list_display("Files", "A: Select, B: Back, X: Refresh, Select: Filters", data, files_update, files_draw_top);
}
void files_open_sd() {

View File

@ -153,8 +153,9 @@ void task_clear_ext_save_data(linked_list* items) {
while(linked_list_iter_has_next(&iter)) {
list_item* item = (list_item*) linked_list_iter_next(&iter);
task_free_ext_save_data(item);
linked_list_iter_remove(&iter);
task_free_ext_save_data(item);
}
}

View File

@ -147,11 +147,15 @@ static void task_populate_files_thread(void* arg) {
Result res = 0;
data->base->containsCias = false;
data->base->containsTickets = false;
list_item* baseItem = NULL;
if(R_SUCCEEDED(res = task_create_file_item(&baseItem, data->base->archive, data->base->path))) {
if(R_SUCCEEDED(res = task_create_file_item(&baseItem, data->archive, data->path))) {
file_info* baseInfo = (file_info*) baseItem->data;
if(baseInfo->isDirectory) {
strncpy(baseItem->name, "<current directory>", LIST_ITEM_NAME_MAX);
} else {
strncpy(baseItem->name, "<current file>", LIST_ITEM_NAME_MAX);
}
linked_list queue;
linked_list_init(&queue);
@ -195,16 +199,6 @@ static void task_populate_files_thread(void* arg) {
list_item* item = NULL;
if(R_SUCCEEDED(res = task_create_file_item(&item, curr->archive, path))) {
if(currItem == baseItem) {
file_info* info = (file_info*) item->data;
if(info->isCia) {
data->base->containsCias = true;
} else if(info->isTicket) {
data->base->containsTickets = true;
}
}
if(data->recursive && ((file_info*) item->data)->isDirectory) {
linked_list_add(&queue, item);
} else {
@ -275,7 +269,7 @@ void task_clear_files(linked_list* items) {
}
Result task_populate_files(populate_files_data* data) {
if(data == NULL || data->base == NULL || data->items == NULL) {
if(data == NULL || data->items == NULL) {
return R_FBI_INVALID_ARGUMENT;
}

View File

@ -118,8 +118,9 @@ void task_clear_pending_titles(linked_list* items) {
while(linked_list_iter_has_next(&iter)) {
list_item* item = (list_item*) linked_list_iter_next(&iter);
task_free_pending_title(item);
linked_list_iter_remove(&iter);
task_free_pending_title(item);
}
}

View File

@ -86,8 +86,9 @@ void task_clear_system_save_data(linked_list* items) {
while(linked_list_iter_has_next(&iter)) {
list_item* item = (list_item*) linked_list_iter_next(&iter);
task_free_system_save_data(item);
linked_list_iter_remove(&iter);
task_free_system_save_data(item);
}
}

View File

@ -92,8 +92,9 @@ void task_clear_tickets(linked_list* items) {
while(linked_list_iter_has_next(&iter)) {
list_item* item = (list_item*) linked_list_iter_next(&iter);
task_free_ticket(item);
linked_list_iter_remove(&iter);
task_free_ticket(item);
}
}

View File

@ -342,8 +342,9 @@ void task_clear_titles(linked_list* items) {
while(linked_list_iter_has_next(&iter)) {
list_item* item = (list_item*) linked_list_iter_next(&iter);
task_free_title(item);
linked_list_iter_remove(&iter);
task_free_title(item);
}
}

View File

@ -60,14 +60,12 @@ typedef struct file_info_s {
char path[FILE_PATH_MAX];
bool isDirectory;
// Files only
u64 size;
bool isCia;
cia_info ciaInfo;
bool isTicket;
ticket_info ticketInfo;
bool containsCias;
bool containsTickets;
} file_info;
typedef struct {
@ -148,7 +146,8 @@ typedef struct {
typedef struct {
linked_list* items;
file_info* base;
FS_Archive archive;
char path[FILE_PATH_MAX];
bool recursive;
bool includeBase;