void recvrequest(const char *cmd, char *volatile local, char *remote, const char *lmode, int printnames) { FILE *volatile fout, *volatile din = 0; int (*volatile closefunc)(FILE *); void (*volatile oldintp)(int); void (*volatile oldintr)(int); volatile int is_retr, tcrflag, bare_lfs = 0; static unsigned bufsize; static char *buf; volatile long bytes = 0, hashbytes = HASHBYTES; register int c, d; struct timeval start, stop; struct stat st; #if 0 printf("%s(%d): recvrequest(cmd=%s,local=%s,remote=%s)\n", __FILE__, __LINE__, cmd, local, remote); #endif is_retr = strcmp(cmd, "RETR") == 0; if (is_retr && ftpverbose && printnames) { if (local && *local != '-') printf("local: %s ", local); if (remote) printf("remote: %s\n", remote); } #if 0 if (proxy && is_retr) { proxtrans(cmd, local, remote); return; } #endif closefunc = NULL; oldintr = NULL; oldintp = NULL; tcrflag = !crflag && is_retr; if (sigsetjmp(recvabort, 1)) { while (cpend) { (void) getreply(0); } if (data >= 0) { (void) close(data); data = -1; } if (oldintr) (void) signal(SIGINT, oldintr); code = -1; return; } oldintr = signal(SIGINT, abortrecv); #if 0 if (strcmp(local, "-") && *local != '|') { if (access(local, W_OK) < 0) { char *dir = rindex(local, '/'); if (errno != ENOENT && errno != EACCES) { fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); (void) signal(SIGINT, oldintr); code = -1; return; } if (dir != NULL) *dir = 0; d = access(dir ? local : ".", W_OK); if (dir != NULL) *dir = '/'; if (d < 0) { fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); (void) signal(SIGINT, oldintr); code = -1; return; } if (!runique && errno == EACCES && chmod(local, 0600) < 0) { fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); /* * Believe it or not, this was actually * repeated in the original source. */ (void) signal(SIGINT, oldintr); /*(void) signal(SIGINT, oldintr);*/ code = -1; return; } if (runique && errno == EACCES && (local = gunique(local)) == NULL) { (void) signal(SIGINT, oldintr); code = -1; return; } } else if (runique && (local = gunique(local)) == NULL) { (void) signal(SIGINT, oldintr); code = -1; return; } } #endif if (!is_retr) { if (curtype != TYPE_A) changetype(TYPE_A, 0); } else if (curtype != type) { changetype(type, 0); } if (initconn()) { (void) signal(SIGINT, oldintr); code = -1; return; } if (sigsetjmp(recvabort, 1)) goto abort; if (is_retr && restart_point && command("REST %ld", (long) restart_point) != CONTINUE) return; if (remote) { if (command("%s %s", cmd, remote) != PRELIM) { (void) signal(SIGINT, oldintr); return; } } else { if (command("%s", cmd) != PRELIM) { (void) signal(SIGINT, oldintr); return; } } din = dataconn("r"); if (din == NULL) goto abort; if (strcmp(local, "-") == 0) fout = stdout; else if (*local == '|') { oldintp = signal(SIGPIPE, SIG_IGN); fout = popen(local + 1, "w"); if (fout == NULL) { perror(local+1); goto abort; } closefunc = pclose; } else { extern int local_fclose(); fout = local_fopen(local, lmode); if (fout == NULL) { fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); goto abort; } closefunc = local_fclose; } if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0) st.st_blksize = BUFSIZ; if (st.st_blksize > bufsize) { if (buf) (void) free(buf); buf = malloc((unsigned)st.st_blksize); if (buf == NULL) { perror("malloc"); bufsize = 0; goto abort; } bufsize = st.st_blksize; } (void) gettimeofday(&start, (struct timezone *)0); switch (curtype) { case TYPE_I: case TYPE_L: if (restart_point && lseek(fileno(fout), (long) restart_point, L_SET) < 0) { fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); if (closefunc != NULL) (*closefunc)(fout); return; } errno = d = 0; while ((c = read(fileno(din), buf, bufsize)) > 0) { if ((d = local_write(fileno(fout), buf, c)) != c) break; bytes += c; if (hash && is_retr) { while (bytes >= hashbytes) { (void) putchar('#'); hashbytes += HASHBYTES; } (void) fflush(stdout); } if (tick && (bytes >= hashbytes) && is_retr) { (void) printf("\rBytes transferred: %ld", bytes); (void) fflush(stdout); while (bytes >= hashbytes) hashbytes += TICKBYTES; } } if (hash && bytes > 0) { if (bytes < HASHBYTES) (void) putchar('#'); (void) putchar('\n'); (void) fflush(stdout); } if (tick && is_retr) { (void) printf("\rBytes transferred: %ld\n", bytes); (void) fflush(stdout); } if (c < 0) { if (errno != EPIPE) perror("netin"); bytes = -1; } if (d < c) { if (d < 0) fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); else fprintf(stderr, "%s: short write\n", local); } break; case TYPE_A: #if 0 /* ascii mode not supported for netflash */ if (restart_point) { register int i, n, ch; if (fseek(fout, 0L, L_SET) < 0) goto done; n = restart_point; for (i = 0; i++ < n;) { if ((ch = getc(fout)) == EOF) goto done; if (ch == '\n') i++; } if (fseek(fout, 0L, L_INCR) < 0) { done: fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); if (closefunc != NULL) (*closefunc)(fout); return; } } while ((c = getc(din)) != EOF) { if (c == '\n') bare_lfs++; while (c == '\r') { while (hash && (bytes >= hashbytes) && is_retr) { (void) putchar('#'); (void) fflush(stdout); hashbytes += HASHBYTES; } if (tick && (bytes >= hashbytes) && is_retr) { printf("\rBytes transferred: %ld", bytes); fflush(stdout); while (bytes >= hashbytes) hashbytes += TICKBYTES; } bytes++; if ((c = getc(din)) != '\n' || tcrflag) { if (ferror(fout)) goto break2; (void) putc('\r', fout); if (c == '\0') { bytes++; goto contin2; } if (c == EOF) goto contin2; } } (void) putc(c, fout); bytes++; contin2: ; } break2: if (hash && is_retr) { if (bytes < hashbytes) (void) putchar('#'); (void) putchar('\n'); (void) fflush(stdout); } if (tick && is_retr) { (void) printf("\rBytes transferred: %ld\n", bytes); (void) fflush(stdout); } if (bare_lfs) { printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs); printf("File may not have transferred correctly.\n"); } if (ferror(din)) { if (errno != EPIPE) perror("netin"); bytes = -1; } if (ferror(fout)) fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); #else printf("Netflash does not support ASCII downloads!\n"); bytes = -1; #endif 0 /* ascii mode not supported for netflash */ break; } if (closefunc != NULL) (*closefunc)(fout); (void) signal(SIGINT, oldintr); if (oldintp) (void) signal(SIGPIPE, oldintp); (void) gettimeofday(&stop, (struct timezone *)0); (void) fclose(din); /* closes data as well, so discard it */ data = -1; (void) getreply(0); if (bytes > 0 && is_retr) ptransfer("received", bytes, &start, &stop); return; abort: /* abort using RFC959 recommended IP,SYNC sequence */ (void) gettimeofday(&stop, (struct timezone *)0); if (oldintp) (void) signal(SIGPIPE, oldintp); (void) signal(SIGINT, SIG_IGN); if (!cpend) { code = -1; (void) signal(SIGINT, oldintr); return; } abort_remote(din); code = -1; if (closefunc != NULL && fout != NULL) (*closefunc)(fout); if (din) { (void) fclose(din); } if (data >= 0) { /* if it just got closed with din, again won't hurt */ (void) close(data); data = -1; } if (bytes > 0) ptransfer("received", bytes, &start, &stop); (void) signal(SIGINT, oldintr); }
void store (const char *name, const char *mode, int unique) { FILE *fout, *din; struct stat st; int (*closefunc) (FILE *); if (unique && stat (name, &st) == 0) { const char *name_unique = gunique (name); if (name_unique) name = name_unique; else { LOGCMD (*mode == 'w' ? "put" : "append", name); return; } } if (restart_point) mode = "r+"; fout = fopen (name, mode); closefunc = fclose; if (fout == NULL) { perror_reply (553, name); LOGCMD (*mode == 'w' ? "put" : "append", name); return; } byte_count = -1; if (restart_point) { if (type == TYPE_A) { off_t i, n; int c; n = restart_point; i = 0; while (i++ < n) { c = getc (fout); if (c == EOF) { perror_reply (550, name); goto done; } if (c == '\n') i++; } /* We must do this seek to "current" position because we are changing from reading to writing. */ if (fseek (fout, 0L, SEEK_CUR) < 0) { perror_reply (550, name); goto done; } } else if (lseek (fileno (fout), restart_point, SEEK_SET) < 0) { perror_reply (550, name); goto done; } } din = dataconn (name, (off_t) - 1, "r"); if (din == NULL) goto done; if (receive_data (din, fout) == 0) { if (unique) reply (226, "Transfer complete (unique file name:%s).", name); else reply (226, "Transfer complete."); } fclose (din); data = -1; pdata = -1; done: LOGBYTES (*mode == 'w' ? "put" : "append", name, byte_count); (*closefunc) (fout); }