glob.c
上传用户:zibowangxu
上传日期:2007-01-04
资源大小:331k
文件大小:12k
源码类别:

Ftp客户端

开发平台:

Unix_Linux

  1. /****************************************************************************    
  2.   Copyright (c) 1999 WU-FTPD Development Group.  
  3.   All rights reserved.
  4.   
  5.   Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994 
  6.     The Regents of the University of California.
  7.   Portions Copyright (c) 1993, 1994 Washington University in Saint Louis. 
  8.   Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc. 
  9.   Portions Copyright (c) 1989 Massachusetts Institute of Technology. 
  10.   Portions Copyright (c) 1998 Sendmail, Inc. 
  11.   Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P.  Allman. 
  12.   Portions Copyright (c) 1997 by Stan Barber. 
  13.   Portions Copyright (c) 1997 by Kent Landfield. 
  14.   Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997 
  15.     Free Software Foundation, Inc.   
  16.   
  17.   Use and distribution of this software and its source code are governed  
  18.   by the terms and conditions of the WU-FTPD Software License ("LICENSE"). 
  19.   
  20.   If you did not receive a copy of the license, it may be obtained online 
  21.   at http://www.wu-ftpd.org/license.html. 
  22.   
  23.   $Id: glob.c,v 1.12 1999/10/05 02:54:42 wuftpd Exp $ 
  24.   
  25. ****************************************************************************/
  26. /*
  27.  * C-shell glob for random programs.
  28.  */
  29. #include "config.h"
  30. #include <sys/param.h>
  31. #include <sys/stat.h>
  32. #ifdef HAVE_DIRENT_H
  33. #include <dirent.h>
  34. #else
  35. #include <sys/dir.h>
  36. #endif
  37. #include <pwd.h>
  38. #include <errno.h>
  39. #include <stdio.h>
  40. #include <string.h>
  41. #include "proto.h"
  42. #define QUOTE 0200
  43. #define TRIM 0177
  44. #define eq(a,b) (strcmp(a, b)==0)
  45. #define GAVSIZ (NCARGS/6)
  46. #define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR)
  47. static char **gargv; /* Pointer to the (stack) arglist */
  48. static int gargc; /* Number args in gargv */
  49. static size_t gnleft;
  50. static short gflag;
  51. static int tglob(register char);
  52. /* Prototypes */
  53. static char *strend(register char *);
  54. static void addpath(char);
  55. static void ginit(char **);
  56. static void collect(register char *);
  57. static void acollect(register char *);
  58. static void sort(void);
  59. static void expand(char *);
  60. static void matchdir(char *);
  61. static int execbrc(char *, char *);
  62. static int match(char *, char *);
  63. static int amatch(char *, char *);
  64. static void Gcat(register char *, register char *);
  65. static void addpath(char);
  66. static void rscan(register char **, int (*f) (register char));
  67. static int tglob(register char c);
  68. void blkfree(char **);
  69. int letter(register char);
  70. int digit(register char);
  71. int gethdir(char *);
  72. int any(register int, register char *);
  73. int blklen(register char **);
  74. char **ftpglob(register char *);
  75. char *strspl(register char *, register char *);
  76. char **copyblk(register char **);
  77. char **blkcpy(char **, register char **);
  78. char *globerr;
  79. char *home;
  80. extern int errno;
  81. static int globcnt;
  82. char *globchars = "`{[*?";
  83. static char *gpath, *gpathp, *lastgpathp;
  84. static int globbed;
  85. static char *entp;
  86. static char **sortbas;
  87. char **ftpglob(register char *v)
  88. {
  89.     char agpath[BUFSIZ];
  90.     char *agargv[GAVSIZ];
  91.     char *vv[2];
  92.     fixpath(v);
  93.     if (v[0] == '')
  94. v = "*";
  95.     else if ((strlen(v) > 1) && (v[strlen(v) - 1] == '/'))
  96. v[strlen(v) - 1] = '';
  97.     vv[0] = v;
  98.     vv[1] = NULL;
  99.     globerr = NULL;
  100.     gflag = 0;
  101.     rscan(vv, tglob);
  102.     if (gflag == 0) {
  103. vv[0] = strspl(v, "");
  104. return (copyblk(vv));
  105.     }
  106.     globerr = NULL;
  107.     gpath = agpath;
  108.     gpathp = gpath;
  109.     *gpathp = 0;
  110.     lastgpathp = &gpath[sizeof agpath - 2];
  111.     ginit(agargv);
  112.     globcnt = 0;
  113.     collect(v);
  114.     if (globcnt == 0 && (gflag & 1)) {
  115. blkfree(gargv), gargv = 0;
  116. return (0);
  117.     }
  118.     else
  119. return (gargv = copyblk(gargv));
  120. }
  121. static void ginit(char **agargv)
  122. {
  123.     agargv[0] = 0;
  124.     gargv = agargv;
  125.     sortbas = agargv;
  126.     gargc = 0;
  127.     gnleft = NCARGS - 4;
  128. }
  129. static void collect(register char *as)
  130. {
  131.     if (eq(as, "{") || eq(as, "{}")) {
  132. Gcat(as, "");
  133. sort();
  134.     }
  135.     else
  136. acollect(as);
  137. }
  138. static void acollect(register char *as)
  139. {
  140.     register int ogargc = gargc;
  141.     gpathp = gpath;
  142.     *gpathp = 0;
  143.     globbed = 0;
  144.     expand(as);
  145.     if (gargc != ogargc)
  146. sort();
  147. }
  148. static void sort(void)
  149. {
  150.     register char **p1, **p2, *c;
  151.     char **Gvp = &gargv[gargc];
  152.     p1 = sortbas;
  153.     while (p1 < Gvp - 1) {
  154. p2 = p1;
  155. while (++p2 < Gvp)
  156.     if (strcmp(*p1, *p2) > 0)
  157. c = *p1, *p1 = *p2, *p2 = c;
  158. p1++;
  159.     }
  160.     sortbas = Gvp;
  161. }
  162. static void expand(char *as)
  163. {
  164.     register char *cs;
  165.     register char *sgpathp, *oldcs;
  166.     struct stat stb;
  167.     if (globerr)
  168. return;
  169.     sgpathp = gpathp;
  170.     cs = as;
  171.     if (*cs == '~' && gpathp == gpath) {
  172. addpath('~');
  173. for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
  174.     addpath(*cs++);
  175. if (!*cs || *cs == '/') {
  176.     if (gpathp != gpath + 1) {
  177. *gpathp = 0;
  178. if (gethdir(gpath + 1))
  179.     globerr = "Unknown user name after ~";
  180. (void) strcpy(gpath, gpath + 1);
  181.     }
  182.     else
  183. (void) strcpy(gpath, home);
  184.     gpathp = strend(gpath);
  185. }
  186.     }
  187.     while (!any(*cs, globchars)) {
  188. if (*cs == 0) {
  189.     if (!globbed)
  190. Gcat(gpath, "");
  191.     else if (stat(gpath, &stb) >= 0) {
  192. Gcat(gpath, "");
  193. globcnt++;
  194.     }
  195.     goto endit;
  196. }
  197. addpath(*cs++);
  198.     }
  199.     oldcs = cs;
  200.     while (cs > as && *cs != '/')
  201. cs--, gpathp--;
  202.     if (*cs == '/')
  203. cs++, gpathp++;
  204.     *gpathp = 0;
  205.     if (*oldcs == '{') {
  206. (void) execbrc(cs, ((char *) 0));
  207. return;
  208.     }
  209.     matchdir(cs);
  210.   endit:
  211.     gpathp = sgpathp;
  212.     *gpathp = 0;
  213. }
  214. static void matchdir(char *pattern)
  215. {
  216.     struct stat stb;
  217. #ifdef HAVE_DIRENT_H
  218.     register struct dirent *dp;
  219. #else
  220.     register struct direct *dp;
  221. #endif
  222.     DIR *dirp;
  223.     dirp = opendir(*gpath == '' ? "." : gpath);
  224.     if (dirp == NULL) {
  225. if (globbed)
  226.     return;
  227. goto patherr2;
  228.     }
  229. #ifdef HAVE_DIRFD
  230.     if (fstat(dirfd(dirp), &stb) < 0)
  231. #else /* HAVE_DIRFD */
  232.     if (fstat(dirp->dd_fd, &stb) < 0)
  233. #endif /* HAVE_DIRFD */
  234. goto patherr1;
  235.     if (!isdir(stb)) {
  236. errno = ENOTDIR;
  237. goto patherr1;
  238.     }
  239.     while (!globerr && ((dp = readdir(dirp)) != NULL)) {
  240. if (dp->d_ino == 0)
  241.     continue;
  242. if (match(dp->d_name, pattern)) {
  243.     Gcat(gpath, dp->d_name);
  244.     globcnt++;
  245. }
  246.     }
  247.     closedir(dirp);
  248.     return;
  249.   patherr1:
  250.     closedir(dirp);
  251.   patherr2:
  252.     globerr = "Bad directory components";
  253. }
  254. static int execbrc(char *p, char *s)
  255. {
  256.     char restbuf[BUFSIZ + 2];
  257.     register char *pe, *pm, *pl;
  258.     int brclev = 0;
  259.     char *lm, savec, *sgpathp;
  260.     for (lm = restbuf; *p != '{'; *lm++ = *p++)
  261. continue;
  262.     for (pe = ++p; *pe; pe++)
  263. switch (*pe) {
  264. case '{':
  265.     brclev++;
  266.     continue;
  267. case '}':
  268.     if (brclev == 0)
  269. goto pend;
  270.     brclev--;
  271.     continue;
  272. case '[':
  273.     for (pe++; *pe && *pe != ']'; pe++)
  274. continue;
  275.     continue;
  276. }
  277.   pend:
  278.     brclev = 0;
  279.     for (pl = pm = p; pm <= pe; pm++)
  280. switch (*pm & (QUOTE | TRIM)) {
  281. case '{':
  282.     brclev++;
  283.     continue;
  284. case '}':
  285.     if (brclev) {
  286. brclev--;
  287. continue;
  288.     }
  289.     goto doit;
  290. case ',' | QUOTE:
  291. case ',':
  292.     if (brclev)
  293. continue;
  294.   doit:
  295.     savec = *pm;
  296.     *pm = 0;
  297.     (void) strcpy(lm, pl);
  298.     (void) strcat(restbuf, pe + 1);
  299.     *pm = savec;
  300.     if (s == 0) {
  301. sgpathp = gpathp;
  302. expand(restbuf);
  303. gpathp = sgpathp;
  304. *gpathp = 0;
  305.     }
  306.     else if (amatch(s, restbuf))
  307. return (1);
  308.     sort();
  309.     pl = pm + 1;
  310.     if (brclev)
  311. return (0);
  312.     continue;
  313. case '[':
  314.     for (pm++; *pm && *pm != ']'; pm++)
  315. continue;
  316.     if (!*pm)
  317. pm--;
  318.     continue;
  319. }
  320.     if (brclev)
  321. goto doit;
  322.     return (0);
  323. }
  324. static int match(char *s, char *p)
  325. {
  326.     register int c;
  327.     register char *sentp;
  328.     char sglobbed = globbed;
  329.     if (*s == '.' && *p != '.')
  330. return (0);
  331.     sentp = entp;
  332.     entp = s;
  333.     c = amatch(s, p);
  334.     entp = sentp;
  335.     globbed = sglobbed;
  336.     return (c);
  337. }
  338. static int amatch(char *s, char *p)
  339. {
  340.     register int scc;
  341.     int ok, lc;
  342.     char *sgpathp;
  343.     struct stat stb;
  344.     int c, cc;
  345.     globbed = 1;
  346.     for (;;) {
  347. scc = *s++ & TRIM;
  348. switch (c = *p++) {
  349. case '{':
  350.     return (execbrc(p - 1, s - 1));
  351. case '[':
  352.     ok = 0;
  353.     lc = 077777;
  354.     while ((cc = *p++)) {
  355. if (cc == ']') {
  356.     if (ok)
  357. break;
  358.     return (0);
  359. }
  360. if (cc == '-') {
  361.     if (lc <= scc && scc <= *p++)
  362. ok++;
  363. }
  364. else if (scc == (lc = cc))
  365.     ok++;
  366.     }
  367.     if (cc == 0)
  368. if (ok)
  369.     p--;
  370. else
  371.     return 0;
  372.     continue;
  373. case '*':
  374.     if (!*p)
  375. return (1);
  376.     if (*p == '/') {
  377. p++;
  378. goto slash;
  379.     }
  380.     s--;
  381.     do {
  382. if (amatch(s, p))
  383.     return (1);
  384.     } while (*s++);
  385.     return (0);
  386. case 0:
  387.     return (scc == 0);
  388. default:
  389.     if (c != scc)
  390. return (0);
  391.     continue;
  392. case '?':
  393.     if (scc == 0)
  394. return (0);
  395.     continue;
  396. case '/':
  397.     if (scc)
  398. return (0);
  399.   slash:
  400.     s = entp;
  401.     sgpathp = gpathp;
  402.     while (*s)
  403. addpath(*s++);
  404.     addpath('/');
  405.     if (stat(gpath, &stb) == 0 && isdir(stb))
  406. if (*p == 0) {
  407.     Gcat(gpath, "");
  408.     globcnt++;
  409. }
  410. else
  411.     expand(p);
  412.     gpathp = sgpathp;
  413.     *gpathp = 0;
  414.     return (0);
  415. }
  416.     }
  417. }
  418. /* This function appears to be unused, so why waste time and space on it? */
  419. #if 0 == 1
  420. static int Gmatch(register char *s, register char *p)
  421. {
  422.     register int scc;
  423.     int ok, lc;
  424.     int c, cc;
  425.     for (;;) {
  426. scc = *s++ & TRIM;
  427. switch (c = *p++) {
  428. case '[':
  429.     ok = 0;
  430.     lc = 077777;
  431.     while (cc = *p++) {
  432. if (cc == ']') {
  433.     if (ok)
  434. break;
  435.     return (0);
  436. }
  437. if (cc == '-') {
  438.     if (lc <= scc && scc <= *p++)
  439. ok++;
  440. }
  441. else if (scc == (lc = cc))
  442.     ok++;
  443.     }
  444.     if (cc == 0)
  445. if (ok)
  446.     p--;
  447. else
  448.     return 0;
  449.     continue;
  450. case '*':
  451.     if (!*p)
  452. return (1);
  453.     for (s--; *s; s++)
  454. if (Gmatch(s, p))
  455.     return (1);
  456.     return (0);
  457. case 0:
  458.     return (scc == 0);
  459. default:
  460.     if ((c & TRIM) != scc)
  461. return (0);
  462.     continue;
  463. case '?':
  464.     if (scc == 0)
  465. return (0);
  466.     continue;
  467. }
  468.     }
  469. }
  470. #endif /* Gmatch exclusion */
  471. static void Gcat(register char *s1, register char *s2)
  472. {
  473.     register size_t len = strlen(s1) + strlen(s2) + 1;
  474.     if (len >= gnleft || gargc >= GAVSIZ - 1)
  475. globerr = "Arguments too long";
  476.     else {
  477. gargc++;
  478. gnleft -= len;
  479. gargv[gargc] = 0;
  480. gargv[gargc - 1] = strspl(s1, s2);
  481.     }
  482. }
  483. static void addpath(char c)
  484. {
  485.     if (gpathp >= lastgpathp)
  486. globerr = "Pathname too long";
  487.     else {
  488. *gpathp++ = c;
  489. *gpathp = 0;
  490.     }
  491. }
  492. static void rscan(register char **t, int (*f) (register char))
  493. {
  494.     register char *p, c;
  495.     while ((p = *t++)) {
  496. if (*p == '~')
  497.     gflag |= 2;
  498. else if (eq(p, "{") || eq(p, "{}"))
  499.     continue;
  500. while ((c = *p++))
  501.     (*f) (c);
  502.     }
  503. }
  504. static int tglob(register char c)
  505. {
  506.     if (any(c, globchars))
  507. gflag |= c == '{' ? 2 : 1;
  508.     return (c);
  509. }
  510. int letter(register char c)
  511. {
  512.     return (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'))
  513.     || (c == '_'));
  514. }
  515. int digit(register char c)
  516. {
  517.     return (c >= '0' && c <= '9');
  518. }
  519. int any(register int c, register char *s)
  520. {
  521.     while (*s)
  522. if (*s++ == c)
  523.     return (1);
  524.     return (0);
  525. }
  526. int blklen(register char **av)
  527. {
  528.     register int i = 0;
  529.     while (*av++)
  530. i++;
  531.     return (i);
  532. }
  533. char **blkcpy(char **oav, register char **bv)
  534. {
  535.     register char **av = oav;
  536.     while ((*av++ = *bv++))
  537. continue;
  538.     return (oav);
  539. }
  540. void blkfree(char **av0)
  541. {
  542.     register char **av = av0;
  543.     while (*av)
  544. free(*av++);
  545. }
  546. char *strspl(register char *cp, register char *dp)
  547. {
  548.     register char *ep =
  549.     (char *) malloc((unsigned) (strlen(cp) + strlen(dp) + 1));
  550.     if (ep == (char *) 0)
  551. fatal("Out of memory");
  552.     (void) strcpy(ep, cp);
  553.     (void) strcat(ep, dp);
  554.     return (ep);
  555. }
  556. char **copyblk(register char **v)
  557. {
  558.     register char **nv = (char **) malloc((unsigned) ((blklen(v) + 1) *
  559.       sizeof(char **)));
  560.     if (nv == (char **) 0)
  561. fatal("Out of memory");
  562.     return (blkcpy(nv, v));
  563. }
  564. static char *strend(register char *cp)
  565. {
  566.     while (*cp)
  567. cp++;
  568.     return (cp);
  569. }
  570. /*
  571.  * Extract a home directory from the password file
  572.  * The argument points to a buffer where the name of the
  573.  * user whose home directory is sought is currently.
  574.  * We write the home directory of the user back there.
  575.  */
  576. int gethdir(char *home)
  577. {
  578.     register struct passwd *pp = getpwnam(home);
  579.     register char *root = NULL;
  580.     if (!pp || home + strlen(pp->pw_dir) >= lastgpathp)
  581. return (1);
  582.     root = strstr(pp->pw_dir, "/./");
  583.     (void) strcpy(home, root ? (root + 2) : pp->pw_dir);
  584.     return (0);
  585. }