|
|
1.1 ! root 1: char *ckzv = "Unix file support, 4C(032) 25 Jul 85"; ! 2: ! 3: /* C K U F I O -- Kermit file system support for Unix systems */ ! 4: ! 5: /* ! 6: Author: Frank da Cruz (SY.FDC@CU20B), ! 7: Columbia University Center for Computing Activities, January 1985. ! 8: Copyright (C) 1985, Trustees of Columbia University in the City of New York. ! 9: Permission is granted to any individual or institution to use, copy, or ! 10: redistribute this software so long as it is not sold for profit, provided this ! 11: copyright notice is retained. ! 12: */ ! 13: /* Includes */ ! 14: ! 15: #include "ckcker.h" /* Kermit definitions */ ! 16: #include "ckcdeb.h" /* Typedefs, debug formats, etc */ ! 17: #include <ctype.h> /* Character types */ ! 18: #include <stdio.h> /* Standard i/o */ ! 19: #include <sys/types.h> /* Data types */ ! 20: #include <sys/dir.h> /* Directory structure */ ! 21: #include <sys/stat.h> /* File status */ ! 22: #include <pwd.h> /* Password file for shell name */ ! 23: ! 24: /* Berkeley Unix Version 4.x */ ! 25: /* 4.1bsd support added by Charles E Brooks, EDN-VAX */ ! 26: ! 27: #ifdef BSD4 ! 28: #ifdef MAXNAMLEN ! 29: #define BSD42 ! 30: char *ckzsys = " 4.2 BSD"; ! 31: #else ! 32: #ifdef FT17 ! 33: #define BSD41 ! 34: char *ckzsys = " For:Pro Fortune 1.7"; ! 35: #else ! 36: #define BSD41 ! 37: char *ckzsys = " 4.1 BSD"; ! 38: #endif ! 39: #endif ! 40: #endif ! 41: ! 42: /* 2.9bsd support contributed by Bradley Smith, UCLA */ ! 43: #ifdef BSD29 ! 44: char *ckzsys = " 2.9 BSD"; ! 45: #endif ! 46: ! 47: /* Version 7 Unix */ ! 48: #ifdef V7 ! 49: char *ckzsys = " Version 7 Unix"; ! 50: #endif ! 51: ! 52: /* DEC Professional-300 series with Venturcom Venix v1 */ ! 53: #ifdef PROVX1 ! 54: char *ckzsys = " DEC Pro-3xx/Venix v1"; ! 55: #endif ! 56: ! 57: /* NCR Tower support contributed by John Bray, Auburn, AL. */ ! 58: /* Tower OS is like Sys III but with BSD features -- mostly follows BSD. */ ! 59: #ifdef TOWER1 ! 60: char *ckzsys = " NCR Tower 1632, OS 1.02"; ! 61: #endif ! 62: ! 63: /* Sys III/V, Xenix, PC/IX,... support by Herm Fischer, Litton Data Systems */ ! 64: #ifdef UXIII ! 65: #ifdef XENIX ! 66: char *ckzsys = " Xenix/286"; ! 67: #else ! 68: #ifdef PCIX ! 69: char *ckzsys = " PC/IX"; ! 70: #else ! 71: #ifdef ISIII ! 72: char *ckzsys = " Interactive Systems Corp, System III"; ! 73: #else ! 74: char *ckzsys = " AT&T System III/System V"; ! 75: #endif ! 76: #endif ! 77: #endif ! 78: #endif ! 79: ! 80: /* Definitions of some Unix system commands */ ! 81: ! 82: char *DIRCMD = "ls -l "; /* For directory listing */ ! 83: char *DELCMD = "rm -f "; /* For file deletion */ ! 84: char *TYPCMD = "cat "; /* For typing a file */ ! 85: char *PWDCMD = "pwd "; /* For saying where I am */ ! 86: ! 87: #ifdef BSD4 ! 88: char *SPACMD = "pwd ; quota ; df ."; /* Space/quota of current directory */ ! 89: #else ! 90: char *SPACMD = "df "; ! 91: #endif ! 92: ! 93: char *SPACM2 = "df "; /* For space in specified directory */ ! 94: ! 95: #ifdef BSD4 ! 96: char *WHOCMD = "finger "; /* For seeing who's logged in */ ! 97: #else ! 98: char *WHOCMD = "who "; /* For seeing who's logged in */ ! 99: #endif ! 100: ! 101: /* ! 102: Functions (n is one of the predefined file numbers from ckermi.h): ! 103: ! 104: zopeni(n,name) -- Opens an existing file for input. ! 105: zopeno(n,name) -- Opens a new file for output. ! 106: zclose(n) -- Closes a file. ! 107: zchin(n,&c) -- Gets the next character from an input file. ! 108: zsout(n,s) -- Write a null-terminated string to output file, buffered. ! 109: zsoutl(n,s) -- Like zsout, but appends a line terminator. ! 110: zsoutx(n,s,x) -- Write x characters to output file, unbuffered. ! 111: zchout(n,c) -- Add a character to an output file, unbuffered. ! 112: zchki(name) -- Check if named file exists and is readable, return size. ! 113: zchko(name) -- Check if named file can be created. ! 114: znewn(name,s) -- Make a new unique file name based on the given name. ! 115: zdelet(name) -- Delete the named file. ! 116: zxpand(string) -- Expands the given wildcard string into a list of files. ! 117: znext(string) -- Returns the next file from the list in "string". ! 118: zxcmd(cmd) -- Execute the command in a lower fork. ! 119: zclosf() -- Close input file associated with zxcmd()'s lower fork. ! 120: zrtol(n1,n2) -- Convert remote filename into local form. ! 121: zltor(n1,n2) -- Convert local filename into remote form. ! 122: zchdir(dirnam) -- Change working directory. ! 123: zhome() -- Return pointer to home directory name string. ! 124: zkself() -- Kill self, log out own job. ! 125: */ ! 126: ! 127: ! 128: #ifdef FT17 ! 129: #define PROVX1 ! 130: #endif ! 131: #ifndef PROVX1 ! 132: #include <sys/file.h> /* File access */ ! 133: #endif ! 134: #ifdef FT17 ! 135: #undef PROVX1 ! 136: #endif ! 137: ! 138: /* Some systems define these in include files, others don't... */ ! 139: #ifndef R_OK ! 140: #define R_OK 4 /* For access */ ! 141: #endif ! 142: ! 143: #ifndef W_OK ! 144: #define W_OK 2 ! 145: #endif ! 146: ! 147: #ifdef PROVX1 ! 148: #define MAXNAMLEN DIRSIZ /* Max file name length */ ! 149: #endif ! 150: ! 151: #ifdef UXIII ! 152: #include <fcntl.h> ! 153: #define MAXNAMLEN DIRSIZ ! 154: #endif ! 155: ! 156: #ifndef O_RDONLY ! 157: #define O_RDONLY 000 ! 158: #endif ! 159: ! 160: #ifndef MAXNAMLEN ! 161: #define MAXNAMLEN 14 /* If still not defined... */ ! 162: #endif ! 163: ! 164: #ifdef PROVX1 ! 165: #define MAXWLD 50 /* Maximum wildcard filenames */ ! 166: #else ! 167: #define MAXWLD 500 ! 168: #endif ! 169: ! 170: /* Declarations */ ! 171: ! 172: FILE *fp[ZNFILS] = { /* File pointers */ ! 173: NULL, NULL, NULL, NULL, NULL, NULL, NULL }; ! 174: ! 175: static int pid; /* pid of child fork */ ! 176: static int fcount; /* Number of files in wild group */ ! 177: static char nambuf[MAXNAMLEN+1]; /* Buffer for a filename */ ! 178: char *malloc(), *getenv(), *strcpy(); /* System functions */ ! 179: extern errno; /* System error code */ ! 180: ! 181: static char *mtchs[MAXWLD], /* Matches found for filename */ ! 182: **mtchptr; /* Pointer to current match */ ! 183: ! 184: /* Z K S E L F -- Kill Self: log out own job, if possible. */ ! 185: ! 186: zkself() { /* For "bye", but no guarantee! */ ! 187: #ifdef PROVX1 ! 188: return(kill(0,9)); ! 189: #else ! 190: #ifdef V7 ! 191: return(kill(0,9)); ! 192: #else ! 193: #ifdef TOWER1 ! 194: return(kill(0,9)); ! 195: #else ! 196: #ifdef FT17 ! 197: return(kill(0,9)); ! 198: #else ! 199: return(kill(getppid(),1)); ! 200: #endif ! 201: #endif ! 202: #endif ! 203: #endif ! 204: } ! 205: ! 206: /* Z O P E N I -- Open an existing file for input. */ ! 207: ! 208: zopeni(n,name) int n; char *name; { ! 209: debug(F111," zopeni",name,n); ! 210: debug(F101," fp","",(int) fp[n]); ! 211: if (chkfn(n) != 0) return(0); ! 212: if (n == ZSYSFN) { /* Input from a system function? */ ! 213: debug(F110," invoking zxcmd",name,0); ! 214: return(zxcmd(name)); /* Try to fork the command */ ! 215: } ! 216: if (n == ZSTDIO) { /* Standard input? */ ! 217: if (isatty(0)) { ! 218: ermsg("Terminal input not allowed"); ! 219: debug(F110,"zopeni: attempts input from unredirected stdin","",0); ! 220: return(0); ! 221: } ! 222: fp[ZIFILE] = stdin; ! 223: return(1); ! 224: } ! 225: fp[n] = fopen(name,"r"); /* Real file. */ ! 226: debug(F111," zopeni", name, (int) fp[n]); ! 227: if (fp[n] == NULL) perror("zopeni"); ! 228: return((fp[n] != NULL) ? 1 : 0); ! 229: } ! 230: ! 231: /* Z O P E N O -- Open a new file for output. */ ! 232: ! 233: zopeno(n,name) int n; char *name; { ! 234: debug(F111," zopeno",name,n); ! 235: if (chkfn(n) != 0) return(0); ! 236: if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */ ! 237: fp[ZOFILE] = stdout; ! 238: debug(F101," fp[]=stdout", "", (int) fp[n]); ! 239: return(1); ! 240: } ! 241: fp[n] = fopen(name,"w"); /* A real file, try to open */ ! 242: if (fp[n] == NULL) { ! 243: perror("zopeno can't open"); ! 244: } else { ! 245: chown(name, getuid(), getgid()); /* In case set[gu]id */ ! 246: if (n == ZDFILE) setbuf(fp[n],NULL); /* Debugging file unbuffered */ ! 247: } ! 248: debug(F101, " fp[n]", "", (int) fp[n]); ! 249: return((fp[n] != NULL) ? 1 : 0); ! 250: } ! 251: ! 252: /* Z C L O S E -- Close the given file. */ ! 253: ! 254: /* Returns 0 if arg out of range, 1 if successful, -1 if close failed. */ ! 255: ! 256: zclose(n) int n; { ! 257: int x; ! 258: if (chkfn(n) < 1) return(0); /* Check range of n */ ! 259: if ((n == ZIFILE) && fp[ZSYSFN]) { /* If system function */ ! 260: x = zclosf(); /* do it specially */ ! 261: } else { ! 262: if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]); ! 263: fp[n] = NULL; ! 264: } ! 265: return((x == EOF) ? -1 : 1); ! 266: } ! 267: ! 268: /* Z C H I N -- Get a character from the input file. */ ! 269: ! 270: /* Returns -1 if EOF, 0 otherwise with character returned in argument */ ! 271: ! 272: zchin(n,c) int n; char *c; { ! 273: int a; ! 274: if (chkfn(n) < 1) return(-1); ! 275: a = getc(fp[n]); ! 276: if (a == EOF) return(-1); ! 277: *c = a & 0377; ! 278: return(0); ! 279: } ! 280: ! 281: /* Z S O U T -- Write a string to the given file, buffered. */ ! 282: ! 283: zsout(n,s) int n; char *s; { ! 284: if (chkfn(n) < 1) return(-1); ! 285: fputs(s,fp[n]); ! 286: return(0); ! 287: } ! 288: ! 289: /* Z S O U T L -- Write string to file, with line terminator, buffered */ ! 290: ! 291: zsoutl(n,s) int n; char *s; { ! 292: if (chkfn(n) < 1) return(-1); ! 293: fputs(s,fp[n]); ! 294: fputs("\n",fp[n]); ! 295: return(0); ! 296: } ! 297: ! 298: /* Z S O U T X -- Write x characters to file, unbuffered. */ ! 299: ! 300: zsoutx(n,s,x) int n, x; char *s; { ! 301: if (chkfn(n) < 1) return(-1); ! 302: return(write(fp[n]->_file,s,x)); ! 303: } ! 304: ! 305: ! 306: /* Z C H O U T -- Add a character to the given file. */ ! 307: ! 308: /* Should return 0 or greater on success, -1 on failure (e.g. disk full) */ ! 309: ! 310: zchout(n,c) int n; char c; { ! 311: if (chkfn(n) < 1) return(-1); ! 312: if (n == ZSFILE) ! 313: return(write(fp[n]->_file,&c,1)); /* Use unbuffered for session log */ ! 314: else { /* Buffered for everything else */ ! 315: if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */ ! 316: return(ferror(fp[n])); /* Check to make sure */ ! 317: else /* Otherwise... */ ! 318: return(0); /* There was no error. */ ! 319: } ! 320: } ! 321: ! 322: /* C H K F N -- Internal function to verify file number is ok */ ! 323: ! 324: /* ! 325: Returns: ! 326: -1: File number n is out of range ! 327: 0: n is in range, but file is not open ! 328: 1: n in range and file is open ! 329: */ ! 330: chkfn(n) int n; { ! 331: switch (n) { ! 332: case ZCTERM: ! 333: case ZSTDIO: ! 334: case ZIFILE: ! 335: case ZOFILE: ! 336: case ZDFILE: ! 337: case ZTFILE: ! 338: case ZPFILE: ! 339: case ZSFILE: ! 340: case ZSYSFN: break; ! 341: default: ! 342: debug(F101,"chkfn: file number out of range","",n); ! 343: fprintf(stderr,"?File number out of range - %d\n",n); ! 344: return(-1); ! 345: } ! 346: return( (fp[n] == NULL) ? 0 : 1 ); ! 347: } ! 348: ! 349: /* Z C H K I -- Check if input file exists and is readable */ ! 350: ! 351: /* ! 352: Returns: ! 353: >= 0 if the file can be read (returns the size). ! 354: -1 if file doesn't exist or can't be accessed, ! 355: -2 if file exists but is not readable (e.g. a directory file). ! 356: -3 if file exists but protected against read access. ! 357: */ ! 358: /* ! 359: For Berkeley Unix, a file must be of type "regular" to be readable. ! 360: Directory files, special files, and symbolic links are not readable. ! 361: */ ! 362: long ! 363: zchki(name) char *name; { ! 364: struct stat buf; ! 365: int x; long y; ! 366: ! 367: x = stat(name,&buf); ! 368: if (x < 0) { ! 369: debug(F111,"zchki stat fails",name,errno); ! 370: return(-1); ! 371: } ! 372: x = buf.st_mode & S_IFMT; /* Isolate file format field */ ! 373: if ((x != 0) && (x != S_IFREG)) { ! 374: debug(F111,"zchki skipping:",name,x); ! 375: return(-2); ! 376: } ! 377: debug(F111,"zchki stat ok:",name,x); ! 378: ! 379: if ((x = access(name,R_OK)) < 0) { /* Is the file accessible? */ ! 380: debug(F111," access failed:",name,x); /* No */ ! 381: return(-3); ! 382: } else { ! 383: y = buf.st_size; ! 384: debug(F111," access ok:",name,(int) y); /* Yes */ ! 385: return( (y > -1) ? y : 0 ); ! 386: } ! 387: } ! 388: ! 389: /* Z C H K O -- Check if output file can be created */ ! 390: ! 391: /* ! 392: Returns -1 if write permission for the file would be denied, 0 otherwise. ! 393: */ ! 394: zchko(name) char *name; { ! 395: int i, x; ! 396: char s[50], *sp; ! 397: ! 398: sp = s; /* Make a copy, get length */ ! 399: x = 0; ! 400: while ((*sp++ = *name++) != '\0') ! 401: x++; ! 402: if (x == 0) return(-1); /* If no filename, fail. */ ! 403: ! 404: debug(F101," length","",x); ! 405: for (i = x; i > 0; i--) /* Strip filename. */ ! 406: if (s[i-1] == '/') break; ! 407: ! 408: debug(F101," i","",i); ! 409: if (i == 0) /* If no path, use current directory */ ! 410: strcpy(s,"./"); ! 411: else /* Otherwise, use given one. */ ! 412: s[i] = '\0'; ! 413: ! 414: x = access(s,W_OK); /* Check access of path. */ ! 415: if (x < 0) { ! 416: debug(F111,"zchko access failed:",s,errno); ! 417: return(-1); ! 418: } else { ! 419: debug(F111,"zchko access ok:",s,x); ! 420: return(0); ! 421: } ! 422: } ! 423: ! 424: /* Z D E L E T -- Delete the named file. */ ! 425: ! 426: zdelet(name) char *name; { ! 427: unlink(name); ! 428: } ! 429: ! 430: ! 431: /* Z R T O L -- Convert remote filename into local form */ ! 432: ! 433: /* For UNIX, this means changing uppercase letters to lowercase. */ ! 434: ! 435: zrtol(name,name2) char *name, *name2; { ! 436: for ( ; *name != '\0'; name++) { ! 437: *name2++ = isupper(*name) ? tolower(*name) : *name; ! 438: } ! 439: *name2 = '\0'; ! 440: debug(F110,"zrtol:",name2,0); ! 441: } ! 442: ! 443: ! 444: /* Z L T O R -- Local TO Remote */ ! 445: ! 446: /* Convert filename from local format to common (remote) form. */ ! 447: ! 448: zltor(name,name2) char *name, *name2; { ! 449: char work[100], *cp, *pp; ! 450: int dc = 0; ! 451: ! 452: debug(F110,"zltor",name,0); ! 453: pp = work; ! 454: for (cp = name; *cp != '\0'; cp++) { /* strip path name */ ! 455: if (*cp == '/') { ! 456: dc = 0; ! 457: pp = work; ! 458: } ! 459: else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */ ! 460: else if (*cp == '~') *pp++ = 'X'; /* Change tilde to 'X' */ ! 461: else if (*cp == '#') *pp++ = 'X'; /* Change number sign to 'X' */ ! 462: else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */ ! 463: else *pp++ = *cp; ! 464: } ! 465: *pp = '\0'; /* Tie it off. */ ! 466: cp = name2; /* If nothing before dot, */ ! 467: if (*work == '.') *cp++ = 'X'; /* insert 'X' */ ! 468: strcpy(cp,work); ! 469: debug(F110," name2",name2,0); ! 470: } ! 471: ! 472: ! 473: /* Z C H D I R -- Change directory */ ! 474: ! 475: zchdir(dirnam) char *dirnam; { ! 476: char *hd; ! 477: if (*dirnam == '\0') hd = getenv("HOME"); ! 478: else hd = dirnam; ! 479: return((chdir(hd) == 0) ? 1 : 0); ! 480: } ! 481: ! 482: ! 483: /* Z H O M E -- Return pointer to user's home directory */ ! 484: ! 485: char * ! 486: zhome() { ! 487: return(getenv("HOME")); ! 488: } ! 489: ! 490: /* Z X C M D -- Run a system command so its output can be read like a file */ ! 491: ! 492: zxcmd(comand) char *comand; { ! 493: int pipes[2]; ! 494: if (pipe(pipes) != 0) return(0); /* can't make pipe, fail */ ! 495: if ((pid = fork()) == 0) { /* child */ ! 496: ! 497: /*#if BSD4*/ /* Code from Dave Tweten@AMES-NAS */ ! 498: /* readapted to use getpwuid to find login shell */ ! 499: /* -- H. Fischer */ ! 500: char *shpath, *shname, *shptr; /* to find desired shell */ ! 501: struct passwd *p; ! 502: extern struct passwd * getpwuid(); ! 503: extern int getuid(); ! 504: char *defShel = "/bin/sh"; /* default shell */ ! 505: /*#endif*/ ! 506: ! 507: close(pipes[0]); /* close input side of pipe */ ! 508: close(0); /* close stdin */ ! 509: if (open("/dev/null",0) < 0) return(0); /* replace input by null */ ! 510: ! 511: #ifndef UXIII ! 512: dup2(pipes[1],1); /* replace stdout & stderr */ ! 513: dup2(pipes[1],2); /* by the pipe */ ! 514: #else ! 515: close(1); /* simulate dup2 */ ! 516: if (dup(pipes[1]) != 1 ) ! 517: conol("trouble duping stdout in routine zxcmd\n"); ! 518: close(2); /* simulate dup2 */ ! 519: if (dup(pipes[1]) != 2 ) ! 520: conol("trouble duping stderr in routine zxcmd\n"); ! 521: #endif ! 522: ! 523: close(pipes[1]); /* get rid of this copy of the pipe */ ! 524: ! 525: /**** shptr = shname = shpath = getenv("SHELL"); /* What shell? */ ! 526: p = getpwuid( getuid() ); /* get login data */ ! 527: if ( p == (struct passwd *) NULL || !*(p->pw_shell) ) shpath = defShel; ! 528: else shpath = p->pw_shell; ! 529: shptr = shname = shpath; ! 530: while (*shptr != '\0') if (*shptr++ == '/') shname = shptr; ! 531: debug(F100,"zxcmd...","",0); ! 532: debug(F110,shpath,shname,0); ! 533: execl(shpath,shname,"-c",comand,0); /* Execute the command */ ! 534: ! 535: /**** execl("/bin/sh","sh","-c",comand,0); /* Execute the command */ ! 536: ! 537: exit(0); /* just punt if it didnt work */ ! 538: } ! 539: close(pipes[1]); /* don't need the output side */ ! 540: fp[ZIFILE] = fdopen(pipes[0],"r"); /* open a stream for it */ ! 541: fp[ZSYSFN] = fp[ZIFILE]; /* Remember. */ ! 542: return(1); ! 543: } ! 544: ! 545: /* Z C L O S F - wait for the child fork to terminate and close the pipe. */ ! 546: ! 547: zclosf() { ! 548: int wstat; ! 549: fclose(fp[ZIFILE]); ! 550: fp[ZIFILE] = fp[ZSYSFN] = NULL; ! 551: while ((wstat = wait(0)) != pid && wstat != -1) ; ! 552: return(1); ! 553: } ! 554: ! 555: /* Z X P A N D -- Expand a wildcard string into an array of strings */ ! 556: /* ! 557: Returns the number of files that match fn1, with data structures set up ! 558: so that first file (if any) will be returned by the next znext() call. ! 559: */ ! 560: zxpand(fn) char *fn; { ! 561: fcount = fgen(fn,mtchs,MAXWLD); /* Look up the file. */ ! 562: if (fcount > 0) { ! 563: mtchptr = mtchs; /* Save pointer for next. */ ! 564: } ! 565: debug(F111,"zxpand",mtchs[0],fcount); ! 566: return(fcount); ! 567: } ! 568: ! 569: ! 570: /* Z N E X T -- Get name of next file from list created by zxpand(). */ ! 571: /* ! 572: Returns >0 if there's another file, with its name copied into the arg string, ! 573: or 0 if no more files in list. ! 574: */ ! 575: znext(fn) char *fn; { ! 576: if (fcount-- > 0) strcpy(fn,*mtchptr++); ! 577: else *fn = '\0'; ! 578: debug(F111,"znext",fn,fcount+1); ! 579: return(fcount+1); ! 580: } ! 581: ! 582: ! 583: /* Z N E W N -- Make a new name for the given file */ ! 584: ! 585: znewn(fn,s) char *fn, **s; { ! 586: static char buf[100]; ! 587: char *bp, *xp; ! 588: int len = 0, n = 0, d = 0, t; ! 589: #ifdef MAXNAMLEN ! 590: int max = MAXNAMLEN; ! 591: #else ! 592: int max = 14; ! 593: #endif ! 594: ! 595: bp = buf; ! 596: while (*fn) { /* Copy name into buf */ ! 597: *bp++ = *fn++; ! 598: len++; ! 599: } ! 600: if (len > max-3) bp -= 3; /* Don't let it get too long */ ! 601: ! 602: *bp++ = '*'; /* Put a star on the end */ ! 603: *bp-- = '\0'; ! 604: ! 605: n = zxpand(buf); /* Expand the resulting wild name */ ! 606: ! 607: while (n-- > 0) { /* Find any existing name~d files */ ! 608: xp = *mtchptr++; ! 609: xp += len; ! 610: if (*xp == '~') { ! 611: t = atoi(xp+1); ! 612: if (t > d) d = t; /* Get maximum d */ ! 613: } ! 614: } ! 615: sprintf(bp,"~%d",d+1); /* Make name~(d+1) */ ! 616: *s = buf; ! 617: } ! 618: ! 619: /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */ ! 620: ! 621: /* ! 622: * The path structure is used to represent the name to match. ! 623: * Each slash-separated segment of the name is kept in one ! 624: * such structure, and they are linked together, to make ! 625: * traversing the name easier. ! 626: */ ! 627: ! 628: struct path { ! 629: char npart[MAXNAMLEN]; /* name part of path segment */ ! 630: struct path *fwd; /* forward ptr */ ! 631: }; ! 632: ! 633: #ifdef PROVX1 ! 634: #define SSPACE 500 ! 635: #else ! 636: #define SSPACE 2000 /* size of string-generating buffer */ ! 637: #endif ! 638: static char sspace[SSPACE]; /* buffer to generate names in */ ! 639: static char *freeptr,**resptr; /* copies of caller's arguments */ ! 640: static int remlen; /* remaining length in caller's array*/ ! 641: static int numfnd; /* number of matches found */ ! 642: ! 643: /* ! 644: * splitpath: ! 645: * takes a string and splits the slash-separated portions into ! 646: * a list of path structures. Returns the head of the list. The ! 647: * structures are allocated by malloc, so they must be freed. ! 648: * Splitpath is used internally by the filename generator. ! 649: * ! 650: * Input: A string. ! 651: * Returns: A linked list of the slash-separated segments of the input. ! 652: */ ! 653: ! 654: struct path * ! 655: splitpath(p) ! 656: char *p; ! 657: { ! 658: struct path *head,*cur,*prv; ! 659: int i; ! 660: head = prv = NULL; ! 661: if (*p == '/') p++; /* skip leading slash */ ! 662: while (*p != '\0') ! 663: { ! 664: cur = (struct path *) malloc(sizeof (struct path)); ! 665: debug(F101,"splitpath malloc","",cur); ! 666: if (cur == NULL) fatal("malloc fails in splitpath()"); ! 667: cur -> fwd = NULL; ! 668: if (head == NULL) head = cur; ! 669: else prv -> fwd = cur; /* link into chain */ ! 670: prv = cur; ! 671: for (i=0; i < MAXNAMLEN && *p != '/' && *p != '\0'; i++) ! 672: cur -> npart[i] = *p++; ! 673: cur -> npart[i] = '\0'; /* end this segment */ ! 674: if (i >= MAXNAMLEN) while (*p != '/' && *p != '\0') p++; ! 675: if (*p == '/') p++; ! 676: } ! 677: return(head); ! 678: } ! 679: ! 680: /* ! 681: * fgen: ! 682: * This is the actual name generator. It is passed a string, ! 683: * possibly containing wildcards, and an array of character pointers. ! 684: * It finds all the matching filenames and stores them into the array. ! 685: * The returned strings are allocated from a static buffer local to ! 686: * this module (so the caller doesn't have to worry about deallocating ! 687: * them); this means that successive calls to fgen will wipe out ! 688: * the results of previous calls. This isn't a problem here ! 689: * because we process one wildcard string at a time. ! 690: * ! 691: * Input: a wildcard string, an array to write names to, the ! 692: * length of the array. ! 693: * Returns: the number of matches. The array is filled with filenames ! 694: * that matched the pattern. If there wasn't enough room in the ! 695: * array, -1 is returned. ! 696: * By: Jeff Damens, CUCCA, 1984. ! 697: */ ! 698: ! 699: fgen(pat,resarry,len) ! 700: char *pat,*resarry[]; ! 701: int len; ! 702: { ! 703: struct path *head; ! 704: char scratch[100],*sptr; ! 705: head = splitpath(pat); ! 706: if (*pat == '/') ! 707: { ! 708: scratch[0] = '/'; ! 709: sptr = scratch+1; ! 710: } ! 711: else ! 712: { ! 713: strcpy(scratch,"./"); ! 714: sptr = scratch+2; ! 715: } /* init buffer correctly */ ! 716: numfnd = 0; /* none found yet */ ! 717: freeptr = sspace; /* this is where matches are copied */ ! 718: resptr = resarry; /* static copies of these so*/ ! 719: remlen = len; /* recursive calls can alter them */ ! 720: traverse(head,scratch,sptr); /* go walk the directory tree */ ! 721: for (; head != NULL; head = head -> fwd) ! 722: free(head); /* return the path segments */ ! 723: return(numfnd); /* and return the number of matches */ ! 724: } ! 725: ! 726: /* traverse: ! 727: * Walks the directory tree looking for matches to its arguments. ! 728: * The algorithm is, briefly: ! 729: * If the current pattern segment contains no wildcards, that ! 730: * segment is added to what we already have. If the name so far ! 731: * exists, we call ourselves recursively with the next segment ! 732: * in the pattern string; otherwise, we just return. ! 733: * ! 734: * If the current pattern segment contains wildcards, we open the name ! 735: * we've accumulated so far (assuming it is really a directory), then read ! 736: * each filename in it, and, if it matches the wildcard pattern segment, add ! 737: * that filename to what we have so far and call ourselves recursively on the ! 738: * next segment. ! 739: * ! 740: * Finally, when no more pattern segments remain, we add what's accumulated ! 741: * so far to the result array and increment the number of matches. ! 742: * ! 743: * Input: a pattern path list (as generated by splitpath), a string ! 744: * pointer that points to what we've traversed so far (this ! 745: * can be initialized to "/" to start the search at the root ! 746: * directory, or to "./" to start the search at the current ! 747: * directory), and a string pointer to the end of the string ! 748: * in the previous argument. ! 749: * Returns: nothing. ! 750: */ ! 751: traverse(pl,sofar,endcur) ! 752: struct path *pl; ! 753: char *sofar,*endcur; ! 754: { ! 755: #ifdef BSD42 ! 756: DIR *fd, *opendir(); ! 757: struct direct *dirbuf; ! 758: #else ! 759: int fd; ! 760: struct direct dir_entry; ! 761: struct direct *dirbuf = &dir_entry; ! 762: #endif ! 763: struct stat statbuf; ! 764: if (pl == NULL) ! 765: { ! 766: *--endcur = '\0'; /* end string, overwrite trailing / */ ! 767: addresult(sofar); ! 768: return; ! 769: } ! 770: if (!iswild(pl -> npart)) ! 771: { ! 772: strcpy(endcur,pl -> npart); ! 773: endcur += strlen(pl -> npart); ! 774: *endcur = '\0'; /* end current string */ ! 775: if (stat(sofar,&statbuf) == 0) /* if current piece exists */ ! 776: { ! 777: *endcur++ = '/'; /* add slash to end */ ! 778: *endcur = '\0'; /* and end the string */ ! 779: traverse(pl -> fwd,sofar,endcur); ! 780: } ! 781: return; ! 782: } ! 783: /* cont'd... */ ! 784: ! 785: /*...traverse, cont'd */ ! 786: ! 787: /* segment contains wildcards, have to search directory */ ! 788: *endcur = '\0'; /* end current string */ ! 789: if (stat(sofar,&statbuf) == -1) return; /* doesn't exist, forget it */ ! 790: if ((statbuf.st_mode & S_IFDIR) == 0) return; /* not a directory, skip */ ! 791: #ifdef BSD42 /* ==BSD4 */ ! 792: if ((fd = opendir(sofar)) == NULL) return; /* can't open, forget it */ ! 793: while (dirbuf = readdir(fd)) ! 794: #else ! 795: if ((fd = open(sofar,O_RDONLY)) < 0) return; /* can't open, forget it */ ! 796: while ( read(fd,dirbuf,sizeof dir_entry) ) ! 797: #endif ! 798: { ! 799: strncpy(nambuf,dirbuf->d_name,MAXNAMLEN); /* Get a null terminated copy!!! */ ! 800: nambuf[MAXNAMLEN] = '\0'; ! 801: if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf)) { ! 802: char *eos; ! 803: strcpy(endcur,nambuf); ! 804: eos = endcur + strlen(nambuf); ! 805: *eos = '/'; /* end this segment */ ! 806: traverse(pl -> fwd,sofar,eos+1); ! 807: } ! 808: } ! 809: #ifdef BSD42 /* ==BSD4 */ ! 810: closedir(fd); ! 811: #else ! 812: close(fd); ! 813: #endif ! 814: } ! 815: ! 816: /* ! 817: * addresult: ! 818: * Adds a result string to the result array. Increments the number ! 819: * of matches found, copies the found string into our string ! 820: * buffer, and puts a pointer to the buffer into the caller's result ! 821: * array. Our free buffer pointer is updated. If there is no ! 822: * more room in the caller's array, the number of matches is set to -1. ! 823: * Input: a result string. ! 824: * Returns: nothing. ! 825: */ ! 826: ! 827: addresult(str) ! 828: char *str; ! 829: { ! 830: int l; ! 831: if (strncmp(str,"./",2) == 0) str += 2; ! 832: if (--remlen < 0) { ! 833: numfnd = -1; ! 834: return; ! 835: } ! 836: l = strlen(str) + 1; /* size this will take up */ ! 837: if ((freeptr + l) > &sspace[SSPACE]) { ! 838: numfnd = -1; /* do not record if not enough space */ ! 839: return; ! 840: } ! 841: strcpy(freeptr,str); ! 842: *resptr++ = freeptr; ! 843: freeptr += l; ! 844: numfnd++; ! 845: } ! 846: ! 847: iswild(str) ! 848: char *str; ! 849: { ! 850: char c; ! 851: while ((c = *str++) != '\0') ! 852: if (c == '*' || c == '?') return(1); ! 853: return(0); ! 854: } ! 855: ! 856: /* ! 857: * match: ! 858: * pattern matcher. Takes a string and a pattern possibly containing ! 859: * the wildcard characters '*' and '?'. Returns true if the pattern ! 860: * matches the string, false otherwise. ! 861: * by: Jeff Damens, CUCCA ! 862: * ! 863: * Input: a string and a wildcard pattern. ! 864: * Returns: 1 if match, 0 if no match. ! 865: */ ! 866: ! 867: match(pattern,string) char *pattern,*string; { ! 868: char *psave,*ssave; /* back up pointers for failure */ ! 869: psave = ssave = NULL; ! 870: while (1) { ! 871: for (; *pattern == *string; pattern++,string++) /* skip first */ ! 872: if (*string == '\0') return(1); /* end of strings, succeed */ ! 873: if (*string != '\0' && *pattern == '?') { ! 874: pattern++; /* '?', let it match */ ! 875: string++; ! 876: } else if (*pattern == '*') { /* '*' ... */ ! 877: psave = ++pattern; /* remember where we saw it */ ! 878: ssave = string; /* let it match 0 chars */ ! 879: } else if (ssave != NULL && *ssave != '\0') { /* if not at end */ ! 880: /* ...have seen a star */ ! 881: string = ++ssave; /* skip 1 char from string */ ! 882: pattern = psave; /* and back up pattern */ ! 883: } else return(0); /* otherwise just fail */ ! 884: } ! 885: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.