📄 lsz.c
字号:
if (rxpos && fseek(input_f, (long) rxpos, 0)) { int er=errno; vfile("fseek failed: %s", strerror(er)); DO_SYSLOG((LOG_INFO, "%s/%s: fseek failed: %s", shortname, protname(), strerror(er))); return ERROR; } if (rxpos) zi->bytes_skipped=rxpos; bytcnt = zi->bytes_sent = rxpos; Lastsync = rxpos -1; return zsendfdata(zi); } }}/* Send the data in the file */static intzsendfdata (struct zm_fileinfo *zi){ static int c; int newcnt; static int junkcount; /* Counts garbage chars received by TX */ static size_t last_txpos = 0; static long last_bps = 0; static long not_printed = 0; static long total_sent = 0; static time_t low_bps=0;#ifdef HAVE_MMAP if (use_mmap && !mm_addr) { struct stat st; if (fstat (fileno (input_f), &st) == 0) { mm_size = st.st_size; mm_addr = mmap (0, mm_size, PROT_READ, MAP_SHARED, fileno (input_f), 0); if ((caddr_t) mm_addr == (caddr_t) - 1) mm_addr = NULL; else { fclose (input_f); input_f = NULL; } } }#endif if (play_with_sigint) signal (SIGINT, onintr); Lrxpos = 0; junkcount = 0; Beenhereb4 = 0; somemore: if (setjmp (intrjmp)) { if (play_with_sigint) signal (SIGINT, onintr); waitack: junkcount = 0; c = getinsync (zi, 0); gotack: switch (c) { default: if (input_f) fclose (input_f); DO_SYSLOG((LOG_INFO, "%s/%s: got %d", shortname, protname(), c)); return ERROR; case ZCAN: if (input_f) fclose (input_f); DO_SYSLOG((LOG_INFO, "%s/%s: got ZCAN", shortname, protname(), c)); return ERROR; case ZSKIP: if (input_f) fclose (input_f); DO_SYSLOG((LOG_INFO, "%s/%s: got ZSKIP", shortname, protname(), c)); return c; case ZACK: case ZRPOS: break; case ZRINIT: return OK; }#ifdef READCHECK /* * If the reverse channel can be tested for data, * this logic may be used to detect error packets * sent by the receiver, in place of setjmp/longjmp * rdchk(fdes) returns non 0 if a character is available */ while (rdchk (io_mode_fd)) {#ifdef READCHECK_READS switch (checked)#else switch (READLINE_PF (1))#endif { case CAN: case ZPAD: c = getinsync (zi, 1); goto gotack; case XOFF: /* Wait a while for an XON */ case XOFF | 0200: READLINE_PF (100); } }#endif } newcnt = Rxbuflen; Txwcnt = 0; stohdr (zi->bytes_sent); zsbhdr (ZDATA, Txhdr); do { size_t n; int e; unsigned old = blklen; blklen = calc_blklen (total_sent); total_sent += blklen + OVERHEAD; if (Verbose > 2 && blklen != old) vstringf (_("blklen now %d\n"), blklen);#ifdef HAVE_MMAP if (mm_addr) { if (zi->bytes_sent + blklen < mm_size) n = blklen; else { n = mm_size - zi->bytes_sent; zi->eof_seen = 1; } } else#endif n = zfilbuf (zi); if (zi->eof_seen) { e = ZCRCE; if (Verbose>3) vstring("e=ZCRCE/eof seen"); } else if (junkcount > 3) { e = ZCRCW; if (Verbose>3) vstring("e=ZCRCW/junkcount > 3"); } else if (bytcnt == Lastsync) { e = ZCRCW; if (Verbose>3) vstringf("e=ZCRCW/bytcnt == Lastsync == %ld", (unsigned long) Lastsync);#if 0 /* what is this good for? Rxbuflen/newcnt normally are short - so after * a few KB ZCRCW will be used? (newcnt is never incremented) */ } else if (Rxbuflen && (newcnt -= n) <= 0) { e = ZCRCW; if (Verbose>3) vstringf("e=ZCRCW/Rxbuflen(newcnt=%ld,n=%ld)", (unsigned long) newcnt,(unsigned long) n);#endif } else if (Txwindow && (Txwcnt += n) >= Txwspac) { Txwcnt = 0; e = ZCRCQ; if (Verbose>3) vstring("e=ZCRCQ/Window"); } else { e = ZCRCG; if (Verbose>3) vstring("e=ZCRCG"); } if ((Verbose > 1 || min_bps || stop_time) && (not_printed > (min_bps ? 3 : 7) || zi->bytes_sent > last_bps / 2 + last_txpos)) { int minleft = 0; int secleft = 0; time_t now; last_bps = (zi->bytes_sent / timing (0,&now)); if (last_bps > 0) { minleft = (zi->bytes_total - zi->bytes_sent) / last_bps / 60; secleft = ((zi->bytes_total - zi->bytes_sent) / last_bps) % 60; } if (min_bps) { if (low_bps) { if (last_bps<min_bps) { if (now-low_bps>=min_bps_time) { /* too bad */ if (Verbose) { vstringf(_("zsendfdata: bps rate %ld below min %ld"), last_bps, min_bps); vstring("\r\n"); } DO_SYSLOG((LOG_INFO, "%s/%s: bps rate low: %ld <%ld", shortname, protname(), last_bps, min_bps)); return ERROR; } } else low_bps=0; } else if (last_bps < min_bps) { low_bps=now; } } if (stop_time && now>=stop_time) { /* too bad */ if (Verbose) { vstring(_("zsendfdata: reached stop time")); vstring("\r\n"); } DO_SYSLOG((LOG_INFO, "%s/%s: reached stop time", shortname, protname())); return ERROR; } if (Verbose > 1) { vchar ('\r'); vstringf (_("Bytes Sent:%7ld/%7ld BPS:%-8ld ETA %02d:%02d "), (long) zi->bytes_sent, (long) zi->bytes_total, last_bps, minleft, secleft); } last_txpos = zi->bytes_sent; } else if (Verbose) not_printed++; ZSDATA (DATAADR, n, e); bytcnt = zi->bytes_sent += n; if (e == ZCRCW) goto waitack;#ifdef READCHECK /* * If the reverse channel can be tested for data, * this logic may be used to detect error packets * sent by the receiver, in place of setjmp/longjmp * rdchk(fdes) returns non 0 if a character is available */ fflush (stdout); while (rdchk (io_mode_fd)) {#ifdef READCHECK_READS switch (checked)#else switch (READLINE_PF (1))#endif { case CAN: case ZPAD: c = getinsync (zi, 1); if (c == ZACK) break; /* zcrce - dinna wanna starta ping-pong game */ ZSDATA (txbuf, 0, ZCRCE); goto gotack; case XOFF: /* Wait a while for an XON */ case XOFF | 0200: READLINE_PF (100); default: ++junkcount; } }#endif /* READCHECK */ if (Txwindow) { size_t tcount = 0; while ((tcount = zi->bytes_sent - Lrxpos) >= Txwindow) { vfile ("%ld (%ld,%ld) window >= %u", tcount, (long) zi->bytes_sent, (long) Lrxpos, Txwindow); if (e != ZCRCQ) ZSDATA (txbuf, 0, e = ZCRCQ); c = getinsync (zi, 1); if (c != ZACK) { ZSDATA (txbuf, 0, ZCRCE); goto gotack; } } vfile ("window = %ld", tcount); } } while (!zi->eof_seen); if (play_with_sigint) signal (SIGINT, SIG_IGN); for (;;) { stohdr (zi->bytes_sent); zsbhdr (ZEOF, Txhdr); switch (getinsync (zi, 0)) { case ZACK: continue; case ZRPOS: goto somemore; case ZRINIT: return OK; case ZSKIP: if (input_f) fclose (input_f); DO_SYSLOG((LOG_INFO, "%s/%s: got ZSKIP", shortname, protname())); return c; default: if (input_f) fclose (input_f); DO_SYSLOG((LOG_INFO, "%s/%s: got %d", shortname, protname(), c)); return ERROR; } }}static intcalc_blklen(long total_sent){ static long total_bytes=0; static int calcs_done=0; static long last_error_count=0; static int last_blklen=0; static long last_bytes_per_error=0; unsigned long best_bytes=0; long best_size=0; long this_bytes_per_error; long d; unsigned int i; if (total_bytes==0) { /* called from countem */ total_bytes=total_sent; return 0; } /* it's not good to calc blklen too early */ if (calcs_done++ < 5) { if (error_count && start_blklen >1024) return last_blklen=1024; else last_blklen/=2; return last_blklen=start_blklen; } if (!error_count) { /* that's fine */ if (start_blklen==max_blklen) return start_blklen; this_bytes_per_error=LONG_MAX; goto calcit; } if (error_count!=last_error_count) { /* the last block was bad. shorten blocks until one block is * ok. this is because very often many errors come in an * short period */ if (error_count & 2) { last_blklen/=2; if (last_blklen < 32) last_blklen = 32; else if (last_blklen > 512) last_blklen=512; if (Verbose > 3) vstringf(_("calc_blklen: reduced to %d due to error\n"), last_blklen); } last_error_count=error_count; last_bytes_per_error=0; /* force recalc */ return last_blklen; } this_bytes_per_error=total_sent / error_count; /* we do not get told about every error, because * there may be more than one error per failed block. * but one the other hand some errors are reported more * than once: If a modem buffers more than one block we * get at least two ZRPOS for the same position in case * *one* block has to be resent. * so don't do this: * this_bytes_per_error/=2; */ /* there has to be a margin */ if (this_bytes_per_error<100) this_bytes_per_error=100; /* be nice to the poor machine and do the complicated things not * too often */ if (last_bytes_per_error>this_bytes_per_error) d=last_bytes_per_error-this_bytes_per_error; else d=this_bytes_per_error-last_bytes_per_error; if (d<4) { if (Verbose > 3) { vstringf(_("calc_blklen: returned old value %d due to low bpe diff\n"), last_blklen); vstringf(_("calc_blklen: old %ld, new %ld, d %ld\n"), last_bytes_per_error,this_bytes_per_error,d ); } return last_blklen; } last_bytes_per_error=this_bytes_per_error;calcit: if (Verbose > 3) vstringf(_("calc_blklen: calc total_bytes=%ld, bpe=%ld, ec=%ld\n"), total_bytes,this_bytes_per_error,(long) error_count); for (i=32;i<=max_blklen;i*=2) { long ok; /* some many ok blocks do we need */ long failed; /* and that's the number of blocks not transmitted ok */ unsigned long transmitted; ok=total_bytes / i + 1; failed=((long) i + OVERHEAD) * ok / this_bytes_per_error; transmitted=total_bytes + ok * OVERHEAD + failed * ((long) i+OVERHEAD+OVER_ERR); if (Verbose > 4) vstringf(_("calc_blklen: blklen %d, ok %ld, failed %ld -> %lu\n"), i,ok,failed,transmitted); if (transmitted < best_bytes || !best_bytes) { best_bytes=transmitted; best_size=i; } } if (best_size > 2*last_blklen) best_size=2*last_blklen; last_blklen=best_size; if (Verbose > 3) vstringf(_("calc_blklen: returned %d as best\n"), last_blklen); return last_blklen;}/* * Respond to receiver's complaint, get back in sync with receiver */static int getinsync(struct zm_fileinfo *zi, int flag){ int c; size_t rxpos; for (;;) { c = zgethdr(Rxhdr, 0, &rxpos); switch (c) { case ZCAN: case ZABORT: case ZFIN: case TIMEOUT: return ERROR; case ZRPOS: /* ************************************* */ /* If sending to a buffered modem, you */ /* might send a break at this point to */ /* dump the modem's buffer. */ if (input_f) clearerr(input_f); /* In case file EOF seen */#ifdef HAVE_MMAP if (!mm_addr)#endif if (fseek(input_f, (long) rxpos, 0)) return ERROR; zi->eof_seen = 0; bytcnt = Lrxpos = zi->bytes_sent = rxpos; if (Lastsync == rxpos) { error_count++; } Lastsync = rxpos; return c; case ZACK: Lrxpos = rxpos; if (flag || zi->bytes_sent == rxpos) return ZACK; continue; case ZRINIT: case ZSKIP: if (input_f) fclose(input_f);#ifdef HAVE_MMAP else if (mm_addr) { munmap(mm_addr,mm_size); mm_addr=NULL; }#endif return c; case ERROR: default: error_count++; zsbhdr(ZNAK, Txhdr); continue; } }}/* Say "bibi" to the receiver, try to do it cleanly */static voidsaybibi(void){ for (;;) { stohdr(0L); /* CAF Was zsbhdr - minor change */ zshhdr(ZFIN, Txhdr); /* to make debugging easier */ switch (zgethdr(Rxhdr, 0,NULL)) { case ZFIN: sendline('O'); sendline('O'); flushmo(); case ZCAN: case TIMEOUT: return; } }}/* Send command and related info */static int zsendcmd(const char *buf, size_t blen){ int c; pid_t cmdnum; size_t rxpos; cmdnum = getpid(); errors = 0; for (;;) { stohdr((size_t) cmdnum); Txhdr[ZF0] = Cmdack1; zsbhdr(ZCOMMAND, Txhdr); ZSDATA(buf, blen, ZCRCW);listen: Rxtimeout = 100; /* Ten second wait for resp. */ c = zgethdr(Rxhdr, 1, &rxpos); switch (c) { case ZRINIT: goto listen; /* CAF 8-21-87 */ case ERROR: case TIMEOUT: if (++errors > Cmdtries) return ERROR; continue; case ZCAN: case ZABORT: case ZFIN: case ZSKIP: case ZRPOS: return ERROR; default: if (++errors > 20) return ERROR; continue; case ZCOMPL: Exitcode = rxpos; saybibi(); return OK; case ZRQINIT: vfile("******** RZ *******"); system("rz"); vfile("******** SZ *******"); goto listen; } }}/* * If called as lsb use YMODEM protocol */static voidchkinvok (const char *s){ const char *p; p = s; while (*p == '-') s = ++p; while (*p) if (*p++ == '/') s = p; if (*s == 'v') { Verbose = 1; ++s; } program_name = s; if (*s == 'l') s++; /* lsz -> sz */ protocol = ZM_ZMODEM; if (s[0] == 's' && s[1] == 'x') protocol = ZM_XMODEM; if (s[0] == 's' && (s[1] == 'b' || s[1] == 'y')) { protocol = ZM_YMODEM; }}static voidcountem (int argc, char **argv){ struct stat f; for (Totalleft = 0, Filesleft = 0; --argc >= 0; ++argv) { f.st_size = -1; if (Verbose > 2) { vstringf ("\nCountem: %03d %s ", argc, *argv); } if (access (*argv, R_OK) >= 0 && stat (*argv, &f) >= 0) {#if defined(S_ISDIR) if (!S_ISDIR(f.st_mode) && !S_ISBLK(f.st_mode)) {#else int c; c = f.st_mode & S_IFMT; if (c != S_IFDIR && c != S_IFBLK) {#endif ++Filesleft; Totalleft += f.st_size; } } else if (strcmp (*argv, "-") == 0) { ++Filesleft; Totalleft += DEFBYTL; } if (Verbose > 2) vstringf (" %ld", (long) f.st_size); } if (Verbose > 2) vstringf (_("\ncountem: Total %d %ld\n"), Filesleft, Totalleft); calc_blklen (Totalleft);}/* End of lsz.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -