/* * functions glob2 and glob3 are mutually recursive; there is one level * of recursion for each segment in the pattern that contains one or * more meta characters. */ static int glob2(struct strbuf *pathbuf, const Char *pattern, glob_t *pglob, int no_match) { struct stat sbuf; int anymeta; const Char *p; size_t orig_len; /* * loop over pattern segments until end of pattern or until segment with * meta character found. */ anymeta = 0; for (;;) { if (*pattern == EOS) { /* end of pattern? */ strbuf_terminate(pathbuf); if (Lstat(pathbuf->s, &sbuf)) return (0); if (((pglob->gl_flags & GLOB_MARK) && pathbuf->s[pathbuf->len - 1] != SEP) && (S_ISDIR(sbuf.st_mode) #ifdef S_IFLNK || (S_ISLNK(sbuf.st_mode) && (Stat(pathbuf->s, &sbuf) == 0) && S_ISDIR(sbuf.st_mode)) #endif )) { strbuf_append1(pathbuf, SEP); strbuf_terminate(pathbuf); } ++pglob->gl_matchc; globextend(pathbuf->s, pglob); return 0; } /* find end of next segment, tentatively copy to pathbuf */ p = pattern; orig_len = pathbuf->len; while (*p != EOS && *p != SEP) { if (ismeta(*p)) anymeta = 1; strbuf_append1(pathbuf, *p++); } if (!anymeta) { /* no expansion, do next segment */ pattern = p; while (*pattern == SEP) strbuf_append1(pathbuf, *pattern++); } else { /* need expansion, recurse */ pathbuf->len = orig_len; return (glob3(pathbuf, pattern, p, pattern, pglob, no_match)); } } /* NOTREACHED */ }
static char * xgetpass(const char *prm) { static struct strbuf pass; /* = strbuf_INIT; */ int fd; sigset_t oset, set; struct sigaction sa, osa; sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; (void)sigaction(SIGINT, &sa, &osa); sigemptyset(&set); sigaddset(&set, SIGINT); (void)sigprocmask(SIG_UNBLOCK, &set, &oset); cleanup_push(&osa, sigint_cleanup); cleanup_push(&oset, sigprocmask_cleanup); (void) Rawmode(); /* Make sure, cause we want echo off */ fd = xopen("/dev/tty", O_RDWR|O_LARGEFILE); if (fd == -1) fd = SHIN; else cleanup_push(&fd, open_cleanup); xprintf("%s", prm); flush(); pass.len = 0; for (;;) { char c; if (xread(fd, &c, 1) < 1 || c == '\n') break; strbuf_append1(&pass, c); } strbuf_terminate(&pass); cleanup_until(&osa); return pass.s; }
static int glob3(struct strbuf *pathbuf, const Char *pattern, const Char *restpattern, const Char *pglobstar, glob_t *pglob, int no_match) { DIR *dirp; struct dirent *dp; struct stat sbuf; int err; Char m_not = (pglob->gl_flags & GLOB_ALTNOT) ? M_ALTNOT : M_NOT; size_t orig_len; int globstar = 0; int chase_symlinks = 0; const Char *termstar = NULL; strbuf_terminate(pathbuf); orig_len = pathbuf->len; errno = err = 0; while (pglobstar < restpattern) { __Char wc; size_t width = One_Char_mbtowc(&wc, pglobstar, MB_LEN_MAX); if ((pglobstar[0] & M_MASK) == M_ALL && (pglobstar[width] & M_MASK) == M_ALL) { globstar = 1; chase_symlinks = (pglobstar[2 * width] & M_MASK) == M_ALL; termstar = pglobstar + (2 + chase_symlinks) * width; break; } pglobstar += width; } if (globstar) { err = pglobstar==pattern && termstar==restpattern ? *restpattern == EOS ? glob2(pathbuf, restpattern - 1, pglob, no_match) : glob2(pathbuf, restpattern + 1, pglob, no_match) : glob3(pathbuf, pattern, restpattern, termstar, pglob, no_match); if (err) return err; pathbuf->len = orig_len; strbuf_terminate(pathbuf); } if (*pathbuf->s && (Lstat(pathbuf->s, &sbuf) || !S_ISDIR(sbuf.st_mode) #ifdef S_IFLINK && ((globstar && !chase_symlinks) || !S_ISLNK(sbuf.st_mode)) #endif )) return 0; if (!(dirp = Opendir(pathbuf->s))) { /* todo: don't call for ENOENT or ENOTDIR? */ if ((pglob->gl_errfunc && (*pglob->gl_errfunc) (pathbuf->s, errno)) || (pglob->gl_flags & GLOB_ERR)) return (GLOB_ABEND); else return (0); } /* search directory for matching names */ while ((dp = readdir(dirp)) != NULL) { /* initial DOT must be matched literally */ if (dp->d_name[0] == DOT && *pattern != DOT) if (!(pglob->gl_flags & GLOB_DOT) || !dp->d_name[1] || (dp->d_name[1] == DOT && !dp->d_name[2])) continue; /*unless globdot and not . or .. */ pathbuf->len = orig_len; strbuf_append(pathbuf, dp->d_name); strbuf_terminate(pathbuf); if (globstar) { #ifdef S_IFLNK if (!chase_symlinks && (Lstat(pathbuf->s, &sbuf) || S_ISLNK(sbuf.st_mode))) continue; #endif if (match(pathbuf->s + orig_len, pattern, termstar, (int)m_not) == no_match) continue; strbuf_append1(pathbuf, SEP); strbuf_terminate(pathbuf); if ((err = glob2(pathbuf, pglobstar, pglob, no_match)) != 0) break; } else { if (match(pathbuf->s + orig_len, pattern, restpattern, (int) m_not) == no_match) continue; if ((err = glob2(pathbuf, restpattern, pglob, no_match)) != 0) break; } } /* todo: check error from readdir? */ closedir(dirp); return (err); }