source: abuse/trunk/src/net/fileman.cpp @ 56

Last change on this file since 56 was 56, checked in by Sam Hocevar, 14 years ago
  • Add licensing terms to most C / C++ files (Ref #5).
File size: 11.6 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *
5 *  This software was released into the Public Domain. As with most public
6 *  domain software, no warranty is made or implied by Crack dot Com or
7 *  Jonathan Clark.
8 */
9
10#include "config.h"
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <fcntl.h>
15#include <unistd.h>
16#include <string.h>
17#include <signal.h>
18
19#ifndef __WATCOMC__
20#   include <sys/stat.h>
21#endif
22
23#include "macs.hpp"
24
25#include "fileman.hpp"
26#include "netface.hpp"
27#include "ghandler.hpp"
28#include "specache.hpp"
29
30extern net_protocol *prot;
31
32
33file_manager *fman=NULL;
34
35file_manager::file_manager(int argc, char **argv, net_protocol *proto) : proto(proto)
36
37  default_fs=NULL;
38  no_security=0;
39  nfs_list=NULL;
40
41  int i;
42  for (i=1;i<argc;i++)
43    if (!strcmp(argv[i],"-bastard"))   // this bypasses filename security features
44    {
45      fprintf(stderr,"Warning : Security measures bypassed (-bastard)\n");
46      no_security=1;
47    }
48}
49
50
51
52void file_manager::process_net()
53{
54  nfs_client *nc,*last=NULL;
55  for (nc=nfs_list;nc;)      // check for nfs request
56  {
57
58    int ok=1;
59
60    if (nc->sock->error())
61    {
62      ok=0;
63      //fprintf(stderr,"Killing nfs client, socket went bad\n");
64    }
65    else if (nc->size_to_read && nc->sock->ready_to_write())
66      ok=nc->send_read();
67    else if (nc->sock->ready_to_read())
68      ok=process_nfs_command(nc);    // if we couldn't process the packeted, delete the connection
69   
70    if (ok)
71    {
72      last=nc;
73      nc=nc->next;
74    } else
75    {
76      if (last) last->next=nc->next;
77      else nfs_list=nc->next;
78      nfs_client *c=nc;
79      nc=nc->next;
80      delete c;
81    }
82  }
83}
84
85
86int file_manager::process_nfs_command(nfs_client *c)
87{
88  char cmd;
89  if (c->sock->read(&cmd,1)!=1) return 0;
90  switch (cmd)
91  {
92    case NFCMD_READ :
93    {
94      int32_t size;
95      if (c->sock->read(&size,sizeof(size))!=sizeof(size)) return 0;
96      size=lltl(size);
97
98      c->size_to_read=size;
99      return c->send_read();
100    } break;
101    case NFCMD_CLOSE :
102    {
103      return 0;
104    } break;
105    case NFCMD_SEEK :
106    {
107      int32_t offset;
108      if (c->sock->read(&offset,sizeof(offset))!=sizeof(offset)) return 0;
109      offset=lltl(offset);
110      offset=lseek(c->file_fd,offset,0);
111      offset=lltl(offset);
112      if (c->sock->write(&offset,sizeof(offset))!=sizeof(offset)) return 0;
113      return 1;
114    } break;
115    case NFCMD_TELL :
116    {
117      int32_t offset=lseek(c->file_fd,0,SEEK_CUR);
118      offset=lltl(offset);
119      if (c->sock->write(&offset,sizeof(offset))!=sizeof(offset)) return 0;
120      return 1;
121    } break;
122   
123    default :
124    { fprintf(stderr,"net driver : bad command from nfs client\n");
125      return 0;
126    }
127  }
128}
129
130int file_manager::nfs_client::send_read()   // return 0 if failure on socket, not failure to read
131{
132  if (file_fd>=0 && sock)
133  {
134    // first make sure the socket isn't 'full'
135    if (sock->ready_to_write())
136    {
137      char buf[READ_PACKET_SIZE];   
138      short read_total;
139      short actual;
140
141      do
142      {     
143        read_total=size_to_read>(READ_PACKET_SIZE-2) ? (READ_PACKET_SIZE-2) : size_to_read;
144
145        actual=read(file_fd,buf+2,read_total);
146        *((ushort *)buf)=lstl(actual);
147
148        int write_amount=sock->write(buf,actual+2);
149        if (write_amount!=actual+2)
150        {
151          fprintf(stderr,"write failed\n");
152          return 0;
153        }
154
155        size_to_read-=actual;
156
157        if (!sock->ready_to_write())
158        {
159          sock->read_unselectable();
160          sock->write_selectable();
161          return 1;    // not ok to write anymore, try again latter
162        }
163
164      } while (size_to_read && actual==read_total);
165
166      sock->read_selectable();
167      sock->write_unselectable();
168
169      size_to_read=0;
170      return 1;
171    } else
172    {
173      sock->read_unselectable();
174      sock->write_selectable();
175      return 1;
176    }
177  }
178  return 0;
179}
180
181
182void file_manager::secure_filename(char *filename, char *mode)
183{
184  if (!no_security)
185  {   
186    if (filename[0]=='/') { filename[0]=0; return ; }
187    int level=0;
188    char *f=filename;
189    while (*f)
190    {
191      if (*f=='/') { f++; level++; }
192      else if (*f=='.' && f[1]=='.')
193      {
194        if (f[3]=='.') while (*f!='.') f++;
195        else
196        {
197          f+=2;
198          level--;
199        }
200      } else f++;
201     
202    }
203    if (level<0)
204      filename[0]=0;
205  }
206}
207
208
209
210
211file_manager::nfs_client::nfs_client(net_socket *sock, int file_fd, nfs_client *next) :
212  sock(sock),file_fd(file_fd),next(next),size_to_read(0)
213{
214  sock->read_selectable();
215
216
217
218file_manager::nfs_client::~nfs_client()
219{
220  delete sock;
221  if (file_fd>=0)
222    close(file_fd);
223}
224
225
226void file_manager::add_nfs_client(net_socket *sock)
227{
228  uint8_t size[2];
229  char filename[300],mode[20],*mp;
230  if (sock->read(size,2)!=2) { delete sock; return ; }
231  if (sock->read(filename,size[0])!=size[0]) { delete sock; return ; }
232  if (sock->read(mode,size[1])!=size[1]) { delete sock; return ; }
233 
234
235  secure_filename(filename,mode);  // make sure this filename isn't a security risk
236  if (filename[0]==0) { fprintf(stderr,"(denied)\n"); delete sock; return ; }
237
238  mp=mode;
239  int flags=0;
240
241#ifdef __WATCOMC__
242    flags|=O_BINARY;
243#endif
244
245  while (*mp)
246  {
247    if (*mp=='w') flags|=O_CREAT|O_RDWR;
248    else if (*mp=='r') flags|=O_RDONLY;
249    mp++;
250  }
251     
252  int f=open(filename,flags,S_IRWXU | S_IRWXG | S_IRWXO);
253
254  FILE *fp=fopen("open.log","ab");
255  fprintf(fp,"open file %s, fd=%d\n",filename,f);
256  fclose(fp);
257 
258  if (f<0)
259    f=-1;  // make sure this is -1
260
261
262  int32_t ret=lltl(f);
263  if (sock->write(&ret,sizeof(ret))!=sizeof(ret)) { delete sock; return ; }
264
265  if (f<0)    // no file, sorry
266    delete sock;
267  else
268  {
269    int32_t cur_pos=lseek(f,0,SEEK_CUR);
270    int32_t size=lseek(f,0,SEEK_END);
271    lseek(f,cur_pos,SEEK_SET);
272    size=lltl(size);
273    if (sock->write(&size,sizeof(size))!=sizeof(size)) {  close(f); delete sock; sock=NULL; return ; }
274
275    nfs_list=new nfs_client(sock,f,nfs_list);
276    nfs_list->size=size;
277  }
278}
279
280
281
282void file_manager::remote_file::r_close(char const *reason)
283{
284//  if (reason) fprintf(stderr,"remote_file : %s\n",reason);
285
286  if (sock)
287  {
288    delete sock;
289    sock=NULL;
290  }
291
292}
293
294file_manager::remote_file::remote_file(net_socket *sock, char const *filename, char const *mode, remote_file *Next) : sock(sock)
295{
296  next=Next;
297  open_local=0;
298
299  uint8_t sizes[3]={CLIENT_NFS,strlen(filename)+1,strlen(mode)+1};
300  if (sock->write(sizes,3)!=3) { r_close("could not send open info"); return ; }
301  if (sock->write(filename,sizes[1])!=sizes[1]) { r_close("could not send filename"); return ; }
302  if (sock->write(mode,sizes[2])!=sizes[2]) { r_close("could not send mode"); return ; }
303
304  int32_t remote_file_fd;
305  if (sock->read(&remote_file_fd,sizeof(remote_file_fd))!=sizeof(remote_file_fd))
306  { r_close("could not read remote fd"); return ; }   
307  remote_file_fd=lltl(remote_file_fd);
308  if (remote_file_fd<0) { r_close("remote fd is bad"); return ; }
309
310  if (sock->read(&size,sizeof(size))!=sizeof(size)) { r_close("could not read remote filesize"); return ; }
311
312  size=lltl(size);
313}
314
315int file_manager::remote_file::unbuffered_read(void *buffer, size_t count)
316{
317  if (sock && count)
318  {
319    uint8_t cmd=NFCMD_READ;
320    if (sock->write(&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("read : could not send command"); return 0; }
321
322    int32_t rsize=lltl(count);
323    if (sock->write(&rsize,sizeof(rsize))!=sizeof(rsize)) { r_close("read : could not send size"); return 0; }
324
325    int32_t total_read=0;
326    char buf[READ_PACKET_SIZE];
327
328    ushort packet_size;
329    do
330    {
331      if (sock->read(&packet_size,sizeof(packet_size))!=sizeof(packet_size))
332      {
333        fprintf(stderr,"could not read packet size\n");
334        return 0;
335      }
336
337      packet_size=lstl(packet_size);
338
339      ushort size_read=sock->read(buf,packet_size);
340
341      if (size_read!=packet_size)
342      {
343        if (sock->read(buf+2+size_read,packet_size-size_read)!=packet_size-size_read)
344        {
345          fprintf(stderr,"incomplete packet\n");
346          return 0;
347        }
348      }
349
350      memcpy(buffer,buf,packet_size);
351      buffer=(void *)(((char *)buffer)+packet_size);
352
353      total_read+=packet_size;
354      count-=packet_size;
355    } while (packet_size==READ_PACKET_SIZE-2 && count);     
356    return total_read;
357  }
358  return 0;
359}
360
361int32_t file_manager::remote_file::unbuffered_tell()   // ask server where the offset of the file pointer is
362{
363  if (sock)
364  {
365    uint8_t cmd=NFCMD_TELL;
366    if (sock->write(&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("tell : could not send command"); return 0; }
367
368    int32_t offset;
369    if (sock->read(&offset,sizeof(offset))!=sizeof(offset)) { r_close("tell : could not read offset"); return 0; }   
370    return lltl(offset);
371  }   
372  return 0;
373}
374
375int32_t file_manager::remote_file::unbuffered_seek(int32_t offset)  // tell server to seek to a spot in a file
376{
377  if (sock)
378  {
379    uint8_t cmd=NFCMD_SEEK;
380    if (sock->write(&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("seek : could not send command"); return 0; }
381
382    int32_t off=lltl(offset);
383    if (sock->write(&off,sizeof(off))!=sizeof(off)) { r_close("seek : could not send offset"); return 0; }
384
385    if (sock->read(&offset,sizeof(offset))!=sizeof(offset)) { r_close("seek : could not read offset"); return 0; }   
386    return lltl(offset);
387  }   
388  return 0;
389}
390
391
392file_manager::remote_file::~remote_file()
393{ r_close(NULL); }
394
395int file_manager::rf_open_file(char const *&filename, char const *mode)
396{
397  net_address *fs_server_addr=NULL;
398
399  if (filename[0]=='/' && filename[1]=='/')   // passive server file reference?
400  {
401    filename+=2;
402
403    fs_server_addr=prot->get_node_address(filename,DEFAULT_COMM_PORT,0);
404    if (!fs_server_addr)
405    {
406      printf("couldn not get address for %s\n",filename);
407      return -1;
408    }
409  } else if (default_fs)
410    fs_server_addr=default_fs->copy();
411 
412  if (fs_server_addr)
413  {
414    net_socket *sock=proto->connect_to_server(fs_server_addr,net_socket::SOCKET_SECURE);
415    delete fs_server_addr;
416
417    if (!sock)
418    {
419      fprintf(stderr,"unable to connect\n");
420      return -1;
421    }
422
423    remote_file *rf=new remote_file(sock,filename,mode,remote_list);
424    if (rf->open_failure())
425    {
426      delete rf;
427      return -1;
428    }
429    else
430    {
431      remote_list=rf;
432      return rf->sock->get_fd();
433    }     
434  }
435
436
437// FIXME: AK - Should we keep this?
438//  secure_filename(filename,mode);
439  if (filename[0]==0) return -1;
440
441  int flags=0;
442  while (*mode)
443  {
444    if (*mode=='w') flags|=O_CREAT|O_RDWR;
445    else if (*mode=='r') flags|=O_RDONLY;
446    mode++;
447  }
448
449  char tmp_name[200];
450  if (get_filename_prefix() && filename[0] != '/')
451    sprintf(tmp_name,"%s%s",get_filename_prefix(),filename);
452  else strcpy(tmp_name,filename);
453
454  int f=open(tmp_name,flags,S_IRWXU | S_IRWXG | S_IRWXO);
455  if (f>=0)
456  { close(f);
457    return -2;
458  }
459 
460  return -1;
461}
462
463
464file_manager::remote_file *file_manager::find_rf(int fd)
465{
466  remote_file *r=remote_list;
467  for (;r && r->sock->get_fd()!=fd;r=r->next)
468  {
469    if (r->sock->get_fd()==-1)
470    {
471      fprintf(stderr,"bad sock\n");
472    }
473  }
474  if (!r) { fprintf(stderr,"Bad fd for remote file %d\n",fd); }
475  return r;
476}
477
478
479int32_t file_manager::rf_tell(int fd)
480{
481  remote_file *rf=find_rf(fd);
482  if (rf) return rf->unbuffered_tell();
483  else return 0;
484}
485
486int32_t file_manager::rf_seek(int fd, int32_t offset)
487{
488  remote_file *rf=find_rf(fd);
489  if (rf) return rf->unbuffered_seek(offset);
490  else return 0;
491}
492
493int file_manager::rf_read(int fd, void *buffer, size_t count)
494{
495  remote_file *rf=find_rf(fd);
496  if (rf) return rf->unbuffered_read(buffer,count);
497  else return 0;
498}
499
500int file_manager::rf_close(int fd)
501{
502  remote_file *rf=remote_list,*last=NULL;
503  while (rf && rf->sock->get_fd()!=fd) rf=rf->next;
504  if (rf)
505  {
506    if (last) last->next=rf->next;
507    else remote_list=rf->next;
508    delete rf;
509    return 1;
510  } else
511  {
512    fprintf(stderr,"Bad fd for remote file %d\n",fd);
513    return 0;
514  } 
515}
516
517int32_t file_manager::rf_file_size(int fd)
518{
519  remote_file *rf=find_rf(fd);
520  if (rf) return rf->file_size();
521  else return 0;
522}
Note: See TracBrowser for help on using the repository browser.