tftp-file.c revision 207614
1207614Simp/* 2207614Simp * Copyright (C) 2008 Edwin Groothuis. All rights reserved. 3207614Simp * 4207614Simp * Redistribution and use in source and binary forms, with or without 5207614Simp * modification, are permitted provided that the following conditions 6207614Simp * are met: 7207614Simp * 1. Redistributions of source code must retain the above copyright 8207614Simp * notice, this list of conditions and the following disclaimer. 9207614Simp * 2. Redistributions in binary form must reproduce the above copyright 10207614Simp * notice, this list of conditions and the following disclaimer in the 11207614Simp * documentation and/or other materials provided with the distribution. 12207614Simp * 13207614Simp * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14207614Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15207614Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16207614Simp * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17207614Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18207614Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19207614Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20207614Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21207614Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22207614Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23207614Simp * SUCH DAMAGE. 24207614Simp */ 25207614Simp 26207614Simp#include <sys/cdefs.h> 27207614Simp__FBSDID("$FreeBSD: head/libexec/tftpd/tftp-file.c 207614 2010-05-04 13:07:40Z imp $"); 28207614Simp 29207614Simp#include <sys/types.h> 30207614Simp#include <sys/stat.h> 31207614Simp 32207614Simp#include <netinet/in.h> 33207614Simp#include <arpa/tftp.h> 34207614Simp 35207614Simp#include <errno.h> 36207614Simp#include <stdio.h> 37207614Simp#include <stdlib.h> 38207614Simp#include <string.h> 39207614Simp#include <syslog.h> 40207614Simp#include <unistd.h> 41207614Simp 42207614Simp#include "tftp-file.h" 43207614Simp#include "tftp-utils.h" 44207614Simp 45207614Simpstatic FILE *file; 46207614Simpstatic int convert; 47207614Simp 48207614Simpstatic char convbuffer[66000]; 49207614Simpstatic int gotcr = 0; 50207614Simp 51207614Simpstatic size_t 52207614Simpconvert_from_net(char *buffer, size_t count) 53207614Simp{ 54207614Simp size_t i, n; 55207614Simp 56207614Simp /* 57207614Simp * Convert all CR/LF to LF and all CR,NUL to CR 58207614Simp */ 59207614Simp 60207614Simp n = 0; 61207614Simp for (i = 0; i < count; i++) { 62207614Simp 63207614Simp if (gotcr == 0) { 64207614Simp convbuffer[n++] = buffer[i]; 65207614Simp gotcr = (buffer[i] == '\r'); 66207614Simp continue; 67207614Simp } 68207614Simp 69207614Simp /* CR, NULL -> CR */ 70207614Simp if (buffer[i] == '\0') { 71207614Simp gotcr = 0; 72207614Simp continue; 73207614Simp } 74207614Simp 75207614Simp /* CR, LF -> LF */ 76207614Simp if (buffer[i] == '\n') { 77207614Simp if (n == 0) { 78207614Simp if (ftell(file) != 0) { 79207614Simp fseek(file, -1, SEEK_END); 80207614Simp convbuffer[n++] = '\n'; 81207614Simp } else { 82207614Simp /* This shouldn't happen */ 83207614Simp tftp_log(LOG_ERR, 84207614Simp "Received LF as first character"); 85207614Simp abort(); 86207614Simp } 87207614Simp } else 88207614Simp convbuffer[n-1] = '\n'; 89207614Simp gotcr = 0; 90207614Simp continue; 91207614Simp } 92207614Simp 93207614Simp /* Everything else just accept as is */ 94207614Simp convbuffer[n++] = buffer[i]; 95207614Simp gotcr = (buffer[i] == '\r'); 96207614Simp continue; 97207614Simp } 98207614Simp 99207614Simp return fwrite(convbuffer, 1, n, file); 100207614Simp} 101207614Simp 102207614Simpstatic size_t 103207614Simpconvert_to_net(char *buffer, size_t count, int init) 104207614Simp{ 105207614Simp size_t i; 106207614Simp static size_t n = 0, read = 0; 107207614Simp static int newline = 0; 108207614Simp 109207614Simp if (init) { 110207614Simp newline = 0; 111207614Simp n = 0; 112207614Simp read = 0; 113207614Simp return 0 ; 114207614Simp } 115207614Simp 116207614Simp /* 117207614Simp * Convert all LF to CR,LF and all CR to CR,NUL 118207614Simp */ 119207614Simp i = 0; 120207614Simp 121207614Simp if (newline) { 122207614Simp buffer[i++] = newline; 123207614Simp newline = 0; 124207614Simp } 125207614Simp 126207614Simp while (i < count) { 127207614Simp if (n == read) { 128207614Simp /* When done we're done */ 129207614Simp if (feof(file)) break; 130207614Simp 131207614Simp /* Otherwise read another bunch */ 132207614Simp read = fread(convbuffer, 1, count, file); 133207614Simp if (read == 0) break; 134207614Simp n = 0; 135207614Simp } 136207614Simp 137207614Simp /* CR -> CR,NULL */ 138207614Simp if (convbuffer[n] == '\r') { 139207614Simp buffer[i++] = '\r'; 140207614Simp buffer[i++] = '\0'; 141207614Simp n++; 142207614Simp continue; 143207614Simp } 144207614Simp 145207614Simp /* LF -> CR,LF */ 146207614Simp if (convbuffer[n] == '\n') { 147207614Simp buffer[i++] = '\r'; 148207614Simp buffer[i++] = '\n'; 149207614Simp n++; 150207614Simp continue; 151207614Simp } 152207614Simp 153207614Simp buffer[i++] = convbuffer[n++]; 154207614Simp } 155207614Simp 156207614Simp if (i > count) { 157207614Simp /* 158207614Simp * Whoops... that isn't alllowed (but it will happen 159207614Simp * when there is a CR or LF at the end of the buffer) 160207614Simp */ 161207614Simp newline = buffer[i-1]; 162207614Simp } 163207614Simp 164207614Simp if (i < count) { 165207614Simp /* We are done! */ 166207614Simp return i; 167207614Simp } else 168207614Simp return count; 169207614Simp 170207614Simp} 171207614Simp 172207614Simpint 173207614Simpwrite_init(int fd, FILE *f, const char *mode) 174207614Simp{ 175207614Simp 176207614Simp if (f == NULL) { 177207614Simp file = fdopen(fd, "w"); 178207614Simp if (file == NULL) { 179207614Simp int en = errno; 180207614Simp tftp_log(LOG_ERR, "fdopen() failed: %s", 181207614Simp strerror(errno)); 182207614Simp return en; 183207614Simp } 184207614Simp } else 185207614Simp file = f; 186207614Simp convert = !strcmp(mode, "netascii"); 187207614Simp return 0; 188207614Simp} 189207614Simp 190207614Simpsize_t 191207614Simpwrite_file(char *buffer, int count) 192207614Simp{ 193207614Simp 194207614Simp if (convert == 0) 195207614Simp return fwrite(buffer, 1, count, file); 196207614Simp 197207614Simp return convert_from_net(buffer, count); 198207614Simp} 199207614Simp 200207614Simpint 201207614Simpwrite_close(void) 202207614Simp{ 203207614Simp 204207614Simp if (fclose(file) != 0) { 205207614Simp tftp_log(LOG_ERR, "fclose() failed: %s", strerror(errno)); 206207614Simp return 1; 207207614Simp } 208207614Simp return 0; 209207614Simp} 210207614Simp 211207614Simpint 212207614Simpread_init(int fd, FILE *f, const char *mode) 213207614Simp{ 214207614Simp 215207614Simp convert_to_net(NULL, 0, 1); 216207614Simp if (f == NULL) { 217207614Simp file = fdopen(fd, "r"); 218207614Simp if (file == NULL) { 219207614Simp int en = errno; 220207614Simp tftp_log(LOG_ERR, "fdopen() failed: %s", 221207614Simp strerror(errno)); 222207614Simp return en; 223207614Simp } 224207614Simp } else 225207614Simp file = f; 226207614Simp convert = !strcmp(mode, "netascii"); 227207614Simp return 0; 228207614Simp} 229207614Simp 230207614Simpsize_t 231207614Simpread_file(char *buffer, int count) 232207614Simp{ 233207614Simp 234207614Simp if (convert == 0) 235207614Simp return fread(buffer, 1, count, file); 236207614Simp 237207614Simp return convert_to_net(buffer, count, 0); 238207614Simp} 239207614Simp 240207614Simpint 241207614Simpread_close(void) 242207614Simp{ 243207614Simp 244207614Simp if (fclose(file) != 0) { 245207614Simp tftp_log(LOG_ERR, "fclose() failed: %s", strerror(errno)); 246207614Simp return 1; 247207614Simp } 248207614Simp return 0; 249207614Simp} 250207614Simp 251207614Simp 252207614Simpint 253207614Simpsynchnet(int peer) 254207614Simp{ 255207614Simp 256207614Simp return 0; 257207614Simp} 258