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