ReactOS  0.4.13-dev-257-gfabbd7c
glob.c
Go to the documentation of this file.
1 /* glob.c
2  *
3  * Copyright (c) 1996-2001 Mike Gleason, NCEMRSoft.
4  * All rights reserved.
5  *
6  */
7 
8 #include "syshdrs.h"
9 
10 static const char *rwx[9] = { "---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx", NULL };
11 
12 
13 
14 /* We need to use this because using NLST gives us more stuff than
15  * we want back sometimes. For example, say we have:
16  *
17  * /a (directory)
18  * /a/b (directory)
19  * /a/b/b1
20  * /a/b/b2
21  * /a/b/b3
22  * /a/c (directory)
23  * /a/c/c1
24  * /a/c/c2
25  * /a/c/c3
26  * /a/file
27  *
28  * If you did an "echo /a/<star>" in a normal unix shell, you would expect
29  * to get back /a/b /a/c /a/file. But NLST gives back:
30  *
31  * /a/b/b1
32  * /a/b/b2
33  * /a/b/b3
34  * /a/c/c1
35  * /a/c/c2
36  * /a/c/c3
37  * /a/file
38  *
39  * So we use the following routine to convert into the format I expect.
40  */
41 
42 static void
43 RemoteGlobCollapse(const char *pattern, LineListPtr fileList)
44 {
45  LinePtr lp, nextLine;
46  string patPrefix;
47  string cur, prev;
48  char *endp, *cp, *dp;
49  const char *pp;
50  int wasGlobChar;
51  size_t plen;
52 
53  /* Copy all characters before the first glob-char. */
54  dp = patPrefix;
55  endp = dp + sizeof(patPrefix) - 1;
56  wasGlobChar = 0;
57  for (cp = (char *) pattern; dp < endp; ) {
58  for (pp=kGlobChars; *pp != '\0'; pp++) {
59  if (*pp == *cp) {
60  wasGlobChar = 1;
61  break;
62  }
63  }
64  if (wasGlobChar)
65  break;
66  *dp++ = *cp++;
67  }
68  *dp = '\0';
69  plen = (size_t) (dp - patPrefix);
70 
71  *prev = '\0';
72  for (lp=fileList->first; lp != NULL; lp = nextLine) {
73  nextLine = lp->next;
74  if (strncmp(lp->line, patPrefix, plen) == 0) {
75  (void) STRNCPY(cur, lp->line + plen);
76  cp = strchr(cur, '/');
77  if (cp == NULL)
78  cp = strchr(cur, '\\');
79  if (cp != NULL)
80  *cp = '\0';
81  if ((*prev != '\0') && (STREQ(cur, prev))) {
82  nextLine = RemoveLine(fileList, lp);
83  } else {
84  (void) STRNCPY(prev, cur);
85  /* We are playing with a dynamically
86  * allocated string, but since the
87  * following expression is guaranteed
88  * to be the same or shorter, we won't
89  * overwrite the bounds.
90  */
91  (void) sprintf(lp->line, "%s%s", patPrefix, cur);
92  }
93  }
94  }
95 } /* RemoteGlobCollapse */
96 
97 
98 
99 
100 #if 0
101 /* May need this later. */
102 static void
103 CheckForLS_d(FTPCIPtr cip)
104 {
105  LineList lines;
106  char *cp;
107 
109  if (FTPListToMemory2(cip, ".", &lines, "-d ", 0, (int *) 0) == kNoErr) {
110  if ((lines.first != NULL) && (lines.first == lines.last)) {
111  /* If we have only one item in the list, see if it really was
112  * an error message we would recognize.
113  */
114  cp = strchr(lines.first->line, ':');
115  if ((cp != NULL) && STREQ(cp, ": No such file or directory")) {
117  } else {
119  }
120  } else {
122  }
123  } else {
125  }
127  }
128 } /* CheckForLS_d */
129 #endif
130 
131 
132 
133 
134 static int
136 {
137  int mon; /* 0..11 */
138 
139  switch (*cp++) {
140  case 'A':
141  mon = (*cp == 'u') ? 7 : 3;
142  break;
143  case 'D':
144  mon = 11;
145  break;
146  case 'F':
147  mon = 1;
148  break;
149  default:
150  case 'J':
151  if (*cp++ == 'u')
152  mon = (*cp == 'l') ? 6 : 5;
153  else
154  mon = 0;
155  break;
156  case 'M':
157  mon = (*++cp == 'r') ? 2 : 4;
158  break;
159  case 'N':
160  mon = 10;
161  break;
162  case 'O':
163  mon = 9;
164  break;
165  case 'S':
166  mon = 8;
167  }
168  return (mon);
169 } /* LsMonthNameToNum */
170 
171 
172 
173 
174 static int
175 UnDosLine( char *const line,
176  const char *const curdir,
177  size_t curdirlen,
178  char *fname,
179  size_t fnamesize,
180  int *ftype,
182  time_t *ftime)
183 {
184  char *cp;
185  int hour, year;
186  char *filestart;
187  char *sizestart;
188  struct tm ftm;
189 
190  /*
191  *
192 0123456789012345678901234567890123456789012345678901234567890123456789
193 04-27-99 10:32PM 270158 Game booklet.pdf
194 03-11-99 10:03PM <DIR> Get A3d Banner
195 
196 We also try to parse the format from CMD.EXE, which is similar:
197 
198 03/22/2001 06:23p 62,325 cls.pdf
199 
200  *
201  */
202  cp = line;
203  if (
204  isdigit((int) cp[0])
205  && isdigit((int) cp[1])
206  && ispunct((int) cp[2])
207  && isdigit((int) cp[3])
208  && isdigit((int) cp[4])
209  && ispunct((int) cp[5])
210  && isdigit((int) cp[6])
211  && isdigit((int) cp[7])
212  ) {
213  (void) memset(&ftm, 0, sizeof(struct tm));
214  ftm.tm_isdst = -1;
215  cp[2] = '\0';
216  ftm.tm_mon = atoi(cp + 0);
217  if (ftm.tm_mon > 0)
218  ftm.tm_mon -= 1;
219  cp[5] = '\0';
220  ftm.tm_mday = atoi(cp + 3);
221  if ((isdigit((int) cp[8])) && (isdigit((int) cp[9]))) {
222  /* Four-digit year */
223  cp[10] = '\0';
224  year = atoi(cp + 6);
225  if (year > 1900)
226  year -= 1900;
227  ftm.tm_year = year; /* years since 1900 */
228  cp += 11;
229  } else {
230  /* Two-digit year */
231  cp[8] = '\0';
232  year = atoi(cp + 6);
233  if (year < 98)
234  year += 100;
235  ftm.tm_year = year; /* years since 1900 */
236  cp += 9;
237  }
238 
239  for (;;) {
240  if (*cp == '\0')
241  return (-1);
242  if (isdigit(*cp))
243  break;
244  cp++;
245  }
246 
247  cp[2] = '\0';
248  hour = atoi(cp);
249  if (((cp[5] == 'P') || (cp[5] == 'p')) && (hour < 12))
250  hour += 12;
251  else if (((cp[5] == 'A') || (cp[5] == 'a')) && (hour == 12))
252  hour -= 12;
253  ftm.tm_hour = hour;
254  cp[5] = '\0';
255  ftm.tm_min = atoi(cp + 3);
256  *ftime = mktime(&ftm);
257  if (*ftype == (time_t) -1)
258  return (-1);
259 
260  cp += 6;
261  *ftype = '-';
262  for (;;) {
263  if (*cp == '\0')
264  return (-1);
265  if ((*cp == '<') && (cp[1] == 'D')) {
266  /* found <DIR> */
267  *ftype = 'd';
268  cp += 5;
269  break; /* size field will end up being empty string */
270  } else if ((*cp == '<') && (cp[1] == 'J')) {
271  /* found <JUNCTION>
272  *
273  * Will we ever really see this?
274  * IIS from Win2000sp1 sends <DIR>
275  * for FTP, but CMD.EXE prints
276  * <JUNCTION>.
277  */
278  *ftype = 'd';
279  cp += 10;
280  break;
281  } else if (isdigit(*cp)) {
282  break;
283  } else {
284  cp++;
285  }
286  }
287 
288  sizestart = cp;
289  for (;;) {
290  if (*cp == '\0')
291  return (-1);
292 #ifdef HAVE_MEMMOVE
293  if (*cp == ',') {
294  /* Yuck -- US Locale dependency */
295  memmove(cp, cp + 1, strlen(cp + 1) + 1);
296  }
297 #endif
298  if (!isdigit(*cp)) {
299  *cp++ = '\0';
300  break;
301  }
302  cp++;
303  }
304 
305  if (fsize != NULL) {
306 #if defined(HAVE_LONG_LONG) && defined(SCANF_LONG_LONG)
307  if (*ftype == 'd')
308  *fsize = 0;
309  else
310  (void) sscanf(sizestart, SCANF_LONG_LONG, fsize);
311 #elif defined(HAVE_LONG_LONG) && defined(HAVE_STRTOQ)
312  if (*ftype == 'd')
313  *fsize = 0;
314  else
315  *fsize = (longest_int) strtoq(sizestart, NULL, 0);
316 #else
317  *fsize = (longest_int) 0;
318  if (*ftype != 'd') {
319  long fsize2 = 0L;
320 
321  (void) sscanf(sizestart, "%ld", &fsize2);
322  *fsize = (longest_int) fsize2;
323  }
324 #endif
325  }
326 
327  for (;;) {
328  if (*cp == '\0')
329  return (-1);
330  if (!isspace(*cp)) {
331  break;
332  }
333  cp++;
334  }
335 
336  filestart = cp;
337  if (curdirlen == 0) {
338  (void) Strncpy(fname, filestart, fnamesize);
339  } else {
340  (void) Strncpy(fname, curdir, fnamesize);
341  (void) Strncat(fname, filestart, fnamesize);
342  }
343 
344  return (0);
345  }
346  return (-1);
347 } /* UnDosLine */
348 
349 
350 
351 
352 static int
353 UnLslRLine( char *const line,
354  const char *const curdir,
355  size_t curdirlen,
356  char *fname,
357  size_t fnamesize,
358  char *linkto,
359  size_t linktosize,
360  int *ftype,
362  time_t *ftime,
363  time_t now,
364  int thisyear,
365  int *plugend)
366 {
367  char *cp;
368  int mon = 0, dd = 0, hr = 0, min = 0, year = 0;
369  char *monstart, *ddstart, *hrstart, *minstart, *yearstart;
370  char *linktostart, *filestart = NULL;
371  char *sizestart;
372  char *pe;
373  struct tm ftm;
374 
375  /*
376  * Look for the digit just before the space
377  * before the month name.
378  *
379 -rw-rw---- 1 gleason sysdev 33404 Mar 24 01:29 RCmd.o
380 -rw-rw-r-- 1 gleason sysdevzz 1829 Jul 7 1996 README
381 -rw-rw-r-- 1 gleason sysdevzz 1829 Jul 7 1996 README
382 -rw-rw-r-- 1 gleason sysdevzz 1829 Jul 7 1996 README
383 -rw-rw-r-- 1 gleason sysdevzz 1829 Jul 7 1996 README
384  *
385  *------------------------------^
386  * 0123456789012345
387  *------plugend--------^
388  * 9876543210
389  *
390  */
391  for (cp = line; *cp != '\0'; cp++) {
392  if ( (isdigit((int) *cp))
393  && (isspace((int) cp[1]))
394  && (isupper((int) cp[2]))
395  && (islower((int) cp[3]))
396  /* && (islower((int) cp[4])) */
397  && (isspace((int) cp[5]))
398  && (
399 ((isdigit((int) cp[6])) && (isdigit((int) cp[7])))
400 || ((isdigit((int) cp[6])) && (isspace((int) cp[7])))
401 || ((isspace((int) cp[6])) && (isdigit((int) cp[7])))
402  )
403  && (isspace((int) cp[8]))
404  ) {
405  monstart = cp + 2;
406  ddstart = cp + 6;
407  if ( ((isspace((int) cp[9])) || (isdigit((int) cp[9])))
408  && (isdigit((int) cp[10]))
409  && (isdigit((int) cp[11]))
410  && (isdigit((int) cp[12]))
411  && ((isdigit((int) cp[13])) || (isspace((int) cp[13])))
412  ) {
413  /* "Mon DD YYYY" form */
414  yearstart = cp + 9;
415  if (isspace((int) *yearstart))
416  yearstart++;
417  hrstart = NULL;
418  minstart = NULL;
419  filestart = cp + 15;
420  cp[1] = '\0'; /* end size */
421  cp[5] = '\0'; /* end mon */
422  cp[8] = '\0'; /* end dd */
423  cp[14] = '\0'; /* end year */
424  mon = LsMonthNameToNum(monstart);
425  dd = atoi(ddstart);
426  hr = 23;
427  min = 59;
428  year = atoi(yearstart);
429 
430  pe = cp;
431  while (isdigit((int) *pe))
432  pe--;
433  while (isspace((int) *pe))
434  pe--;
435  *plugend = (int) (pe - line) + 1;
436  break;
437  } else if ( /*
438  * Windows NT does not 0 pad.
439  (isdigit((int) cp[9])) &&
440  */
441  (isdigit((int) cp[10]))
442  && (cp[11] == ':')
443  && (isdigit((int) cp[12]))
444  && (isdigit((int) cp[13]))
445  ) {
446  /* "Mon DD HH:MM" form */
447  yearstart = NULL;
448  hrstart = cp + 9;
449  minstart = cp + 12;
450  filestart = cp + 15;
451  cp[1] = '\0'; /* end size */
452  cp[5] = '\0'; /* end mon */
453  cp[8] = '\0'; /* end dd */
454  cp[11] = '\0'; /* end hr */
455  cp[14] = '\0'; /* end min */
456  mon = LsMonthNameToNum(monstart);
457  dd = atoi(ddstart);
458  hr = atoi(hrstart);
459  min = atoi(minstart);
460  year = 0;
461 
462  pe = cp;
463  while (isdigit((int) *pe))
464  pe--;
465  while (isspace((int) *pe))
466  pe--;
467  *plugend = (int) (pe - line) + 1;
468  break;
469  }
470  }
471  }
472 
473  if (*cp == '\0')
474  return (-1);
475 
476  linktostart = strstr(filestart, " -> ");
477  if (linktostart != NULL) {
478  *linktostart = '\0';
479  linktostart += 4;
480  (void) Strncpy(linkto, linktostart, linktosize);
481  } else {
482  *linkto = '\0';
483  }
484 
485  if (curdirlen == 0) {
486  (void) Strncpy(fname, filestart, fnamesize);
487  } else {
488  (void) Strncpy(fname, curdir, fnamesize);
489  (void) Strncat(fname, filestart, fnamesize);
490  }
491 
492  if (ftime != NULL) {
493  (void) memset(&ftm, 0, sizeof(struct tm));
494  ftm.tm_mon = mon;
495  ftm.tm_mday = dd;
496  ftm.tm_hour = hr;
497  ftm.tm_min = min;
498  ftm.tm_isdst = -1;
499  if (year == 0) {
500  /* We guess the year, based on what the
501  * current year is. We know the file
502  * on the remote server is either less
503  * than six months old or less than
504  * one hour into the future.
505  */
506  ftm.tm_year = thisyear - 1900;
507  *ftime = mktime(&ftm);
508  if (*ftime == (time_t) -1) {
509  /* panic */
510  } else if (*ftime > (now + (15552000L + 86400L))) {
511  --ftm.tm_year;
512  *ftime = mktime(&ftm);
513  } else if (*ftime < (now - (15552000L + 86400L))) {
514  ++ftm.tm_year;
515  *ftime = mktime(&ftm);
516  }
517  } else {
518  ftm.tm_year = year - 1900;
519  *ftime = mktime(&ftm);
520  }
521  }
522 
523  if (fsize != NULL) {
524  while ((cp > line) && (isdigit((int) *cp)))
525  --cp;
526  sizestart = cp + 1;
527 #if defined(HAVE_LONG_LONG) && defined(SCANF_LONG_LONG)
528  (void) sscanf(sizestart, SCANF_LONG_LONG, fsize);
529 #elif defined(HAVE_LONG_LONG) && defined(HAVE_STRTOQ)
530  *fsize = (longest_int) strtoq(sizestart, NULL, 0);
531 #else
532  {
533  long fsize2 = 0L;
534 
535  (void) sscanf(sizestart, "%ld", &fsize2);
536  *fsize = (longest_int) fsize2;
537  }
538 #endif
539  }
540 
541  switch (line[0]) {
542  case 'd':
543  case 'l':
544  *ftype = (int) line[0];
545  break;
546  case 'b':
547  case 'c':
548  case 's':
549  *ftype = (int) line[0];
550  return (-1);
551  default:
552  *ftype = '-';
553  }
554 
555  return (0);
556 } /* UnLslRLine */
557 
558 
559 
560 int
561 UnLslR(FileInfoListPtr filp, LineListPtr llp, int serverType)
562 {
563  char curdir[256];
564  char line[256];
565  int hadblankline = 0;
566  int len;
567  size_t curdirlen = 0;
568  char fname[256];
569  char linkto[256];
570  char *cp;
572  int ftype;
573  time_t ftime, now;
574  int thisyear;
575  struct tm *nowtm;
576  int rc;
577  LinePtr lp;
578  FileInfo fi;
579  int linesread = 0;
580  int linesconverted = 0;
581  size_t maxFileLen = 0;
582  size_t maxPlugLen = 0;
583  size_t fileLen;
584  int plugend;
585 
586  (void) time(&now);
587  nowtm = localtime(&now);
588  if (nowtm == NULL)
589  thisyear = 1970; /* should never happen */
590  else
591  thisyear = nowtm->tm_year + 1900;
592 
593  curdir[0] = '\0';
594 
595  InitFileInfoList(filp);
596  for (lp = llp->first; lp != NULL; lp = lp->next) {
597  len = (int) strlen(STRNCPY(line, lp->line));
598  if ((line[0] == 't') && (strncmp(line, "total", 5) == 0)) {
599  /* total XX line? */
600  if (line[len - 1] != ':') {
601  hadblankline = 0;
602  continue;
603  }
604  /* else it was a subdir named total */
605  } else {
606  for (cp = line; ; cp++) {
607  if ((*cp == '\0') || (!isspace((int) *cp)))
608  break;
609  }
610  if (*cp == '\0') {
611  /* Entire line was blank. */
612  /* separator line between dirs */
613  hadblankline = 1;
614  continue;
615  }
616  }
617 
618  if ((hadblankline != 0) && (line[len - 1] == ':')) {
619  /* newdir */
620  hadblankline = 0;
621  if ((line[0] == '.') && (line[1] == '/')) {
622  line[len - 1] = '/';
623  (void) memcpy(curdir, line + 2, (size_t) len + 1 - 2);
624  curdirlen = (size_t) (len - 2);
625  } else if ((line[0] == '.') && (line[1] == '\\')) {
626  line[len - 1] = '\\';
627  (void) memcpy(curdir, line + 2, (size_t) len + 1 - 2);
628  curdirlen = (size_t) (len - 2);
629  } else {
630  line[len - 1] = '/';
631  (void) memcpy(curdir, line, (size_t) len + 1);
632  curdirlen = (size_t) len;
633  }
634  continue;
635  }
636 
637  linesread++;
638  rc = UnLslRLine(line, curdir, curdirlen, fname, sizeof(fname), linkto, sizeof(linkto), &ftype, &fsize, &ftime, now, thisyear, &plugend);
639  if ((rc < 0) && (serverType == kServerTypeMicrosoftFTP)) {
640  rc = UnDosLine(line, curdir, curdirlen, fname, sizeof(fname), &ftype, &fsize, &ftime);
641  if (rc == 0) {
642  *linkto = '\0';
643  plugend = 0;
644  }
645  }
646  if (rc == 0) {
647  linesconverted++;
648  fileLen = strlen(fname);
649  if (fileLen > maxFileLen)
650  maxFileLen = fileLen;
651  fi.relnameLen = fileLen;
652  fi.relname = StrDup(fname);
653  fi.rname = NULL;
654  fi.lname = NULL;
655  fi.rlinkto = (linkto[0] == '\0') ? NULL : StrDup(linkto);
656  fi.mdtm = ftime;
657  fi.size = (longest_int) fsize;
658  fi.type = ftype;
659  if (plugend > 0) {
660  fi.plug = (char *) malloc((size_t) plugend + 1);
661  if (fi.plug != NULL) {
662  (void) memcpy(fi.plug, line, (size_t) plugend);
663  fi.plug[plugend] = '\0';
664  if ((size_t) plugend > maxPlugLen)
665  maxPlugLen = (size_t) plugend;
666  }
667  } else {
668  fi.plug = (char *) malloc(32);
669  if (fi.plug != NULL) {
670  strcpy(fi.plug, "---------- 1 ftpuser ftpusers");
671  fi.plug[0] = (char) ftype;
672  if (30 > maxPlugLen)
673  maxPlugLen = (size_t) 30;
674  }
675  }
676  (void) AddFileInfo(filp, &fi);
677  }
678 
679  hadblankline = 0;
680  }
681 
682  filp->maxFileLen = maxFileLen;
683  filp->maxPlugLen = maxPlugLen;
684  if (linesread == 0)
685  return (0);
686  return ((linesconverted > 0) ? linesconverted : (-1));
687 } /* UnLslR */
688 
689 
690 
691 
692 int
693 UnMlsT(const char *const line0, const MLstItemPtr mlip)
694 {
695  char *cp, *val, *fact;
696  int ec;
697  size_t len;
698  char line[1024];
699 
700  memset(mlip, 0, sizeof(MLstItem));
701  mlip->mode = -1;
702  mlip->fsize = kSizeUnknown;
703  mlip->ftype = '-';
704  mlip->ftime = kModTimeUnknown;
705 
706  len = strlen(line0);
707  if (len > (sizeof(line) - 1))
708  return (-1); /* Line too long, sorry. */
709  /* This should be re-coded so does not need to make a
710  * copy of the buffer; it could be done in place.
711  */
712  memcpy(line, line0, len + 1);
713 
714  /* Skip leading whitespace. */
715  for (cp = line; *cp != '\0'; cp++) {
716  if (! isspace(*cp))
717  break;
718  }
719 
720  while (*cp != '\0') {
721  for (fact = cp; ; cp++) {
722  if ((*cp == '\0') || (*cp == ' ')) {
723  /* protocol violation */
724  return (-1);
725  }
726  if (*cp == '=') {
727  /* End of fact name. */
728  *cp++ = '\0';
729  break;
730  }
731  }
732  for (val = cp; ; cp++) {
733  if (*cp == '\0') {
734  /* protocol violation */
735  return (-1);
736  }
737  if (*cp == ' ') {
738  ec = ' ';
739  *cp++ = '\0';
740  break;
741  } else if (*cp == ';') {
742  if (cp[1] == ' ') {
743  ec = ' ';
744  *cp++ = '\0';
745  *cp++ = '\0';
746  } else {
747  ec = ';';
748  *cp++ = '\0';
749  }
750  break;
751  }
752  }
753  if (ISTRNEQ(fact, "OS.", 3))
754  fact += 3;
755  if (ISTREQ(fact, "type")) {
756  if (ISTREQ(val, "file")) {
757  mlip->ftype = '-';
758  } else if (ISTREQ(val, "dir")) {
759  mlip->ftype = 'd';
760  } else if (ISTREQ(val, "cdir")) {
761  /* not supported: current directory */
762  return (-2);
763  } else if (ISTREQ(val, "pdir")) {
764  /* not supported: parent directory */
765  return (-2);
766  } else {
767  /* ? */
768  return (-1);
769  }
770  } else if (ISTREQ(fact, "UNIX.mode")) {
771  if (val[0] == '0')
772  sscanf(val, "%o", &mlip->mode);
773  else
774  sscanf(val, "%i", &mlip->mode);
775  if (mlip->mode != (-1))
776  mlip->mode &= 00777;
777  } else if (ISTREQ(fact, "perm")) {
778  STRNCPY(mlip->perm, val);
779  } else if (ISTREQ(fact, "size")) {
780 #if defined(HAVE_LONG_LONG) && defined(SCANF_LONG_LONG)
781  (void) sscanf(val, SCANF_LONG_LONG, &mlip->fsize);
782 #elif defined(HAVE_LONG_LONG) && defined(HAVE_STRTOQ)
783  mlip->fsize = (longest_int) strtoq(val, NULL, 0);
784 #else
785  {
786  long fsize2 = 0L;
787 
788  (void) sscanf(val, "%ld", &fsize2);
789  mlip->fsize = (longest_int) fsize2;
790  }
791 #endif
792  } else if (ISTREQ(fact, "modify")) {
793  mlip->ftime = UnMDTMDate(val);
794  } else if (ISTREQ(fact, "UNIX.owner")) {
795  STRNCPY(mlip->owner, val);
796  } else if (ISTREQ(fact, "UNIX.group")) {
797  STRNCPY(mlip->group, val);
798  } else if (ISTREQ(fact, "UNIX.uid")) {
799  mlip->uid = atoi(val);
800  } else if (ISTREQ(fact, "UNIX.gid")) {
801  mlip->gid = atoi(val);
802  } else if (ISTREQ(fact, "perm")) {
803  STRNCPY(mlip->perm, val);
804  }
805 
806  /* End of facts? */
807  if (ec == ' ')
808  break;
809  }
810 
811  len = strlen(cp);
812  if (len > (sizeof(mlip->fname) - 1)) {
813  /* Filename too long */
814  return (-1);
815  }
816  memcpy(mlip->fname, cp, len);
817 
818  /* also set linkto here if used */
819 
820  return (0);
821 } /* UnMlsT */
822 
823 
824 
825 
826 int
828 {
829  MLstItem mli;
830  char plug[64];
831  char og[32];
832  int rc;
833  LinePtr lp;
834  FileInfo fi;
835  int linesread = 0;
836  int linesconverted = 0;
837  int linesignored = 0;
838  size_t maxFileLen = 0;
839  size_t maxPlugLen = 0;
840  size_t fileLen, plugLen;
841  int m1, m2, m3;
842  const char *cm1, *cm2, *cm3;
843 
844  InitFileInfoList(filp);
845  for (lp = llp->first; lp != NULL; lp = lp->next) {
846  linesread++;
847  rc = UnMlsT(lp->line, &mli);
848  if (rc == 0) {
849  linesconverted++;
850  fileLen = strlen(mli.fname);
851  if (fileLen > maxFileLen)
852  maxFileLen = fileLen;
853  fi.relnameLen = fileLen;
854  fi.relname = StrDup(mli.fname);
855  fi.rname = NULL;
856  fi.lname = NULL;
857  fi.rlinkto = (mli.linkto[0] == '\0') ? NULL : StrDup(mli.linkto);
858  fi.mdtm = mli.ftime;
859  fi.size = (longest_int) mli.fsize;
860  fi.type = mli.ftype;
861  plug[0] = (char) mli.ftype;
862  plug[1] = '\0';
863  m1 = 0;
864  m2 = 0;
865  m3 = -1;
866  if (mli.mode != (-1)) {
867  m1 = (mli.mode & 00700) >> 6;
868  m2 = (mli.mode & 00070) >> 3;
869  m3 = (mli.mode & 00007);
870  }
871  if (mli.perm[0] != '\0') {
872  m3 = 0;
873  if (fi.type == 'd') {
874  if (strchr(mli.perm, 'e') != NULL) {
875  /* execute -> execute */
876  m3 |= 00001;
877  }
878  if (strchr(mli.perm, 'c') != NULL) {
879  /* create -> write */
880  m3 |= 00002;
881  }
882  if (strchr(mli.perm, 'l') != NULL) {
883  /* list -> read */
884  m3 |= 00004;
885  }
886  } else {
887  if (strchr(mli.perm, 'w') != NULL) {
888  /* write -> write */
889  m3 |= 00002;
890  }
891  if (strchr(mli.perm, 'r') != NULL) {
892  /* read -> read */
893  m3 |= 00004;
894  }
895  }
896  }
897  if (m3 != (-1)) {
898  cm1 = rwx[m1];
899  cm2 = rwx[m2];
900  cm3 = rwx[m3];
901  sprintf(plug + 1, "%s%s%s", cm1, cm2, cm3);
902  }
903  if (mli.owner[0] != '\0') {
904  if (mli.group[0] != '\0') {
905 #ifdef HAVE_SNPRINTF
906  snprintf(og, sizeof(og) - 1,
907 #else
908  sprintf(og,
909 #endif /* HAVE_SNPRINTF */
910  " %-8.8s %s",
911  mli.owner, mli.group
912  );
913  STRNCAT(plug, og);
914  } else {
915  STRNCAT(plug, " ");
916  STRNCAT(plug, mli.owner);
917  }
918  }
919  fi.plug = StrDup(plug);
920  if (fi.plug != NULL) {
921  plugLen = strlen(plug);
922  if (plugLen > maxPlugLen)
923  maxPlugLen = plugLen;
924  }
925  (void) AddFileInfo(filp, &fi);
926  } else if (rc == (-2)) {
927  linesignored++;
928  }
929  }
930 
931  filp->maxFileLen = maxFileLen;
932  filp->maxPlugLen = maxPlugLen;
933  if (linesread == 0)
934  return (0);
935  linesconverted += linesignored;
936  return ((linesconverted > 0) ? linesconverted : (-1));
937 } /* UnMlsD */
938 
939 
940 
941 #if 0
942 static void
943 print1(FileInfoListPtr list)
944 {
945  FileInfoPtr fip;
946  int i;
947 
948  for (i = 1, fip = list->first; fip != NULL; fip = fip->next, i++)
949  printf("%d: %s\n", i, fip->relname == NULL ? "NULL" : fip->relname);
950 }
951 
952 
953 
954 static void
955 print2(FileInfoListPtr list)
956 {
957  FileInfoPtr fip;
958  int i, n;
959 
960  n = list->nFileInfos;
961  for (i=0; i<n; i++) {
962  fip = list->vec[i];
963  printf("%d: %s\n", i + 1, fip->relname == NULL ? "NULL" : fip->relname);
964  }
965 }
966 
967 
968 
969 
970 static void
971 SortRecursiveFileList(FileInfoListPtr files)
972 {
973  VectorizeFileInfoList(files);
974  SortFileInfoList(files, 'b', '?');
976 } /* SortRecursiveFileList */
977 #endif
978 
979 
980 
981 
982 int
984 {
985  LineList dirContents;
986  FileInfoList fil;
987  char cwd[512];
988  int result;
989 
990  if ((result = FTPGetCWD(cip, cwd, sizeof(cwd))) < 0)
991  return (result);
992 
993  InitFileInfoList(files);
994 
995  if (rdir == NULL)
996  return (-1);
997 
998  if (FTPChdir(cip, rdir) < 0) {
999  /* Probably not a directory.
1000  * Just add it as a plain file
1001  * to the list.
1002  */
1003  (void) ConcatFileToFileInfoList(files, rdir);
1004  return (kNoErr);
1005  }
1006 
1007  /* Paths collected must be relative. */
1008  if ((result = FTPListToMemory2(cip, "", &dirContents, "-lRa", 1, (int *) 0)) < 0) {
1009  if ((result = FTPChdir(cip, cwd)) < 0) {
1010  return (result);
1011  }
1012  }
1013 
1014  (void) UnLslR(&fil, &dirContents, cip->serverType);
1015  DisposeLineListContents(&dirContents);
1016  /* Could sort it to breadth-first here. */
1017  /* (void) SortRecursiveFileList(&fil); */
1018  (void) ComputeRNames(&fil, rdir, 1, 1);
1019  (void) ConcatFileInfoList(files, &fil);
1021 
1022  if ((result = FTPChdir(cip, cwd)) < 0) {
1023  return (result);
1024  }
1025  return (kNoErr);
1026 } /* FTPRemoteRecursiveFileList1 */
1027 
1028 
1029 
1030 
1031 int
1033 {
1034  LinePtr filePtr, nextFilePtr;
1035  LineList dirContents;
1036  FileInfoList fil;
1037  char cwd[512];
1038  int result;
1039  char *rdir;
1040 
1041  if ((result = FTPGetCWD(cip, cwd, sizeof(cwd))) < 0)
1042  return (result);
1043 
1044  InitFileInfoList(files);
1045 
1046  for (filePtr = fileList->first;
1047  filePtr != NULL;
1048  filePtr = nextFilePtr)
1049  {
1050  nextFilePtr = filePtr->next;
1051 
1052  rdir = filePtr->line;
1053  if (rdir == NULL)
1054  continue;
1055 
1056  if (FTPChdir(cip, rdir) < 0) {
1057  /* Probably not a directory.
1058  * Just add it as a plain file
1059  * to the list.
1060  */
1061  (void) ConcatFileToFileInfoList(files, rdir);
1062  continue;
1063  }
1064 
1065  /* Paths collected must be relative. */
1066  if ((result = FTPListToMemory2(cip, "", &dirContents, "-lRa", 1, (int *) 0)) < 0) {
1067  goto goback;
1068  }
1069 
1070  (void) UnLslR(&fil, &dirContents, cip->serverType);
1071  DisposeLineListContents(&dirContents);
1072  (void) ComputeRNames(&fil, rdir, 1, 1);
1073  (void) ConcatFileInfoList(files, &fil);
1075 
1076 goback:
1077  if ((result = FTPChdir(cip, cwd)) < 0) {
1078  return (result);
1079  }
1080  }
1081  return (kNoErr);
1082 } /* FTPRemoteRecursiveFileList */
1083 
1084 
1085 
1086 #if defined(WIN32) || defined(_WINDOWS)
1087 
1088 static void
1089 Traverse(FTPCIPtr cip, char *fullpath, struct Stat *st, char *relpath, FileInfoListPtr filp)
1090 {
1091  WIN32_FIND_DATA ffd;
1092  HANDLE searchHandle;
1093  DWORD dwErr;
1094  char *cp, *c2;
1095  const char *file;
1096  FileInfo fi;
1097 
1098  /* Handle directory entry first. */
1099  if (relpath[0] != '\0') {
1100  fi.relname = StrDup(relpath);
1101  fi.rname = NULL;
1102  fi.lname = StrDup(fullpath);
1103  fi.rlinkto = NULL;
1104  fi.plug = NULL;
1105  fi.mdtm = st->st_mtime;
1106  fi.size = (longest_int) st->st_size;
1107  fi.type = 'd';
1108  (void) AddFileInfo(filp, &fi);
1109  }
1110 
1111  cp = fullpath + strlen(fullpath);
1112  *cp++ = LOCAL_PATH_DELIM;
1113  strcpy(cp, "*.*");
1114 
1115  c2 = relpath + strlen(relpath);
1116  *c2++ = LOCAL_PATH_DELIM;
1117  *c2 = '\0';
1118 
1119  memset(&ffd, 0, sizeof(ffd));
1120 
1121  /* "Open" the directory. */
1122  searchHandle = FindFirstFile(fullpath, &ffd);
1123  if (searchHandle == INVALID_HANDLE_VALUE) {
1124  return;
1125  }
1126 
1127  for (;;) {
1128 
1129  file = ffd.cFileName;
1130  if ((*file == '.') && ((file[1] == '\0') || ((file[1] == '.') && (file[2] == '\0')))) {
1131  /* It was "." or "..", so skip it. */
1132  goto next;
1133  }
1134 
1135  (void) strcpy(cp, file); /* append name after slash */
1136  (void) strcpy(c2, file);
1137 
1138  if (Lstat(fullpath, st) < 0) {
1139  Error(cip, kDoPerror, "could not stat %s.\n", fullpath);
1140  goto next;
1141  }
1142 
1143  fi.relname = StrDup(relpath + (((relpath[0] == '/') || (relpath[0] == '\\')) ? 1 : 0));
1144  fi.rname = NULL;
1145  fi.lname = StrDup(fullpath);
1146  fi.mdtm = st->st_mtime;
1147  fi.size = (longest_int) st->st_size;
1148  fi.rlinkto = NULL;
1149  fi.plug = NULL;
1150 
1151  if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1152  Traverse(cip, fullpath, st, relpath, filp);
1153  } else {
1154  /* file */
1155  fi.type = '-';
1156  (void) AddFileInfo(filp, &fi);
1157  }
1158 
1159 next:
1160 #if _DEBUG
1161  memset(&ffd, 0, sizeof(ffd));
1162 #endif
1163  if (!FindNextFile(searchHandle, &ffd)) {
1164  dwErr = GetLastError();
1165  if (dwErr != ERROR_NO_MORE_FILES) {
1166  FindClose(searchHandle);
1167  return;
1168  }
1169  break;
1170  }
1171  }
1172  FindClose(searchHandle);
1173 } // Traverse
1174 
1175 #else
1176 
1177 static void
1178 Traverse(FTPCIPtr cip, char *fullpath, struct Stat *st, char *relpath, FileInfoListPtr filp)
1179 {
1180  char *dname;
1181  struct dirent *dirp;
1182  mode_t m;
1183  DIR *dp;
1184  char *cp;
1185  char *c2;
1186  FileInfo fi;
1187 
1188  if (relpath[0] != '\0') {
1189  fi.relname = StrDup(relpath);
1190  fi.rname = NULL;
1191  fi.lname = StrDup(fullpath);
1192  fi.rlinkto = NULL;
1193  fi.plug = NULL;
1194  fi.mdtm = st->st_mtime;
1195  fi.size = (longest_int) st->st_size;
1196  fi.type = 'd';
1197  (void) AddFileInfo(filp, &fi);
1198  }
1199 
1200  /* Handle directory entry first. */
1201  cp = fullpath + strlen(fullpath);
1202  *cp++ = '/';
1203  *cp = '\0';
1204 
1205  c2 = relpath + strlen(relpath);
1206  *c2++ = '/';
1207  *c2 = '\0';
1208 
1209  if ((dp = opendir(fullpath)) == NULL) {
1210  cp[-1] = '\0';
1211  c2[-1] = '\0';
1212  Error(cip, kDoPerror, "could not opendir %s.\n", fullpath);
1213  return;
1214  }
1215 
1216  while ((dirp = readdir(dp)) != NULL) {
1217  dname = dirp->d_name;
1218  if ((dname[0] == '.') && ((dname[1] == '\0') || ((dname[1] == '.') && (dname[2] == '\0'))))
1219  continue; /* skip "." and ".." directories. */
1220 
1221  (void) strcpy(cp, dirp->d_name); /* append name after slash */
1222  (void) strcpy(c2, dirp->d_name);
1223  if (Lstat(fullpath, st) < 0) {
1224  Error(cip, kDoPerror, "could not stat %s.\n", fullpath);
1225  continue;
1226  }
1227 
1228  fi.relname = StrDup(relpath + (((relpath[0] == '/') || (relpath[0] == '\\')) ? 1 : 0));
1229  fi.rname = NULL;
1230  fi.lname = StrDup(fullpath);
1231  fi.mdtm = st->st_mtime;
1232  fi.size = (longest_int) st->st_size;
1233  fi.rlinkto = NULL;
1234  fi.plug = NULL;
1235 
1236  m = st->st_mode;
1237  if (S_ISREG(m) != 0) {
1238  /* file */
1239  fi.type = '-';
1240  (void) AddFileInfo(filp, &fi);
1241  } else if (S_ISDIR(m)) {
1242  Traverse(cip, fullpath, st, relpath, filp);
1243 #ifdef S_ISLNK
1244  } else if (S_ISLNK(m)) {
1245  fi.type = 'l';
1246  fi.rlinkto = calloc(128, 1);
1247  if (fi.rlinkto != NULL) {
1248  if (readlink(fullpath, fi.rlinkto, 127) < 0) {
1249  free(fi.rlinkto);
1250  } else {
1251  (void) AddFileInfo(filp, &fi);
1252  }
1253  }
1254 #endif /* S_ISLNK */
1255  }
1256  }
1257  cp[-1] = '\0';
1258  c2[-1] = '\0';
1259 
1260  (void) closedir(dp);
1261 } /* Traverse */
1262 
1263 #endif
1264 
1265 
1266 
1267 
1268 
1269 int
1271 {
1272  LinePtr filePtr, nextFilePtr;
1273 #if defined(WIN32) || defined(_WINDOWS)
1274  char fullpath[_MAX_PATH + 1];
1275  char relpath[_MAX_PATH + 1];
1276 #else
1277  char fullpath[512];
1278  char relpath[512];
1279 #endif
1280  struct Stat st;
1281  FileInfo fi;
1282  char *cp;
1283 
1284  InitFileInfoList(files);
1285 
1286  for (filePtr = fileList->first;
1287  filePtr != NULL;
1288  filePtr = nextFilePtr)
1289  {
1290  nextFilePtr = filePtr->next;
1291 
1292  (void) STRNCPY(fullpath, filePtr->line); /* initialize fullpath */
1293  if ((erelative != 0) || (strcmp(filePtr->line, ".") == 0) || (filePtr->line[0] == '\0'))
1294  (void) STRNCPY(relpath, "");
1295  else if ((cp = StrRFindLocalPathDelim(filePtr->line)) == NULL)
1296  (void) STRNCPY(relpath, filePtr->line);
1297  else
1298  (void) STRNCPY(relpath, cp + 1);
1299  if (Lstat(fullpath, &st) < 0) {
1300  Error(cip, kDoPerror, "could not stat %s.\n", fullpath);
1301  continue;
1302  }
1303 
1304  if (S_ISDIR(st.st_mode) == 0) {
1305  fi.relname = StrDup(relpath);
1306  fi.rname = NULL;
1307  fi.lname = StrDup(fullpath);
1308  fi.mdtm = st.st_mtime;
1309  fi.size = (longest_int) st.st_size;
1310  fi.rlinkto = NULL;
1311  fi.plug = NULL;
1312  fi.type = '-';
1313  (void) AddFileInfo(files, &fi);
1314  continue; /* wasn't a directory */
1315  }
1316 
1317  /* Paths collected must be relative. */
1318  Traverse(cip, fullpath, &st, relpath, files);
1319  }
1320  return (kNoErr);
1321 } /* FTPLocalRecursiveFileList */
1322 
1323 
1324 
1325 
1326 int
1328 {
1329  return (FTPLocalRecursiveFileList2(cip, fileList, files, 0));
1330 } /* FTPLocalRecursiveFileList */
1331 
1332 
1333 
1334 int
1335 FTPRemoteGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob)
1336 {
1337  char *cp;
1338  const char *lsflags;
1339  LinePtr lp;
1340  int result;
1341 
1342  if (cip == NULL)
1343  return (kErrBadParameter);
1344  if (strcmp(cip->magic, kLibraryMagic))
1345  return (kErrBadMagic);
1346 
1347  if (fileList == NULL)
1348  return (kErrBadParameter);
1349  InitLineList(fileList);
1350 
1351  if ((pattern == NULL) || (pattern[0] == '\0'))
1352  return (kErrBadParameter);
1353 
1354  /* Note that we do attempt to use glob characters even if the remote
1355  * host isn't UNIX. Most non-UNIX remote FTP servers look for UNIX
1356  * style wildcards.
1357  */
1358  if ((doGlob == 1) && (GLOBCHARSINSTR(pattern))) {
1359  /* Use NLST, which lists files one per line. */
1360  lsflags = "";
1361 
1362  /* Optimize for "NLST *" case which is same as "NLST". */
1363  if (strcmp(pattern, "*") == 0) {
1364  pattern = "";
1365  } else if (strcmp(pattern, "**") == 0) {
1366  /* Hack; Lets you try "NLST -a" if you're daring. */
1367  pattern = "";
1368  lsflags = "-a";
1369  }
1370 
1371  if ((result = FTPListToMemory2(cip, pattern, fileList, lsflags, 0, (int *) 0)) < 0) {
1372  if (*lsflags == '\0')
1373  return (result);
1374  /* Try again, without "-a" */
1375  lsflags = "";
1376  if ((result = FTPListToMemory2(cip, pattern, fileList, lsflags, 0, (int *) 0)) < 0) {
1377  return (result);
1378  }
1379  }
1380  if (fileList->first == NULL) {
1381  cip->errNo = kErrGlobNoMatch;
1382  return (kErrGlobNoMatch);
1383  }
1384  if (fileList->first == fileList->last) {
1385 #define glberr(a) (ISTRNEQ(cp, a, strlen(a)))
1386  /* If we have only one item in the list, see if it really was
1387  * an error message we would recognize.
1388  */
1389  cp = strchr(fileList->first->line, ':');
1390  if (cp != NULL) {
1391  if (glberr(": No such file or directory")) {
1392  (void) RemoveLine(fileList, fileList->first);
1393  cip->errNo = kErrGlobFailed;
1394  return (kErrGlobFailed);
1395  } else if (glberr(": No match")) {
1396  cip->errNo = kErrGlobNoMatch;
1397  return (kErrGlobNoMatch);
1398  }
1399  }
1400  }
1401  RemoteGlobCollapse(pattern, fileList);
1402  for (lp=fileList->first; lp != NULL; lp = lp->next)
1403  PrintF(cip, " Rglob [%s]\n", lp->line);
1404  } else {
1405  /* Or, if there were no globbing characters in 'pattern', then the
1406  * pattern is really just a filename. So for this case the
1407  * file list is really just a single file.
1408  */
1409  fileList->first = fileList->last = NULL;
1410  (void) AddLine(fileList, pattern);
1411  }
1412  return (kNoErr);
1413 } /* FTPRemoteGlob */
1414 
1415 
1416 
1417 
1418 /* This does "tilde-expansion." Examples:
1419  * ~/pub --> /usr/gleason/pub
1420  * ~pdietz/junk --> /usr/pdietz/junk
1421  */
1422 static void
1423 ExpandTilde(char *pattern, size_t siz)
1424 {
1425  string pat;
1426  char *cp, *rest, *firstent;
1427 #if defined(WIN32) || defined(_WINDOWS)
1428 #else
1429  struct passwd *pw;
1430 #endif
1431  string hdir;
1432 
1433  if ((pattern[0] == '~') &&
1434  (isalnum((int) pattern[1]) || IsLocalPathDelim(pattern[1]) || (pattern[1] == '\0'))) {
1435  (void) STRNCPY(pat, pattern);
1436  if ((cp = StrFindLocalPathDelim(pat)) != NULL) {
1437  *cp = 0;
1438  rest = cp + 1; /* Remember stuff after the ~/ part. */
1439  } else {
1440  rest = NULL; /* Was just a ~ or ~username. */
1441  }
1442  if (pat[1] == '\0') {
1443  /* Was just a ~ or ~/rest type. */
1444  GetHomeDir(hdir, sizeof(hdir));
1445  firstent = hdir;
1446  } else {
1447 #if defined(WIN32) || defined(_WINDOWS)
1448  return;
1449 #else
1450  /* Was just a ~username or ~username/rest type. */
1451  pw = getpwnam(pat + 1);
1452  if (pw != NULL)
1453  firstent = pw->pw_dir;
1454  else
1455  return; /* Bad user -- leave it alone. */
1456 #endif
1457  }
1458 
1459  (void) Strncpy(pattern, firstent, siz);
1460  if (rest != NULL) {
1462  (void) Strncat(pattern, rest, siz);
1463  }
1464  }
1465 } /* ExpandTilde */
1466 
1467 
1468 
1469 
1470 
1471 #if defined(WIN32) || defined(_WINDOWS)
1472 
1473 static int
1474 WinLocalGlob(FTPCIPtr cip, LineListPtr fileList, const char *const srcpat)
1475 {
1476  char pattern[_MAX_PATH];
1477  WIN32_FIND_DATA ffd;
1478  HANDLE searchHandle;
1479  DWORD dwErr;
1480  char *cp;
1481  const char *file;
1482  int result;
1483 
1484  STRNCPY(pattern, srcpat);
1485 
1486  /* Get rid of trailing slashes. */
1487  cp = pattern + strlen(pattern) - 1;
1488  while ((cp >= pattern) && IsLocalPathDelim(*cp))
1489  *cp-- = '\0';
1490 
1491  memset(&ffd, 0, sizeof(ffd));
1492 
1493  /* "Open" the directory. */
1494  searchHandle = FindFirstFile(pattern, &ffd);
1495  if (searchHandle == INVALID_HANDLE_VALUE) {
1496  dwErr = GetLastError();
1497  return ((dwErr == 0) ? 0 : -1);
1498  }
1499 
1500  /* Get rid of basename. */
1502  if (cp == NULL)
1503  cp = pattern;
1504  else
1505  cp++;
1506  *cp = '\0';
1507 
1508  for (result = 0;;) {
1509  file = ffd.cFileName;
1510  if ((file[0] == '.') && ((file[1] == '\0') || ((file[1] == '.') && (file[2] == '\0')))) {
1511  /* skip */
1512  } else {
1513  Strncpy(cp, ffd.cFileName, sizeof(pattern) - (cp - pattern));
1514  PrintF(cip, " Lglob [%s]\n", pattern);
1515  (void) AddLine(fileList, pattern);
1516  }
1517 
1518  if (!FindNextFile(searchHandle, &ffd)) {
1519  dwErr = GetLastError();
1520  if (dwErr != ERROR_NO_MORE_FILES) {
1521  result = ((dwErr == 0) ? 0 : -1);
1522  }
1523  break;
1524  }
1525  }
1526 
1527  return (result);
1528 } // WinLocalGlob
1529 
1530 #else
1531 
1532 static int
1533 LazyUnixLocalGlob(FTPCIPtr cip, LineListPtr fileList, const char *const pattern)
1534 {
1535  string cmd;
1536  longstring gfile;
1537  FILE *fp;
1538  FTPSigProc sp;
1539 
1540  /* Do it the easy way and have the shell do the dirty
1541  * work for us.
1542  */
1543 #ifdef HAVE_SNPRINTF
1544  (void) snprintf(cmd, sizeof(cmd) - 1, "%s -c \"%s %s %s\"", "/bin/sh", "/bin/ls",
1545  "-d", pattern);
1546  cmd[sizeof(cmd) - 1] = '\0';
1547 #else
1548  (void) sprintf(cmd, "%s -c \"%s %s %s\"", "/bin/sh", "/bin/ls",
1549  "-d", pattern);
1550 #endif
1551 
1552  fp = (FILE *) popen(cmd, "r");
1553  if (fp == NULL) {
1554  Error(cip, kDoPerror, "Could not Lglob: [%s]\n", cmd);
1555  cip->errNo = kErrGlobFailed;
1556  return (kErrGlobFailed);
1557  }
1559  while (FGets(gfile, sizeof(gfile), (FILE *) fp) != NULL) {
1560  PrintF(cip, " Lglob [%s]\n", gfile);
1561  (void) AddLine(fileList, gfile);
1562  }
1563  (void) pclose(fp);
1564  (void) NcSignal(SIGPIPE, sp);
1565  return (kNoErr);
1566 } /* LazyUnixLocalGlob */
1567 
1568 #endif
1569 
1570 
1571 
1572 
1573 int
1574 FTPLocalGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob)
1575 {
1576  string pattern2;
1577  int result;
1578 
1579  if (cip == NULL)
1580  return (kErrBadParameter);
1581  if (strcmp(cip->magic, kLibraryMagic))
1582  return (kErrBadMagic);
1583 
1584  if (fileList == NULL)
1585  return (kErrBadParameter);
1586  InitLineList(fileList);
1587 
1588  if ((pattern == NULL) || (pattern[0] == '\0'))
1589  return (kErrBadParameter);
1590 
1591  (void) STRNCPY(pattern2, pattern); /* Don't nuke the original. */
1592 
1593  /* Pre-process for ~'s. */
1594  ExpandTilde(pattern2, sizeof(pattern2));
1595  InitLineList(fileList);
1596  result = kNoErr;
1597 
1598  if ((doGlob == 1) && (GLOBCHARSINSTR(pattern2))) {
1599 #if defined(WIN32) || defined(_WINDOWS)
1600  result = WinLocalGlob(cip, fileList, pattern2);
1601 #else
1602  result = LazyUnixLocalGlob(cip, fileList, pattern2);
1603 #endif
1604  } else {
1605  /* Or, if there were no globbing characters in 'pattern', then
1606  * the pattern is really just a single pathname.
1607  */
1608  (void) AddLine(fileList, pattern2);
1609  }
1610 
1611  return (result);
1612 } /* FTPLocalGlob */
1613 
1614 
1615 
1616 
1617 static int
1618 FTPFtwL2(const FTPCIPtr cip, char *dir, char *end, size_t dirsize, FTPFtwProc proc, int maxdepth)
1619 {
1620  LineList fileList;
1621  LinePtr filePtr;
1622  char *file, *cp;
1623  int result;
1624 
1625  if (maxdepth <= 0) {
1627  return (result);
1628  }
1629 
1630  result = FTPRemoteGlob(cip, &fileList, "**", kGlobYes);
1631  if (result != kNoErr) {
1632  if (result == kErrGlobNoMatch)
1633  result = kNoErr; /* empty directory is okay. */
1634  return (result);
1635  }
1636 
1637  for (filePtr = fileList.first;
1638  filePtr != NULL;
1639  filePtr = filePtr->next)
1640  {
1641  file = filePtr->line;
1642  if (file == NULL) {
1643  cip->errNo = kErrBadLineList;
1644  break;
1645  }
1646 
1647  if ((file[0] == '.') && ((file[1] == '\0') || ((file[1] == '.') && (file[2] == '\0'))))
1648  continue; /* Skip . and .. */
1649 
1650  result = FTPIsDir(cip, file);
1651  if (result < 0) {
1652  /* error */
1653  /* could be just a stat error, so continue */
1654  continue;
1655  } else if (result == 1) {
1656  /* directory */
1657  cp = Strnpcat(dir, file, dirsize);
1658  result = (*proc)(cip, dir, kFtwDir);
1659  if (result != kNoErr)
1660  break;
1661 
1662  if ((strchr(dir, '/') == NULL) && (strrchr(dir, '\\') != NULL))
1663  *cp++ = '\\';
1664  else
1665  *cp++ = '/';
1666  *cp = '\0';
1667 
1668  result = FTPChdir(cip, file);
1669  if (result == kNoErr) {
1670  result = FTPFtwL2(cip, dir, cp, dirsize, proc, maxdepth - 1);
1671  if (result != kNoErr)
1672  break;
1673  if (FTPChdir(cip, "..") < 0) {
1675  cip->errNo = kErrCannotGoToPrevDir;
1676  break;
1677  }
1678  }
1679 
1680  *end = '\0';
1681  if (result != 0)
1682  break;
1683  } else {
1684  /* file */
1685  cp = Strnpcat(dir, file, dirsize);
1686  result = (*proc)(cip, dir, kFtwFile);
1687  *end = '\0';
1688  if (result != 0)
1689  break;
1690  }
1691  }
1692  DisposeLineListContents(&fileList);
1693 
1694  return (result);
1695 } /* FTPFtwL2 */
1696 
1697 
1698 
1699 int
1700 FTPFtw(const FTPCIPtr cip, const char *const dir, FTPFtwProc proc, int maxdepth)
1701 {
1702  int result, result2;
1703  char *cp;
1704  char savedcwd[1024];
1705  char curcwd[2048];
1706 
1707  result = FTPIsDir(cip, dir);
1708  if (result < 0) {
1709  /* error */
1710  return result;
1711  } else if (result == 0) {
1712  result = cip->errNo = kErrNotADirectory;
1713  return (result);
1714  }
1715 
1716  /* Preserve old working directory. */
1717  (void) FTPGetCWD(cip, savedcwd, sizeof(savedcwd));
1718 
1719  result = FTPChdir(cip, dir);
1720  if (result != kNoErr) {
1721  return (result);
1722  }
1723 
1724  /* Get full working directory we just changed to. */
1725  result = FTPGetCWD(cip, curcwd, sizeof(curcwd) - 3);
1726  if (result != kNoErr) {
1727  if (FTPChdir(cip, savedcwd) != kNoErr) {
1730  }
1731  return (result);
1732  }
1733 
1734  result2 = (*proc)(cip, curcwd, kFtwDir);
1735  if (result2 == kNoErr) {
1736  cp = curcwd + strlen(curcwd);
1737 
1738  if ((strchr(curcwd, '/') == NULL) && (strrchr(curcwd, '\\') != NULL))
1739  *cp++ = '\\';
1740  else
1741  *cp++ = '/';
1742  *cp = '\0';
1743  result = FTPFtwL2(cip, curcwd, cp, sizeof(curcwd), proc, maxdepth - 1);
1744  }
1745 
1746 
1747  if (FTPChdir(cip, savedcwd) != kNoErr) {
1748  /* Could not cd back to the original user directory -- bad. */
1750  cip->errNo = kErrCannotGoToPrevDir;
1751  return (result);
1752  }
1753 
1754  if ((result2 != kNoErr) && (result == kNoErr))
1755  result = result2;
1756 
1757  return (result);
1758 } /* FTPFtw */
1759 
1760 /* eof */
int ComputeRNames(FileInfoListPtr dst, const char *dstdir, int pflag, int nochop)
Definition: linelist.c:579
LinePtr last
Definition: ncftp.h:85
#define IsLocalPathDelim(c)
Definition: ncftp.h:497
#define isspace(c)
Definition: acclib.h:69
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
int tm_min
Definition: time.h:78
void SortFileInfoList(FileInfoListPtr list, int sortKey, int sortOrder)
Definition: linelist.c:353
int UnMlsT(const char *const line0, const MLstItemPtr mlip)
Definition: glob.c:693
#define kErrBadParameter
Definition: ncftp_errno.h:56
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
#define kCommandAvailable
Definition: ncftp.h:380
size_t relnameLen
Definition: ncftp.h:261
HRESULT hr
Definition: shlfolder.c:183
int FTPLocalRecursiveFileList(FTPCIPtr cip, LineListPtr fileList, FileInfoListPtr files)
Definition: glob.c:1327
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
Definition: ftp_var.h:139
int FTPFtw(const FTPCIPtr cip, const char *const dir, FTPFtwProc proc, int maxdepth)
Definition: glob.c:1700
char fname[512]
Definition: ncftp.h:276
char * strstr(char *String1, char *String2)
Definition: utclib.c:653
static void ExpandTilde(char *pattern, size_t siz)
Definition: glob.c:1423
#define free
Definition: debug_ros.c:5
int tm_mday
Definition: time.h:80
#define kCommandAvailabilityUnknown
Definition: ncftp.h:379
time_t UnMDTMDate(char *)
Definition: util.c:486
GLdouble n
Definition: glext.h:7729
LinePtr next
Definition: ncftp.h:80
#define ISTRNEQ(a, b, s)
Definition: util.h:34
#define snprintf
Definition: wintirpc.h:48
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
#define STRNCPY(dst, src, n)
Definition: rdesktop.h:168
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
void VectorizeFileInfoList(FileInfoListPtr list)
Definition: linelist.c:423
longest_int fsize
Definition: ncftp.h:279
char * cmd
Definition: vfdcmd.c:85
char owner[16]
Definition: ncftp.h:285
char linkto[512]
Definition: ncftp.h:277
GLuint GLuint end
Definition: gl.h:1545
static HANDLE proc()
Definition: pdb.c:32
int FTPLocalRecursiveFileList2(FTPCIPtr cip, LineListPtr fileList, FileInfoListPtr files, int erelative)
Definition: glob.c:1270
int tm_year
Definition: time.h:82
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
#define kErrGlobFailed
Definition: ncftp_errno.h:68
__u16 time
Definition: mkdosfs.c:366
char * lname
Definition: ncftp.h:256
_Check_return_ _CRTIMP int __cdecl isalnum(_In_ int _C)
char * rname
Definition: ncftp.h:254
int gid
Definition: ncftp.h:283
char magic[16]
Definition: ncftp.h:135
int mode
Definition: ncftp.h:281
const GLfloat * m
Definition: glext.h:10848
Definition: fatfs.h:198
#define ISTREQ(a, b)
Definition: util.h:33
int ConcatFileInfoList(FileInfoListPtr dst, FileInfoListPtr src)
Definition: linelist.c:556
#define kErrGlobNoMatch
Definition: ncftp_errno.h:89
char perm[16]
Definition: ncftp.h:284
char * plug
Definition: ncftp.h:257
#define S_ISLNK(m)
Definition: ext2fs.h:368
#define sprintf(buf, format,...)
Definition: sprintf.c:55
DIR *__cdecl opendir(const char *)
char * Strncat(char *const, const char *const, const size_t)
Definition: Strncat.c:13
#define StrDup
Definition: shlwapi.h:1533
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
void UnvectorizeFileInfoList(FileInfoListPtr list)
Definition: linelist.c:441
int ConcatFileToFileInfoList(FileInfoListPtr dst, char *rfile)
Definition: linelist.c:740
int UnLslR(FileInfoListPtr filp, LineListPtr llp, int serverType)
Definition: glob.c:561
time_t now
Definition: finger.c:65
#define _MAX_PATH
Definition: utility.h:77
static int LsMonthNameToNum(char *cp)
Definition: glob.c:135
#define pp
Definition: hlsl.yy.c:978
Definition: dirent.h:39
int FTPLocalGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob)
Definition: glob.c:1574
smooth NULL
Definition: ftsmooth.c:416
unsigned char
Definition: typeof.h:29
#define kServerTypeMicrosoftFTP
Definition: ncftp.h:465
char group[16]
Definition: ncftp.h:286
Definition: parser.c:48
FileInfoPtr AddFileInfo(FileInfoListPtr list, FileInfoPtr src)
Definition: linelist.c:530
char * rlinkto
Definition: ncftp.h:255
_Check_return_ _CRTIMP int __cdecl sscanf(_In_z_ const char *_Src, _In_z_ _Scanf_format_string_ const char *_Format,...)
int tm_mon
Definition: time.h:81
unsigned int dir
Definition: maze.c:112
#define SCANF_LONG_LONG
Definition: wincfg.h:30
#define FindFirstFile
Definition: winbase.h:3596
char * relname
Definition: ncftp.h:253
#define isdigit(c)
Definition: acclib.h:68
#define ERROR_NO_MORE_FILES
Definition: winerror.h:121
void InitFileInfoList(FileInfoListPtr list)
Definition: linelist.c:193
static int UnDosLine(char *const line, const char *const curdir, size_t curdirlen, char *fname, size_t fnamesize, int *ftype, longest_int *fsize, time_t *ftime)
Definition: glob.c:175
GLuint GLfloat * val
Definition: glext.h:7180
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define kFtwDir
Definition: ncftp.h:414
char * d_name
Definition: dirent.h:29
DWORD dwErr
Definition: service.c:36
#define STREQ(a, b)
Definition: util.h:20
#define STRNCAT(d, s)
Definition: Strn.h:48
eMaj lines
Definition: tritemp.h:206
__kernel_size_t size_t
Definition: linux.h:237
char * FGets(char *, size_t, FILE *)
Definition: util.c:111
int FTPRemoteRecursiveFileList1(FTPCIPtr cip, char *const rdir, FileInfoListPtr files)
Definition: glob.c:983
if(!(yy_init))
Definition: macro.lex.yy.c:714
#define isupper(c)
Definition: acclib.h:71
#define FindNextFile
Definition: winbase.h:3602
static int LazyUnixLocalGlob(FTPCIPtr cip, LineListPtr fileList, const char *const pattern)
Definition: glob.c:1533
#define S_ISDIR(mode)
Definition: various.h:18
#define longest_int
Definition: ncftp.h:68
#define kErrBadMagic
Definition: ncftp_errno.h:55
const char file[]
Definition: icontest.c:11
#define kGlobYes
Definition: ncftp.h:360
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
LinePtr AddLine(LineListPtr list, const char *buf1)
Definition: linelist.c:94
unsigned long DWORD
Definition: ntddk_ex.h:95
BOOL Error
Definition: chkdsk.c:66
size_t maxFileLen
Definition: ncftp.h:267
void(* FTPSigProc)(int)
Definition: ncftp.h:76
size_t maxPlugLen
Definition: ncftp.h:268
time_t ftime
Definition: ncftp.h:280
Definition: ncftp.h:79
#define kErrNotADirectory
Definition: ncftp_errno.h:108
#define kFtwFile
Definition: ncftp.h:413
#define kErrCannotGoToPrevDir
Definition: ncftp_errno.h:58
#define SIGPIPE
Definition: signal.h:35
char line[200]
Definition: main.c:97
Definition: ncftp.h:84
#define kGlobChars
Definition: ncftp.h:357
int FTPRemoteRecursiveFileList(FTPCIPtr cip, LineListPtr fileList, FileInfoListPtr files)
Definition: glob.c:1032
static const WCHAR L[]
Definition: oid.c:1250
#define Lstat
Definition: syshdrs.h:80
#define kDoPerror
Definition: util.h:44
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
Definition: _list.h:228
LinePtr first
Definition: ncftp.h:85
Definition: time.h:76
#define islower(c)
Definition: acclib.h:72
_CRTIMP struct tm *__cdecl localtime(const time_t *_Time)
Definition: time.h:426
#define pclose
Definition: syshdrs.h:73
int __cdecl closedir(DIR *)
int FTPListToMemory2(const FTPCIPtr cip, const char *const pattern, const LineListPtr llines, const char *const lsflags, const int blankLines, int *const tryMLSD)
Definition: io.c:366
#define kCommandNotAvailable
Definition: ncftp.h:381
int ftype
Definition: ncftp.h:278
struct dirent *__cdecl readdir(DIR *)
int type
Definition: ncftp.h:258
int FTPChdir(const FTPCIPtr cip, const char *const cdCwd)
Definition: cmds.c:11
time_t mdtm
Definition: ncftp.h:259
static int UnLslRLine(char *const line, const char *const curdir, size_t curdirlen, char *fname, size_t fnamesize, char *linkto, size_t linktosize, int *ftype, longest_int *fsize, time_t *ftime, time_t now, int thisyear, int *plugend)
Definition: glob.c:353
#define NcSignal
Definition: ncftp.h:604
int FTPRemoteGlob(FTPCIPtr cip, LineListPtr fileList, const char *pattern, int doGlob)
Definition: glob.c:1335
#define kErrRecursionLimitReached
Definition: ncftp_errno.h:109
__CRT_INLINE void __cdecl ftime(struct timeb *_Tmb)
Definition: timeb.h:96
void PrintF(const FTPCIPtr cip, const char *const fmt,...)
Definition: util.c:340
void DisposeFileInfoListContents(FileInfoListPtr list)
Definition: linelist.c:152
#define Stat
Definition: syshdrs.h:78
int UnMlsD(FileInfoListPtr filp, LineListPtr llp)
Definition: glob.c:827
static unsigned __int64 next
Definition: rand_nt.c:6
__kernel_mode_t mode_t
Definition: linux.h:199
__kernel_time_t time_t
Definition: linux.h:252
#define popen
Definition: syshdrs.h:72
char * Strnpcat(char *const, const char *const, size_t)
Definition: Strnpcat.c:16
#define GLOBCHARSINSTR(a)
Definition: ncftp.h:358
char * Strncpy(char *const, const char *const, const size_t)
Definition: Strncpy.c:11
#define LOCAL_PATH_DELIM_STR
Definition: ncftp.h:493
LinePtr RemoveLine(LineListPtr list, LinePtr killMe)
Definition: linelist.c:63
void InitLineList(LineListPtr list)
Definition: linelist.c:54
_CRTIMP time_t __cdecl mktime(struct tm *_Tm)
Definition: time.h:428
int FTPGetCWD(const FTPCIPtr cip, char *const newCwd, const size_t newCwdSize)
Definition: cmds.c:254
#define min(a, b)
Definition: monoChain.cc:55
int FTPIsDir(const FTPCIPtr cip, const char *const dir)
Definition: cmds.c:1531
#define LOCAL_PATH_DELIM
Definition: ncftp.h:492
char * strchr(const char *String, int ch)
Definition: utclib.c:501
char longstring[512]
Definition: util.h:12
void GetHomeDir(char *, size_t)
Definition: util.c:240
_Check_return_ int __cdecl atoi(_In_z_ const char *_Str)
#define kModTimeUnknown
Definition: ncftp.h:377
POINT cp
Definition: magnifier.c:61
#define calloc
Definition: rosglue.h:14
#define kSizeUnknown
Definition: ncftp.h:376
#define kErrBadLineList
Definition: ncftp_errno.h:44
#define kLibraryMagic
Definition: ncftp.h:65
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
int tm_hour
Definition: time.h:79
#define kNoErr
Definition: ncftp_errno.h:9
#define StrRFindLocalPathDelim(a)
Definition: ncftp.h:495
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
int readlink(const char *path, char *buf, size_t size)
static const WCHAR sp[]
Definition: suminfo.c:288
#define malloc
Definition: debug_ros.c:4
int(* FTPFtwProc)(const FTPCIPtr cip, const char *fn, int flag)
Definition: ncftp.h:131
_Check_return_ _CRTIMP int __cdecl ispunct(_In_ int _C)
void DisposeLineListContents(LineListPtr list)
Definition: linelist.c:33
static int FTPFtwL2(const FTPCIPtr cip, char *dir, char *end, size_t dirsize, FTPFtwProc proc, int maxdepth)
Definition: glob.c:1618
static void Traverse(FTPCIPtr cip, char *fullpath, struct Stat *st, char *relpath, FileInfoListPtr filp)
Definition: glob.c:1178
#define SIG_IGN
Definition: signal.h:48
int tm_isdst
Definition: time.h:85
GLuint64EXT * result
Definition: glext.h:11304
#define memset(x, y, z)
Definition: compat.h:39
#define S_ISREG(mode)
Definition: various.h:17
char * line
Definition: ncftp.h:81
#define StrFindLocalPathDelim(a)
Definition: ncftp.h:494
#define glberr(a)
longest_int size
Definition: ncftp.h:260
static const char * rwx[9]
Definition: glob.c:10
int uid
Definition: ncftp.h:282
GLubyte * pattern
Definition: glext.h:7787
#define printf
Definition: config.h:203
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
Definition: fci.c:126
FileInfoPtr next
Definition: ncftp.h:252
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
GLint fsize
Definition: glext.h:9408
static void RemoteGlobCollapse(const char *pattern, LineListPtr fileList)
Definition: glob.c:43