void change_directory(char *root) {
	ftp_connect();
	if (!FtpChdir(root, conn)) {
		fprintf(stderr, "Change directory failed\n%s", FtpLastResponse(conn));
		exit(EX_REMCMD);
	}
}
// ========================***************************==============================
void fileSelect(const char *startdir, char *out_dir, char *out_fname, netbuf *buf,
  bool allow_cancel, bool allow_up)
{
	bool select = false;
	static int size_list = 18;
	
	int num_files = 0;
	int sel_file = 0;
	int first_file = 0;
	
	// get list of files in current dir
	if (buf)
		ftpGetFileList("/", buf, num_files);
	else
		fileGetFileList(startdir, num_files);
	filePrintFileList(startdir, first_file, sel_file, num_files, allow_cancel);
		
	while (!select) {
		// get_event
		uint32 keys = keysCurrent();
		
		// handle_event
		if (keys & KEY_DOWN) {
			if (sel_file < num_files-1) {
				sel_file++;
				if (sel_file >= first_file + size_list - 1)
					first_file = sel_file - (size_list - 1);
				filePrintFileList(startdir, first_file, sel_file, num_files, allow_cancel);
			} else {
				// wrap around to top of list
				sel_file = 0;
				first_file = 0;
				filePrintFileList(startdir, first_file, sel_file, num_files, allow_cancel);
			}
		} else if (keys & KEY_UP) {
			if (sel_file > 0) {
				sel_file--;
				if (sel_file < first_file)
					first_file = sel_file;
				filePrintFileList(startdir, first_file, sel_file, num_files, allow_cancel);
			} else {
				// wrap around to bottom of list
				sel_file = num_files - 1;
				first_file = sel_file - (size_list - 1);
				filePrintFileList(startdir, first_file, sel_file, num_files, allow_cancel);
			}
		} else if (keys & KEY_A) {
			// get selected file name
			char *buf2 = (char*)data;
			char fname[128];
			for (int i = 0; i < sel_file; i++) {
				buf2 = strchr(buf2, '\n') + 1;
			}
			char c;
			sscanf(buf2, "%c%[^\n]", &c, fname); // gets 'd' or 'f' - dir or file			
			// special cases
			if (stricmp(fname, ".") == 0)
				// don't do anything
				continue;
			if (stricmp(fname, "..") == 0) {
				// return to parent function (usually results in "back to higher level")
				while (keysCurrent() & (KEY_A | KEY_B));
				if (!allow_up)
					continue;
				if (buf)
					FtpChdir("..", buf);
				return;
			}
			
			// get selected file properties
			char fullname[512];
			sprintf(fullname, "%s%s", startdir, fname);
			struct stat statbuf;
			stat(fullname, &statbuf);
			if (c == 'd') {
				char fullpath[512];
				sprintf(fullpath, "%s%s/", startdir, fname);
				if (buf)
					FtpChdir(fname, buf);
				fileSelect(fullpath, out_dir, out_fname, buf, allow_cancel, true);
				if ((keysCurrent() & (KEY_L | KEY_R)) && allow_cancel)
					return;
				while (keysCurrent() & (KEY_A | KEY_B));
				
				// did we select a file? if so, keep returning to parent calling function
				if (strlen(out_fname))
					return;
				
				// we did not select anything, so regenerate the old list
				num_files = 0;
				if (buf)
					ftpGetFileList("/", buf, num_files);
				else
					fileGetFileList(startdir, num_files);
				filePrintFileList(startdir, first_file, sel_file, num_files, allow_cancel);
				continue;
			} else {
				sprintf(out_dir, "%s", startdir);
				sprintf(out_fname, "%s", fname);
				while (keysCurrent() & (KEY_A | KEY_B));
				return;
			}
		} else if (keys & KEY_B) {
			if (!allow_up)
				continue;
			if (buf)
				FtpChdir("..", buf);
			return;
		} else if (keys & (KEY_L | KEY_R)) {
			if (allow_cancel) {
				sprintf(out_dir, "%s", startdir);
				out_fname[0] = 0;
				return;
			}
		}
		
		for (int i = 0; i < 5; i++)
			swiWaitForVBlank();
	}
}