2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (C) 2008 Edwin Groothuis. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/types.h>
32 #include <sys/ioctl.h>
33 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/tftp.h>
46 #include "tftp-file.h"
47 #include "tftp-utils.h"
52 static char convbuffer[66000];
56 convert_from_net(char *buffer, size_t count)
61 * Convert all CR/LF to LF and all CR,NUL to CR
65 for (i = 0; i < count; i++) {
68 convbuffer[n++] = buffer[i];
69 gotcr = (buffer[i] == '\r');
74 if (buffer[i] == '\0') {
80 if (buffer[i] == '\n') {
82 if (ftell(file) != 0) {
83 fseek(file, -1, SEEK_END);
84 convbuffer[n++] = '\n';
86 /* This shouldn't happen */
88 "Received LF as first character");
92 convbuffer[n-1] = '\n';
97 /* Everything else just accept as is */
98 convbuffer[n++] = buffer[i];
99 gotcr = (buffer[i] == '\r');
103 return fwrite(convbuffer, 1, n, file);
107 convert_to_net(char *buffer, size_t count, int init)
110 static size_t n = 0, in = 0;
111 static int newline = 0;
121 * Convert all LF to CR,LF and all CR to CR,NUL
126 buffer[i++] = newline;
132 /* When done we're done */
133 if (feof(file)) break;
135 /* Otherwise read another bunch */
136 in = fread(convbuffer, 1, count, file);
142 if (convbuffer[n] == '\r') {
150 if (convbuffer[n] == '\n') {
157 buffer[i++] = convbuffer[n++];
162 * Whoops... that isn't alllowed (but it will happen
163 * when there is a CR or LF at the end of the buffer)
165 newline = buffer[i-1];
177 write_init(int fd, FILE *f, const char *mode)
181 file = fdopen(fd, "w");
184 tftp_log(LOG_ERR, "fdopen() failed: %s",
190 convert = !strcmp(mode, "netascii");
195 write_file(char *buffer, int count)
199 return fwrite(buffer, 1, count, file);
201 return convert_from_net(buffer, count);
208 if (fclose(file) != 0) {
209 tftp_log(LOG_ERR, "fclose() failed: %s", strerror(errno));
216 read_init(int fd, FILE *f, const char *mode)
219 convert_to_net(NULL, 0, 1);
221 file = fdopen(fd, "r");
224 tftp_log(LOG_ERR, "fdopen() failed: %s",
230 convert = !strcmp(mode, "netascii");
235 read_file(char *buffer, int count)
239 return fread(buffer, 1, count, file);
241 return convert_to_net(buffer, count, 0);
248 if (fclose(file) != 0) {
249 tftp_log(LOG_ERR, "fclose() failed: %s", strerror(errno));
256 /* When an error has occurred, it is possible that the two sides
257 * are out of synch. Ie: that what I think is the other side's
258 * response to packet N is really their response to packet N-1.
260 * So, to try to prevent that, we flush all the input queued up
261 * for us on the network connection on our host.
263 * We return the number of packets we flushed (mostly for reporting
264 * when trace is active).
268 synchnet(int peer) /* socket to flush */
271 char rbuf[MAXPKTSIZE];
272 struct sockaddr_storage from;
276 (void) ioctl(peer, FIONREAD, &i);
279 fromlen = sizeof from;
280 (void) recvfrom(peer, rbuf, sizeof (rbuf), 0,
281 (struct sockaddr *)&from, &fromlen);