diff options
author | Ron Yorston <rmy@pobox.com> | 2020-06-30 15:44:20 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2020-06-30 15:52:54 +0100 |
commit | 90b695c255eeeddb2bb90e5cacbd3253663bfa7f (patch) | |
tree | 623627f54f8f131db7eb1029c556a60c0a0649dc | |
parent | 9114e110a59a77909132af6d97bccdf5056adfa4 (diff) | |
download | busybox-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.c | 91 | ||||
-rw-r--r-- | win32/mingw.c | 3 |
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. */ |