diff --git a/src/cmd.c b/src/cmd.c index 6cb939344..e55c24d66 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1376,3 +1376,60 @@ toggle_listing_cmd (void) set_basic_panel_listing_to (current, (p->list_type + 1) % LIST_TYPES); } +/* add "#enc:encodning" to end of path */ +/* if path end width a previous #enc:, only encoding is changed no additional + * #enc: is appended + * retun new string + */ +static char +*add_encoding_to_path (const char *path, const char *encoding) +{ + char *result; + char *semi; + char *slash; + + semi = g_strrstr (path, "#enc:"); + + if (semi != NULL) { + slash = strchr (semi, PATH_SEP); + if (slash != NULL) { + result = g_strconcat (path, "/#enc:", encoding, NULL); + } else { + *semi = 0; + result = g_strconcat (path, "/#enc:", encoding, NULL); + *semi = '#'; + } + } else { + result = g_strconcat (path, "/#enc:", encoding, NULL); + } + + return result; +} + +static void +set_panel_encoding (WPanel *panel) +{ + char *encoding; + char *cd_path; + + encoding = input_dialog ("Encoding", "Select encoding", NULL); + + if (encoding) { + cd_path = add_encoding_to_path (panel->cwd, encoding); + if (!do_panel_cd (MENU_PANEL, cd_path, 0)) + message (1, MSG_ERROR, _(" Cannot chdir to %s "), cd_path); + g_free (cd_path); + } +} + +void +encoding_cmd (void) +{ + WPanel *panel; + + if (!SELECTED_IS_PANEL) + return; + + panel = MENU_PANEL; + set_panel_encoding (panel); +} diff --git a/src/cmd.h b/src/cmd.h index ace6c28c9..9171b40cd 100644 --- a/src/cmd.h +++ b/src/cmd.h @@ -57,5 +57,6 @@ void quick_cmd_no_menu (void); void info_cmd_no_menu (void); void quick_view_cmd (void); void toggle_listing_cmd (void); +void encoding_cmd (void); #endif diff --git a/src/execute.c b/src/execute.c index 970a1772c..a989563ae 100644 --- a/src/execute.c +++ b/src/execute.c @@ -30,6 +30,7 @@ #include "dialog.h" #include "wtools.h" #include "execute.h" +#include "../vfs/vfs.h" static void @@ -342,7 +343,9 @@ execute_with_vfs_arg (const char *command, const char *filename) /* Simplest case, this file is local */ if (!filename || vfs_file_is_local (filename)) { - do_execute (command, filename, EXECUTE_INTERNAL); + fn = vfs_canon_and_translate (filename); + do_execute (command, fn, EXECUTE_INTERNAL); + g_free (fn); return; } diff --git a/src/ext.c b/src/ext.c index 14d888fa3..4661b8a42 100644 --- a/src/ext.c +++ b/src/ext.c @@ -62,6 +62,7 @@ static void exec_extension (const char *filename, const char *data, int *move_dir, int start_line) { + char *fn; char *file_name; int cmd_file_fd; FILE *cmd_file; @@ -174,10 +175,13 @@ exec_extension (const char *filename, const char *data, int *move_dir, localmtime = mystat.st_mtime; text = (*quote_func) (localcopy, 0); } else { - text = (*quote_func) (filename, 0); + fn = vfs_canon_and_translate (filename); + text = (*quote_func) (fn, 0); + g_free (fn); } - } else + } else { text = expand_format (NULL, *data, !is_cd); + } if (!is_cd) fputs (text, cmd_file); else { diff --git a/src/main.c b/src/main.c index ba1735254..a1bc7f012 100644 --- a/src/main.c +++ b/src/main.c @@ -810,6 +810,8 @@ static menu_entry LeftMenu[] = { {' ', N_("&Sort order..."), NULL_HOTKEY, sort_cmd}, {' ', "", NULL_HOTKEY, 0}, {' ', N_("&Filter..."), NULL_HOTKEY, filter_cmd}, + {' ', "",NULL_HOTKEY, 0}, + {' ', N_("&Encoding..."), NULL_HOTKEY, encoding_cmd}, #ifdef USE_NETCODE {' ', "", NULL_HOTKEY, 0}, #ifdef WITH_MCFS @@ -834,6 +836,8 @@ static menu_entry RightMenu[] = { {' ', N_("&Sort order..."), NULL_HOTKEY, sort_cmd}, {' ', "", NULL_HOTKEY, 0}, {' ', N_("&Filter..."), NULL_HOTKEY, filter_cmd}, + {' ', "",NULL_HOTKEY, 0}, + {' ', N_("&Encoding..."), NULL_HOTKEY, encoding_cmd}, #ifdef USE_NETCODE {' ', "", NULL_HOTKEY, 0}, #ifdef WITH_MCFS diff --git a/src/subshell.c b/src/subshell.c index ddd1fe6d7..67815537a 100644 --- a/src/subshell.c +++ b/src/subshell.c @@ -530,6 +530,8 @@ static void init_raw_mode () int invoke_subshell (const char *command, int how, char **new_dir) { + char *pcwd; + /* Make the MC terminal transparent */ tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode); @@ -560,8 +562,10 @@ int invoke_subshell (const char *command, int how, char **new_dir) feed_subshell (how, FALSE); - if (new_dir && subshell_alive && strcmp (subshell_cwd, current_panel->cwd)) + pcwd = vfs_translate_path_n (current_panel->cwd); + if (new_dir && subshell_alive && strcmp (subshell_cwd, pcwd)) *new_dir = subshell_cwd; /* Make MC change to the subshell's CWD */ + g_free (pcwd); /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */ while (!subshell_alive && !quit && use_subshell) @@ -752,15 +756,22 @@ subshell_name_quote (const char *s) void do_subshell_chdir (const char *directory, int do_update, int reset_prompt) { + char *pcwd; + char *temp; + char *translate; + + pcwd = vfs_translate_path_n (current_panel->cwd); + if (! (subshell_state == INACTIVE - && strcmp (subshell_cwd, current_panel->cwd))) { + && strcmp (subshell_cwd, pcwd))) { /* We have to repaint the subshell prompt if we read it from * the main program. Please note that in the code after this * if, the cd command that is sent will make the subshell * repaint the prompt, so we don't have to paint it. */ if (do_update) do_update_prompt (); + g_free (pcwd); return; } @@ -768,7 +779,9 @@ do_subshell_chdir (const char *directory, int do_update, int reset_prompt) because we set "HISTCONTROL=ignorespace") */ write_all (subshell_pty, " cd ", 4); if (*directory) { - char *temp = subshell_name_quote (directory); + translate = vfs_translate_path_n (directory); + if (translate) { + temp = subshell_name_quote (translate); if (temp) { write_all (subshell_pty, temp, strlen (temp)); g_free (temp); @@ -777,6 +790,10 @@ do_subshell_chdir (const char *directory, int do_update, int reset_prompt) that we don't have memory to quote it. */ write_all (subshell_pty, ".", 1); } + g_free (translate); + } else { + write_all (subshell_pty, ".", 1); + } } else { write_all (subshell_pty, "/", 1); } @@ -786,7 +803,7 @@ do_subshell_chdir (const char *directory, int do_update, int reset_prompt) feed_subshell (QUIETLY, FALSE); if (subshell_alive) { - int bPathNotEq = strcmp (subshell_cwd, current_panel->cwd); + int bPathNotEq = strcmp (subshell_cwd, pcwd); if (bPathNotEq && subshell_type == TCSH) { char rp_subshell_cwd[PATH_MAX]; @@ -795,17 +812,17 @@ do_subshell_chdir (const char *directory, int do_update, int reset_prompt) char *p_subshell_cwd = mc_realpath (subshell_cwd, rp_subshell_cwd); char *p_current_panel_cwd = - mc_realpath (current_panel->cwd, rp_current_panel_cwd); + mc_realpath (pcwd, rp_current_panel_cwd); if (p_subshell_cwd == NULL) p_subshell_cwd = subshell_cwd; if (p_current_panel_cwd == NULL) - p_current_panel_cwd = current_panel->cwd; + p_current_panel_cwd = pcwd; bPathNotEq = strcmp (p_subshell_cwd, p_current_panel_cwd); } - if (bPathNotEq && strcmp (current_panel->cwd, ".")) { - char *cwd = strip_password (g_strdup (current_panel->cwd), 1); + if (bPathNotEq && strcmp (pcwd, ".")) { + char *cwd = strip_password (g_strdup (pcwd), 1); fprintf (stderr, _("Warning: Cannot change to %s.\n"), cwd); g_free (cwd); } @@ -814,6 +831,8 @@ do_subshell_chdir (const char *directory, int do_update, int reset_prompt) if (reset_prompt) prompt_pos = 0; update_prompt = FALSE; + + g_free (pcwd); /* Make sure that MC never stores the CWD in a silly format */ /* like /usr////lib/../bin, or the strcmp() above will fail */ } diff --git a/vfs/vfs.c b/vfs/vfs.c index 8ea71f77d..325160a26 100644 --- a/vfs/vfs.c +++ b/vfs/vfs.c @@ -42,6 +42,7 @@ #include "../src/tty.h" /* enable/disable interrupt key */ #include "../src/wtools.h" /* message() */ #include "../src/main.h" /* print_vfs_message */ +#include "../src/strutil.h" #include "utilvfs.h" #include "gc.h" @@ -64,10 +65,32 @@ struct vfs_openfile { void *fsinfo; }; +struct vfs_dirinfo{ + DIR *info; + str_conv_t converter; +}; + + static GSList *vfs_openfiles; #define VFS_FIRST_HANDLE 100 static struct vfs_class *localfs_class; +static struct str_buffer *vfs_str_buffer; + +static const char *supported_encodings[] = { + "UTF8", + "UTF-8", + "BIG5", + "ASCII", + "ISO8859", + "ISO-8859", + "ISO_8859", + "KOI8", + "CP852", + "CP866", + "CP125", + NULL +}; /* Create new VFS handle and put it to the list */ static int @@ -309,6 +332,161 @@ vfs_get_class (const char *pathname) return vfs; } +const char * +vfs_get_encoding (const char *path) +{ + static char result[16]; + char *work; + char *semi; + char *slash; + + work = g_strdup (path); + semi = g_strrstr (work, "#enc:"); + + if (semi != NULL) { + semi+= 5 * sizeof (char); + slash = strchr (semi, PATH_SEP); + if (slash != NULL) + slash[0] = '\0'; + + g_strlcpy (result, semi, sizeof(result)); + g_free (work); + return result; + } else { + g_free (work); + return NULL; + } +} + +/* return if encoding can by used in vfs (is ascci full compactible) */ +/* contains only a few encoding now */ +static int +vfs_supported_enconding (const char *encoding) { + int t; + int result = 0; + + for (t = 0; supported_encodings[t] != NULL; t++) { + result+= (g_ascii_strncasecmp (encoding, supported_encodings[t], + strlen (supported_encodings[t])) == 0); + } + + return result; +} + +/* now used only by vfs_translate_path, but could be used in other vfs + * plugin to automatic detect encoding + * path - path to translate + * size - how many bytes from path translate + * defcnv - convertor, that is used as default, when path does not contain any + * #enc: subtring + * buffer - used to store result of translation + */ +static int +_vfs_translate_path (const char *path, int size, + str_conv_t defcnv, struct str_buffer *buffer) +{ + const char *semi; + const char *ps; + const char *slash; + int state = 0; + static char encoding[16]; + str_conv_t coder; + int ms; + + if (size == 0) return 0; + size = (size > 0) ? size : strlen (path); + + /* try found #end: */ + semi = g_strrstr_len (path, size, "#enc:"); + if (semi != NULL) { + /* first must be translated part before #enc: */ + ms = semi - path; + + /* remove '/' before #enc */ + ps = str_cget_prev_char (semi); + if (ps[0] == PATH_SEP) ms = ps - path; + + state = _vfs_translate_path (path, ms, defcnv, buffer); + + if (state != 0) return state; + /* now can be translated part after #enc: */ + + semi+= 5; + slash = strchr (semi, PATH_SEP); + // ignore slashes after size; + if (slash - path >= size) slash = NULL; + + ms = (slash != NULL) ? slash - semi : strlen (semi); + ms = min (ms, sizeof (encoding) - 1); + // limit encoding size (ms) to path size (size) + if (semi + ms > path + size) ms = path + size - semi; + memcpy (encoding, semi, ms); + encoding[ms] = '\0'; + + switch (vfs_supported_enconding (encoding)) { + case 1: + coder = str_crt_conv_to (encoding); + if (coder != (iconv_t) (-1)) { + if (slash != NULL) { + state = str_vfs_convert_to (coder, slash, + path + size - slash, buffer); + } else if (buffer->data[0] == '\0') { + /* exmaple "/#enc:utf-8" */ + str_insert_char (PATH_SEP, buffer); + } + str_close_conv (coder); + return state; + } else { + errno = EINVAL; + return ESTR_FAILURE; + } + break; + default: + errno = EINVAL; + return ESTR_FAILURE; + } + + } else { + /* path can be translated whole at once */ + state = str_vfs_convert_to (defcnv, path, size, buffer); + return state; + } + + return 0; +} + +char * +vfs_translate_path (const char *path) +{ + int state; + + str_reset_buffer (vfs_str_buffer); + state = _vfs_translate_path (path, -1, str_cnv_from_term, vfs_str_buffer); + // strict version + //return (state == 0) ? vfs_str_buffer->data : NULL; + return (state != ESTR_FAILURE) ? vfs_str_buffer->data : NULL; +} + +char * +vfs_translate_path_n (const char *path) +{ + char *result; + + result = vfs_translate_path (path); + return (result != NULL) ? g_strdup (result) : NULL; +} + +char * +vfs_canon_and_translate (const char *path) +{ + char *canon; + char *result; + canon = vfs_canon (path); + result = vfs_translate_path_n (canon); + g_free (canon); + return result; +} + static int ferrno (struct vfs_class *vfs) { @@ -323,7 +501,8 @@ mc_open (const char *filename, int flags, ...) void *info; va_list ap; - char *file = vfs_canon (filename); + char *file = vfs_canon_and_translate (filename); + if (file != NULL) { struct vfs_class *vfs = vfs_get_class (file); /* Get the mode flag */ @@ -348,6 +527,7 @@ mc_open (const char *filename, int flags, ...) } return vfs_new_handle (vfs, info); + } else return -1; } @@ -356,13 +536,15 @@ int mc_##name inarg \ { \ struct vfs_class *vfs; \ int result; \ - char *mpath = vfs_canon (path); \ + char *mpath = vfs_canon_and_translate (path); \ + if (mpath != NULL) { \ vfs = vfs_get_class (mpath); \ result = vfs->name ? (*vfs->name)callarg : -1; \ g_free (mpath); \ if (result == -1) \ errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \ return result; \ + } else return -1; \ } MC_NAMEOP (chmod, (const char *path, mode_t mode), (vfs, mpath, mode)) @@ -370,11 +552,38 @@ MC_NAMEOP (chown, (const char *path, uid_t owner, gid_t group), (vfs, mpath, own MC_NAMEOP (utime, (const char *path, struct utimbuf *times), (vfs, mpath, times)) MC_NAMEOP (readlink, (const char *path, char *buf, int bufsiz), (vfs, mpath, buf, bufsiz)) MC_NAMEOP (unlink, (const char *path), (vfs, mpath)) -MC_NAMEOP (symlink, (const char *name1, const char *path), (vfs, name1, mpath)) MC_NAMEOP (mkdir, (const char *path, mode_t mode), (vfs, mpath, mode)) MC_NAMEOP (rmdir, (const char *path), (vfs, mpath)) MC_NAMEOP (mknod, (const char *path, mode_t mode, dev_t dev), (vfs, mpath, mode, dev)) +int +mc_symlink (const char *name1, const char *path) +{ + struct vfs_class *vfs; + int result; + char *mpath; + char *lpath; + char *tmp; + + mpath = vfs_canon_and_translate (path); + if (mpath != NULL) { + tmp = g_strdup (name1); + lpath = vfs_translate_path_n (tmp); + g_free (tmp); + + if (lpath != NULL) { + vfs = vfs_get_class (mpath); + result = vfs->symlink ? (*vfs->symlink) (vfs, lpath, mpath) : -1; + g_free (lpath); + + if (result == -1) + errno = vfs->symlink ? ferrno (vfs) : E_NOTSUPP; + return result; + } + g_free (mpath); + } + return -1; +} #define MC_HANDLEOP(name, inarg, callarg) \ ssize_t mc_##name inarg \ @@ -399,9 +608,12 @@ int mc_##name (const char *fname1, const char *fname2) \ { \ struct vfs_class *vfs; \ int result; \ - char *name2, *name1 = vfs_canon (fname1); \ + char *name2, *name1; \ + name1 = vfs_canon_and_translate (fname1); \ + if (name1 != NULL) { \ + name2 = vfs_canon_and_translate (fname2); \ + if (name2 != NULL) { \ vfs = vfs_get_class (name1); \ - name2 = vfs_canon (fname2); \ if (vfs != vfs_get_class (name2)){ \ errno = EXDEV; \ g_free (name1); \ @@ -414,6 +626,11 @@ int mc_##name (const char *fname1, const char *fname2) \ if (result == -1) \ errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; \ return result; \ + } else { \ + g_free (name1); \ + return -1; \ + } \ + } else return -1; \ } MC_RENAMEOP (link) @@ -438,11 +655,13 @@ mc_setctl (const char *path, int ctlop, void *arg) if (!path) vfs_die("You don't want to pass NULL to mc_setctl."); - mpath = vfs_canon (path); + mpath = vfs_canon_and_translate (path); + if (mpath != NULL) { vfs = vfs_get_class (mpath); result = vfs->setctl ? (*vfs->setctl)(vfs, mpath, ctlop, arg) : 0; g_free (mpath); return result; + } else return -1; } int @@ -474,22 +693,43 @@ mc_opendir (const char *dirname) int handle, *handlep; void *info; struct vfs_class *vfs; + char *canon; char *dname; + struct vfs_dirinfo *dirinfo; + const char *encoding; - dname = vfs_canon (dirname); - vfs = vfs_get_class (dname); + canon = vfs_canon (dirname); + dname = vfs_translate_path_n (canon); + if (dname != NULL) { + vfs = vfs_get_class (dname); info = vfs->opendir ? (*vfs->opendir)(vfs, dname) : NULL; g_free (dname); + if (!info){ errno = vfs->opendir ? ferrno (vfs) : E_NOTSUPP; + g_free (canon); return NULL; } - handle = vfs_new_handle (vfs, info); + + dirinfo = g_new (struct vfs_dirinfo, 1); + dirinfo->info = info; + + encoding = vfs_get_encoding (canon); + g_free (canon); + dirinfo->converter = (encoding != NULL) ? str_crt_conv_from (encoding) : + str_cnv_from_term; + if (dirinfo->converter == (iconv_t) (-1)) dirinfo->converter =str_cnv_from_term; + + handle = vfs_new_handle (vfs, dirinfo); handlep = g_new (int, 1); *handlep = handle; return (DIR *) handlep; + } else { + g_free (canon); + return NULL; + } } struct dirent * @@ -497,7 +737,10 @@ mc_readdir (DIR *dirp) { int handle; struct vfs_class *vfs; - struct dirent *result = NULL; + static struct dirent result; + struct dirent *entry = NULL; + struct vfs_dirinfo *dirinfo; + int state; if (!dirp) { errno = EFAULT; @@ -505,11 +748,21 @@ mc_readdir (DIR *dirp) } handle = *(int *) dirp; vfs = vfs_op (handle); - if (vfs->readdir) - result = (*vfs->readdir) (vfs_info (handle)); - if (!result) - errno = vfs->readdir ? ferrno (vfs) : E_NOTSUPP; - return result; + dirinfo = vfs_info (handle); + if (vfs->readdir) { + do { + entry = (*vfs->readdir) (dirinfo->info); + if (entry == NULL) return NULL; + str_reset_buffer (vfs_str_buffer); + state = str_vfs_convert_from (dirinfo->converter, + entry->d_name, vfs_str_buffer); + } while (state != 0); + memcpy (&result, entry, sizeof (struct dirent)); + g_strlcpy (result.d_name, vfs_str_buffer->data, NAME_MAX + 1); + result.d_reclen = strlen (result.d_name); + } + if (entry == NULL) errno = vfs->readdir ? ferrno (vfs) : E_NOTSUPP; + return (entry != NULL) ? &result : NULL; } int @@ -518,9 +771,14 @@ mc_closedir (DIR *dirp) int handle = *(int *) dirp; struct vfs_class *vfs = vfs_op (handle); int result; + struct vfs_dirinfo *dirinfo; - result = vfs->closedir ? (*vfs->closedir)(vfs_info (handle)) : -1; + dirinfo = vfs_info (handle); + if (dirinfo->converter != str_cnv_from_term) str_close_conv (dirinfo->converter); + + result = vfs->closedir ? (*vfs->closedir)(dirinfo->info) : -1; vfs_free_handle (handle); + g_free (dirinfo); g_free (dirp); return result; } @@ -529,24 +787,37 @@ int mc_stat (const char *filename, struct stat *buf) { struct vfs_class *vfs; int result; char *path; - path = vfs_canon (filename); vfs = vfs_get_class (path); + + path = vfs_canon_and_translate (filename); + + if (path != NULL) { + vfs = vfs_get_class (path); + result = vfs->stat ? (*vfs->stat) (vfs, path, buf) : -1; + g_free (path); + if (result == -1) errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; return result; + } else return -1; } int mc_lstat (const char *filename, struct stat *buf) { struct vfs_class *vfs; int result; char *path; - path = vfs_canon (filename); vfs = vfs_get_class (path); + + path = vfs_canon_and_translate (filename); + + if (path != NULL) { + vfs = vfs_get_class (path); result = vfs->lstat ? (*vfs->lstat) (vfs, path, buf) : -1; g_free (path); if (result == -1) errno = vfs->name ? ferrno (vfs) : E_NOTSUPP; return result; + } else return -1; } int mc_fstat (int handle, struct stat *buf) { @@ -569,25 +840,40 @@ int mc_fstat (int handle, struct stat *buf) { static const char * _vfs_get_cwd (void) { - char *p; + char *sys_cwd; + char *trans; + const char *encoding; + char *tmp; + int state; struct stat my_stat, my_stat2; - if (!_vfs_get_class (current_dir)) { - p = g_get_current_dir (); - if (!p) /* One of the directories in the path is not readable */ + trans = vfs_translate_path_n (current_dir); //add check if NULL + + if (!_vfs_get_class (trans)) { + encoding = vfs_get_encoding (current_dir); + if (encoding == NULL) { + tmp = g_get_current_dir (); + if (tmp != NULL) { /* One of the directories in the path is not readable */ + str_reset_buffer (vfs_str_buffer); + state = str_vfs_convert_from (str_cnv_from_term, tmp, vfs_str_buffer); + g_free (tmp); + sys_cwd = (state == 0) ? g_strdup (vfs_str_buffer->data) : NULL; + if (!sys_cwd) return current_dir; /* Otherwise check if it is O.K. to use the current_dir */ - if (!cd_symlinks || mc_stat (p, &my_stat) + if (!cd_symlinks || mc_stat (sys_cwd, &my_stat) || mc_stat (current_dir, &my_stat2) || my_stat.st_ino != my_stat2.st_ino || my_stat.st_dev != my_stat2.st_dev) { g_free (current_dir); - current_dir = p; - return p; - } /* Otherwise we return current_dir below */ - g_free (p); + current_dir = sys_cwd; + return sys_cwd; + }/* Otherwise we return current_dir below */ + } } + } + g_free (trans); return current_dir; } @@ -682,22 +968,27 @@ int mc_chdir (const char *path) { char *new_dir; + char *trans_dir; struct vfs_class *old_vfs, *new_vfs; vfsid old_vfsid; int result; new_dir = vfs_canon (path); - new_vfs = vfs_get_class (new_dir); + trans_dir = vfs_translate_path_n (new_dir); + if (trans_dir != NULL) { + new_vfs = vfs_get_class (trans_dir); if (!new_vfs->chdir) { g_free (new_dir); + g_free (trans_dir); return -1; } - result = (*new_vfs->chdir) (new_vfs, new_dir); + result = (*new_vfs->chdir) (new_vfs, trans_dir); if (result == -1) { errno = ferrno (new_vfs); g_free (new_dir); + g_free (trans_dir); return -1; } @@ -720,7 +1011,12 @@ mc_chdir (const char *path) *p = 0; } + g_free (trans_dir); return 0; + } else { + g_free (new_dir); + return -1; + } } /* Return 1 is the current VFS class is local */ @@ -737,10 +1033,12 @@ vfs_file_class_flags (const char *filename) struct vfs_class *vfs; char *fname; - fname = vfs_canon (filename); + fname = vfs_canon_and_translate (filename); + if (fname != NULL) { vfs = vfs_get_class (fname); g_free (fname); return vfs->flags; + } else return -1; } static char * @@ -792,7 +1090,10 @@ char * mc_getlocalcopy (const char *pathname) { char *result; - char *path = vfs_canon (pathname); + char *path; + + path = vfs_canon_and_translate (pathname); + if (path != NULL) { struct vfs_class *vfs = vfs_get_class (path); result = vfs->getlocalcopy ? (*vfs->getlocalcopy)(vfs, path) : @@ -801,6 +1102,7 @@ mc_getlocalcopy (const char *pathname) if (!result) errno = ferrno (vfs); return result; + } else return NULL; } static int @@ -854,7 +1156,10 @@ int mc_ungetlocalcopy (const char *pathname, const char *local, int has_changed) { int return_value = 0; - char *path = vfs_canon (pathname); + char *path; + + path = vfs_canon_and_translate (pathname); + if (path != NULL) { struct vfs_class *vfs = vfs_get_class (path); return_value = vfs->ungetlocalcopy ? @@ -862,12 +1167,14 @@ mc_ungetlocalcopy (const char *pathname, const char *local, int has_changed) mc_def_ungetlocalcopy (vfs, path, local, has_changed); g_free (path); return return_value; + } else return -1; } void vfs_init (void) { + vfs_str_buffer = str_get_buffer (); /* localfs needs to be the first one */ init_localfs(); /* fallback value for vfs_get_class() */ @@ -911,6 +1218,8 @@ vfs_shut (void) (*vfs->done) (vfs); g_slist_free (vfs_openfiles); + + str_release_buffer (vfs_str_buffer); } /* diff --git a/vfs/vfs.h b/vfs/vfs.h index d79c706f4..01e286d6a 100644 --- a/vfs/vfs.h +++ b/vfs/vfs.h @@ -10,6 +10,17 @@ char *mc_get_current_wd (char *buffer, int bufsize); char *vfs_get_current_dir (void); int vfs_current_is_local (void); int vfs_file_is_local (const char *filename); +/* translate path back to terminal encoding, remove all #enc: + * every invalid character is replaced with question mark + * return static buffer */ +char *vfs_translate_path (const char *path); +/* return new string */ +char *vfs_translate_path_n (const char *path); +/* return encoding after last #enc: or NULL, if part does not contain #enc: + * return static buffer */ +const char *vfs_get_encoding (const char *path); +// canonize and translate path, return new string */ +char *vfs_canon_and_translate (const char *path); /* Only the routines outside of the VFS module need the emulation macros */