From d332606fd51c0ee1c1eb972550097c525a9258cb Mon Sep 17 00:00:00 2001 From: "Andrew V. Samoilov" Date: Thu, 13 Jan 2005 19:37:46 +0000 Subject: [PATCH] * subshell.c (do_subshell_chdir): Use mc_realpath() to fix tcsh's problem with symlink. * utilunix.c: Add function mc_realpath(). Is the BSD version of realpath(3). * util.h: Add mc_realpath() declaration. --- src/ChangeLog | 8 ++++ src/subshell.c | 18 +++++++- src/util.h | 18 ++++++++ src/utilunix.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 160 insertions(+), 2 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 55d143421..630a95e39 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,11 @@ +2005-01-14 Pavel Shirshov + + * subshell.c (do_subshell_chdir): Use mc_realpath() to fix tcsh's + problem with symlink. + * utilunix.c: Add function mc_realpath(). Is the BSD version of + realpath(3). + * util.h: Add mc_realpath() declaration. + 2004-12-13 Andrew V. Samoilov * find.c (find_parameters): Use translated string. diff --git a/src/subshell.c b/src/subshell.c index fe5e7ef6d..52b55eb4d 100644 --- a/src/subshell.c +++ b/src/subshell.c @@ -753,6 +753,8 @@ subshell_name_quote (const char *s) void do_subshell_chdir (const char *directory, int do_update, int reset_prompt) { + int bPathNotEq; + if (! (subshell_state == INACTIVE && strcmp (subshell_cwd, current_panel->cwd))) { @@ -787,8 +789,20 @@ do_subshell_chdir (const char *directory, int do_update, int reset_prompt) subshell_state = RUNNING_COMMAND; feed_subshell (QUIETLY, FALSE); - if (subshell_alive && strcmp (subshell_cwd, current_panel->cwd) - && strcmp (current_panel->cwd, ".")) { + if (subshell_type == TCSH) { + char rp_subshell_cwd[PATH_MAX]; + char rp_current_panel_cwd[PATH_MAX]; + + if (mc_realpath(subshell_cwd, rp_subshell_cwd) == NULL) + strlcpy(rp_subshell_cwd, subshell_cwd, PATH_MAX); + + if (mc_realpath(current_panel->cwd, rp_current_panel_cwd) == NULL) + strlcpy(rp_current_panel_cwd, current_panel->cwd, PATH_MAX); + + bPathNotEq = strcmp (rp_subshell_cwd, rp_current_panel_cwd); + } else bPathNotEq = strcmp (subshell_cwd, current_panel->cwd); + + if (subshell_alive && bPathNotEq && strcmp (current_panel->cwd, ".")) { char *cwd = strip_password (g_strdup (current_panel->cwd), 1); fprintf (stderr, _("Warning: Cannot change to %s.\n"), cwd); diff --git a/src/util.h b/src/util.h index 17e360900..474169b61 100644 --- a/src/util.h +++ b/src/util.h @@ -148,6 +148,24 @@ void rotate_dash (void); const char *mc_tmpdir (void); int mc_mkstemps(char **pname, const char *prefix, const char *suffix); +#ifndef PATH_MAX +#ifdef _POSIX_VERSION +#define PATH_MAX _POSIX_PATH_MAX +#else +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif +#endif + +#ifndef MAXSYMLINKS +#define MAXSYMLINKS 32 +#endif + +char *mc_realpath(const char *path, char resolved_path[]); + enum { COMPRESSION_NONE, COMPRESSION_GZIP, diff --git a/src/utilunix.c b/src/utilunix.c index 0c196161d..713dee6fe 100644 --- a/src/utilunix.c +++ b/src/utilunix.c @@ -4,6 +4,9 @@ Miguel de Icaza, Janne Kukonlehto, Dugan Porter, Jakub Jelinek, Mauricio Plaza. + The mc_realpath routine is mostly from uClibc package, written + by Rick Sladkey + 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 2 of the License, or @@ -27,6 +30,7 @@ #include /* struct sigaction */ #include /* INT_MAX */ #include +#include /* for MAXPATHLEN */ #include #include /* errno */ #include @@ -673,3 +677,117 @@ putenv (char *string) } #endif /* !HAVE_PUTENV */ +char * +mc_realpath (const char *path, char resolved_path[]) +{ + char copy_path[PATH_MAX]; + char link_path[PATH_MAX]; + char got_path[PATH_MAX]; + char *new_path = got_path; + char *max_path; + int readlinks = 0; + int n; + + /* Make a copy of the source path since we may need to modify it. */ + if (strlen (path) >= PATH_MAX - 2) { + errno = ENAMETOOLONG; + return NULL; + } + strcpy (copy_path, path); + path = copy_path; + max_path = copy_path + PATH_MAX - 2; + /* If it's a relative pathname use getwd for starters. */ + if (*path != '/') { + /* Ohoo... */ +#ifdef HAVE_GETCWD + getcwd (new_path, PATH_MAX - 1); +#else + getwd (new_path); +#endif + new_path += strlen (new_path); + if (new_path[-1] != '/') + *new_path++ = '/'; + } else { + *new_path++ = '/'; + path++; + } + /* Expand each slash-separated pathname component. */ + while (*path != '\0') { + /* Ignore stray "/". */ + if (*path == '/') { + path++; + continue; + } + if (*path == '.') { + /* Ignore ".". */ + if (path[1] == '\0' || path[1] == '/') { + path++; + continue; + } + if (path[1] == '.') { + if (path[2] == '\0' || path[2] == '/') { + path += 2; + /* Ignore ".." at root. */ + if (new_path == got_path + 1) + continue; + /* Handle ".." by backing up. */ + while ((--new_path)[-1] != '/'); + continue; + } + } + } + /* Safely copy the next pathname component. */ + while (*path != '\0' && *path != '/') { + if (path > max_path) { + errno = ENAMETOOLONG; + return NULL; + } + *new_path++ = *path++; + } +#ifdef S_IFLNK + /* Protect against infinite loops. */ + if (readlinks++ > MAXSYMLINKS) { + errno = ELOOP; + return NULL; + } + /* See if latest pathname component is a symlink. */ + *new_path = '\0'; + n = readlink (got_path, link_path, PATH_MAX - 1); + if (n < 0) { + /* EINVAL means the file exists but isn't a symlink. */ + if (errno != EINVAL) { + /* Make sure it's null terminated. */ + *new_path = '\0'; + strcpy (resolved_path, got_path); + return NULL; + } + } else { + /* Note: readlink doesn't add the null byte. */ + link_path[n] = '\0'; + if (*link_path == '/') + /* Start over for an absolute symlink. */ + new_path = got_path; + else + /* Otherwise back up over this component. */ + while (*(--new_path) != '/'); + /* Safe sex check. */ + if (strlen (path) + n >= PATH_MAX - 2) { + errno = ENAMETOOLONG; + return NULL; + } + /* Insert symlink contents into path. */ + strcat (link_path, path); + strcpy (copy_path, link_path); + path = copy_path; + } +#endif /* S_IFLNK */ + *new_path++ = '/'; + } + /* Delete trailing slash but don't whomp a lone slash. */ + if (new_path != got_path + 1 && new_path[-1] == '/') + new_path--; + /* Make sure it's null terminated. */ + *new_path = '\0'; + strcpy (resolved_path, got_path); + return resolved_path; +}