|
|
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.