diff --git a/include/arm11/menu/menu_fsel.h b/include/arm11/menu/menu_fsel.h
new file mode 100644
index 0000000..883ccf4
--- /dev/null
+++ b/include/arm11/menu/menu_fsel.h
@@ -0,0 +1,23 @@
+#pragma once
+
+/*
+ * This file is part of fastboot 3DS
+ * Copyright (C) 2017 derrek, profi200, d0k3
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "types.h"
+
+u32 menuFileSelector(char* result, const char* start, const char* pattern);
diff --git a/source/arm11/menu/menu_fsel.c b/source/arm11/menu/menu_fsel.c
new file mode 100644
index 0000000..76f1da6
--- /dev/null
+++ b/source/arm11/menu/menu_fsel.c
@@ -0,0 +1,201 @@
+/*
+ * This file is part of fastboot 3DS
+ * Copyright (C) 2017 derrek, profi200, d0k3
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include "types.h"
+#include "fs.h"
+#include "util.h"
+#include "arm11/hardware/hid.h"
+#include "arm11/fsutils.h"
+#include "arm11/console.h"
+#include "arm11/debug.h"
+#include "arm11/fmt.h"
+
+#define MAX_DIR_ENTRIES 0x200 // 512 -> worst case, approx 128kiB (yes, this is limited)
+#define N_DIR_READ 0x10 // 16 at a time
+
+typedef struct {
+ u32 fsize; // size of the file
+ u8 is_dir; // > 0 if is directory
+ char* fname; // filename (handle via malloc)
+} DirBufferEntry;
+
+
+static char* mallocpyString(const char* str)
+{
+ u32 strsize = strlen(str) + 1;
+ char* astr = (char*) malloc(strsize);
+
+ if (astr) strncpy(astr, str, strsize);
+ return astr;
+}
+
+
+// inspired by http://www.geeksforgeeks.org/wildcard-character-matching/
+static bool matchName(const char* path, const char* pattern)
+{
+ // handling non asterisk chars
+ for (; *pattern != '*'; pattern++, path++)
+ {
+ if ((*pattern == '\0') && (*path == '\0'))
+ {
+ return true; // end reached simultaneously, match found
+ }
+ else if ((*pattern == '\0') || (*path == '\0'))
+ {
+ return false; // end reached on only one, failure
+ }
+ else if ((*pattern != '?') && (tolower(*pattern) != tolower(*path)))
+ {
+ return false; // chars don't match, failure
+ }
+ }
+
+ // handling the asterisk (matches one or more chars in path)
+ if ((*(pattern+1) == '?') || (*(pattern+1) == '*'))
+ {
+ return false; // stupid user/dev shenanigans, failure
+ }
+ else if (*path == '\0')
+ {
+ return false; // asterisk, but end reached on path, failure
+ }
+ else if (*(pattern+1) == '\0')
+ {
+ return true; // nothing after the asterisk, match found
+ }
+ else
+ {
+ // we couldn't really go without recursion here
+ for (path++; *path != '\0'; path++)
+ {
+ if (matchName(path, pattern + 1) == true) return true;
+ }
+ }
+
+ return false;
+}
+
+
+static void freeDirBufferContent(DirBufferEntry* dir_buffer, s32 n_entries)
+{
+ for(s32 i = 0; i < n_entries; i++)
+ {
+ if(dir_buffer[i].fname == NULL)
+ break; // this should never happen
+
+ free (dir_buffer[i].fname);
+ }
+}
+
+
+static void sortDirBuffer(DirBufferEntry* dir_buffer, s32 n_entries)
+{
+ for(s32 s = 0; s < n_entries; s++)
+ {
+ DirBufferEntry* cmp0 = &(dir_buffer[s]);
+ DirBufferEntry* min0 = cmp0;
+
+ for(s32 c = s + 1; c < n_entries; c++)
+ {
+ DirBufferEntry* cmp1 = &(dir_buffer[c]);
+ if(min0->is_dir != cmp1->is_dir)
+ {
+ if (min0->is_dir)
+ min0 = cmp1;
+ continue;
+ }
+ if(strnicmp(min0->fname, cmp1->fname, 256) > 0)
+ {
+ min0 = cmp1;
+ }
+ }
+
+ if(min0 != cmp0)
+ {
+ DirBufferEntry swap; // swap entries
+ memcpy(&swap, cmp0, sizeof(DirBufferEntry));
+ memcpy(cmp0, min0, sizeof(DirBufferEntry));
+ memcpy(min0, &swap, sizeof(DirBufferEntry));
+ }
+ }
+}
+
+
+static s32 readDirToBuffer(DirBufferEntry* dir_buffer, const char* path, const char* pattern)
+{
+ FsFileInfo finfo[N_DIR_READ];
+ s32 n_entries = 0;
+ s32 dhandle;
+
+ // set dir_buffer to all zeroes
+ memset(dir_buffer, 0, sizeof(DirBufferEntry) * MAX_DIR_ENTRIES);
+
+ // open directory
+ dhandle = fOpenDir(path);
+ if(dhandle < 0) return -1;
+
+ s32 n_read = 0;
+ while((n_read = fReadDir(dhandle, finfo, N_DIR_READ)) > 0)
+ {
+ if (n_read < 0) // error reading dir
+ return -1;
+
+ for(s32 i = 0; i < n_read; i++)
+ {
+ if(pattern && !matchName(finfo[i].fname, pattern))
+ continue; // not a match with the provided pattern
+
+ // take over data
+ dir_buffer[n_entries].fsize = finfo[i].fsize;
+ dir_buffer[n_entries].is_dir = finfo[i].fattrib & AM_DIR;
+ dir_buffer[n_entries].fname = mallocpyString(finfo[i].fname);
+
+ // check for out of memory
+ if (!dir_buffer[n_entries].fname)
+ return -1;
+
+ // max dir buffer size reached?
+ if (++n_entries >= MAX_DIR_ENTRIES)
+ break;
+ }
+
+ // max dir buffer size reached?
+ if (n_entries >= MAX_DIR_ENTRIES)
+ break; // WARNING: no errors here - list just isn't complete
+ }
+
+ return n_entries;
+}
+
+
+u32 menuFileSelector(char* path, const char* start, const char* pattern)
+{
+ DirBufferEntry* dir_buffer;
+ bool result = false;
+
+ dir_buffer = (DirBufferEntry*) malloc(MAX_DIR_ENTRIES * sizeof(DirBufferEntry));
+ if (!dir_buffer) return false;
+
+ free(dir_buffer);
+
+ return result;
+}
\ No newline at end of file