aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2020-06-30 15:44:20 +0100
committerRon Yorston <rmy@pobox.com>2020-06-30 15:52:54 +0100
commit90b695c255eeeddb2bb90e5cacbd3253663bfa7f (patch)
tree623627f54f8f131db7eb1029c556a60c0a0649dc
parent9114e110a59a77909132af6d97bccdf5056adfa4 (diff)
downloadbusybox-w32-90b695c255eeeddb2bb90e5cacbd3253663bfa7f.tar.gz
busybox-w32-90b695c255eeeddb2bb90e5cacbd3253663bfa7f.tar.bz2
busybox-w32-90b695c255eeeddb2bb90e5cacbd3253663bfa7f.zip
ash: improve handling of UNC paths
Be more strict about identifying UNC paths in unc_root_len(). In updatepwd() in ash: - Skip duplicate leading slashes unless the directory is a UNC path. - Rewrite detection and handling of the five possible types of path. This improves cases like 'cd ///' and 'cd /xyz' when the current directory is a UNC path. See GitHub issue #192.
-rw-r--r--shell/ash.c91
-rw-r--r--win32/mingw.c3
2 files changed, 56 insertions, 38 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 3c53b25ff..397995d9a 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -2998,7 +2998,8 @@ updatepwd(const char *dir)
2998 char *p; 2998 char *p;
2999 char *cdcomppath; 2999 char *cdcomppath;
3000 const char *lim; 3000 const char *lim;
3001 int len = 0; 3001 int len;
3002 char buffer[PATH_MAX];
3002 /* 3003 /*
3003 * There are five cases that make some kind of sense 3004 * There are five cases that make some kind of sense
3004 * 3005 *
@@ -3006,65 +3007,81 @@ updatepwd(const char *dir)
3006 * c:/path 3007 * c:/path
3007 * //host/share 3008 * //host/share
3008 * 3009 *
3009 * Relative to current drive: 3010 * Relative to current working directory of other drive:
3011 * c:path
3012 *
3013 * Relative to current root (drive/share):
3010 * /path 3014 * /path
3011 * 3015 *
3012 * Relative to current working directory of current drive 3016 * Relative to current working directory of current root (drive/share):
3013 * path 3017 * path
3014 *
3015 * Relative to current working directory of other drive
3016 * c:path
3017 */ 3018 */
3018 int absdrive = has_dos_drive_prefix(dir); 3019 enum {ABS_DRIVE, ABS_SHARE, REL_OTHER, REL_ROOT, REL_CWD} target;
3019 int curr_relpath = !absdrive && !is_path_sep(*dir); 3020
3020 int other_relpath = absdrive && !is_path_sep(dir[2]); 3021 /* skip multiple leading separators unless dir is a UNC path */
3021 int relpath = curr_relpath || other_relpath; 3022 if (is_path_sep(*dir) && unc_root_len(dir) == 0) {
3023 while (is_path_sep(dir[1]))
3024 ++dir;
3025 }
3026
3027 len = strlen(dir);
3028 if (len >= 2 && has_dos_drive_prefix(dir))
3029 target = len >= 3 && is_path_sep(dir[2]) ? ABS_DRIVE : REL_OTHER;
3030 else if (unc_root_len(dir) != 0)
3031 target = ABS_SHARE;
3032 else if (is_path_sep(*dir))
3033 target = REL_ROOT;
3034 else
3035 target = REL_CWD;
3022 3036
3023 cdcomppath = sstrdup(dir); 3037 cdcomppath = sstrdup(dir);
3024 STARTSTACKSTR(new); 3038 STARTSTACKSTR(new);
3025 3039
3026 /* prefix new path with current directory, if required */ 3040 switch (target) {
3027 if (other_relpath) { 3041 case REL_OTHER:
3028 /* c:path */ 3042 /* c:path */
3029 char buffer[PATH_MAX];
3030
3031 if (get_drive_cwd(dir, buffer, PATH_MAX) == NULL) 3043 if (get_drive_cwd(dir, buffer, PATH_MAX) == NULL)
3032 return 0; 3044 return 0;
3033 new = stack_putstr(buffer, new); 3045 new = stack_putstr(buffer, new);
3034 } 3046 len = 2;
3035 else if (curr_relpath || (is_root(dir) && unc_root_len(curdir))) { 3047 cdcomppath += len;
3036 /* relative path on current drive or explicit root of UNC curdir */ 3048 dir += len;
3037 if (curdir == nullstr) 3049 break;
3050 case REL_CWD:
3051 case REL_ROOT:
3052 /* path or /path */
3053 len = root_len(curdir);
3054 if (len == 0)
3038 return 0; 3055 return 0;
3039 new = stack_putstr(curdir, new); 3056 new = target == REL_CWD ? stack_putstr(curdir, new) :
3057 stnputs(curdir, len, new);
3058 break;
3059 default:
3060 /* //host/share or c:/path */
3061 len = root_len(dir);
3062 if (len == 0)
3063 return 0;
3064 new = stnputs(dir, len, new);
3065 cdcomppath += len;
3066 dir += len;
3067 break;
3040 } 3068 }
3041 3069
3042 new = makestrspace(strlen(dir) + 2, new); 3070 new = makestrspace(strlen(dir) + 2, new);
3071 lim = (char *)stackblock() + len + 1;
3043 3072
3044 if ( (len=unc_root_len(dir)) || ((len=unc_root_len(curdir)) && 3073 if (!is_path_sep(*dir)) {
3045 (is_root(dir) || curr_relpath)) ) {
3046 /* //host/share or path relative to //host/share */
3047 lim = (char *)stackblock() + len;
3048 }
3049 else {
3050 if (absdrive) {
3051 if (!relpath)
3052 new = stnputs(dir, 2, new);
3053 cdcomppath += 2;
3054 dir += 2;
3055 }
3056 lim = (char *)stackblock() + 3;
3057 }
3058
3059 if (relpath) {
3060 if (!is_path_sep(new[-1])) 3074 if (!is_path_sep(new[-1]))
3061 USTPUTC('/', new); 3075 USTPUTC('/', new);
3076 if (new > lim && is_path_sep(*lim))
3077 lim++;
3062 } else { 3078 } else {
3063 USTPUTC('/', new); 3079 USTPUTC('/', new);
3064 cdcomppath ++; 3080 cdcomppath++;
3065 if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) { 3081 if (is_path_sep(dir[1]) && !is_path_sep(dir[2])) {
3066 USTPUTC('/', new); 3082 USTPUTC('/', new);
3067 cdcomppath++; 3083 cdcomppath++;
3084 lim++;
3068 } 3085 }
3069 } 3086 }
3070 p = strtok(cdcomppath, "/\\"); 3087 p = strtok(cdcomppath, "/\\");
@@ -3086,7 +3103,7 @@ updatepwd(const char *dir)
3086 new = stack_putstr(p, new); 3103 new = stack_putstr(p, new);
3087 USTPUTC('/', new); 3104 USTPUTC('/', new);
3088 } 3105 }
3089 p = strtok(0, "/\\"); 3106 p = strtok(NULL, "/\\");
3090 } 3107 }
3091 if (new > lim) 3108 if (new > lim)
3092 STUNPUTC(new); 3109 STUNPUTC(new);
diff --git a/win32/mingw.c b/win32/mingw.c
index 06b22a2ed..78d662e50 100644
--- a/win32/mingw.c
+++ b/win32/mingw.c
@@ -1643,7 +1643,8 @@ void hide_console(void)
1643#endif 1643#endif
1644 1644
1645#define is_path_sep(x) ((x) == '/' || (x) == '\\') 1645#define is_path_sep(x) ((x) == '/' || (x) == '\\')
1646#define is_unc_path(x) (is_path_sep(x[0]) && is_path_sep(x[1])) 1646#define is_unc_path(x) (strlen(x) > 4 && is_path_sep(x[0]) && \
1647 is_path_sep(x[1]) && !is_path_sep(x[2]))
1647 1648
1648/* Return the length of the root of a UNC path, i.e. the '//host/share' 1649/* Return the length of the root of a UNC path, i.e. the '//host/share'
1649 * component, or 0 if the path doesn't look like that. */ 1650 * component, or 0 if the path doesn't look like that. */