aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/ash.c67
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 */
7578typedef struct exp_t {
7579 char *dir;
7580 unsigned dir_max;
7581} exp_t;
7578static void 7582static void
7579expmeta(char *expdir, char *enddir, char *name) 7583expmeta(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
7690static struct strlist * 7707static 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;