1 /* #include "files.h" */
2 
3 /*
4  * file transfer handling for tomenet - evileye
5  * tcp already handles connection/errors, so we do
6  * not need to worry about this.
7  */
8 
9 /* #include <stdio.h>
10 #include <stdlib.h>
11 #include <fcntl.h> */
12 
13 #include "angband.h"
14 
15 extern errr path_build(char *buf, int max, cptr path, cptr file);
16 
17 int remote_update(int ind, char *fname);
18 int check_return(int ind, unsigned short fnum, u32b sum, int Ind);
19 void kill_xfers(int ind);
20 void do_xfers(void);
21 int get_xfers_num(void);
22 int local_file_check(char *fname, u32b *sum);
23 int local_file_ack(int ind, unsigned short fnum);
24 int local_file_err(int ind, unsigned short fnum);
25 int local_file_send(int ind, char *fname);
26 int local_file_init(int ind, unsigned short fnum, char *fname);
27 int local_file_write(int ind, unsigned short fnum, unsigned long len);
28 int local_file_close(int ind, unsigned short fnum);
29 
30 extern const char *ANGBAND_DIR;
31 
32 #define FS_READY 1	/* if ready for more data, set. */
33 #define FS_SEND 2	/* sending connection? */
34 #define FS_NEW 4	/* queued? */
35 #define FS_DONE 8	/* ready to send end packet on final ack */
36 #define FS_CHECK 16	/* file data block open for sum compare only */
37 
38 #define MAX_TNF_SEND	256	/* maximum bytes in a transfer
39 				 * make this a power of 2 if possible
40 				 */
41 
42 struct ft_data{
43 	struct ft_data *next;	/* next in list */
44 	unsigned short id;	/* unique xfer ID */
45 	int ind;		/* server security - who has this transfer */
46 	char fname[256];	/* actual filename */
47 	char tname[256];	/* temporary filename */
48 	FILE* fp;		/* FILE pointer */
49 	unsigned short state;	/* status of transfer */
50 	char buffer[MAX_TNF_SEND];
51 };
52 
53 struct ft_data *fdata = NULL;	/* our pointer to the transfer data */
54 
getfile(int ind,unsigned short fnum)55 static struct ft_data *getfile(int ind, unsigned short fnum){
56 	struct ft_data *trav, *new_ft;
57 	if (fnum == 0) {
58 		new_ft = (struct ft_data*)malloc(sizeof(struct ft_data));
59 		if (new_ft == (struct ft_data*)NULL) return(NULL);
60 		memset(new_ft, 0, sizeof(struct ft_data));
61 		new_ft->next = fdata;
62 		fdata = new_ft;
63 		return(new_ft);
64 	}
65 	trav = fdata;
66 	while (trav) {
67 		if (trav->id == fnum && trav->ind == ind) {
68 			return(trav);
69 		}
70 		trav = trav->next;
71 	}
72 	return(NULL);
73 }
74 
remove_ft(struct ft_data * d_ft)75 static void remove_ft(struct ft_data *d_ft) {
76 	struct ft_data *trav;
77 	trav = fdata;
78 	if (trav == d_ft) {
79 		fdata = trav->next;
80 		free(trav);
81 		return;
82 	}
83 	while (trav) {
84 		if (trav->next == d_ft) {
85 			trav->next = d_ft->next;
86 			free(d_ft);
87 			return;
88 		}
89 		trav = trav->next;
90 	}
91 }
92 
93 /* server and client need to be synchronised on this
94    but for now, clashes are UNLIKELY in the extreme
95    so they can generate their own. */
new_fileid()96 static int new_fileid() {
97 	static int c_id = 0;
98 	c_id++;
99 	if (!c_id) c_id = 1;
100 	return(c_id);
101 }
102 
103 /* acknowledge recipient ready to receive more */
local_file_ack(int ind,unsigned short fnum)104 int local_file_ack(int ind, unsigned short fnum) {
105 	struct ft_data *c_fd;
106 	c_fd = getfile(ind, fnum);
107 	if (c_fd == (struct ft_data*)NULL) return(0);
108 	if (c_fd->state&FS_SEND) {
109 		c_fd->state |= FS_READY;
110 	}
111 	if (c_fd->state & FS_DONE) {
112 		fclose(c_fd->fp);
113 		remove_ft(c_fd);
114 	}
115 	return(1);
116 }
117 
118 /* for now, just kill the connection completely */
local_file_err(int ind,unsigned short fnum)119 int local_file_err(int ind, unsigned short fnum) {
120 	struct ft_data *c_fd;
121 	c_fd = getfile(ind, fnum);
122 	if (c_fd == (struct ft_data*)NULL) return(0);
123 	fclose(c_fd->fp);	/* close the file */
124 	remove_ft(c_fd);
125 	return(1);
126 }
127 
128 /* initialise an file to send */
local_file_send(int ind,char * fname)129 int local_file_send(int ind, char *fname) {
130 	struct ft_data *c_fd;
131 	FILE* fp;
132 	char buf[256];
133 
134 	c_fd = getfile(ind, 0);
135 	if (c_fd == (struct ft_data*)NULL) return(0);
136 	path_build(buf, 256, ANGBAND_DIR, fname);
137 	fp = fopen(buf, "rb");
138 	if (!fp) return(0);
139 	c_fd->fp = fp;
140 	c_fd->ind = ind;
141 	c_fd->id = new_fileid();	/* ALWAYS succeed */
142 	c_fd->state = (FS_SEND|FS_NEW);
143 	strncpy(c_fd->fname, fname, 255);
144 	Send_file_init(c_fd->ind, c_fd->id, c_fd->fname);
145 	return(1);
146 }
147 
148 /* request checksum of remote file */
remote_update(int ind,char * fname)149 int remote_update(int ind, char *fname) {
150 	struct ft_data *c_fd;
151 	c_fd = getfile(ind, 0);
152 	if (c_fd == (struct ft_data*)NULL) return(0);
153 	c_fd->ind = ind;
154 	c_fd->id = new_fileid();	/* ALWAYS succeed */
155 	c_fd->state = (FS_CHECK);
156 	strncpy(c_fd->fname, fname, 255);
157 	Send_file_check(c_fd->ind, c_fd->id, c_fd->fname);
158 	return(1);
159 }
160 
161 /* compare checksums of local/remote files - update if
162    necessary */
check_return(int ind,unsigned short fnum,u32b sum,int Ind)163 int check_return(int ind, unsigned short fnum, u32b sum, int Ind) {
164 	struct ft_data *c_fd;
165 	FILE* fp;
166 	u32b lsum;
167 	char buf[256];
168 
169 	/* check how many LUA files were already checked (for 4.4.8.1.0.0 crash bug) */
170 	if (Ind) Players[Ind]->warning_lua_count--;
171 
172 	c_fd = getfile(ind, fnum);
173 	if (c_fd == (struct ft_data*)NULL) {
174 		return(0);
175 	}
176 	local_file_check(c_fd->fname, &lsum);
177 	if (!(c_fd->state & FS_CHECK)) {
178 		return(0);
179 	}
180 	if (lsum != sum) {
181 		/* Hack: Client 4.4.8.1 apparently was compiled by a MinGW version
182 		   that broke lua updating, resulting in a client crash on logon.
183 		   So skip any lua updates for players using that version.
184 		   That means that players playing spell-casters that use spells in
185 		   the affected LUA files will probably have to update their client
186 		   at some point. */
187 		if (Ind && is_same_as(&Players[Ind]->version, 4, 4, 8, 1, 0, 0)) {
188 			/* Don't give him messages if he cannot help it */
189 			if (!Players[Ind]->v_latest) {
190 				Players[Ind]->warning_lua_update = 1;
191 				msg_format(Ind, "\377oLUA file %s is outdated.", c_fd->fname);
192 			}
193 
194 			return 0;
195 		}
196 
197 		path_build(buf, 256, ANGBAND_DIR, c_fd->fname);
198 		fp = fopen(buf, "rb");
199 		if (!fp) {
200 			remove_ft(c_fd);
201 			return(0);
202 		}
203 		c_fd->fp = fp;
204 		c_fd->ind = ind;
205 		c_fd->state = (FS_SEND | FS_NEW);
206 		Send_file_init(c_fd->ind, c_fd->id, c_fd->fname);
207 		return(1);
208 	}
209 	remove_ft(c_fd);
210 	return(1);
211 }
212 
kill_xfers(int ind)213 void kill_xfers(int ind){
214 	struct ft_data *trav, *next;
215 	trav = fdata;
216 	for (; trav; trav = next) {
217 		next = trav->next;
218 		if (!trav->id) continue;
219 		if (trav->ind == ind) {
220 			if (trav->fp) fclose(trav->fp);
221 			remove_ft(trav);
222 		}
223 	}
224 }
225 
226 /* handle all current SEND type file transfers */
227 /* laid out long like this for testing. DO NOT CHANGE */
do_xfers()228 void do_xfers(){
229 	int x;
230 	struct ft_data *trav;
231 	trav = fdata;
232 	for (; trav; trav = trav->next) {
233 		if (!trav->id) continue;	/* non existent */
234 		if (!(trav->state & FS_SEND)) continue; /* wrong type */
235 		if (!(trav->state & FS_READY)) continue; /* not ready */
236 		x = fread(trav->buffer, 1, MAX_TNF_SEND, trav->fp);
237 		if (!(trav->state & FS_DONE)) {
238 			if (x == 0) {
239 				trav->state |= FS_DONE;
240 			}
241 			else {
242 				Send_file_data(trav->ind, trav->id, trav->buffer, x);
243 				trav->state &= ~(FS_READY);
244 			}
245 		}
246 		else {
247 			Send_file_end(trav->ind, trav->id);
248 			trav->state &= ~(FS_READY);
249 		}
250 	}
251 }
252 
253 /*
254  * Return the number of file transfers in progress
255  * Can be used to check if all file transfers are complete.
256  */
get_xfers_num()257 int get_xfers_num() {
258 	int num = 0;
259 	struct ft_data *trav;
260 	trav = fdata;
261 	for (; trav; trav = trav->next) {
262 		num++;
263 	}
264 	return num;
265 }
266 
267 #ifdef WIN32
268 /*
269  * Create a temporary file on Windows. Code borrowed from ToME.
270  */
ftmpopen(char * template)271 FILE *ftmpopen(char *template) {
272 	static u32b tmp_counter;
273 	static char valid_characters[] =
274 			"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
275 	char f[256];
276 	FILE *fp;
277 	char rand_ext[4];
278 
279 	rand_ext[0] = valid_characters[rand_int(sizeof (valid_characters))];
280 	rand_ext[1] = valid_characters[rand_int(sizeof (valid_characters))];
281 	rand_ext[2] = valid_characters[rand_int(sizeof (valid_characters))];
282 	rand_ext[3] = '\0';
283 	strnfmt(f, 256, "%s/xfer_%ud.%s", ANGBAND_DIR, tmp_counter, rand_ext);
284 	tmp_counter++;
285 
286 	fp = fopen(f, "wb+");
287 	strcpy(template, f);	/* give back our filename */
288 	return fp;
289 }
290 #endif
291 
292 /* Open file for receive/writing */
local_file_init(int ind,unsigned short fnum,char * fname)293 int local_file_init(int ind, unsigned short fnum, char *fname) {
294 	struct ft_data *c_fd;
295 #ifndef WIN32
296 	int fd;
297 #endif
298 	char tname[256] = "tomexfer.XXXXXX";
299 	c_fd = getfile(ind, 0);		/* get empty space */
300 	if (c_fd == (struct ft_data*)NULL) return(0);
301 
302 	if (fname[0] == '/') return(0);	/* lame security */
303 	if (strstr(fname, "..")) return(0);
304 
305 #ifndef WIN32
306 	fd = mkstemp(tname);
307 	c_fd->fp = fdopen(fd, "wb+");
308 #else
309 	c_fd->fp = ftmpopen(tname);
310 #endif
311 	c_fd->state = FS_READY;
312 	if (c_fd->fp) {
313 #ifndef __MINGW32__
314 		unlink(tname);		/* don't fill up /tmp */
315 #endif
316 		c_fd->id = fnum;
317 		c_fd->ind = ind;	/* not really needed for client */
318 		strncpy(c_fd->fname, fname, 255);
319 		strncpy(c_fd->tname, tname, 255);
320 		return(1);
321 	}
322 	remove_ft(c_fd);
323 	return(0);
324 }
325 
326 
327 
328 /* Write received data to temporary file */
local_file_write(int ind,unsigned short fnum,unsigned long len)329 int local_file_write(int ind, unsigned short fnum, unsigned long len) {
330 	struct ft_data *c_fd;
331 	c_fd = getfile(ind, fnum);
332 	if (c_fd == (struct ft_data*) NULL) return(0);
333 	if (Receive_file_data(ind, len, c_fd->buffer) == 0) {
334 		/* Not enough data available */
335 		return -1;
336 	}
337 	if (fwrite(&c_fd->buffer, 1, len, c_fd->fp) < len) {
338 		fprintf(stderr, "fwrite failed\n");
339 		fclose(c_fd->fp);	/* close & remove temp file */
340 #ifdef __MINGW32__
341 		unlink(c_fd->tname);	/* remove it on Windows OS */
342 #endif
343 		remove_ft(c_fd);
344 		return -2;
345 	}
346 	return(1);
347 }
348 
349 /* Close file and make the changes */
local_file_close(int ind,unsigned short fnum)350 int local_file_close(int ind, unsigned short fnum) {
351 	int x;
352 	struct ft_data *c_fd;
353 	char buf[4096];
354 	int size = 4096;
355 	int success = 1;
356 	FILE *wp;
357 	c_fd = getfile(ind, fnum);
358 	if(c_fd == (struct ft_data *) NULL) return 0;
359 
360 	path_build(buf, 4096, ANGBAND_DIR, c_fd->fname);
361 
362 	wp = fopen(buf, "wb");	/* b for windows */
363 	if (wp) {
364 		fseek(c_fd->fp, 0, SEEK_SET);
365 
366 		while ((x = fread(buf, 1, size, c_fd->fp)) > 0) {
367 			if (fwrite(buf, 1, x, wp) < x) {
368 				fprintf(stderr, "fwrite failed\n");
369 				success = 0;
370 				break;
371 			}
372 		}
373 
374 		fclose(wp);
375 	} else {
376 		success = 0;
377 	}
378 
379 	fclose(c_fd->fp);	/* close & remove temp file */
380 #ifdef __MINGW32__
381 	unlink(c_fd->tname);	/* remove it on Windows OS */
382 #endif
383 	remove_ft(c_fd);
384 
385 	return success;
386 }
387 
388 u32b total;
389 
390 /* uses adler checksum now - (client/server) compat essential */
391 /* This is a broken version of Adler-32. This version is only half as
392  * effective as a properly implemented Adler-32. - mikaelh
393  */
do_sum(unsigned char * buffer,int size)394 static void do_sum(unsigned char *buffer, int size) {
395 	u32b s1, s2;
396 	int n;
397 
398 	s1 = total & 0xffff;
399 	s2 = (total >> 16) & 0xffff;
400 
401 #if 0
402 	for (n = 0; n < size; n++) {
403 		s1 = (s1 + buffer[n]) % 65521;
404 		s2 = (s1 + s1) % 65521; /* This is WRONG - mikaelh */
405 	}
406 #else
407 	/* Optimized version of the broken implementation above - mikaelh */
408 	for (n = 0; n < size; n++) {
409 		s1 += buffer[n];
410 	}
411 
412 	if (n) {
413 		s2 = (s1 + s1) % 65521;
414 		s1 %= 65521;
415 	}
416 #endif
417 
418 	total = (s2 << 16) | s1;
419 }
420 
421 /* Get checksum of file */
422 /* don't waste a file transfer data space locally */
local_file_check(char * fname,u32b * sum)423 int local_file_check(char *fname, u32b *sum) {
424 	FILE *fp;
425 	unsigned char *buffer;
426 	int success = 0;
427 	int size = 4096;
428 	char buf[256];
429 
430 	path_build(buf, 256, ANGBAND_DIR, fname);
431 
432 	fp = fopen(buf, "rb");	/* b for windows.. */
433 
434 	if (!fp) return(0);
435 
436 	buffer = (unsigned char*) malloc(size);
437 
438 	if (buffer) {
439 		total = 1L;
440 #if 0
441 		unsigned long tbytes = 0;
442 		unsigned long pos;
443 
444 		while (size) {
445 			pos = ftell(fp);
446 			if (fread(buffer, size, 1, fp)) {
447 				tbytes += size;
448 				do_sum(buffer, size);
449 			}
450 			else {
451 				if (feof(fp)) {
452 					fseek(fp, pos, SEEK_SET);
453 					size /= 2;
454 				}
455 				else if (ferror(fp))
456 					break;
457 			}
458 		}
459 
460 		if (!size) success = 1;
461 #else
462 		/*
463 		 * The above code makes sure that size is always a power of two
464 		 * which really isn't necessary.
465 		 *  - mikaelh
466 		 */
467 		unsigned long n;
468 
469 		while ((n = fread(buffer, 1, size, fp)) > 0) {
470 			do_sum(buffer, n);
471 		}
472 
473 		if (!ferror(fp)) {
474 			success = 1;
475 		}
476 #endif
477 		free(buffer);
478 	}
479 
480 	fclose(fp);
481 	*sum = total;
482 	return (success);
483 }
484