|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)ftp.c 4.11 (Berkeley) 7/26/83"; ! 3: #endif ! 4: ! 5: #include <sys/param.h> ! 6: #include <sys/stat.h> ! 7: #include <sys/ioctl.h> ! 8: #include <sys/socket.h> ! 9: #include <sys/time.h> ! 10: ! 11: #include <netinet/in.h> ! 12: #include <arpa/ftp.h> ! 13: ! 14: #include <stdio.h> ! 15: #include <signal.h> ! 16: #include <errno.h> ! 17: #include <netdb.h> ! 18: ! 19: #include "ftp_var.h" ! 20: ! 21: struct sockaddr_in hisctladdr; ! 22: struct sockaddr_in data_addr; ! 23: int data = -1; ! 24: int connected; ! 25: struct sockaddr_in myctladdr; ! 26: ! 27: FILE *cin, *cout; ! 28: FILE *dataconn(); ! 29: ! 30: ! 31: /* ! 32: Changes made to this file : ! 33: ! 34: (1) recvrequest() : ! 35: a. Move the logic to check if the local file is successfully ! 36: opened before sending the RETR cmd to remote server. Just ! 37: to make sure user ftp is ready to accept data from server ! 38: before the RETR cmd is sent. ! 39: b. Add logic to report actual no of bytes received from server ! 40: and actual size of new file. They are different because ftp ! 41: user program strips '\n' characters. ! 42: c. Fix for 1st char. lost when print out error message to ! 43: indicate local cannot be opened. ! 44: ! 45: d. If you try to retrieve something into a local file, and you ! 46: don't have the write permission on the file, it should test ! 47: whether you have write permission on the directory contain- ! 48: ing the file. But, previously, if the local file is a path ! 49: name containing slashes, it does a test on a null pathname ! 50: rather than on the containing directory. This is wrong. ! 51: ! 52: (2) empty(): Peter P. 07/02/85 ! 53: @ removed because no routine uses it. Peter P. 07/02/85 ! 54: ! 55: (3) getreply(): Peter P. 07/02/85 ! 56: a. Prevent the reply getter to get more replies than necessary. ! 57: only one reply is gotten per call to this routine. ! 58: */ ! 59: ! 60: struct hostent * ! 61: hookup(host, port) ! 62: char *host; ! 63: int port; ! 64: { ! 65: register struct hostent *hp; ! 66: int s, len; ! 67: ! 68: bzero((char *)&hisctladdr, sizeof (hisctladdr)); ! 69: hp = gethostbyname(host); ! 70: if (hp == NULL) { ! 71: static struct hostent def; ! 72: static struct in_addr defaddr; ! 73: static char namebuf[128]; ! 74: int inet_addr(); ! 75: ! 76: defaddr.s_addr = inet_addr(host); ! 77: if (defaddr.s_addr == -1) { ! 78: fprintf(stderr, "%s: Unknown host.\n", host); ! 79: return (0); ! 80: } ! 81: strcpy(namebuf, host); ! 82: def.h_name = namebuf; ! 83: hostname = namebuf; ! 84: def.h_addr = (char *)&defaddr; ! 85: def.h_length = sizeof (struct in_addr); ! 86: def.h_addrtype = AF_INET; ! 87: def.h_aliases = 0; ! 88: hp = &def; ! 89: } ! 90: hostname = hp->h_name; ! 91: hisctladdr.sin_family = hp->h_addrtype; ! 92: s = socket(hp->h_addrtype, SOCK_STREAM, 0, 0); ! 93: if (s < 0) { ! 94: perror("ftp: socket"); ! 95: return (0); ! 96: } ! 97: if (bind(s, (char *)&hisctladdr, sizeof (hisctladdr), 0) < 0) { ! 98: perror("ftp: bind"); ! 99: goto bad; ! 100: } ! 101: bcopy(hp->h_addr, (char *)&hisctladdr.sin_addr, hp->h_length); ! 102: hisctladdr.sin_port = port; ! 103: if (connect(s, (char *)&hisctladdr, sizeof (hisctladdr), 0) < 0) { ! 104: perror("ftp: connect"); ! 105: goto bad; ! 106: } ! 107: len = sizeof (myctladdr); ! 108: if (getsockname(s, (char *)&myctladdr, &len) < 0) { ! 109: perror("ftp: getsockname"); ! 110: goto bad; ! 111: } ! 112: cin = fdopen(s, "r"); ! 113: cout = fdopen(s, "w"); ! 114: if (cin == NULL || cout == NULL) { ! 115: fprintf(stderr, "ftp: fdopen failed.\n"); ! 116: if (cin) ! 117: fclose(cin); ! 118: if (cout) ! 119: fclose(cout); ! 120: goto bad; ! 121: } ! 122: if (verbose) ! 123: printf("Connected to %s.\n", hp->h_name); ! 124: (void) getreply(0); /* read startup message from server */ ! 125: return (hp); ! 126: bad: ! 127: close(s); ! 128: return ((struct hostent *)0); ! 129: } ! 130: ! 131: login(hp) ! 132: struct hostent *hp; ! 133: { ! 134: char acct[80]; ! 135: char *user, *pass; ! 136: int n; ! 137: ! 138: user = pass = 0; ! 139: ruserpass(hp->h_name, &user, &pass); ! 140: n = command("USER %s", user); ! 141: if (n == CONTINUE) ! 142: n = command("PASS %s", pass); ! 143: if (n == CONTINUE) { ! 144: printf("Account: "); (void) fflush(stdout); ! 145: (void) fgets(acct, sizeof(acct) - 1, stdin); ! 146: acct[strlen(acct) - 1] = '\0'; ! 147: n = command("ACCT %s", acct); ! 148: } ! 149: if (n != COMPLETE) { ! 150: fprintf(stderr, "Login failed.\n"); ! 151: return (0); ! 152: } ! 153: return (1); ! 154: } ! 155: ! 156: /*VARARGS 1*/ ! 157: command(fmt, args) ! 158: char *fmt; ! 159: { ! 160: ! 161: if (debug) { ! 162: printf("---> "); ! 163: _doprnt(fmt, &args, stdout); ! 164: printf("\n"); ! 165: (void) fflush(stdout); ! 166: } ! 167: if (cout == NULL) { ! 168: perror ("No control connection for command"); ! 169: return (0); ! 170: } ! 171: _doprnt(fmt, &args, cout); ! 172: fprintf(cout, "\r\n"); ! 173: (void) fflush(cout); ! 174: return (getreply(!strcmp(fmt, "QUIT"))); ! 175: } ! 176: ! 177: #include <ctype.h> ! 178: ! 179: getreply(expecteof) ! 180: int expecteof; ! 181: { ! 182: register int n; ! 183: register char c; ! 184: register int code, dig; ! 185: int originalcode = 0, continuation = 0; ! 186: ! 187: for (;;) { ! 188: dig = n = code = 0; ! 189: while ((c = getc(cin)) != '\n') { ! 190: dig++; ! 191: if (c == EOF) { ! 192: if (expecteof) ! 193: return (0); ! 194: lostpeer(); ! 195: exit(1); ! 196: } ! 197: if (verbose && c != '\r' || ! 198: (n == '5' && dig > 4)) ! 199: putchar(c); ! 200: if (dig < 4 && isdigit(c)) ! 201: code = code * 10 + (c - '0'); ! 202: if (dig == 4 && c == '-') ! 203: continuation++; ! 204: if (n == 0) ! 205: n = c; ! 206: } ! 207: if (verbose || n == '5') { ! 208: putchar(c); ! 209: (void) fflush (stdout); ! 210: } ! 211: if (continuation && code != originalcode) { ! 212: if (originalcode == 0) ! 213: originalcode = code; ! 214: continue; ! 215: } ! 216: /* if (expecteof || empty(cin)) Peter 07/02/85 */ ! 217: return (n - '0'); ! 218: } ! 219: } ! 220: ! 221: /* not called by anyone anymore... Peter P. 07/02/85 ! 222: empty(f) ! 223: FILE *f; ! 224: { ! 225: long mask; ! 226: struct timeval t; ! 227: ! 228: if (f->_cnt > 0) ! 229: return (0); ! 230: mask = (1 << fileno(f)); ! 231: t.tv_sec = t.tv_usec = 0; ! 232: (void) select(20, &mask, 0, 0, &t); ! 233: return (mask == 0); ! 234: } ! 235: */ ! 236: ! 237: jmp_buf sendabort; ! 238: ! 239: abortsend() ! 240: { ! 241: ! 242: longjmp(sendabort, 1); ! 243: } ! 244: ! 245: sendrequest(cmd, local, remote) ! 246: char *cmd, *local, *remote; ! 247: { ! 248: FILE *fin, *dout, *popen(); ! 249: int (*closefunc)(), pclose(), fclose(), (*oldintr)(); ! 250: char buf[BUFSIZ]; ! 251: long bytes = 0, hashbytes = sizeof (buf); ! 252: long wscnt = 0; ! 253: register int c, d; ! 254: struct stat st; ! 255: struct timeval start, stop; ! 256: ! 257: closefunc = NULL; ! 258: if (setjmp(sendabort)) ! 259: goto bad; ! 260: oldintr = signal(SIGINT, abortsend); ! 261: if (strcmp(local, "-") == 0) ! 262: fin = stdin; ! 263: else if (*local == '|') { ! 264: fin = popen(local + 1, "r"); ! 265: if (fin == NULL) { ! 266: perror(local + 1); ! 267: goto bad; ! 268: } ! 269: closefunc = pclose; ! 270: } else { ! 271: fin = fopen(local, "r"); ! 272: if (fin == NULL) { ! 273: perror(local); ! 274: goto bad; ! 275: } ! 276: closefunc = fclose; ! 277: if (fstat(fileno(fin), &st) < 0 || ! 278: (st.st_mode&S_IFMT) != S_IFREG) { ! 279: fprintf(stderr, "%s: not a plain file.", local); ! 280: goto bad; ! 281: } ! 282: } ! 283: if (initconn()) ! 284: goto bad; ! 285: if (remote) { ! 286: if (command("%s %s", cmd, remote) != PRELIM) ! 287: goto bad; ! 288: } else ! 289: if (command("%s", cmd) != PRELIM) ! 290: goto bad; ! 291: dout = dataconn("w"); ! 292: if (dout == NULL) ! 293: goto bad; ! 294: gettimeofday(&start, (struct timezone *)0); ! 295: switch (type) { ! 296: ! 297: case TYPE_I: ! 298: case TYPE_L: ! 299: errno = d = 0; ! 300: while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) { ! 301: if ((d = write(fileno (dout), buf, c)) < 0) ! 302: break; ! 303: bytes += c; ! 304: if (hash) { ! 305: putchar('#'); ! 306: fflush(stdout); ! 307: } ! 308: } ! 309: wscnt = bytes; ! 310: if (hash && bytes > 0) { ! 311: putchar('\n'); ! 312: fflush(stdout); ! 313: } ! 314: if (c < 0) ! 315: perror(local); ! 316: if (d < 0) ! 317: perror("netout"); ! 318: break; ! 319: ! 320: case TYPE_A: ! 321: while ((c = getc(fin)) != EOF) { ! 322: wscnt++; ! 323: if (c == '\n') { ! 324: while (hash && (bytes >= hashbytes)) { ! 325: putchar('#'); ! 326: fflush(stdout); ! 327: hashbytes += sizeof (buf); ! 328: } ! 329: if (ferror(dout)) ! 330: break; ! 331: putc('\r', dout); ! 332: bytes++; ! 333: } ! 334: putc(c, dout); ! 335: bytes++; ! 336: if (c == '\r') { ! 337: putc('\0', dout); ! 338: bytes++; ! 339: } ! 340: } ! 341: if (hash) { ! 342: if (bytes < hashbytes) ! 343: putchar('#'); ! 344: putchar('\n'); ! 345: fflush(stdout); ! 346: } ! 347: if (ferror(fin)) ! 348: perror(local); ! 349: if (ferror(dout)) ! 350: perror("netout"); ! 351: break; ! 352: } ! 353: if (closefunc != NULL) ! 354: (*closefunc)(fin); ! 355: (void) fclose(dout); ! 356: (void) getreply(0); ! 357: done: ! 358: gettimeofday(&stop, (struct timezone *)0); ! 359: signal(SIGINT, oldintr); ! 360: if (bytes > 0 && verbose) { ! 361: if (fin != stdin) ! 362: printf("Actual size of %s is %d bytes\n", local, wscnt); ! 363: ptransfer("sent", bytes, &start, &stop); ! 364: } ! 365: return; ! 366: bad: ! 367: if (data >= 0) ! 368: (void) close(data), data = -1; ! 369: if (closefunc != NULL && fin != NULL) ! 370: (*closefunc)(fin); ! 371: goto done; ! 372: } ! 373: ! 374: jmp_buf recvabort; ! 375: ! 376: abortrecv() ! 377: { ! 378: ! 379: longjmp(recvabort, 1); ! 380: } ! 381: ! 382: recvrequest(cmd, local, remote, mode) ! 383: char *cmd, *local, *remote, *mode; ! 384: { ! 385: FILE *fout, *din, *popen(); ! 386: int (*closefunc)(), pclose(), fclose(), (*oldintr)(); ! 387: char buf[BUFSIZ]; ! 388: long wrcnt = 0; ! 389: long bytes = 0, hashbytes = sizeof (buf); ! 390: register int c, d; ! 391: struct timeval start, stop; ! 392: ! 393: din = NULL; ! 394: closefunc = NULL; ! 395: if (setjmp(recvabort)) ! 396: goto bad; ! 397: oldintr = signal(SIGINT, abortrecv); ! 398: if (strcmp(local, "-") && *local != '|') ! 399: if (access(local, 2) < 0) { ! 400: if (errno == ENOENT) { ! 401: char *dir = rindex(local, '/'); ! 402: ! 403: if (dir != NULL) ! 404: *dir = 0; ! 405: if (access(dir ? local : ".", 2) < 0) { ! 406: perror(local); ! 407: goto bad; ! 408: } ! 409: if (dir != NULL) ! 410: *dir = '/'; ! 411: } ! 412: else { ! 413: perror(local); ! 414: goto bad; ! 415: } ! 416: } ! 417: if (strcmp(local, "-") == 0) ! 418: fout = stdout; ! 419: else if (*local == '|') { ! 420: fout = popen(local + 1, "w"); ! 421: closefunc = pclose; ! 422: } else { ! 423: fout = fopen(local, mode); ! 424: closefunc = fclose; ! 425: } ! 426: if (fout == NULL) { ! 427: if (*local == '|') perror(local + 1); ! 428: else perror(local); ! 429: goto bad; ! 430: } ! 431: if (initconn()) ! 432: goto bad; ! 433: if (remote) { ! 434: if (command("%s %s", cmd, remote) != PRELIM) ! 435: goto bad; ! 436: } else ! 437: if (command("%s", cmd) != PRELIM) ! 438: goto bad; ! 439: din = dataconn("r"); ! 440: if (din == NULL) ! 441: goto bad; ! 442: gettimeofday(&start, (struct timezone *)0); ! 443: switch (type) { ! 444: ! 445: case TYPE_I: ! 446: case TYPE_L: ! 447: errno = d = 0; ! 448: while ((c = read(fileno(din), buf, sizeof (buf))) > 0) { ! 449: if ((d = write(fileno(fout), buf, c)) < 0) ! 450: break; ! 451: bytes += d; ! 452: if (hash) { ! 453: putchar('#'); ! 454: fflush(stdout); ! 455: } ! 456: } ! 457: wrcnt = bytes; ! 458: if (hash && bytes > 0) { ! 459: putchar('\n'); ! 460: fflush(stdout); ! 461: } ! 462: if (c < 0) ! 463: perror("netin"); ! 464: if (d < 0) ! 465: perror(local); ! 466: break; ! 467: ! 468: case TYPE_A: ! 469: while ((c = getc(din)) != EOF) { ! 470: bytes++; ! 471: if (c == '\r') { ! 472: while (hash && (bytes >= hashbytes)) { ! 473: putchar('#'); ! 474: fflush(stdout); ! 475: hashbytes += sizeof (buf); ! 476: } ! 477: c = getc(din); ! 478: bytes++; ! 479: if (c != '\n') { ! 480: if (ferror (fout)) ! 481: break; ! 482: putc ('\r', fout); ! 483: wrcnt++; ! 484: } ! 485: if (c == '\0') { ! 486: continue; ! 487: } ! 488: } ! 489: putc (c, fout); ! 490: wrcnt++; ! 491: } ! 492: if (hash) { ! 493: if (bytes < hashbytes) ! 494: putchar('#'); ! 495: putchar('\n'); ! 496: fflush(stdout); ! 497: } ! 498: if (ferror (din)) ! 499: perror ("netin"); ! 500: if (ferror (fout)) ! 501: perror (local); ! 502: break; ! 503: } ! 504: (void) fclose(din); ! 505: if (closefunc != NULL) ! 506: (*closefunc)(fout); ! 507: (void) getreply(0); ! 508: done: ! 509: gettimeofday(&stop, (struct timezone *)0); ! 510: signal(SIGINT, oldintr); ! 511: if (bytes > 0 && verbose) { ! 512: ptransfer("received", bytes, &start, &stop); ! 513: if (fout != stdout) ! 514: printf("Actual size of %s is %d bytes\n", local, wrcnt); ! 515: } ! 516: return; ! 517: bad: ! 518: if (data >= 0) { ! 519: /* ! 520: /* if (din != NULL) { ! 521: /* printf("\nstart drainning..\n"); ! 522: /* if (!empty(din)) ! 523: /* for(;;) { c=getc(din); ! 524: /* if (c == EOF) break; ! 525: /* } ! 526: /* } ! 527: /* (void) getreply(0); ! 528: /**/ ! 529: (void) close(data), data = -1; ! 530: } ! 531: if (closefunc != NULL && fout != NULL) ! 532: (*closefunc)(fout); ! 533: goto done; ! 534: } ! 535: ! 536: /* ! 537: * Need to start a listen on the data channel ! 538: * before we send the command, otherwise the ! 539: * server's connect may fail. ! 540: */ ! 541: static int sendport = -1; ! 542: ! 543: initconn() ! 544: { ! 545: register char *p, *a; ! 546: int result, len; ! 547: ! 548: noport: ! 549: data_addr = myctladdr; ! 550: if (sendport) ! 551: data_addr.sin_port = 0; /* let system pick one */ ! 552: if (data != -1) ! 553: (void) close (data); ! 554: data = socket(AF_INET, SOCK_STREAM, 0, 0); ! 555: if (data < 0) { ! 556: perror("ftp: socket"); ! 557: return (1); ! 558: } ! 559: if (!sendport) ! 560: if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0) { ! 561: perror("ftp: setsockopt (resuse address)"); ! 562: goto bad; ! 563: } ! 564: if (bind(data, (char *)&data_addr, sizeof (data_addr), 0) < 0) { ! 565: perror("ftp: bind"); ! 566: goto bad; ! 567: } ! 568: if (options & SO_DEBUG && ! 569: setsockopt(data, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) ! 570: perror("ftp: setsockopt (ignored)"); ! 571: len = sizeof (data_addr); ! 572: if (getsockname(data, (char *)&data_addr, &len) < 0) { ! 573: perror("ftp: getsockname"); ! 574: goto bad; ! 575: } ! 576: if (listen(data, 1) < 0) { ! 577: perror("ftp: listen"); ! 578: goto bad; ! 579: } ! 580: if (sendport) { ! 581: a = (char *)&data_addr.sin_addr; ! 582: p = (char *)&data_addr.sin_port; ! 583: #define UC(b) (((int)b)&0xff) ! 584: result = ! 585: command("PORT %d,%d,%d,%d,%d,%d", ! 586: UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), ! 587: UC(p[0]), UC(p[1])); ! 588: if (result == ERROR && sendport == -1) { ! 589: sendport = 0; ! 590: goto noport; ! 591: } ! 592: return (result != COMPLETE); ! 593: } ! 594: return (0); ! 595: bad: ! 596: (void) close(data), data = -1; ! 597: return (1); ! 598: } ! 599: ! 600: FILE * ! 601: dataconn(mode) ! 602: char *mode; ! 603: { ! 604: struct sockaddr_in from; ! 605: int s, fromlen = sizeof (from); ! 606: ! 607: s = accept(data, &from, &fromlen, 0); ! 608: if (s < 0) { ! 609: perror("ftp: accept"); ! 610: (void) close(data), data = -1; ! 611: return (NULL); ! 612: } ! 613: (void) close(data); ! 614: data = s; ! 615: return (fdopen(data, mode)); ! 616: } ! 617: ! 618: ptransfer(direction, bytes, t0, t1) ! 619: char *direction; ! 620: long bytes; ! 621: struct timeval *t0, *t1; ! 622: { ! 623: struct timeval td; ! 624: long ms; ! 625: float bs; ! 626: ! 627: tvsub(&td, t1, t0); ! 628: ms = (td.tv_sec * 1000) + (td.tv_usec / 1000); ! 629: #define nz(x) ((x) == 0 ? 1 : (x)) ! 630: bs = ((bytes * NBBY * 1000) / (float) nz(ms)) / NBBY; ! 631: printf("%ld bytes %s in %d.%02d seconds (%.2g Kbytes/s)\n", ! 632: bytes, direction, td.tv_sec, td.tv_usec / 10000, bs / 1024.); ! 633: } ! 634: ! 635: tvadd(tsum, t0) ! 636: struct timeval *tsum, *t0; ! 637: { ! 638: ! 639: tsum->tv_sec += t0->tv_sec; ! 640: tsum->tv_usec += t0->tv_usec; ! 641: if (tsum->tv_usec > 1000000) ! 642: tsum->tv_sec++, tsum->tv_usec -= 1000000; ! 643: } ! 644: ! 645: tvsub(tdiff, t1, t0) ! 646: struct timeval *tdiff, *t1, *t0; ! 647: { ! 648: ! 649: tdiff->tv_sec = t1->tv_sec - t0->tv_sec; ! 650: tdiff->tv_usec = t1->tv_usec - t0->tv_usec; ! 651: if (tdiff->tv_usec < 0) ! 652: tdiff->tv_sec--, tdiff->tv_usec += 1000000; ! 653: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.