/* Compare version strings. * * @s1 first string to compare * @s2 second string to compare * * @return an integer less than, equal to, or greater than zero, if @s1 is <, == or > than @s2. */ int filevercmp (const char *s1, const char *s2) { const char *s1_pos, *s2_pos; const char *s1_suffix, *s2_suffix; size_t s1_len, s2_len; int simple_cmp, result; /* easy comparison to see if strings are identical */ simple_cmp = strcmp (s1, s2); if (simple_cmp == 0) return 0; /* special handle for "", "." and ".." */ if (*s1 == '\0') return -1; if (*s2 == '\0') return 1; if (DIR_IS_DOT (s1)) return -1; if (DIR_IS_DOT (s2)) return 1; if (DIR_IS_DOTDOT (s1)) return -1; if (DIR_IS_DOTDOT (s2)) return 1; /* special handle for other hidden files */ if (*s1 == '.' && *s2 != '.') return -1; if (*s1 != '.' && *s2 == '.') return 1; if (*s1 == '.' && *s2 == '.') { s1++; s2++; } /* "cut" file suffixes */ s1_pos = s1; s2_pos = s2; s1_suffix = match_suffix (&s1_pos); s2_suffix = match_suffix (&s2_pos); s1_len = (s1_suffix != NULL ? s1_suffix : s1_pos) - s1; s2_len = (s2_suffix != NULL ? s2_suffix : s2_pos) - s2; /* restore file suffixes if strings are identical after "cut" */ if ((s1_suffix != NULL || s2_suffix != NULL) && (s1_len == s2_len) && strncmp (s1, s2, s1_len) == 0) { s1_len = s1_pos - s1; s2_len = s2_pos - s2; } result = verrevcmp (s1, s1_len, s2, s2_len); return result == 0 ? simple_cmp : result; }
gboolean handle_path (const char *path, struct stat * buf1, int *link_to_dir, int *stale_link) { vfs_path_t *vpath; if (DIR_IS_DOT (path) || DIR_IS_DOTDOT (path)) return FALSE; vpath = vfs_path_from_str (path); if (mc_lstat (vpath, buf1) == -1) { vfs_path_free (vpath); return FALSE; } if (S_ISDIR (buf1->st_mode)) tree_store_mark_checked (path); /* A link to a file or a directory? */ *link_to_dir = 0; *stale_link = 0; if (S_ISLNK (buf1->st_mode)) { struct stat buf2; if (mc_stat (vpath, &buf2) == 0) *link_to_dir = S_ISDIR (buf2.st_mode) != 0; else *stale_link = 1; } vfs_path_free (vpath); return TRUE; }
void smart_dirsize_cmd (void) { WPanel *panel = current_panel; file_entry_t *entry; entry = &(panel->dir.list[panel->selected]); if ((S_ISDIR (entry->st.st_mode) && DIR_IS_DOTDOT (entry->fname)) || panel->dirs_marked) dirsizes_cmd (); else single_dirsize_cmd (); }
void mkdir_cmd (void) { char *dir; const char *name = ""; /* If 'on' then automatically fills name with current selected item name */ if (auto_fill_mkdir_name && !DIR_IS_DOTDOT (selection (current_panel)->fname)) name = selection (current_panel)->fname; dir = input_expand_dialog (_("Create a new Directory"), _("Enter directory name:"), MC_HISTORY_FM_MKDIR, name, INPUT_COMPLETE_FILENAMES); if (dir != NULL && *dir != '\0') { vfs_path_t *absdir; if (dir[0] == '/' || dir[0] == '~') absdir = vfs_path_from_str (dir); else { /* possible escaped '~' */ /* allow create directory with name '~' */ char *tmpdir = dir; if (dir[0] == '\\' && dir[1] == '~') tmpdir = dir + 1; absdir = vfs_path_append_new (current_panel->cwd_vpath, tmpdir, NULL); } save_cwds_stat (); if (my_mkdir (absdir, 0777) == 0) { update_panels (UP_OPTIMIZE, dir); repaint_screen (); select_item (current_panel); } else { message (D_ERROR, MSG_ERROR, "%s", unix_error_string (errno)); } vfs_path_free (absdir); } g_free (dir); }
static gboolean handle_dirent (struct dirent *dp, const char *fltr, struct stat *buf1, int *link_to_dir, int *stale_link) { vfs_path_t *vpath; if (DIR_IS_DOT (dp->d_name) || DIR_IS_DOTDOT (dp->d_name)) return FALSE; if (!panels_options.show_dot_files && (dp->d_name[0] == '.')) return FALSE; if (!panels_options.show_backups && dp->d_name[strlen (dp->d_name) - 1] == '~') return FALSE; vpath = vfs_path_from_str (dp->d_name); if (mc_lstat (vpath, buf1) == -1) { /* * lstat() fails - such entries should be identified by * buf1->st_mode being 0. * It happens on QNX Neutrino for /fs/cd0 if no CD is inserted. */ memset (buf1, 0, sizeof (*buf1)); } if (S_ISDIR (buf1->st_mode)) tree_store_mark_checked (dp->d_name); /* A link to a file or a directory? */ *link_to_dir = 0; *stale_link = 0; if (S_ISLNK (buf1->st_mode)) { struct stat buf2; if (mc_stat (vpath, &buf2) == 0) *link_to_dir = S_ISDIR (buf2.st_mode) != 0; else *stale_link = 1; } vfs_path_free (vpath); return (S_ISDIR (buf1->st_mode) || *link_to_dir != 0 || fltr == NULL || mc_search (fltr, NULL, dp->d_name, MC_SEARCH_T_GLOB)); }
void single_dirsize_cmd (void) { WPanel *panel = current_panel; file_entry_t *entry; entry = &(panel->dir.list[panel->selected]); if (S_ISDIR (entry->st.st_mode) && !DIR_IS_DOTDOT (entry->fname)) { size_t dir_count = 0; size_t count = 0; uintmax_t total = 0; dirsize_status_msg_t dsm; vfs_path_t *p; p = vfs_path_from_str (entry->fname); memset (&dsm, 0, sizeof (dsm)); status_msg_init (STATUS_MSG (&dsm), _("Directory scanning"), 1.0, dirsize_status_init_cb, dirsize_status_update_cb, dirsize_status_deinit_cb); if (compute_dir_size (p, &dsm, &dir_count, &count, &total, TRUE) == FILE_CONT) { entry->st.st_size = (off_t) total; entry->f.dir_size_computed = 1; } vfs_path_free (p); status_msg_deinit (STATUS_MSG (&dsm)); } if (panels_options.mark_moves_down) send_message (panel, NULL, MSG_ACTION, CK_Down, NULL); recalculate_panel_summary (panel); if (current_panel->sort_field->sort_routine == (GCompareFunc) sort_size) panel_re_sort (panel); panel->dirty = 1; }
void dirsizes_cmd (void) { WPanel *panel = current_panel; int i; dirsize_status_msg_t dsm; memset (&dsm, 0, sizeof (dsm)); status_msg_init (STATUS_MSG (&dsm), _("Directory scanning"), 1.0, dirsize_status_init_cb, dirsize_status_update_cb, dirsize_status_deinit_cb); for (i = 0; i < panel->dir.len; i++) if (S_ISDIR (panel->dir.list[i].st.st_mode) && ((panel->dirs_marked && panel->dir.list[i].f.marked) || !panel->dirs_marked) && !DIR_IS_DOTDOT (panel->dir.list[i].fname)) { vfs_path_t *p; size_t dir_count = 0; size_t count = 0; uintmax_t total = 0; gboolean ok; p = vfs_path_from_str (panel->dir.list[i].fname); ok = compute_dir_size (p, &dsm, &dir_count, &count, &total, TRUE) != FILE_CONT; vfs_path_free (p); if (ok) break; panel->dir.list[i].st.st_size = (off_t) total; panel->dir.list[i].f.dir_size_computed = 1; } status_msg_deinit (STATUS_MSG (&dsm)); recalculate_panel_summary (panel); if (current_panel->sort_field->sort_routine == (GCompareFunc) sort_size) panel_re_sort (panel); panel->dirty = 1; }
void dir_list_sort (dir_list * list, GCompareFunc sort, const dir_sort_options_t * sort_op) { file_entry_t *fentry; int dot_dot_found = 0; if (list->len < 2 || sort == (GCompareFunc) unsorted) return; /* If there is an ".." entry the caller must take care to ensure that it occupies the first list element. */ fentry = &list->list[0]; if (DIR_IS_DOTDOT (fentry->fname)) dot_dot_found = 1; reverse = sort_op->reverse ? -1 : 1; case_sensitive = sort_op->case_sensitive ? 1 : 0; exec_first = sort_op->exec_first; qsort (&(list->list)[dot_dot_found], list->len - dot_dot_found, sizeof (file_entry_t), sort); clean_sort_keys (list, dot_dot_found, list->len - dot_dot_found); }
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); } }
gboolean vfs_parse_ls_lga (const char *p, struct stat * s, char **filename, char **linkname, size_t * num_spaces) { int idx, idx2, num_cols; int i; char *p_copy = NULL; char *t = NULL; const char *line = p; size_t skipped; if (strncmp (p, "total", 5) == 0) return FALSE; if (!vfs_parse_filetype (p, &skipped, &s->st_mode)) goto error; p += skipped; if (*p == ' ') /* Notwell 4 */ p++; if (*p == '[') { if (strlen (p) <= 8 || p[8] != ']') goto error; /* Should parse here the Notwell permissions :) */ if (S_ISDIR (s->st_mode)) s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH); else s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR); p += 9; } else { size_t lc_skipped; mode_t perms; if (!vfs_parse_fileperms (p, &lc_skipped, &perms)) goto error; p += lc_skipped; s->st_mode |= perms; } p_copy = g_strdup (p); num_cols = vfs_split_text (p_copy); s->st_nlink = atol (columns[0]); if (s->st_nlink <= 0) goto error; if (!is_num (1)) s->st_uid = vfs_finduid (columns[1]); else s->st_uid = (uid_t) atol (columns[1]); /* Mhm, the ls -lg did not produce a group field */ for (idx = 3; idx <= 5; idx++) if (is_month (columns[idx], NULL) || is_week (columns[idx], NULL) || is_dos_date (columns[idx]) || is_localized_month (columns[idx])) break; if (idx == 6 || (idx == 5 && !S_ISCHR (s->st_mode) && !S_ISBLK (s->st_mode))) goto error; /* We don't have gid */ if (idx == 3 || (idx == 4 && (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode)))) idx2 = 2; else { /* We have gid field */ if (is_num (2)) s->st_gid = (gid_t) atol (columns[2]); else s->st_gid = vfs_findgid (columns[2]); idx2 = 3; } /* This is device */ if (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode)) { int maj, min; /* Corner case: there is no whitespace(s) between maj & min */ if (!is_num (idx2) && idx2 == 2) { /* cppcheck-suppress invalidscanf */ if (!is_num (++idx2) || sscanf (columns[idx2], " %d,%d", &maj, &min) != 2) goto error; } else { /* cppcheck-suppress invalidscanf */ if (!is_num (idx2) || sscanf (columns[idx2], " %d,", &maj) != 1) goto error; /* cppcheck-suppress invalidscanf */ if (!is_num (++idx2) || sscanf (columns[idx2], " %d", &min) != 1) goto error; } #ifdef HAVE_STRUCT_STAT_ST_RDEV s->st_rdev = makedev (maj, min); #endif s->st_size = 0; } else { /* Common file size */ if (!is_num (idx2)) goto error; s->st_size = (off_t) g_ascii_strtoll (columns[idx2], NULL, 10); #ifdef HAVE_STRUCT_STAT_ST_RDEV s->st_rdev = 0; #endif } idx = vfs_parse_filedate (idx, &s->st_mtime); if (!idx) goto error; /* Use resulting time value */ s->st_atime = s->st_ctime = s->st_mtime; /* s->st_dev and s->st_ino must be initialized by vfs_s_new_inode () */ #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE s->st_blksize = 512; #endif #ifdef HAVE_STRUCT_STAT_ST_BLOCKS s->st_blocks = (s->st_size + 511) / 512; #endif if (num_spaces != NULL) { *num_spaces = column_ptr[idx] - column_ptr[idx - 1] - strlen (columns[idx - 1]); if (DIR_IS_DOTDOT (columns[idx])) vfs_parce_ls_final_num_spaces = *num_spaces; } for (i = idx + 1, idx2 = 0; i < num_cols; i++) if (strcmp (columns[i], "->") == 0) { idx2 = i; break; } if (((S_ISLNK (s->st_mode) || (num_cols == idx + 3 && s->st_nlink > 1))) /* Maybe a hardlink? (in extfs) */ && idx2) { if (filename) { *filename = g_strndup (p + column_ptr[idx], column_ptr[idx2] - column_ptr[idx] - 1); } if (linkname) { t = g_strdup (p + column_ptr[idx2 + 1]); *linkname = t; } } else { /* Extract the filename from the string copy, not from the columns * this way we have a chance of entering hidden directories like ". ." */ if (filename) { /* * filename = g_strdup (columns [idx++]); */ t = g_strdup (p + column_ptr[idx]); *filename = t; } if (linkname) *linkname = NULL; } if (t) { int p2 = strlen (t); if ((--p2 > 0) && (t[p2] == '\r' || t[p2] == '\n')) t[p2] = 0; if ((--p2 > 0) && (t[p2] == '\r' || t[p2] == '\n')) t[p2] = 0; } g_free (p_copy); return TRUE; error: { static int errorcount = 0; if (++errorcount < 5) { message (D_ERROR, _("Cannot parse:"), "%s", (p_copy && *p_copy) ? p_copy : line); } else if (errorcount == 5) message (D_ERROR, MSG_ERROR, _("More parsing errors will be ignored.")); } g_free (p_copy); return FALSE; }
void do_cd_command (char *orig_cmd) { int len; int operand_pos = CD_OPERAND_OFFSET; const char *cmd; /* Any final whitespace should be removed here (to see why, try "cd fred "). */ /* NOTE: I think we should not remove the extra space, that way, we can cd into hidden directories */ /* FIXME: what about interpreting quoted strings like the shell. so one could type "cd <tab> M-a <enter>" and it would work. */ len = strlen (orig_cmd) - 1; while (len >= 0 && (orig_cmd[len] == ' ' || orig_cmd[len] == '\t' || orig_cmd[len] == '\n')) { orig_cmd[len] = 0; len--; } cmd = orig_cmd; if (cmd[CD_OPERAND_OFFSET - 1] == 0) cmd = "cd "; /* 0..2 => given text, 3 => \0 */ /* allow any amount of white space in front of the path operand */ while (cmd[operand_pos] == ' ' || cmd[operand_pos] == '\t') operand_pos++; if (get_current_type () == view_tree) { if (cmd[0] == 0) { sync_tree (mc_config_get_home_dir ()); } else if (DIR_IS_DOTDOT (cmd + operand_pos)) { if (vfs_path_elements_count (current_panel->cwd_vpath) != 1 || strlen (vfs_path_get_by_index (current_panel->cwd_vpath, 0)->path) > 1) { vfs_path_t *tmp_vpath = current_panel->cwd_vpath; current_panel->cwd_vpath = vfs_path_vtokens_get (tmp_vpath, 0, vfs_path_tokens_count (tmp_vpath) - 1); vfs_path_free (tmp_vpath); } sync_tree (vfs_path_as_str (current_panel->cwd_vpath)); } else if (cmd[operand_pos] == PATH_SEP) { sync_tree (cmd + operand_pos); } else { vfs_path_t *new_vpath; new_vpath = vfs_path_append_new (current_panel->cwd_vpath, cmd + operand_pos, NULL); sync_tree (vfs_path_as_str (new_vpath)); vfs_path_free (new_vpath); } } else { char *path; vfs_path_t *q_vpath; gboolean ok; path = examine_cd (&cmd[operand_pos]); if (*path == '\0') q_vpath = vfs_path_from_str (mc_config_get_home_dir ()); else q_vpath = vfs_path_from_str_flags (path, VPF_NO_CANON); ok = do_cd (q_vpath, cd_parse_command); if (!ok) ok = handle_cdpath (path); if (!ok) { char *d; d = vfs_path_to_str_flags (q_vpath, 0, VPF_STRIP_PASSWORD); message (D_ERROR, MSG_ERROR, _("Cannot chdir to \"%s\"\n%s"), d, unix_error_string (errno)); g_free (d); } vfs_path_free (q_vpath); g_free (path); } }