]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - libexec/tftpd/tftp-file.c
Guess when all the bits will be in place for announcing 8.2-RELEASE.
[FreeBSD/releng/8.2.git] / libexec / tftpd / tftp-file.c
1 /*
2  * Copyright (C) 2008 Edwin Groothuis. All rights reserved.
3  * 
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31
32 #include <netinet/in.h>
33 #include <arpa/tftp.h>
34
35 #include <errno.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <syslog.h>
40 #include <unistd.h>
41
42 #include "tftp-file.h"
43 #include "tftp-utils.h"
44
45 static FILE     *file;
46 static int      convert;
47
48 static char     convbuffer[66000];
49 static int      gotcr = 0;
50
51 static size_t
52 convert_from_net(char *buffer, size_t count)
53 {
54         size_t i, n;
55
56         /*
57          * Convert all CR/LF to LF and all CR,NUL to CR
58          */
59
60         n = 0;
61         for (i = 0; i < count; i++) {
62
63                 if (gotcr == 0) {
64                         convbuffer[n++] = buffer[i];
65                         gotcr = (buffer[i] == '\r');
66                         continue;
67                 }
68
69                 /* CR, NULL -> CR */
70                 if (buffer[i] == '\0') {
71                         gotcr = 0;
72                         continue;
73                 }
74
75                 /* CR, LF -> LF */
76                 if (buffer[i] == '\n') {
77                         if (n == 0) {
78                                 if (ftell(file) != 0) {
79                                         fseek(file, -1, SEEK_END);
80                                         convbuffer[n++] = '\n';
81                                 } else {
82                                         /* This shouldn't happen */
83                                         tftp_log(LOG_ERR,
84                                             "Received LF as first character");
85                                         abort();
86                                 }
87                         } else
88                                 convbuffer[n-1] = '\n';
89                         gotcr = 0;
90                         continue;
91                 }
92
93                 /* Everything else just accept as is */
94                 convbuffer[n++] = buffer[i];
95                 gotcr = (buffer[i] == '\r');
96                 continue;
97         }
98
99         return fwrite(convbuffer, 1, n, file);
100 }
101
102 static size_t
103 convert_to_net(char *buffer, size_t count, int init)
104 {
105         size_t i;
106         static size_t n = 0, in = 0;
107         static int newline = 0;
108
109         if (init) {
110                 newline = 0;
111                 n = 0;
112                 in = 0;
113                 return 0 ;
114         }
115
116         /*
117          * Convert all LF to CR,LF and all CR to CR,NUL
118          */
119         i = 0;
120
121         if (newline) {
122                 buffer[i++] = newline;
123                 newline = 0;
124         }
125
126         while (i < count) {
127                 if (n == in) {
128                         /* When done we're done */
129                         if (feof(file)) break;
130
131                         /* Otherwise read another bunch */
132                         in = fread(convbuffer, 1, count, file);
133                         if (in == 0) break;
134                         n = 0;
135                 }
136
137                 /* CR -> CR,NULL */
138                 if (convbuffer[n] == '\r') {
139                         buffer[i++] = '\r';
140                         buffer[i++] = '\0';
141                         n++;
142                         continue;
143                 }
144
145                 /* LF -> CR,LF */
146                 if (convbuffer[n] == '\n') {
147                         buffer[i++] = '\r';
148                         buffer[i++] = '\n';
149                         n++;
150                         continue;
151                 }
152
153                 buffer[i++] = convbuffer[n++];
154         }
155
156         if (i > count) {
157                 /*
158                  * Whoops... that isn't alllowed (but it will happen
159                  * when there is a CR or LF at the end of the buffer)
160                  */
161                 newline = buffer[i-1];
162         }
163
164         if (i < count) {
165                 /* We are done! */
166                 return i;
167         } else
168                 return count;
169
170 }
171
172 int
173 write_init(int fd, FILE *f, const char *mode)
174 {
175
176         if (f == NULL) {
177                 file = fdopen(fd, "w");
178                 if (file == NULL) {
179                         int en = errno;
180                         tftp_log(LOG_ERR, "fdopen() failed: %s",
181                             strerror(errno));
182                         return en;
183                 }
184         } else
185                 file = f;
186         convert = !strcmp(mode, "netascii");
187         return 0;
188 }
189
190 size_t
191 write_file(char *buffer, int count)
192 {
193
194         if (convert == 0)
195                 return fwrite(buffer, 1, count, file);
196
197         return convert_from_net(buffer, count);
198 }
199
200 int
201 write_close(void)
202 {
203
204         if (fclose(file) != 0) {
205                 tftp_log(LOG_ERR, "fclose() failed: %s", strerror(errno));
206                 return 1;
207         }
208         return 0;
209 }
210
211 int
212 read_init(int fd, FILE *f, const char *mode)
213 {
214
215         convert_to_net(NULL, 0, 1);
216         if (f == NULL) {
217                 file = fdopen(fd, "r");
218                 if (file == NULL) {
219                         int en = errno;
220                         tftp_log(LOG_ERR, "fdopen() failed: %s",
221                             strerror(errno));
222                         return en;
223                 }
224         } else
225                 file = f;
226         convert = !strcmp(mode, "netascii");
227         return 0;
228 }
229
230 size_t
231 read_file(char *buffer, int count)
232 {
233
234         if (convert == 0)
235                 return fread(buffer, 1, count, file);
236
237         return convert_to_net(buffer, count, 0);
238 }
239
240 int
241 read_close(void)
242 {
243
244         if (fclose(file) != 0) {
245                 tftp_log(LOG_ERR, "fclose() failed: %s", strerror(errno));
246                 return 1;
247         }
248         return 0;
249 }
250
251
252 int
253 synchnet(int peer __unused)
254 {
255
256         return 0;
257 }