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

Last change on this file since 555 was 555, checked in by Sam Hocevar, 10 years ago

ps3: make everything compile on the PS3. Of course, nothing links yet
because so much support is missing.

File size: 11.7 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5 *
6 *  This software was released into the Public Domain. As with most public
7 *  domain software, no warranty is made or implied by Crack dot Com, by
8 *  Jonathan Clark, or by Sam Hocevar.
9 */
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <fcntl.h>
18#include <unistd.h>
19#include <string.h>
20#include <signal.h>
21#include <sys/stat.h>
22
23#include "common.h"
24
25#include "fileman.h"
26#include "netface.h"
27#include "ghandler.h"
28#include "specache.h"
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 packet, 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 tmp = lstl(actual);
147    memcpy(buf, &tmp, sizeof(tmp));
148
149    int write_amount=sock->write(buf,actual+2);
150    if (write_amount!=actual+2)
151    {
152      fprintf(stderr,"write failed\n");
153      return 0;
154    }
155
156    size_to_read-=actual;
157
158    if (!sock->ready_to_write())
159    {
160      sock->read_unselectable();
161      sock->write_selectable();
162      return 1;    // not ok to write anymore, try again latter
163    }
164
165      } while (size_to_read && actual==read_total);
166
167      sock->read_selectable();
168      sock->write_unselectable();
169
170      size_to_read=0;
171      return 1;
172    } else
173    {
174      sock->read_unselectable();
175      sock->write_selectable();
176      return 1;
177    }
178  }
179  return 0;
180}
181
182
183void file_manager::secure_filename(char *filename, char *mode)
184{
185  if (!no_security)
186  {
187    if (filename[0]=='/') { filename[0]=0; return ; }
188    int level=0;
189    char *f=filename;
190    while (*f)
191    {
192      if (*f=='/') { f++; level++; }
193      else if (*f=='.' && f[1]=='.')
194      {
195    if (f[3]=='.') while (*f!='.') f++;
196    else
197    {
198      f+=2;
199      level--;
200    }
201      } else f++;
202
203    }
204    if (level<0)
205      filename[0]=0;
206  }
207}
208
209
210
211
212file_manager::nfs_client::nfs_client(net_socket *sock, int file_fd, nfs_client *next) :
213  sock(sock),file_fd(file_fd),next(next),size_to_read(0)
214{
215  sock->read_selectable();
216}
217
218
219file_manager::nfs_client::~nfs_client()
220{
221  delete sock;
222  if (file_fd>=0)
223    close(file_fd);
224}
225
226
227void file_manager::add_nfs_client(net_socket *sock)
228{
229  uint8_t size[2];
230  char filename[300],mode[20],*mp;
231  if (sock->read(size,2)!=2) { delete sock; return ; }
232  if (sock->read(filename,size[0])!=size[0]) { delete sock; return ; }
233  if (sock->read(mode,size[1])!=size[1]) { delete sock; return ; }
234
235
236  secure_filename(filename,mode);  // make sure this filename isn't a security risk
237  if (filename[0]==0) { fprintf(stderr,"(denied)\n"); delete sock; return ; }
238
239  mp=mode;
240  int flags=0;
241
242  while (*mp)
243  {
244    if (*mp=='w') flags|=O_CREAT|O_RDWR;
245    else if (*mp=='r') flags|=O_RDONLY;
246    mp++;
247  }
248
249  int f=open(filename,flags,S_IRWXU | S_IRWXG | S_IRWXO);
250
251  FILE *fp=fopen("open.log","ab");
252  fprintf(fp,"open file %s, fd=%d\n",filename,f);
253  fclose(fp);
254
255  if (f<0)
256    f=-1;  // make sure this is -1
257
258
259  int32_t ret=lltl(f);
260  if (sock->write(&ret,sizeof(ret))!=sizeof(ret)) { delete sock; return ; }
261
262  if (f<0)    // no file, sorry
263    delete sock;
264  else
265  {
266    int32_t cur_pos=lseek(f,0,SEEK_CUR);
267    int32_t size=lseek(f,0,SEEK_END);
268    lseek(f,cur_pos,SEEK_SET);
269    size=lltl(size);
270    if (sock->write(&size,sizeof(size))!=sizeof(size)) {  close(f); delete sock; sock=NULL; return ; }
271
272    nfs_list=new nfs_client(sock,f,nfs_list);
273    nfs_list->size=size;
274  }
275}
276
277
278
279void file_manager::remote_file::r_close(char const *reason)
280{
281//  if (reason) fprintf(stderr,"remote_file : %s\n",reason);
282
283  if (sock)
284  {
285    delete sock;
286    sock=NULL;
287  }
288
289}
290
291file_manager::remote_file::remote_file(net_socket *sock, char const *filename, char const *mode, remote_file *Next) : sock(sock)
292{
293  next=Next;
294  open_local=0;
295
296  uint8_t sizes[3]={ CLIENT_NFS,strlen(filename)+1,strlen(mode)+1};
297  if (sock->write(sizes,3)!=3) { r_close("could not send open info"); return ; }
298  if (sock->write(filename,sizes[1])!=sizes[1]) { r_close("could not send filename"); return ; }
299  if (sock->write(mode,sizes[2])!=sizes[2]) { r_close("could not send mode"); return ; }
300
301  int32_t remote_file_fd;
302  if (sock->read(&remote_file_fd,sizeof(remote_file_fd))!=sizeof(remote_file_fd))
303  { r_close("could not read remote fd"); return ; }
304  remote_file_fd=lltl(remote_file_fd);
305  if (remote_file_fd<0) { r_close("remote fd is bad"); return ; }
306
307  if (sock->read(&size,sizeof(size))!=sizeof(size)) { r_close("could not read remote filesize"); return ; }
308
309  size=lltl(size);
310}
311
312int file_manager::remote_file::unbuffered_read(void *buffer, size_t count)
313{
314  if (sock && count)
315  {
316    uint8_t cmd=NFCMD_READ;
317    if (sock->write(&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("read : could not send command"); return 0; }
318
319    int32_t rsize=lltl(count);
320    if (sock->write(&rsize,sizeof(rsize))!=sizeof(rsize)) { r_close("read : could not send size"); return 0; }
321
322    int32_t total_read=0;
323    char buf[READ_PACKET_SIZE];
324
325    ushort packet_size;
326    do
327    {
328      if (sock->read(&packet_size,sizeof(packet_size))!=sizeof(packet_size))
329      {
330    fprintf(stderr,"could not read packet size\n");
331    return 0;
332      }
333
334      packet_size=lstl(packet_size);
335
336      ushort size_read=sock->read(buf,packet_size);
337
338      if (size_read!=packet_size)
339      {
340    if (sock->read(buf+2+size_read,packet_size-size_read)!=packet_size-size_read)
341    {
342      fprintf(stderr,"incomplete packet\n");
343      return 0;
344    }
345      }
346
347      memcpy(buffer,buf,packet_size);
348      buffer=(void *)(((char *)buffer)+packet_size);
349
350      total_read+=packet_size;
351      count-=packet_size;
352    } while (packet_size==READ_PACKET_SIZE-2 && count);
353    return total_read;
354  }
355  return 0;
356}
357
358int32_t file_manager::remote_file::unbuffered_tell()   // ask server where the offset of the file pointer is
359{
360  if (sock)
361  {
362    uint8_t cmd=NFCMD_TELL;
363    if (sock->write(&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("tell : could not send command"); return 0; }
364
365    int32_t offset;
366    if (sock->read(&offset,sizeof(offset))!=sizeof(offset)) { r_close("tell : could not read offset"); return 0; }
367    return lltl(offset);
368  }
369  return 0;
370}
371
372int32_t file_manager::remote_file::unbuffered_seek(int32_t offset)  // tell server to seek to a spot in a file
373{
374  if (sock)
375  {
376    uint8_t cmd=NFCMD_SEEK;
377    if (sock->write(&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("seek : could not send command"); return 0; }
378
379    int32_t off=lltl(offset);
380    if (sock->write(&off,sizeof(off))!=sizeof(off)) { r_close("seek : could not send offset"); return 0; }
381
382    if (sock->read(&offset,sizeof(offset))!=sizeof(offset)) { r_close("seek : could not read offset"); return 0; }
383    return lltl(offset);
384  }
385  return 0;
386}
387
388
389file_manager::remote_file::~remote_file()
390{ r_close(NULL); }
391
392int file_manager::rf_open_file(char const *&filename, char const *mode)
393{
394  net_address *fs_server_addr=NULL;
395
396  if (filename[0]=='/' && filename[1]=='/')   // passive server file reference?
397  {
398    filename+=2;
399
400    fs_server_addr=prot->get_node_address(filename,DEFAULT_COMM_PORT,0);
401    if (!fs_server_addr)
402    {
403      printf("couldn not get address for %s\n",filename);
404      return -1;
405    }
406  } else if (default_fs)
407    fs_server_addr=default_fs->copy();
408
409  if (fs_server_addr)
410  {
411    net_socket *sock=proto->connect_to_server(fs_server_addr,net_socket::SOCKET_SECURE);
412    delete fs_server_addr;
413
414    if (!sock)
415    {
416      fprintf(stderr,"unable to connect\n");
417      return -1;
418    }
419
420    remote_file *rf=new remote_file(sock,filename,mode,remote_list);
421    if (rf->open_failure())
422    {
423      delete rf;
424      return -1;
425    }
426    else
427    {
428      remote_list=rf;
429      return rf->sock->get_fd();
430    }
431  }
432
433
434// FIXME: AK - Should we keep this?
435//  secure_filename(filename,mode);
436  if (filename[0]==0) return -1;
437
438  int flags=0;
439  while (*mode)
440  {
441    if (*mode=='w') flags|=O_CREAT|O_RDWR;
442    else if (*mode=='r') flags|=O_RDONLY;
443    mode++;
444  }
445
446  char tmp_name[200];
447  if (get_filename_prefix() && filename[0] != '/')
448    sprintf(tmp_name,"%s%s",get_filename_prefix(),filename);
449  else strcpy(tmp_name,filename);
450
451  int f=open(tmp_name,flags,S_IRWXU | S_IRWXG | S_IRWXO);
452  if (f>=0)
453  { close(f);
454    return -2;
455  }
456
457  return -1;
458}
459
460
461file_manager::remote_file *file_manager::find_rf(int fd)
462{
463  remote_file *r=remote_list;
464  for (; r && r->sock->get_fd()!=fd; r=r->next)
465  {
466    if (r->sock->get_fd()==-1)
467    {
468      fprintf(stderr,"bad sock\n");
469    }
470  }
471  if (!r) { fprintf(stderr,"Bad fd for remote file %d\n",fd); }
472  return r;
473}
474
475
476int32_t file_manager::rf_tell(int fd)
477{
478  remote_file *rf=find_rf(fd);
479  if (rf) return rf->unbuffered_tell();
480  else return 0;
481}
482
483int32_t file_manager::rf_seek(int fd, int32_t offset)
484{
485  remote_file *rf=find_rf(fd);
486  if (rf) return rf->unbuffered_seek(offset);
487  else return 0;
488}
489
490int file_manager::rf_read(int fd, void *buffer, size_t count)
491{
492  remote_file *rf=find_rf(fd);
493  if (rf) return rf->unbuffered_read(buffer,count);
494  else return 0;
495}
496
497int file_manager::rf_close(int fd)
498{
499  remote_file *rf=remote_list,*last=NULL;
500  while (rf && rf->sock->get_fd()!=fd) rf=rf->next;
501  if (rf)
502  {
503    if (last) last->next=rf->next;
504    else remote_list=rf->next;
505    delete rf;
506    return 1;
507  } else
508  {
509    fprintf(stderr,"Bad fd for remote file %d\n",fd);
510    return 0;
511  }
512}
513
514int32_t file_manager::rf_file_size(int fd)
515{
516  remote_file *rf=find_rf(fd);
517  if (rf) return rf->file_size();
518  else return 0;
519}
Note: See TracBrowser for help on using the repository browser.