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