void dir_list_load (dir_list * list, const vfs_path_t * vpath, GCompareFunc sort, const dir_sort_options_t * sort_op, const char *fltr) { DIR *dirp; struct dirent *dp; int link_to_dir, stale_link; struct stat st; file_entry_t *fentry; /* ".." (if any) must be the first entry in the list */ if (!dir_list_init (list)) return; fentry = &list->list[0]; if (dir_get_dotdot_stat (vpath, &st)) fentry->st = st; dirp = mc_opendir (vpath); if (dirp == NULL) { message (D_ERROR, MSG_ERROR, _("Cannot read directory contents")); return; } tree_store_start_check (vpath); { const char *vpath_str; vpath_str = vfs_path_as_str (vpath); /* Do not add a ".." entry to the root directory */ if ((vpath_str[0] == PATH_SEP) && (vpath_str[1] == '\0')) list->len--; } while ((dp = mc_readdir (dirp)) != NULL) { if (!handle_dirent (dp, fltr, &st, &link_to_dir, &stale_link)) continue; if (!dir_list_append (list, dp->d_name, &st, link_to_dir != 0, stale_link != 0)) goto ret; if ((list->len & 31) == 0) rotate_dash (TRUE); } dir_list_sort (list, sort, sort_op); ret: mc_closedir (dirp); tree_store_end_check (); rotate_dash (FALSE); }
static char * filename_completion_function (const char *text, int state, input_complete_t flags) { static DIR *directory = NULL; static char *filename = NULL; static char *dirname = NULL; static char *users_dirname = NULL; static size_t filename_len; int isdir = 1, isexec = 0; static vfs_path_t *dirname_vpath = NULL; struct dirent *entry = NULL; SHOW_C_CTX ("filename_completion_function"); if (text && (flags & INPUT_COMPLETE_SHELL_ESC)) { char *u_text; char *result; char *e_result; u_text = strutils_shell_unescape (text); result = filename_completion_function (u_text, state, flags & (~INPUT_COMPLETE_SHELL_ESC)); g_free (u_text); e_result = strutils_shell_escape (result); g_free (result); return e_result; } /* If we're starting the match process, initialize us a bit. */ if (state == 0) { const char *temp; g_free (dirname); g_free (filename); g_free (users_dirname); vfs_path_free (dirname_vpath); if ((*text != '\0') && (temp = strrchr (text, PATH_SEP)) != NULL) { filename = g_strdup (++temp); dirname = g_strndup (text, temp - text); } else { dirname = g_strdup ("."); filename = g_strdup (text); } /* We aren't done yet. We also support the "~user" syntax. */ /* Save the version of the directory that the user typed. */ users_dirname = dirname; dirname = tilde_expand (dirname); canonicalize_pathname (dirname); dirname_vpath = vfs_path_from_str (dirname); /* Here we should do something with variable expansion and `command`. Maybe a dream - UNIMPLEMENTED yet. */ directory = mc_opendir (dirname_vpath); filename_len = strlen (filename); } /* Now that we have some state, we can read the directory. */ while (directory && (entry = mc_readdir (directory))) { if (!str_is_valid_string (entry->d_name)) continue; /* Special case for no filename. All entries except "." and ".." match. */ if (filename_len == 0) { if (DIR_IS_DOT (entry->d_name) || DIR_IS_DOTDOT (entry->d_name)) continue; } else { /* Otherwise, if these match up to the length of filename, then it may be a match. */ if ((entry->d_name[0] != filename[0]) || ((NLENGTH (entry)) < filename_len) || strncmp (filename, entry->d_name, filename_len)) continue; } isdir = 1; isexec = 0; { struct stat tempstat; vfs_path_t *tmp_vpath; tmp_vpath = vfs_path_build_filename (dirname, entry->d_name, (char *) NULL); /* Unix version */ if (mc_stat (tmp_vpath, &tempstat) == 0) { uid_t my_uid = getuid (); gid_t my_gid = getgid (); if (!S_ISDIR (tempstat.st_mode)) { isdir = 0; if ((!my_uid && (tempstat.st_mode & 0111)) || (my_uid == tempstat.st_uid && (tempstat.st_mode & 0100)) || (my_gid == tempstat.st_gid && (tempstat.st_mode & 0010)) || (tempstat.st_mode & 0001)) isexec = 1; } } else { /* stat failed, strange. not a dir in any case */ isdir = 0; } vfs_path_free (tmp_vpath); } if ((flags & INPUT_COMPLETE_COMMANDS) && (isexec || isdir)) break; if ((flags & INPUT_COMPLETE_CD) && isdir) break; if (flags & (INPUT_COMPLETE_FILENAMES)) break; } if (entry == NULL) { if (directory) { mc_closedir (directory); directory = NULL; } g_free (dirname); dirname = NULL; vfs_path_free (dirname_vpath); dirname_vpath = NULL; g_free (filename); filename = NULL; g_free (users_dirname); users_dirname = NULL; return NULL; } { GString *temp; temp = g_string_sized_new (16); if (users_dirname != NULL && (users_dirname[0] != '.' || users_dirname[1] != '\0')) { g_string_append (temp, users_dirname); /* We need a '/' at the end. */ if (temp->str[temp->len - 1] != PATH_SEP) g_string_append_c (temp, PATH_SEP); } g_string_append (temp, entry->d_name); if (isdir) g_string_append_c (temp, PATH_SEP); return g_string_free (temp, FALSE); } }
void dir_list_reload (dir_list * list, const vfs_path_t * vpath, GCompareFunc sort, const dir_sort_options_t * sort_op, const char *fltr) { DIR *dirp; struct dirent *dp; int i, link_to_dir, stale_link; struct stat st; int marked_cnt; GHashTable *marked_files; const char *tmp_path; dirp = mc_opendir (vpath); if (dirp == NULL) { message (D_ERROR, MSG_ERROR, _("Cannot read directory contents")); dir_list_clean (list); dir_list_init (list); return; } tree_store_start_check (vpath); marked_files = g_hash_table_new (g_str_hash, g_str_equal); alloc_dir_copy (list->len); for (marked_cnt = i = 0; i < list->len; i++) { file_entry_t *fentry, *dfentry; fentry = &list->list[i]; dfentry = &dir_copy.list[i]; dfentry->fnamelen = fentry->fnamelen; dfentry->fname = g_strndup (fentry->fname, fentry->fnamelen); dfentry->f.marked = fentry->f.marked; dfentry->f.dir_size_computed = fentry->f.dir_size_computed; dfentry->f.link_to_dir = fentry->f.link_to_dir; dfentry->f.stale_link = fentry->f.stale_link; dfentry->sort_key = NULL; dfentry->second_sort_key = NULL; if (fentry->f.marked) { g_hash_table_insert (marked_files, dfentry->fname, dfentry); marked_cnt++; } } /* save len for later dir_list_clean() */ dir_copy.len = list->len; /* Add ".." except to the root directory. The ".." entry (if any) must be the first in the list. */ tmp_path = vfs_path_get_by_index (vpath, 0)->path; if (vfs_path_elements_count (vpath) == 1 && IS_PATH_SEP (tmp_path[0]) && tmp_path[1] == '\0') { /* root directory */ dir_list_clean (list); } else { dir_list_clean (list); if (!dir_list_init (list)) { dir_list_clean (&dir_copy); return; } if (dir_get_dotdot_stat (vpath, &st)) { file_entry_t *fentry; fentry = &list->list[0]; fentry->st = st; } } while ((dp = mc_readdir (dirp)) != NULL) { file_entry_t *fentry; if (!handle_dirent (dp, fltr, &st, &link_to_dir, &stale_link)) continue; if (!dir_list_append (list, dp->d_name, &st, link_to_dir != 0, stale_link != 0)) { mc_closedir (dirp); /* Norbert (Feb 12, 1997): Just in case someone finds this memory leak: -1 means big trouble (at the moment no memory left), I don't bother with further cleanup because if one gets to this point he will have more problems than a few memory leaks and because one 'dir_list_clean' would not be enough (and because I don't want to spent the time to make it working, IMHO it's not worthwhile). dir_list_clean (&dir_copy); */ tree_store_end_check (); g_hash_table_destroy (marked_files); return; } fentry = &list->list[list->len - 1]; fentry->f.marked = 0; /* * If we have marked files in the copy, scan through the copy * to find matching file. Decrease number of remaining marks if * we copied one. */ if (marked_cnt > 0 && g_hash_table_lookup (marked_files, dp->d_name) != NULL) { fentry->f.marked = 1; marked_cnt--; } if ((list->len & 15) == 0) rotate_dash (TRUE); } mc_closedir (dirp); tree_store_end_check (); g_hash_table_destroy (marked_files); dir_list_sort (list, sort, sort_op); dir_list_clean (&dir_copy); rotate_dash (FALSE); }
static char * filename_completion_function (char *text, int state) { static DIR *directory; static char *filename = NULL; static char *dirname = NULL; static char *users_dirname = NULL; static size_t filename_len; int isdir = 1, isexec = 0; struct dirent *entry = NULL; /* If we're starting the match process, initialize us a bit. */ if (!state){ const char *temp; g_free (dirname); g_free (filename); g_free (users_dirname); if ((*text) && (temp = strrchr (text, PATH_SEP))){ filename = g_strdup (++temp); dirname = g_strndup (text, temp - text); } else { dirname = g_strdup ("."); filename = g_strdup (text); } /* We aren't done yet. We also support the "~user" syntax. */ /* Save the version of the directory that the user typed. */ users_dirname = dirname; { dirname = tilde_expand (dirname); canonicalize_pathname (dirname); /* Here we should do something with variable expansion and `command`. Maybe a dream - UNIMPLEMENTED yet. */ } directory = mc_opendir (dirname); filename_len = strlen (filename); } /* Now that we have some state, we can read the directory. */ while (directory && (entry = mc_readdir (directory))){ /* Special case for no filename. All entries except "." and ".." match. */ if (!filename_len){ if (!strcmp (entry->d_name, ".") || !strcmp (entry->d_name, "..")) continue; } else { /* Otherwise, if these match up to the length of filename, then it may be a match. */ if ((entry->d_name[0] != filename[0]) || ((NLENGTH (entry)) < filename_len) || strncmp (filename, entry->d_name, filename_len)) continue; } isdir = 1; isexec = 0; { char *tmp = g_malloc (3 + strlen (dirname) + NLENGTH (entry)); struct stat tempstat; strcpy (tmp, dirname); strcat (tmp, PATH_SEP_STR); strcat (tmp, entry->d_name); canonicalize_pathname (tmp); /* Unix version */ if (!mc_stat (tmp, &tempstat)){ uid_t my_uid = getuid (); gid_t my_gid = getgid (); if (!S_ISDIR (tempstat.st_mode)){ isdir = 0; if ((!my_uid && (tempstat.st_mode & 0111)) || (my_uid == tempstat.st_uid && (tempstat.st_mode & 0100)) || (my_gid == tempstat.st_gid && (tempstat.st_mode & 0010)) || (tempstat.st_mode & 0001)) isexec = 1; } } g_free (tmp); } switch (look_for_executables) { case 2: if (!isexec) continue; break; case 1: if (!isexec && !isdir) continue; break; } if (ignore_filenames && !isdir) continue; break; } if (!entry){ if (directory){ mc_closedir (directory); directory = NULL; } g_free (dirname); dirname = NULL; g_free (filename); filename = NULL; g_free (users_dirname); users_dirname = NULL; return NULL; } else { char *temp; if (users_dirname && (users_dirname[0] != '.' || users_dirname[1])){ int dirlen = strlen (users_dirname); temp = g_malloc (3 + dirlen + NLENGTH (entry)); strcpy (temp, users_dirname); /* We need a `/' at the end. */ if (users_dirname[dirlen - 1] != PATH_SEP){ temp[dirlen] = PATH_SEP; temp[dirlen + 1] = 0; } strcat (temp, entry->d_name); } else { temp = g_malloc (2 + NLENGTH (entry)); strcpy (temp, entry->d_name); } if (isdir) strcat (temp, PATH_SEP_STR); return temp; } }
int do_reload_dir (const vfs_path_t * vpath, dir_list * list, sortfn * sort, int count, gboolean lc_reverse, gboolean lc_case_sensitive, gboolean exec_ff, const char *fltr) { DIR *dirp; struct dirent *dp; int next_free = 0; int i, status, link_to_dir, stale_link; struct stat st; int marked_cnt; GHashTable *marked_files; const char *tmp_path; dirp = mc_opendir (vpath); if (dirp == NULL) { message (D_ERROR, MSG_ERROR, _("Cannot read directory contents")); clean_dir (list, count); return set_zero_dir (list) ? 1 : 0; } tree_store_start_check (vpath); marked_files = g_hash_table_new (g_str_hash, g_str_equal); alloc_dir_copy (list->size); for (marked_cnt = i = 0; i < count; i++) { dir_copy.list[i].fnamelen = list->list[i].fnamelen; dir_copy.list[i].fname = list->list[i].fname; dir_copy.list[i].f.marked = list->list[i].f.marked; dir_copy.list[i].f.dir_size_computed = list->list[i].f.dir_size_computed; dir_copy.list[i].f.link_to_dir = list->list[i].f.link_to_dir; dir_copy.list[i].f.stale_link = list->list[i].f.stale_link; dir_copy.list[i].sort_key = NULL; dir_copy.list[i].second_sort_key = NULL; if (list->list[i].f.marked) { g_hash_table_insert (marked_files, dir_copy.list[i].fname, &dir_copy.list[i]); marked_cnt++; } } /* Add ".." except to the root directory. The ".." entry (if any) must be the first in the list. */ tmp_path = vfs_path_get_by_index (vpath, 0)->path; if (! (vfs_path_elements_count (vpath) == 1 && (tmp_path[0] == PATH_SEP) && (tmp_path[1] == '\0'))) { if (!set_zero_dir (list)) { clean_dir (list, count); clean_dir (&dir_copy, count); return next_free; } if (get_dotdot_dir_stat (vpath, &st)) list->list[next_free].st = st; next_free++; } while ((dp = mc_readdir (dirp))) { status = handle_dirent (list, fltr, dp, &st, next_free, &link_to_dir, &stale_link); if (status == 0) continue; if (status == -1) { mc_closedir (dirp); /* Norbert (Feb 12, 1997): Just in case someone finds this memory leak: -1 means big trouble (at the moment no memory left), I don't bother with further cleanup because if one gets to this point he will have more problems than a few memory leaks and because one 'clean_dir' would not be enough (and because I don't want to spent the time to make it working, IMHO it's not worthwhile). clean_dir (&dir_copy, count); */ tree_store_end_check (); g_hash_table_destroy (marked_files); return next_free; } list->list[next_free].f.marked = 0; /* * If we have marked files in the copy, scan through the copy * to find matching file. Decrease number of remaining marks if * we copied one. */ if (marked_cnt > 0) { if ((g_hash_table_lookup (marked_files, dp->d_name))) { list->list[next_free].f.marked = 1; marked_cnt--; } } list->list[next_free].fnamelen = NLENGTH (dp); list->list[next_free].fname = g_strndup (dp->d_name, list->list[next_free].fnamelen); list->list[next_free].f.link_to_dir = link_to_dir; list->list[next_free].f.stale_link = stale_link; list->list[next_free].f.dir_size_computed = 0; list->list[next_free].st = st; list->list[next_free].sort_key = NULL; list->list[next_free].second_sort_key = NULL; next_free++; if (!(next_free % 16)) rotate_dash (); } mc_closedir (dirp); tree_store_end_check (); g_hash_table_destroy (marked_files); if (next_free) { do_sort (list, sort, next_free - 1, lc_reverse, lc_case_sensitive, exec_ff); } clean_dir (&dir_copy, count); return next_free; }
int do_load_dir (const vfs_path_t * vpath, dir_list * list, sortfn * sort, gboolean lc_reverse, gboolean lc_case_sensitive, gboolean exec_ff, const char *fltr) { DIR *dirp; struct dirent *dp; int status, link_to_dir, stale_link; int next_free = 0; struct stat st; char *path; /* ".." (if any) must be the first entry in the list */ if (!set_zero_dir (list)) return next_free; if (get_dotdot_dir_stat (vpath, &st)) list->list[next_free].st = st; next_free++; dirp = mc_opendir (vpath); if (dirp == NULL) { message (D_ERROR, MSG_ERROR, _("Cannot read directory contents")); return next_free; } tree_store_start_check (vpath); /* Do not add a ".." entry to the root directory */ path = vfs_path_to_str (vpath); if ((path[0] == PATH_SEP) && (path[1] == '\0')) next_free--; g_free (path); while ((dp = mc_readdir (dirp)) != NULL) { status = handle_dirent (list, fltr, dp, &st, next_free, &link_to_dir, &stale_link); if (status == 0) continue; if (status == -1) goto ret; list->list[next_free].fnamelen = NLENGTH (dp); list->list[next_free].fname = g_strndup (dp->d_name, list->list[next_free].fnamelen); list->list[next_free].f.marked = 0; list->list[next_free].f.link_to_dir = link_to_dir; list->list[next_free].f.stale_link = stale_link; list->list[next_free].f.dir_size_computed = 0; list->list[next_free].st = st; list->list[next_free].sort_key = NULL; list->list[next_free].second_sort_key = NULL; next_free++; if ((next_free & 31) == 0) rotate_dash (); } if (next_free != 0) do_sort (list, sort, next_free - 1, lc_reverse, lc_case_sensitive, exec_ff); ret: mc_closedir (dirp); tree_store_end_check (); return next_free; }