diff options
-rw-r--r-- | shell/ash.c | 67 |
1 files changed, 42 insertions, 25 deletions
diff --git a/shell/ash.c b/shell/ash.c index 40ca82d0b..051cc671f 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -7575,9 +7575,16 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
7575 | /* | 7575 | /* |
7576 | * Do metacharacter (i.e. *, ?, [...]) expansion. | 7576 | * Do metacharacter (i.e. *, ?, [...]) expansion. |
7577 | */ | 7577 | */ |
7578 | typedef struct exp_t { | ||
7579 | char *dir; | ||
7580 | unsigned dir_max; | ||
7581 | } exp_t; | ||
7578 | static void | 7582 | static void |
7579 | expmeta(char *expdir, char *enddir, char *name) | 7583 | expmeta(exp_t *exp, char *name, unsigned name_len, unsigned expdir_len) |
7580 | { | 7584 | { |
7585 | #define expdir exp->dir | ||
7586 | #define expdir_max exp->dir_max | ||
7587 | char *enddir = expdir + expdir_len; | ||
7581 | char *p; | 7588 | char *p; |
7582 | const char *cp; | 7589 | const char *cp; |
7583 | char *start; | 7590 | char *start; |
@@ -7620,15 +7627,15 @@ expmeta(char *expdir, char *enddir, char *name) | |||
7620 | } | 7627 | } |
7621 | } | 7628 | } |
7622 | if (metaflag == 0) { /* we've reached the end of the file name */ | 7629 | if (metaflag == 0) { /* we've reached the end of the file name */ |
7623 | if (enddir != expdir) | 7630 | if (!expdir_len) |
7624 | metaflag++; | 7631 | return; |
7625 | p = name; | 7632 | p = name; |
7626 | do { | 7633 | do { |
7627 | if (*p == '\\') | 7634 | if (*p == '\\') |
7628 | p++; | 7635 | p++; |
7629 | *enddir++ = *p; | 7636 | *enddir++ = *p; |
7630 | } while (*p++); | 7637 | } while (*p++); |
7631 | if (metaflag == 0 || lstat(expdir, &statb) >= 0) | 7638 | if (lstat(expdir, &statb) == 0) |
7632 | addfname(expdir); | 7639 | addfname(expdir); |
7633 | return; | 7640 | return; |
7634 | } | 7641 | } |
@@ -7641,19 +7648,14 @@ expmeta(char *expdir, char *enddir, char *name) | |||
7641 | *enddir++ = *p++; | 7648 | *enddir++ = *p++; |
7642 | } while (p < start); | 7649 | } while (p < start); |
7643 | } | 7650 | } |
7644 | if (enddir == expdir) { | 7651 | *enddir = '\0'; |
7652 | cp = expdir; | ||
7653 | expdir_len = enddir - cp; | ||
7654 | if (!expdir_len) | ||
7645 | cp = "."; | 7655 | cp = "."; |
7646 | } else if (enddir == expdir + 1 && *expdir == '/') { | ||
7647 | cp = "/"; | ||
7648 | } else { | ||
7649 | cp = expdir; | ||
7650 | enddir[-1] = '\0'; | ||
7651 | } | ||
7652 | dirp = opendir(cp); | 7656 | dirp = opendir(cp); |
7653 | if (dirp == NULL) | 7657 | if (dirp == NULL) |
7654 | return; | 7658 | return; |
7655 | if (enddir != expdir) | ||
7656 | enddir[-1] = '/'; | ||
7657 | if (*endname == 0) { | 7659 | if (*endname == 0) { |
7658 | atend = 1; | 7660 | atend = 1; |
7659 | } else { | 7661 | } else { |
@@ -7661,6 +7663,7 @@ expmeta(char *expdir, char *enddir, char *name) | |||
7661 | *endname = '\0'; | 7663 | *endname = '\0'; |
7662 | endname += esc + 1; | 7664 | endname += esc + 1; |
7663 | } | 7665 | } |
7666 | name_len -= endname - name; | ||
7664 | matchdot = 0; | 7667 | matchdot = 0; |
7665 | p = start; | 7668 | p = start; |
7666 | if (*p == '\\') | 7669 | if (*p == '\\') |
@@ -7675,16 +7678,30 @@ expmeta(char *expdir, char *enddir, char *name) | |||
7675 | strcpy(enddir, dp->d_name); | 7678 | strcpy(enddir, dp->d_name); |
7676 | addfname(expdir); | 7679 | addfname(expdir); |
7677 | } else { | 7680 | } else { |
7678 | for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';) | 7681 | unsigned offset; |
7679 | continue; | 7682 | unsigned len; |
7680 | p[-1] = '/'; | 7683 | |
7681 | expmeta(expdir, p, endname); | 7684 | p = stpcpy(enddir, dp->d_name); |
7685 | *p = '/'; | ||
7686 | |||
7687 | offset = p - expdir + 1; | ||
7688 | len = offset + name_len + NAME_MAX; | ||
7689 | if (len > expdir_max) { | ||
7690 | len += PATH_MAX; | ||
7691 | expdir = ckrealloc(expdir, len); | ||
7692 | expdir_max = len; | ||
7693 | } | ||
7694 | |||
7695 | expmeta(exp, endname, name_len, offset); | ||
7696 | enddir = expdir + expdir_len; | ||
7682 | } | 7697 | } |
7683 | } | 7698 | } |
7684 | } | 7699 | } |
7685 | closedir(dirp); | 7700 | closedir(dirp); |
7686 | if (!atend) | 7701 | if (!atend) |
7687 | endname[-esc - 1] = esc ? '\\' : '/'; | 7702 | endname[-esc - 1] = esc ? '\\' : '/'; |
7703 | #undef expdir | ||
7704 | #undef expdir_max | ||
7688 | } | 7705 | } |
7689 | 7706 | ||
7690 | static struct strlist * | 7707 | static struct strlist * |
@@ -7757,10 +7774,11 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
7757 | /* TODO - EXP_REDIR */ | 7774 | /* TODO - EXP_REDIR */ |
7758 | 7775 | ||
7759 | while (str) { | 7776 | while (str) { |
7760 | char *expdir; | 7777 | exp_t exp; |
7761 | struct strlist **savelastp; | 7778 | struct strlist **savelastp; |
7762 | struct strlist *sp; | 7779 | struct strlist *sp; |
7763 | char *p; | 7780 | char *p; |
7781 | unsigned len; | ||
7764 | 7782 | ||
7765 | if (fflag) | 7783 | if (fflag) |
7766 | goto nometa; | 7784 | goto nometa; |
@@ -7770,13 +7788,12 @@ expandmeta(struct strlist *str /*, int flag*/) | |||
7770 | 7788 | ||
7771 | INT_OFF; | 7789 | INT_OFF; |
7772 | p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); | 7790 | p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); |
7773 | { | 7791 | len = strlen(p); |
7774 | int i = strlen(str->text); | 7792 | exp.dir_max = len + PATH_MAX; |
7775 | //BUGGY estimation of how long expanded name can be | 7793 | exp.dir = ckmalloc(exp.dir_max); |
7776 | expdir = ckmalloc(i < 2048 ? 2048 : i+1); | 7794 | |
7777 | } | 7795 | expmeta(&exp, p, len, 0); |
7778 | expmeta(expdir, expdir, p); | 7796 | free(exp.dir); |
7779 | free(expdir); | ||
7780 | if (p != str->text) | 7797 | if (p != str->text) |
7781 | free(p); | 7798 | free(p); |
7782 | INT_ON; | 7799 | INT_ON; |