/* *Copyright (c) 1996 by Oracle Corporation. All Rights Reserved. \ $Header: filep.c 23-aug-96.12:52:57 aswang Exp $ */ /* * Routines to open/close/read/write local file * For binary transmission, we use the UNIX open/read/write system calls * For ascii transmission, we use the UNIX standard i/o routine * fopen/getc/putc */ #ifndef TFTPDEF # include "tftpdef.h" #endif #include #ifdef VMS #include #endif int err_dump(); static int lastcr = 0; /* 1 if last char was a carriage-return */ static int nextchar = 0; FILE *file_open(fname, mode, initblknum) char *fname; char *mode; int initblknum; { register FILE *fp; if (strcmp(fname, "-") == 0) fp = stdout; else if ((fp = fopen(fname, mode)) == NULL) return ((FILE *)0); nextblknum = initblknum; /* for first data or ACK packet */ lastcr = 0; /* for file_write() */ nextchar = -1; /* for file_read() */ DEBUG2("file_open: opened %s, mode = %s", fname, mode); return(fp); } void file_close(fp) FILE *fp; { if (lastcr) err_dump("final character was a CR"); if (nextchar >= 0) err_dump("nextchar >= 0"); if (fp == stdout) return; else if (fclose(fp) == EOF) err_dump("fclose error"); } /* * Read data from local file. * Here we handle any conversion between the file's mode on the local system * and the network mode * * Return the number of bytes read (between 1 and maxnbytes, inclusive) * or 0 on EOF */ int file_read(fp, ptr, maxnbytes, mode) FILE *fp; char *ptr; int maxnbytes; int mode; { register int c, count; if (mode == MODE_BINARY) { #ifndef WIN32 count = read(fileno(fp), ptr, maxnbytes); #else count = _read(fileno(fp), ptr, maxnbytes); #endif if (count < 0) err_dump("read error from local file"); return (count); } else if (mode == MODE_ASCII) { /* * For files that are transferred in netascii, we must perform the reverse * conversions that file_write() does. Note that we have to use the * global "nextchar" to remember if the next character to output is a * linefeed or a null, since the second byte of a 2-byte sequence may not * fit in the current buffer, and may have to go as the first byte of * the next buffer (i.e., we have to remember this fact from one call * to the next) */ for (count = 0; count < maxnbytes; count++) { if (nextchar >=0 ) { *ptr++ = nextchar; nextchar = -1; continue; } c = getc(fp); if (c == EOF) /* EOF return means eof or error */ { if (ferror(fp)) err_dump("read error from getc on local file"); return(count); } else if (c == '\n') { c = '\r'; /* newline -> CR, LF */ nextchar = '\n'; } else if (c == '\r') { nextchar = '\0'; /* CR -> CR, NULL */ } else nextchar = -1; *ptr++ = c; } return(count); } else err_dump("unknown Mode value"); } /* * Write data to the local file. * Here we handle any conversion between the mode of the file on the network * and the local system's conversion. */ void file_write(fp, ptr, nbytes, mode) FILE *fp; char *ptr; int nbytes; int mode; { register int c, i; if (mode == MODE_BINARY) { #ifndef WIN32 i = write(fileno(fp), ptr, nbytes); #else i = _write(fileno(fp), ptr, nbytes); #endif if (i != nbytes) err_dump("write error to local file, i = %d", i); } else if (mode == MODE_ASCII) { /* * For files that are transferred in netascii, we must perform the * following conversion * CR, LF -> newline = '\n' * CR, NULL -> CR = '\r' * CR, anything else -> undefined * * Note that we have to use the global "lastcr" to remember if the last * character was a CR, LF or not, since if the last character of a buffer * is a CR, we have to remember that when we are called for the next * buffer. */ for (i = 0; i < nbytes; i++) { c = *ptr++; if (lastcr) { if (c == '\n') c = '\n'; else if ( c == '\0') c = '\r'; else err_dump("CR followed by 0x%02x", c); lastcr = 0; } else if ( c == '\r') { lastcr = 1; continue; /* get next char */ } if (putc(c, fp) == EOF) err_dump("write error to local file"); } } else err_dump("Unknown MODE value"); }