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

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