123599Sbloom #ifndef lint 2*44710Strent static char sccsid[] = "@(#)fio.c 5.6 (Berkeley) 06/29/90"; 323599Sbloom #endif 423599Sbloom 523599Sbloom /* 623599Sbloom * flow control protocol. 723599Sbloom * 823599Sbloom * This protocol relies on flow control of the data stream. 923599Sbloom * It is meant for working over links that can (almost) be 1023599Sbloom * guaranteed to be errorfree, specifically X.25/PAD links. 1123599Sbloom * A sumcheck is carried out over a whole file only. If a 1223599Sbloom * transport fails the receiver can request retransmission(s). 1323599Sbloom * This protocol uses a 7-bit datapath only, so it can be 1423599Sbloom * used on links that are not 8-bit transparent. 1523599Sbloom * 1623599Sbloom * When using this protocol with an X.25 PAD: 1723599Sbloom * Although this protocol uses no control chars except CR, 1823599Sbloom * control chars NULL and ^P are used before this protocol 1923599Sbloom * is started; since ^P is the default char for accessing 2023599Sbloom * PAD X.28 command mode, be sure to disable that access 2123599Sbloom * (PAD par 1). Also make sure both flow control pars 2223599Sbloom * (5 and 12) are set. The CR used in this proto is meant 2323599Sbloom * to trigger packet transmission, hence par 3 should be 2423599Sbloom * set to 2; a good value for the Idle Timer (par 4) is 10. 2523599Sbloom * All other pars should be set to 0. 2625130Sbloom * 2723599Sbloom * Normally a calling site will take care of setting the 2823599Sbloom * local PAD pars via an X.28 command and those of the remote 2923599Sbloom * PAD via an X.29 command, unless the remote site has a 3023599Sbloom * special channel assigned for this protocol with the proper 3123599Sbloom * par settings. 3223599Sbloom * 3325130Sbloom * Additional comments for hosts with direct X.25 access: 3425130Sbloom * - the global variable IsTcpIp, when set, excludes the ioctl's, 3525130Sbloom * so the same binary can run on X.25 and non-X.25 hosts; 3625130Sbloom * - reads are done in small chunks, which can be smaller than 3725130Sbloom * the packet size; your X.25 driver must support that. 3825130Sbloom * 3925130Sbloom * 4025130Sbloom * Author: 4125130Sbloom * Piet Beertema, CWI, Amsterdam, Sep 1984 4225130Sbloom * Modified for X.25 hosts: 4325130Sbloom * Robert Elz, Melbourne Univ, Mar 1985 4423599Sbloom */ 4523599Sbloom 4625130Sbloom #include "uucp.h" 4723599Sbloom #include <signal.h> 4823599Sbloom #ifdef USG 4923599Sbloom #include <termio.h> 5023599Sbloom #else !USG 5123599Sbloom #include <sgtty.h> 5223599Sbloom #endif !USG 5323599Sbloom #include <setjmp.h> 5423599Sbloom 5533563Srick #define FIBUFSIZ 4096 /* for X.25 interfaces: set equal to packet size, 5625130Sbloom * but see comment above 5725130Sbloom */ 5823599Sbloom 5933563Srick #define FOBUFSIZ 4096 /* for X.25 interfaces: set equal to packet size; 6025130Sbloom * otherwise make as large as feasible to reduce 6125130Sbloom * number of write system calls 6225130Sbloom */ 6325130Sbloom 6423599Sbloom #ifndef MAXMSGLEN 6523599Sbloom #define MAXMSGLEN BUFSIZ 6623599Sbloom #endif MAXMSGLEN 6723599Sbloom 6823599Sbloom static int fchksum; 6923599Sbloom static jmp_buf Ffailbuf; 7023599Sbloom 7133563Srick extern long Bytes_Sent, Bytes_Received; 7233563Srick 7323599Sbloom static 7423599Sbloom falarm() 7523599Sbloom { 7623599Sbloom signal(SIGALRM, falarm); 7723599Sbloom longjmp(Ffailbuf, 1); 7823599Sbloom } 7923599Sbloom 80*44710Strent static void (*fsig)(); 8123599Sbloom 8223599Sbloom #ifndef USG 8323599Sbloom #define TCGETA TIOCGETP 8433969Srick #define TCSETAF TIOCSETP 8523599Sbloom #define termio sgttyb 8623599Sbloom #endif USG 8733563Srick static struct termio ttbuf; 8823599Sbloom 8923599Sbloom fturnon() 9023599Sbloom { 9133563Srick int ttbuf_flags; 9223599Sbloom 9325130Sbloom if (!IsTcpIp) { 9425130Sbloom ioctl(Ifn, TCGETA, &ttbuf); 9523599Sbloom #ifdef USG 9633563Srick ttbuf_flags = ttbuf.c_iflag; 9725130Sbloom ttbuf.c_iflag = IXOFF|IXON|ISTRIP; 9825130Sbloom ttbuf.c_cc[VMIN] = FIBUFSIZ > 64 ? 64 : FIBUFSIZ; 9925130Sbloom ttbuf.c_cc[VTIME] = 5; 10033969Srick if (ioctl(Ifn, TCSETAF, &ttbuf) < 0) { 10133969Srick syslog(LOG_ERR, "ioctl(TCSETAF) failed: %m"); 10233969Srick cleanup(FAIL); 10333969Srick } 10433563Srick ttbuf.c_iflag = ttbuf_flags; 10525130Sbloom #else !USG 10633563Srick ttbuf_flags = ttbuf.sg_flags; 10733563Srick ttbuf.sg_flags = ANYP|CBREAK; 10833969Srick if (ioctl(Ifn, TCSETAF, &ttbuf) < 0) { 10933969Srick syslog(LOG_ERR, "ioctl(TCSETAF) failed: %m"); 11033969Srick cleanup(FAIL); 11133969Srick } 11233563Srick /* this is two seperate ioctls to set the x.29 params */ 11333563Srick ttbuf.sg_flags |= TANDEM; 11433969Srick if (ioctl(Ifn, TCSETAF, &ttbuf) < 0) { 11533969Srick syslog(LOG_ERR, "ioctl(TCSETAF) failed: %m"); 11633969Srick cleanup(FAIL); 11733969Srick } 11833563Srick ttbuf.sg_flags = ttbuf_flags; 11933563Srick #endif USG 12025130Sbloom } 12123599Sbloom fsig = signal(SIGALRM, falarm); 12223599Sbloom /* give the other side time to perform its ioctl; 12323599Sbloom * otherwise it may flush out the first data this 12423599Sbloom * side is about to send. 12523599Sbloom */ 12623599Sbloom sleep(2); 12723599Sbloom return SUCCESS; 12823599Sbloom } 12923599Sbloom 13023599Sbloom fturnoff() 13123599Sbloom { 13233563Srick if (!IsTcpIp) 13333969Srick ioctl(Ifn, TCSETAF, &ttbuf); 13423599Sbloom (void) signal(SIGALRM, fsig); 13533563Srick sleep(2); 13623599Sbloom return SUCCESS; 13723599Sbloom } 13823599Sbloom 13923599Sbloom fwrmsg(type, str, fn) 14023599Sbloom register char *str; 14123599Sbloom int fn; 14223599Sbloom char type; 14323599Sbloom { 14423599Sbloom register char *s; 14523599Sbloom char bufr[MAXMSGLEN]; 14623599Sbloom 14723599Sbloom s = bufr; 14823599Sbloom *s++ = type; 14923599Sbloom while (*str) 15023599Sbloom *s++ = *str++; 15123599Sbloom if (*(s-1) == '\n') 15223599Sbloom s--; 15323599Sbloom *s++ = '\r'; 15425130Sbloom *s = 0; 15523599Sbloom (void) write(fn, bufr, s - bufr); 15623599Sbloom return SUCCESS; 15723599Sbloom } 15823599Sbloom 15923599Sbloom frdmsg(str, fn) 16023599Sbloom register char *str; 16123599Sbloom register int fn; 16223599Sbloom { 16323599Sbloom register char *smax; 16423599Sbloom 16523599Sbloom if (setjmp(Ffailbuf)) 16623599Sbloom return FAIL; 16723599Sbloom smax = str + MAXMSGLEN - 1; 16823599Sbloom (void) alarm(2*MAXMSGTIME); 16923599Sbloom for (;;) { 17023599Sbloom if (read(fn, str, 1) <= 0) 17123599Sbloom goto msgerr; 17225130Sbloom *str &= 0177; 17323599Sbloom if (*str == '\r') 17423599Sbloom break; 17525130Sbloom if (*str < ' ') { 17623599Sbloom continue; 17725130Sbloom } 17823599Sbloom if (str++ >= smax) 17923599Sbloom goto msgerr; 18023599Sbloom } 18123599Sbloom *str = '\0'; 18223599Sbloom (void) alarm(0); 18323599Sbloom return SUCCESS; 18423599Sbloom msgerr: 18523599Sbloom (void) alarm(0); 18623599Sbloom return FAIL; 18723599Sbloom } 18823599Sbloom 18923599Sbloom fwrdata(fp1, fn) 19023599Sbloom FILE *fp1; 19123599Sbloom int fn; 19223599Sbloom { 19325130Sbloom register int alen, ret; 19425130Sbloom char ack, ibuf[MAXMSGLEN]; 19525130Sbloom int flen, mil, retries = 0; 19623599Sbloom long abytes, fbytes; 19723599Sbloom struct timeb t1, t2; 19833563Srick float ft; 19923599Sbloom 20023599Sbloom ret = FAIL; 20123599Sbloom retry: 20223599Sbloom fchksum = 0xffff; 20323599Sbloom abytes = fbytes = 0L; 20423599Sbloom ack = '\0'; 20523599Sbloom #ifdef USG 20623599Sbloom time(&t1.time); 20723599Sbloom t1.millitm = 0; 20823599Sbloom #else !USG 20923599Sbloom ftime(&t1); 21023599Sbloom #endif !USG 21125130Sbloom do { 21225130Sbloom alen = fwrblk(fn, fp1, &flen); 21325130Sbloom fbytes += flen; 21425130Sbloom if (alen <= 0) { 21525130Sbloom abytes -= alen; 21623599Sbloom goto acct; 21723599Sbloom } 21825130Sbloom abytes += alen; 21925130Sbloom } while (!feof(fp1) && !ferror(fp1)); 22025130Sbloom DEBUG(8, "\nchecksum: %04x\n", fchksum); 22125130Sbloom if (frdmsg(ibuf, fn) != FAIL) { 22225130Sbloom if ((ack = ibuf[0]) == 'G') 22325130Sbloom ret = SUCCESS; 22425130Sbloom DEBUG(4, "ack - '%c'\n", ack); 22523599Sbloom } 22623599Sbloom acct: 22723599Sbloom #ifdef USG 22823599Sbloom time(&t2.time); 22923599Sbloom t2.millitm = 0; 23023599Sbloom #else !USG 23123599Sbloom ftime(&t2); 23223599Sbloom #endif !USG 23323599Sbloom Now = t2; 23423599Sbloom t2.time -= t1.time; 23523599Sbloom mil = t2.millitm - t1.millitm; 23623599Sbloom if (mil < 0) { 23723599Sbloom --t2.time; 23823599Sbloom mil += 1000; 23923599Sbloom } 24033563Srick ft = (float)t2.time + (float)mil/1000.; 24133563Srick sprintf(ibuf, "sent data %ld bytes %.2f secs %ld bps", 24233563Srick fbytes, ft, (long)((float)fbytes*8./ft)); 24325149Sbloom sysacct(abytes, t2.time); 24433563Srick Bytes_Sent += fbytes; 24525130Sbloom if (retries > 0) 24625130Sbloom sprintf(&ibuf[strlen(ibuf)], ", %d retries", retries); 24723599Sbloom DEBUG(1, "%s\n", ibuf); 24833969Srick log_xferstats(ibuf); 24925130Sbloom if (ack == 'R') { 25025130Sbloom DEBUG(4, "RETRY:\n", 0); 25125130Sbloom fseek(fp1, 0L, 0); 25225130Sbloom retries++; 25325130Sbloom goto retry; 25425130Sbloom } 25523599Sbloom #ifdef SYSACCT 25625130Sbloom if (ret == FAIL) 25723599Sbloom sysaccf(NULL); /* force accounting */ 25823599Sbloom #endif SYSACCT 25923599Sbloom return ret; 26023599Sbloom } 26123599Sbloom 26223599Sbloom /* max. attempts to retransmit a file: */ 26323599Sbloom #define MAXRETRIES (fbytes < 10000L ? 2 : 1) 26423599Sbloom 26523599Sbloom frddata(fn, fp2) 26623599Sbloom register int fn; 26723599Sbloom register FILE *fp2; 26823599Sbloom { 26923599Sbloom register int flen; 27023599Sbloom register char eof; 27125130Sbloom char ibuf[FIBUFSIZ]; 27225130Sbloom int ret, mil, retries = 0; 27323599Sbloom long alen, abytes, fbytes; 27423599Sbloom struct timeb t1, t2; 27533563Srick float ft; 27623599Sbloom 27723599Sbloom ret = FAIL; 27823599Sbloom retry: 27923599Sbloom fchksum = 0xffff; 28023599Sbloom abytes = fbytes = 0L; 28123599Sbloom #ifdef USG 28223599Sbloom time(&t1.time); 28323599Sbloom t1.millitm = 0; 28423599Sbloom #else !USG 28523599Sbloom ftime(&t1); 28623599Sbloom #endif !USG 28723599Sbloom do { 28823599Sbloom flen = frdblk(ibuf, fn, &alen); 28923599Sbloom abytes += alen; 29023599Sbloom if (flen < 0) 29123599Sbloom goto acct; 29225130Sbloom if (eof = flen > FIBUFSIZ) 29325130Sbloom flen -= FIBUFSIZ + 1; 29423599Sbloom fbytes += flen; 29523599Sbloom if (fwrite(ibuf, sizeof (char), flen, fp2) != flen) 29623599Sbloom goto acct; 29723599Sbloom } while (!eof); 29825130Sbloom ret = SUCCESS; 29923599Sbloom acct: 30023599Sbloom #ifdef USG 30123599Sbloom time(&t2.time); 30223599Sbloom t2.millitm = 0; 30323599Sbloom #else !USG 30423599Sbloom ftime(&t2); 30523599Sbloom #endif !USG 30623599Sbloom Now = t2; 30723599Sbloom t2.time -= t1.time; 30823599Sbloom mil = t2.millitm - t1.millitm; 30923599Sbloom if (mil < 0) { 31023599Sbloom --t2.time; 31123599Sbloom mil += 1000; 31223599Sbloom } 31333563Srick ft = (float)t2.time + (float)mil/1000.; 31433563Srick sprintf(ibuf, "received data %ld bytes %.2f secs %ld bps", 31533563Srick fbytes, ft, (long)((float)fbytes*8./ft)); 31625130Sbloom if (retries > 0) 31725130Sbloom sprintf(&ibuf[strlen(ibuf)]," %d retries", retries); 31825149Sbloom sysacct(abytes, t2.time); 31933563Srick Bytes_Received += fbytes; 32023599Sbloom DEBUG(1, "%s\n", ibuf); 32133969Srick log_xferstats(ibuf); 32225130Sbloom if (ret == FAIL) { 32325130Sbloom if (retries++ < MAXRETRIES) { 32425130Sbloom DEBUG(8, "send ack: 'R'\n", 0); 32525130Sbloom fwrmsg('R', "", fn); 32625130Sbloom fseek(fp2, 0L, 0); 32725130Sbloom DEBUG(4, "RETRY:\n", 0); 32825130Sbloom goto retry; 32925130Sbloom } 33025130Sbloom DEBUG(8, "send ack: 'Q'\n", 0); 33125130Sbloom fwrmsg('Q', "", fn); 33225130Sbloom #ifdef SYSACCT 33325130Sbloom sysaccf(NULL); /* force accounting */ 33425130Sbloom #endif SYSACCT 33525130Sbloom } 33625130Sbloom else { 33725130Sbloom DEBUG(8, "send ack: 'G'\n", 0); 33825130Sbloom fwrmsg('G', "", fn); 33925130Sbloom } 34023599Sbloom return ret; 34123599Sbloom } 34223599Sbloom 34323599Sbloom static 34423599Sbloom frdbuf(blk, len, fn) 34523599Sbloom register char *blk; 34623599Sbloom register int len; 34723599Sbloom register int fn; 34823599Sbloom { 34925130Sbloom static int ret = FIBUFSIZ / 2; 35023599Sbloom 35123599Sbloom if (setjmp(Ffailbuf)) 35223599Sbloom return FAIL; 35323599Sbloom (void) alarm(MAXMSGTIME); 35423599Sbloom ret = read(fn, blk, len); 35523599Sbloom alarm(0); 35623599Sbloom return ret <= 0 ? FAIL : ret; 35723599Sbloom } 35823599Sbloom 35925130Sbloom #if !defined(BSD4_2) && !defined(USG) 36023599Sbloom /* call ultouch every TC calls to either frdblk or fwrblk */ 36125130Sbloom #define TC 20 36225130Sbloom static int tc = TC; 36325130Sbloom #endif !defined(BSD4_2) && !defined(USG) 36423599Sbloom 36523599Sbloom /* Byte conversion: 36623599Sbloom * 36725130Sbloom * from pre to 36825130Sbloom * 000-037 172 100-137 36925130Sbloom * 040-171 040-171 37025130Sbloom * 172-177 173 072-077 37125130Sbloom * 200-237 174 100-137 37225130Sbloom * 240-371 175 040-171 37325130Sbloom * 372-377 176 072-077 37423599Sbloom */ 37523599Sbloom 37623599Sbloom static 37725130Sbloom fwrblk(fn, fp, lenp) 37823599Sbloom int fn; 37925130Sbloom register FILE *fp; 38025130Sbloom int *lenp; 38123599Sbloom { 38223599Sbloom register char *op; 38325130Sbloom register int c, sum, nl, len; 38425130Sbloom char obuf[FOBUFSIZ + 8]; 38523599Sbloom int ret; 38623599Sbloom 38725130Sbloom #if !defined(BSD4_2) && !defined(USG) 38823599Sbloom /* call ultouch occasionally */ 38923599Sbloom if (--tc < 0) { 39023599Sbloom tc = TC; 39123599Sbloom ultouch(); 39223599Sbloom } 39325130Sbloom #endif !defined(BSD4_2) && !defined(USG) 39423599Sbloom op = obuf; 39523599Sbloom nl = 0; 39625130Sbloom len = 0; 39723599Sbloom sum = fchksum; 39825130Sbloom while ((c = getc(fp)) != EOF) { 39925130Sbloom len++; 40023599Sbloom if (sum & 0x8000) { 40123599Sbloom sum <<= 1; 40223599Sbloom sum++; 40323599Sbloom } else 40423599Sbloom sum <<= 1; 40525130Sbloom sum += c; 40623599Sbloom sum &= 0xffff; 40725130Sbloom if (c & 0200) { 40825130Sbloom c &= 0177; 40925130Sbloom if (c < 040) { 41023599Sbloom *op++ = '\174'; 41125130Sbloom *op++ = c + 0100; 41223599Sbloom } else 41325130Sbloom if (c <= 0171) { 41423599Sbloom *op++ = '\175'; 41525130Sbloom *op++ = c; 41623599Sbloom } 41723599Sbloom else { 41823599Sbloom *op++ = '\176'; 41925130Sbloom *op++ = c - 0100; 42023599Sbloom } 42123599Sbloom nl += 2; 42223599Sbloom } else { 42325130Sbloom if (c < 040) { 42423599Sbloom *op++ = '\172'; 42525130Sbloom *op++ = c + 0100; 42623599Sbloom nl += 2; 42723599Sbloom } else 42825130Sbloom if (c <= 0171) { 42925130Sbloom *op++ = c; 43023599Sbloom nl++; 43123599Sbloom } else { 43223599Sbloom *op++ = '\173'; 43325130Sbloom *op++ = c - 0100; 43423599Sbloom nl += 2; 43523599Sbloom } 43623599Sbloom } 43725130Sbloom if (nl >= FOBUFSIZ - 1) { 43825130Sbloom /* 43925130Sbloom * peek at next char, see if it will fit 44025130Sbloom */ 44125130Sbloom c = getc(fp); 44225130Sbloom if (c == EOF) 44325130Sbloom break; 44425130Sbloom (void) ungetc(c, fp); 44525130Sbloom if (nl >= FOBUFSIZ || c < 040 || c > 0171) 44625130Sbloom goto writeit; 44725130Sbloom } 44825130Sbloom } 44925130Sbloom /* 45025130Sbloom * At EOF - append checksum, there is space for it... 45125130Sbloom */ 45225130Sbloom sprintf(op, "\176\176%04x\r", sum); 45325130Sbloom nl += strlen(op); 45425130Sbloom writeit: 45525130Sbloom *lenp = len; 45623599Sbloom fchksum = sum; 45725130Sbloom DEBUG(8, "%d/", len); 45823599Sbloom DEBUG(8, "%d,", nl); 45923599Sbloom ret = write(fn, obuf, nl); 46023599Sbloom return ret == nl ? nl : ret < 0 ? 0 : -ret; 46123599Sbloom } 46223599Sbloom 46323599Sbloom static 46423599Sbloom frdblk(ip, fn, rlen) 46523599Sbloom register char *ip; 46623599Sbloom int fn; 46723599Sbloom long *rlen; 46823599Sbloom { 46923599Sbloom register char *op, c; 47023599Sbloom register int sum, len, nl; 47123599Sbloom char buf[5], *erbp = ip; 47223599Sbloom int i; 47323599Sbloom static char special = 0; 47423599Sbloom 47525130Sbloom #if !defined(BSD4_2) && !defined(USG) 47623599Sbloom /* call ultouch occasionally */ 47723599Sbloom if (--tc < 0) { 47823599Sbloom tc = TC; 47923599Sbloom ultouch(); 48023599Sbloom } 48125130Sbloom #endif !defined(BSD4_2) && !defined(USG) 48225130Sbloom if ((len = frdbuf(ip, FIBUFSIZ, fn)) == FAIL) { 48323599Sbloom *rlen = 0; 48423599Sbloom goto dcorr; 48523599Sbloom } 48623599Sbloom *rlen = len; 48723599Sbloom DEBUG(8, "%d/", len); 48823599Sbloom op = ip; 48923599Sbloom nl = 0; 49023599Sbloom sum = fchksum; 49123599Sbloom do { 49223599Sbloom if ((*ip &= 0177) >= '\172') { 49323599Sbloom if (special) { 49423599Sbloom DEBUG(8, "%d", nl); 49523599Sbloom special = 0; 49623599Sbloom op = buf; 49723599Sbloom if (*ip++ != '\176' || (i = --len) > 5) 49823599Sbloom goto dcorr; 49923599Sbloom while (i--) 50025130Sbloom *op++ = *ip++ & 0177; 50123599Sbloom while (len < 5) { 50223599Sbloom i = frdbuf(&buf[len], 5 - len, fn); 50323599Sbloom if (i == FAIL) { 50423599Sbloom len = FAIL; 50523599Sbloom goto dcorr; 50623599Sbloom } 50723599Sbloom DEBUG(8, ",%d", i); 50823599Sbloom len += i; 50923599Sbloom *rlen += i; 51025130Sbloom while (i--) 51125130Sbloom *op++ &= 0177; 51223599Sbloom } 51323599Sbloom if (buf[4] != '\r') 51423599Sbloom goto dcorr; 51523599Sbloom sscanf(buf, "%4x", &fchksum); 51623599Sbloom DEBUG(8, "\nchecksum: %04x\n", sum); 51723599Sbloom if (fchksum == sum) 51825130Sbloom return FIBUFSIZ + 1 + nl; 51923599Sbloom else { 52023599Sbloom DEBUG(8, "\n", 0); 52123599Sbloom DEBUG(4, "Bad checksum\n", 0); 52223599Sbloom return FAIL; 52323599Sbloom } 52423599Sbloom } 52523599Sbloom special = *ip++; 52623599Sbloom } else { 52723599Sbloom if (*ip < '\040') { 52823599Sbloom /* error: shouldn't get control chars */ 52923599Sbloom goto dcorr; 53023599Sbloom } 53123599Sbloom switch (special) { 53223599Sbloom case 0: 53323599Sbloom c = *ip++; 53423599Sbloom break; 53523599Sbloom case '\172': 53623599Sbloom c = *ip++ - 0100; 53723599Sbloom break; 53823599Sbloom case '\173': 53923599Sbloom c = *ip++ + 0100; 54023599Sbloom break; 54123599Sbloom case '\174': 54223599Sbloom c = *ip++ + 0100; 54323599Sbloom break; 54423599Sbloom case '\175': 54523599Sbloom c = *ip++ + 0200; 54623599Sbloom break; 54723599Sbloom case '\176': 54823599Sbloom c = *ip++ + 0300; 54923599Sbloom break; 55023599Sbloom } 55123599Sbloom *op++ = c; 55223599Sbloom if (sum & 0x8000) { 55323599Sbloom sum <<= 1; 55423599Sbloom sum++; 55523599Sbloom } else 55623599Sbloom sum <<= 1; 55723599Sbloom sum += c & 0377; 55823599Sbloom sum &= 0xffff; 55923599Sbloom special = 0; 56023599Sbloom nl++; 56123599Sbloom } 56223599Sbloom } while (--len); 56323599Sbloom fchksum = sum; 56423599Sbloom DEBUG(8, "%d,", nl); 56523599Sbloom return nl; 56623599Sbloom dcorr: 56723599Sbloom DEBUG(8, "\n", 0); 56823599Sbloom DEBUG(4, "Data corrupted\n", 0); 56923599Sbloom while (len != FAIL) { 57025130Sbloom if ((len = frdbuf(erbp, FIBUFSIZ, fn)) != FAIL) 57123599Sbloom *rlen += len; 57223599Sbloom } 57323599Sbloom return FAIL; 57423599Sbloom } 57525130Sbloom 576