/[LeafOK_CVS]/pvpgn-1.7.4/src/bnetd/file.c
ViewVC logotype

Annotation of /pvpgn-1.7.4/src/bnetd/file.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (hide annotations) (vendor branch)
Tue Jun 6 03:41:37 2006 UTC (19 years, 9 months ago) by sysadm
Branch: GNU, MAIN
CVS Tags: pvpgn_1-7-4-0_MIL, arelease, HEAD
Changes since 1.1: +0 -0 lines
Content type: text/x-csrc
no message

1 sysadm 1.1 /*
2     * Copyright (C) 1998,1999 Ross Combs (rocombs@cs.nmsu.edu)
3     * Copyright (C) 1999 Rob Crittenden (rcrit@greyoak.com)
4     *
5     * This program is free software; you can redistribute it and/or
6     * modify it under the terms of the GNU General Public License
7     * as published by the Free Software Foundation; either version 2
8     * of the License, or (at your option) any later version.
9     *
10     * This program is distributed in the hope that it will be useful,
11     * but WITHOUT ANY WARRANTY; without even the implied warranty of
12     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     * GNU General Public License for more details.
14     *
15     * You should have received a copy of the GNU General Public License
16     * along with this program; if not, write to the Free Software
17     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18     */
19     #include "common/setup_before.h"
20     #include <stdio.h>
21     #ifdef HAVE_STDDEF_H
22     # include <stddef.h>
23     #else
24     # ifndef NULL
25     # define NULL ((void *)0)
26     # endif
27     #endif
28     #ifdef STDC_HEADERS
29     # include <stdlib.h>
30     #else
31     # ifdef HAVE_MALLOC_H
32     # include <malloc.h>
33     # endif
34     #endif
35     #ifdef HAVE_STRING_H
36     # include <string.h>
37     #else
38     # ifdef HAVE_STRINGS_H
39     # include <strings.h>
40     # endif
41     #endif
42     #include "compat/strchr.h"
43     #include <errno.h>
44     #include "compat/strerror.h"
45     #ifdef HAVE_SYS_TYPES_H
46     # include <sys/types.h>
47     #endif
48     #ifdef HAVE_SYS_STAT_H
49     # include <sys/stat.h>
50     #endif
51     #include "common/bn_type.h"
52     #include "common/queue.h"
53     #include "connection.h"
54     #include "common/packet.h"
55     #include "common/file_protocol.h"
56     #include "common/eventlog.h"
57     #include "prefs.h"
58     #include "common/bnettime.h"
59     #include "common/util.h"
60     #include "common/xalloc.h"
61     #include "file.h"
62     #include "common/setup_after.h"
63    
64    
65     static char const * file_get_info(char const * rawname, unsigned int * len, bn_long * modtime);
66    
67     static char * file_find_default(const char *rawname)
68     {
69     /* Add new default files here */
70     const char * defaultfiles[]={"termsofservice-",".txt",
71     "newaccount-",".txt",
72     "chathelp-war3-",".txt",
73     "matchmaking-war3-",".dat",
74     NULL,NULL};
75     const char ** pattern, **extension;
76     char *filename = NULL;
77    
78     for (pattern = defaultfiles, extension = defaultfiles + 1; *pattern; pattern+=2, extension+=2)
79     if (!strncmp(rawname, *pattern,strlen(*pattern))) { /* Check if there is a default file available for this kind of file */
80     filename = (char*)xmalloc(strlen(prefs_get_filedir()) + 1 + strlen(*pattern) + 7 + strlen(*extension) + 1);
81    
82     strcpy(filename, prefs_get_filedir());
83     strcat(filename, "/");
84     strcat(filename, *pattern);
85     strcat(filename, "default");
86     strcat(filename, *extension);
87    
88     break;
89     }
90    
91     return filename;
92     }
93    
94     static char const * file_get_info(char const * rawname, unsigned int * len, bn_long * modtime)
95     {
96     char *filename;
97     struct stat sfile;
98     t_bnettime bt;
99    
100     if (!rawname) {
101     eventlog(eventlog_level_error,__FUNCTION__,"got NULL rawname");
102     return NULL;
103     }
104    
105     if (!len) {
106     eventlog(eventlog_level_error,__FUNCTION__,"got NULL len");
107     return NULL;
108     }
109    
110     if (!modtime) {
111     eventlog(eventlog_level_error,__FUNCTION__,"got NULL modtime");
112     return NULL;
113     }
114    
115     if (strchr(rawname,'/') || strchr(rawname,'\\')) {
116     eventlog(eventlog_level_warn,__FUNCTION__,"got rawname containing '/' or '\\' \"%s\"",rawname);
117     return NULL;
118     }
119    
120     filename = buildpath(prefs_get_filedir(), rawname);
121    
122     if (stat(filename,&sfile)<0) { /* if it doesn't exist, try to replace with default file */
123     xfree((void*)filename);
124     filename = file_find_default(rawname);
125     if (!filename) return NULL; /* no default version */
126    
127     if (stat(filename,&sfile)<0) { /* try again */
128     /* FIXME: check for lower-case version of filename */
129     xfree(filename);
130     return NULL;
131     }
132     }
133    
134     *len = (unsigned int)sfile.st_size;
135     bt = time_to_bnettime(sfile.st_mtime,0);
136     bnettime_to_bn_long(bt,modtime);
137    
138     return filename;
139     }
140    
141    
142     extern int file_to_mod_time(char const * rawname, bn_long * modtime)
143     {
144     char const * filename;
145     unsigned int len;
146    
147     if (!rawname)
148     {
149     eventlog(eventlog_level_error,__FUNCTION__,"got NULL rawname");
150     return -1;
151     }
152     if (!modtime)
153     {
154     eventlog(eventlog_level_error,__FUNCTION__,"got NULL modtime");
155     return -1;
156     }
157    
158     if (!(filename = file_get_info(rawname, &len, modtime)))
159     return -1;
160    
161     xfree((void *)filename); /* avoid warning */
162    
163     return 0;
164     }
165    
166    
167     /* Send a file. If the file doesn't exist we still need to respond
168     * to the file request. This will set filelen to 0 and send the server
169     * reply message and the client will be happy and not hang.
170     */
171     extern int file_send(t_connection * c, char const * rawname, unsigned int adid, unsigned int etag, unsigned int startoffset, int need_header)
172     {
173     char const * filename;
174     t_packet * rpacket;
175     FILE * fp;
176     unsigned int filelen;
177     int nbytes;
178    
179     if (!c)
180     {
181     eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
182     return -1;
183     }
184     if (!rawname)
185     {
186     eventlog(eventlog_level_error,__FUNCTION__,"got NULL rawname");
187     return -1;
188     }
189    
190     if (!(rpacket = packet_create(packet_class_file)))
191     {
192     eventlog(eventlog_level_error,__FUNCTION__,"could not create file packet");
193     return -1;
194     }
195     packet_set_size(rpacket,sizeof(t_server_file_reply));
196     packet_set_type(rpacket,SERVER_FILE_REPLY);
197    
198     if ((filename = file_get_info(rawname,&filelen,&rpacket->u.server_file_reply.timestamp)))
199     {
200     if (!(fp = fopen(filename,"rb")))
201     {
202     /* FIXME: check for lower-case version of filename */
203     eventlog(eventlog_level_error,__FUNCTION__,"stat() succeeded yet could not open file \"%s\" for reading (fclose: %s)",filename,pstrerror(errno));
204     filelen = 0;
205     }
206     xfree((void *)filename); /* avoid warning */
207     }
208     else
209     {
210     fp = NULL;
211     filelen = 0;
212     bn_long_set_a_b(&rpacket->u.server_file_reply.timestamp,0,0);
213     }
214    
215     if (fp)
216     {
217     if (startoffset<filelen) {
218     fseek(fp,startoffset,SEEK_SET);
219     } else {
220     eventlog(eventlog_level_warn,__FUNCTION__,"[%d] startoffset is beyond end of file (%u>%u)",conn_get_socket(c),startoffset,filelen);
221     /* Keep the real filesize. Battle.net does it the same way ... */
222     fclose(fp);
223     fp = NULL;
224     }
225     }
226    
227     if (need_header)
228     {
229     /* send the header from the server with the rawname and length. */
230     bn_int_set(&rpacket->u.server_file_reply.filelen,filelen);
231     bn_int_set(&rpacket->u.server_file_reply.adid,adid);
232     bn_int_set(&rpacket->u.server_file_reply.extensiontag,etag);
233     /* rpacket->u.server_file_reply.timestamp is set above */
234     packet_append_string(rpacket,rawname);
235     conn_push_outqueue(c,rpacket);
236     }
237     packet_del_ref(rpacket);
238    
239     /* Now send the data. Since it may be longer than a packet; we use
240     * the raw packet class.
241     */
242     if (!fp)
243     {
244     eventlog(eventlog_level_warn,__FUNCTION__,"[%d] sending no data for file \"%s\"",conn_get_socket(c),rawname);
245     return -1;
246     }
247    
248     eventlog(eventlog_level_info,__FUNCTION__,"[%d] sending file \"%s\" of length %d",conn_get_socket(c),rawname,filelen);
249     for (;;)
250     {
251     if (!(rpacket = packet_create(packet_class_raw)))
252     {
253     eventlog(eventlog_level_error,__FUNCTION__,"could not create raw packet");
254     if (fclose(fp)<0)
255     eventlog(eventlog_level_error,__FUNCTION__,"could not close file \"%s\" after reading (fclose: %s)",rawname,pstrerror(errno));
256     return -1;
257     }
258     if ((nbytes = fread(packet_get_raw_data_build(rpacket,0),1,MAX_PACKET_SIZE,fp))<(int)MAX_PACKET_SIZE)
259     {
260     if (nbytes>0) /* send out last portion */
261     {
262     packet_set_size(rpacket,nbytes);
263     conn_push_outqueue(c,rpacket);
264     }
265     packet_del_ref(rpacket);
266     if (ferror(fp))
267     eventlog(eventlog_level_error,__FUNCTION__,"read failed before EOF on file \"%s\" (fread: %s)",rawname,pstrerror(errno));
268     break;
269     }
270     packet_set_size(rpacket,nbytes);
271     conn_push_outqueue(c,rpacket);
272     packet_del_ref(rpacket);
273     }
274    
275     if (fclose(fp)<0)
276     eventlog(eventlog_level_error,__FUNCTION__,"could not close file \"%s\" after reading (fclose: %s)",rawname,pstrerror(errno));
277     return 0;
278     }

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1