1 /***************************************
2  Functions to handle files.
3 
4  Part of the Routino routing software.
5  ******************/ /******************
6  This file Copyright 2008-2015 Andrew M. Bishop
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU Affero General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU Affero General Public License for more details.
17 
18  You should have received a copy of the GNU Affero General Public License
19  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  ***************************************/
21 
22 
23 #if defined(_MSC_VER)
24 #include <io.h>
25 #include <basetsd.h>
26 #define read(fd,address,length)  _read(fd,address,(unsigned int)(length))
27 #define write(fd,address,length) _write(fd,address,(unsigned int)(length))
28 #define open    _open
29 #define close   _close
30 #define unlink  _unlink
31 #define ssize_t SSIZE_T
32 #else
33 #include <unistd.h>
34 #endif
35 
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <fcntl.h>
40 #include <errno.h>
41 #include <sys/stat.h>
42 
43 #if defined(_MSC_VER) || defined(__MINGW32__)
44 #undef lseek
45 #undef stat
46 #undef fstat
47 #define lseek _lseeki64
48 #define stat  _stati64
49 #define fstat _fstati64
50 #endif
51 
52 #if defined(_MSC_VER) || defined(__MINGW32__)
53 #include "mman-win32.h"
54 #else
55 #include <sys/mman.h>
56 #endif
57 
58 #include <sys/types.h>
59 
60 #include "files.h"
61 
62 
63 /*+ A structure to contain the list of memory mapped files. +*/
64 struct mmapinfo
65 {
66  const char  *filename;         /*+ The name of the file (the index of the list). +*/
67        int    fd;               /*+ The file descriptor used when it was opened. +*/
68        char  *address;          /*+ The address the file was mapped to. +*/
69        size_t length;           /*+ The length of the file. +*/
70 };
71 
72 /*+ The list of memory mapped files. +*/
73 static struct mmapinfo *mappedfiles;
74 
75 /*+ The number of mapped files. +*/
76 static int nmappedfiles=0;
77 
78 
79 #define BUFFLEN 4096
80 
81 /*+ A structure to contain the list of file buffers. +*/
82 struct filebuffer
83 {
84  char   buffer[BUFFLEN];        /*+ The data buffer. +*/
85  size_t pointer;                /*+ The read/write pointer for the file buffer. +*/
86  size_t length;                 /*+ The read pointer for the file buffer. +*/
87  int    reading;                /*+ A flag to indicate if the file is for reading. +*/
88 };
89 
90 /*+ The list of file buffers. +*/
91 static struct filebuffer **filebuffers=NULL;
92 
93 /*+ The number of allocated file buffer pointers. +*/
94 static int nfilebuffers=0;
95 
96 
97 #if defined(_MSC_VER) || defined(__MINGW32__)
98 
99 /*+ A structure to contain the list of opened files to record which are to be deleted when closed. +*/
100 struct openedfile
101 {
102  const char *filename;          /*+ The name of the file. +*/
103        int   delete;            /*+ Set to non-zero value if the file is to be deleted when closed. +*/
104 };
105 
106 /*+ The list of opened files. +*/
107 static struct openedfile **openedfiles=NULL;
108 
109 /*+ The number of allocated opened file buffer pointers. +*/
110 static int nopenedfiles=0;
111 
112 #endif
113 
114 
115 /* Local functions */
116 
117 static void CreateFileBuffer(int fd,int read_write);
118 
119 #if defined(_MSC_VER) || defined(__MINGW32__)
120 
121 static void CreateOpenedFile(int fd,const char *filename);
122 
123 #endif
124 
125 
126 /*++++++++++++++++++++++++++++++++++++++
127   Return a filename composed of the dirname, prefix and name.
128 
129   char *FileName Returns a pointer to memory allocated to the filename.
130 
131   const char *dirname The directory name.
132 
133   const char *prefix The file prefix.
134 
135   const char *name The main part of the name.
136   ++++++++++++++++++++++++++++++++++++++*/
137 
FileName(const char * dirname,const char * prefix,const char * name)138 char *FileName(const char *dirname,const char *prefix, const char *name)
139 {
140  char *filename=(char*)malloc((dirname?strlen(dirname):0)+1+(prefix?strlen(prefix):0)+1+strlen(name)+1);
141 
142  sprintf(filename,"%s%s%s%s%s",dirname?dirname:"",dirname?"/":"",prefix?prefix:"",prefix?"-":"",name);
143 
144  return(filename);
145 }
146 
147 
148 /*++++++++++++++++++++++++++++++++++++++
149   Open a file read-only and map it into memory.
150 
151   void *MapFile Returns the address of the file or exits in case of an error.
152 
153   const char *filename The name of the file to open.
154   ++++++++++++++++++++++++++++++++++++++*/
155 
MapFile(const char * filename)156 void *MapFile(const char *filename)
157 {
158  int fd;
159  struct stat buf;
160  offset_t size;
161  void *address;
162 
163  /* Open the file */
164 
165 #if defined(_MSC_VER) || defined(__MINGW32__)
166  fd=open(filename,O_RDONLY|O_BINARY|O_RANDOM);
167 #else
168  fd=open(filename,O_RDONLY);
169 #endif
170 
171  if(fd<0)
172    {
173 #ifdef LIBROUTINO
174     return(NULL);
175 #else
176     fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",filename,strerror(errno));
177     exit(EXIT_FAILURE);
178 #endif
179    }
180 
181  /* Get its size */
182 
183  if(stat(filename,&buf))
184    {
185 #ifdef LIBROUTINO
186     return(NULL);
187 #else
188     fprintf(stderr,"Cannot stat file '%s' [%s].\n",filename,strerror(errno));
189     exit(EXIT_FAILURE);
190 #endif
191    }
192 
193  size=buf.st_size;
194 
195  /* Map the file */
196 
197  address=mmap(NULL,size,PROT_READ,MAP_SHARED,fd,0);
198 
199  if(address==MAP_FAILED)
200    {
201     close(fd);
202 
203 #ifdef LIBROUTINO
204     return(NULL);
205 #else
206     fprintf(stderr,"Cannot mmap file '%s' for reading [%s].\n",filename,strerror(errno));
207     exit(EXIT_FAILURE);
208 #endif
209    }
210 
211 #ifndef LIBROUTINO
212  log_mmap(size);
213 #endif
214 
215  /* Store the information about the mapped file */
216 
217  mappedfiles=(struct mmapinfo*)realloc((void*)mappedfiles,(nmappedfiles+1)*sizeof(struct mmapinfo));
218 
219  mappedfiles[nmappedfiles].filename=filename;
220  mappedfiles[nmappedfiles].fd=fd;
221  mappedfiles[nmappedfiles].address=address;
222  mappedfiles[nmappedfiles].length=size;
223 
224  nmappedfiles++;
225 
226  return(address);
227 }
228 
229 
230 /*++++++++++++++++++++++++++++++++++++++
231   Open a file read-write and map it into memory.
232 
233   void *MapFileWriteable Returns the address of the file or exits in case of an error.
234 
235   const char *filename The name of the file to open.
236   ++++++++++++++++++++++++++++++++++++++*/
237 
MapFileWriteable(const char * filename)238 void *MapFileWriteable(const char *filename)
239 {
240  int fd;
241  struct stat buf;
242  offset_t size;
243  void *address;
244 
245  /* Open the file */
246 
247 #if defined(_MSC_VER) || defined(__MINGW32__)
248  fd=open(filename,O_RDWR|O_BINARY|O_RANDOM);
249 #else
250  fd=open(filename,O_RDWR);
251 #endif
252 
253  if(fd<0)
254    {
255 #ifdef LIBROUTINO
256     return(NULL);
257 #else
258     fprintf(stderr,"Cannot open file '%s' for reading and writing [%s].\n",filename,strerror(errno));
259     exit(EXIT_FAILURE);
260 #endif
261    }
262 
263  /* Get its size */
264 
265  if(stat(filename,&buf))
266    {
267 #ifdef LIBROUTINO
268     return(NULL);
269 #else
270     fprintf(stderr,"Cannot stat file '%s' [%s].\n",filename,strerror(errno));
271     exit(EXIT_FAILURE);
272 #endif
273    }
274 
275  size=buf.st_size;
276 
277  /* Map the file */
278 
279  address=mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
280 
281  if(address==MAP_FAILED)
282    {
283     close(fd);
284 
285 #ifdef LIBROUTINO
286     return(NULL);
287 #else
288     fprintf(stderr,"Cannot mmap file '%s' for reading and writing [%s].\n",filename,strerror(errno));
289     exit(EXIT_FAILURE);
290 #endif
291    }
292 
293 #ifndef LIBROUTINO
294  log_mmap(size);
295 #endif
296 
297  /* Store the information about the mapped file */
298 
299  mappedfiles=(struct mmapinfo*)realloc((void*)mappedfiles,(nmappedfiles+1)*sizeof(struct mmapinfo));
300 
301  mappedfiles[nmappedfiles].filename=filename;
302  mappedfiles[nmappedfiles].fd=fd;
303  mappedfiles[nmappedfiles].address=address;
304  mappedfiles[nmappedfiles].length=size;
305 
306  nmappedfiles++;
307 
308  return(address);
309 }
310 
311 
312 /*++++++++++++++++++++++++++++++++++++++
313   Unmap a file and close it.
314 
315   void *UnmapFile Returns NULL (for similarity to the MapFile function).
316 
317   const void *address The address of the mapped file in memory.
318   ++++++++++++++++++++++++++++++++++++++*/
319 
UnmapFile(const void * address)320 void *UnmapFile(const void *address)
321 {
322  int i;
323 
324  for(i=0;i<nmappedfiles;i++)
325     if(mappedfiles[i].address==address)
326        break;
327 
328  if(i==nmappedfiles)
329    {
330 #ifdef LIBROUTINO
331     return(NULL);
332 #else
333     fprintf(stderr,"The data at address %p was not mapped using MapFile().\n",address);
334     exit(EXIT_FAILURE);
335 #endif
336    }
337 
338  /* Close the file */
339 
340  close(mappedfiles[i].fd);
341 
342  /* Unmap the file */
343 
344  munmap(mappedfiles[i].address,mappedfiles[i].length);
345 
346 #ifndef LIBROUTINO
347  log_munmap(mappedfiles[i].length);
348 #endif
349 
350  /* Shuffle the list of files */
351 
352  nmappedfiles--;
353 
354  if(nmappedfiles>i)
355     memmove(&mappedfiles[i],&mappedfiles[i+1],(nmappedfiles-i)*sizeof(struct mmapinfo));
356 
357  return(NULL);
358 }
359 
360 
361 /*++++++++++++++++++++++++++++++++++++++
362   Open an existing file on disk for reading.
363 
364   int SlimMapFile Returns the file descriptor if OK or exits in case of an error.
365 
366   const char *filename The name of the file to open.
367   ++++++++++++++++++++++++++++++++++++++*/
368 
SlimMapFile(const char * filename)369 int SlimMapFile(const char *filename)
370 {
371  int fd;
372 
373  /* Open the file */
374 
375 #if defined(_MSC_VER) || defined(__MINGW32__)
376  fd=open(filename,O_RDONLY|O_BINARY|O_RANDOM);
377 #else
378  fd=open(filename,O_RDONLY);
379 #endif
380 
381  if(fd<0)
382    {
383 #ifdef LIBROUTINO
384     return(-1);
385 #else
386     fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",filename,strerror(errno));
387     exit(EXIT_FAILURE);
388 #endif
389    }
390 
391  CreateFileBuffer(fd,0);
392 
393  return(fd);
394 }
395 
396 
397 /*++++++++++++++++++++++++++++++++++++++
398   Open an existing file on disk for reading or writing.
399 
400   int SlimMapFileWriteable Returns the file descriptor if OK or exits in case of an error.
401 
402   const char *filename The name of the file to open.
403   ++++++++++++++++++++++++++++++++++++++*/
404 
SlimMapFileWriteable(const char * filename)405 int SlimMapFileWriteable(const char *filename)
406 {
407  int fd;
408 
409  /* Open the file */
410 
411 #if defined(_MSC_VER) || defined(__MINGW32__)
412  fd=open(filename,O_RDWR|O_BINARY|O_RANDOM);
413 #else
414  fd=open(filename,O_RDWR);
415 #endif
416 
417  if(fd<0)
418    {
419 #ifdef LIBROUTINO
420     return(-1);
421 #else
422     fprintf(stderr,"Cannot open file '%s' for reading and writing [%s].\n",filename,strerror(errno));
423     exit(EXIT_FAILURE);
424 #endif
425    }
426 
427  CreateFileBuffer(fd,0);
428 
429  return(fd);
430 }
431 
432 
433 /*++++++++++++++++++++++++++++++++++++++
434   Close a file on disk.
435 
436   int SlimUnmapFile returns -1 (for similarity to the UnmapFile function).
437 
438   int fd The file descriptor to close.
439   ++++++++++++++++++++++++++++++++++++++*/
440 
SlimUnmapFile(int fd)441 int SlimUnmapFile(int fd)
442 {
443  close(fd);
444 
445  return(-1);
446 }
447 
448 
449 /*++++++++++++++++++++++++++++++++++++++
450   Open a new file on disk for writing (with buffering).
451 
452   int OpenFileBufferedNew Returns the file descriptor if OK or exits in case of an error.
453 
454   const char *filename The name of the file to create.
455   ++++++++++++++++++++++++++++++++++++++*/
456 
OpenFileBufferedNew(const char * filename)457 int OpenFileBufferedNew(const char *filename)
458 {
459  int fd;
460 
461  /* Open the file */
462 
463 #if defined(_MSC_VER) || defined(__MINGW32__)
464  fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY|O_RANDOM,S_IREAD|S_IWRITE);
465 #else
466  fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC                  ,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
467 #endif
468 
469  if(fd<0)
470    {
471 #ifdef LIBROUTINO
472     return(-1);
473 #else
474     fprintf(stderr,"Cannot open file '%s' for writing [%s].\n",filename,strerror(errno));
475     exit(EXIT_FAILURE);
476 #endif
477    }
478 
479  CreateFileBuffer(fd,-1);
480 
481 #if defined(_MSC_VER) || defined(__MINGW32__)
482  CreateOpenedFile(fd,filename);
483 #endif
484 
485  return(fd);
486 }
487 
488 
489 /*++++++++++++++++++++++++++++++++++++++
490   Open a new or existing file on disk for appending (with buffering).
491 
492   int OpenFileBufferedAppend Returns the file descriptor if OK or exits in case of an error.
493 
494   const char *filename The name of the file to create or open.
495   ++++++++++++++++++++++++++++++++++++++*/
496 
OpenFileBufferedAppend(const char * filename)497 int OpenFileBufferedAppend(const char *filename)
498 {
499  int fd;
500 
501  /* Open the file */
502 
503 #if defined(_MSC_VER) || defined(__MINGW32__)
504  fd=open(filename,O_WRONLY|O_CREAT|O_APPEND|O_BINARY|O_RANDOM,S_IREAD|S_IWRITE);
505 #else
506  fd=open(filename,O_WRONLY|O_CREAT|O_APPEND                  ,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
507 #endif
508 
509  if(fd<0)
510    {
511 #ifdef LIBROUTINO
512     return(-1);
513 #else
514     fprintf(stderr,"Cannot open file '%s' for appending [%s].\n",filename,strerror(errno));
515     exit(EXIT_FAILURE);
516 #endif
517    }
518 
519  CreateFileBuffer(fd,-1);
520 
521 #if defined(_MSC_VER) || defined(__MINGW32__)
522  CreateOpenedFile(fd,filename);
523 #endif
524 
525  return(fd);
526 }
527 
528 
529 /*++++++++++++++++++++++++++++++++++++++
530   Open an existing file on disk for reading (with buffering).
531 
532   int ReOpenFileBuffered Returns the file descriptor if OK or exits in case of an error.
533 
534   const char *filename The name of the file to open.
535   ++++++++++++++++++++++++++++++++++++++*/
536 
ReOpenFileBuffered(const char * filename)537 int ReOpenFileBuffered(const char *filename)
538 {
539  int fd;
540 
541  /* Open the file */
542 
543 #if defined(_MSC_VER) || defined(__MINGW32__)
544  fd=open(filename,O_RDONLY|O_BINARY|O_RANDOM);
545 #else
546  fd=open(filename,O_RDONLY);
547 #endif
548 
549  if(fd<0)
550    {
551 #ifdef LIBROUTINO
552     return(-1);
553 #else
554     fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",filename,strerror(errno));
555     exit(EXIT_FAILURE);
556 #endif
557    }
558 
559  CreateFileBuffer(fd,1);
560 
561 #if defined(_MSC_VER) || defined(__MINGW32__)
562  CreateOpenedFile(fd,filename);
563 #endif
564 
565  return(fd);
566 }
567 
568 
569 /*++++++++++++++++++++++++++++++++++++++
570   Open an existing file on disk for reading (with buffering), delete
571   it and open a new file on disk for writing (with buffering).
572 
573   int ReplaceFileBuffered Returns the file descriptor of the new writable file.
574 
575   const char *filename The name of the file to open, delete and replace.
576 
577   int *oldfd Returns the file descriptor of the old, readable file.
578   ++++++++++++++++++++++++++++++++++++++*/
579 
ReplaceFileBuffered(const char * filename,int * oldfd)580 int ReplaceFileBuffered(const char *filename,int *oldfd)
581 {
582  int newfd;
583 
584 #if defined(_MSC_VER) || defined(__MINGW32__)
585 
586  char *filename2;
587 
588  filename2=strcpy(malloc(strlen(filename)+2),filename);
589  strcat(filename2,"2");
590 
591  RenameFile(filename,filename2);
592 
593  *oldfd=ReOpenFileBuffered(filename2);
594 
595  DeleteFile(filename2);
596 
597 #else
598 
599  *oldfd=ReOpenFileBuffered(filename);
600 
601  DeleteFile(filename);
602 
603 #endif
604 
605  newfd=OpenFileBufferedNew(filename);
606 
607  return(newfd);
608 }
609 
610 
611 /*++++++++++++++++++++++++++++++++++++++
612   Write data to a file descriptor (via a buffer).
613 
614   int WriteFileBuffered Returns 0 if OK or something else in case of an error.
615 
616   int fd The file descriptor to write to.
617 
618   const void *address The address of the data to be written.
619 
620   size_t length The length of data to write.
621   ++++++++++++++++++++++++++++++++++++++*/
622 
WriteFileBuffered(int fd,const void * address,size_t length)623 int WriteFileBuffered(int fd,const void *address,size_t length)
624 {
625 #ifndef LIBROUTINO
626  logassert(fd!=-1,"File descriptor is in error - report a bug");
627 
628  logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
629 
630  logassert(!filebuffers[fd]->reading,"File descriptor was not opened for writing - report a bug");
631 #endif
632 
633  /* Write the data */
634 
635  if((filebuffers[fd]->pointer+length)>BUFFLEN)
636    {
637     if(write(fd,filebuffers[fd]->buffer,filebuffers[fd]->pointer)!=(ssize_t)filebuffers[fd]->pointer)
638        return(-1);
639 
640     filebuffers[fd]->pointer=0;
641    }
642 
643  if(length>=BUFFLEN)
644    {
645     if(write(fd,address,length)!=(ssize_t)length)
646        return(-1);
647 
648     return(0);
649    }
650 
651  memcpy(filebuffers[fd]->buffer+filebuffers[fd]->pointer,address,length);
652 
653  filebuffers[fd]->pointer+=length;
654 
655  return(0);
656 }
657 
658 
659 /*++++++++++++++++++++++++++++++++++++++
660   Read data from a file descriptor (via a buffer).
661 
662   int ReadFileBuffered Returns 0 if OK or something else in case of an error.
663 
664   int fd The file descriptor to read from.
665 
666   void *address The address the data is to be read into.
667 
668   size_t length The length of data to read.
669   ++++++++++++++++++++++++++++++++++++++*/
670 
ReadFileBuffered(int fd,void * address,size_t length)671 int ReadFileBuffered(int fd,void *address,size_t length)
672 {
673 #ifndef LIBROUTINO
674  logassert(fd!=-1,"File descriptor is in error - report a bug");
675 
676  logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
677 
678  logassert(filebuffers[fd]->reading,"File descriptor was not opened for reading - report a bug");
679 #endif
680 
681  /* Read the data */
682 
683  if((filebuffers[fd]->pointer+length)>filebuffers[fd]->length)
684     if(filebuffers[fd]->pointer<filebuffers[fd]->length)
685       {
686        memcpy(address,filebuffers[fd]->buffer+filebuffers[fd]->pointer,filebuffers[fd]->length-filebuffers[fd]->pointer);
687 
688        address=(char*)address+filebuffers[fd]->length-filebuffers[fd]->pointer;
689        length-=filebuffers[fd]->length-filebuffers[fd]->pointer;
690 
691        filebuffers[fd]->pointer=0;
692        filebuffers[fd]->length=0;
693       }
694 
695  if(length>=BUFFLEN)
696    {
697     if(read(fd,address,length)!=(ssize_t)length)
698        return(-1);
699 
700     return(0);
701    }
702 
703  if(filebuffers[fd]->pointer==filebuffers[fd]->length)
704    {
705     ssize_t len=read(fd,filebuffers[fd]->buffer,BUFFLEN);
706 
707     if(len<=0)
708        return(-1);
709 
710     filebuffers[fd]->length=len;
711     filebuffers[fd]->pointer=0;
712    }
713 
714  if(filebuffers[fd]->length==0)
715     return(-1);
716 
717  memcpy(address,filebuffers[fd]->buffer+filebuffers[fd]->pointer,length);
718 
719  filebuffers[fd]->pointer+=length;
720 
721  return(0);
722 }
723 
724 
725 /*++++++++++++++++++++++++++++++++++++++
726   Seek to a position in a file descriptor that uses a buffer.
727 
728   int SeekFileBuffered Returns 0 if OK or something else in case of an error.
729 
730   int fd The file descriptor to seek within.
731 
732   offset_t position The position to seek to.
733   ++++++++++++++++++++++++++++++++++++++*/
734 
SeekFileBuffered(int fd,offset_t position)735 int SeekFileBuffered(int fd,offset_t position)
736 {
737 #ifndef LIBROUTINO
738  logassert(fd!=-1,"File descriptor is in error - report a bug");
739 
740  logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
741 #endif
742 
743  /* Seek the data - doesn't need to be highly optimised */
744 
745  if(!filebuffers[fd]->reading)
746     if(write(fd,filebuffers[fd]->buffer,filebuffers[fd]->pointer)!=(ssize_t)filebuffers[fd]->pointer)
747        return(-1);
748 
749  filebuffers[fd]->pointer=0;
750  filebuffers[fd]->length=0;
751 
752  if(lseek(fd,position,SEEK_SET)!=position)
753     return(-1);
754 
755  return(0);
756 }
757 
758 
759 /*++++++++++++++++++++++++++++++++++++++
760   Skip forward by an offset in a file descriptor that uses a buffer.
761 
762   int SkipFileBuffered Returns 0 if OK or something else in case of an error.
763 
764   int fd The file descriptor to skip within.
765 
766   offset_t skip The amount to skip forward.
767   ++++++++++++++++++++++++++++++++++++++*/
768 
SkipFileBuffered(int fd,offset_t skip)769 int SkipFileBuffered(int fd,offset_t skip)
770 {
771 #ifndef LIBROUTINO
772  logassert(fd!=-1,"File descriptor is in error - report a bug");
773 
774  logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
775 
776  logassert(filebuffers[fd]->reading,"File descriptor was not opened for reading - report a bug");
777 #endif
778 
779  /* Skip the data - needs to be optimised */
780 
781  if((filebuffers[fd]->pointer+skip)>filebuffers[fd]->length)
782    {
783     skip-=(offset_t)(filebuffers[fd]->length-filebuffers[fd]->pointer);
784 
785     filebuffers[fd]->pointer=0;
786     filebuffers[fd]->length=0;
787 
788     if(lseek(fd,skip,SEEK_CUR)==-1)
789        return(-1);
790    }
791  else
792     filebuffers[fd]->pointer+=skip;
793 
794  return(0);
795 }
796 
797 
798 /*++++++++++++++++++++++++++++++++++++++
799   Get the size of a file.
800 
801   offset_t SizeFile Returns the file size if OK or exits in case of an error.
802 
803   const char *filename The name of the file to check.
804   ++++++++++++++++++++++++++++++++++++++*/
805 
SizeFile(const char * filename)806 offset_t SizeFile(const char *filename)
807 {
808  struct stat buf;
809 
810  if(stat(filename,&buf))
811    {
812 #ifdef LIBROUTINO
813     return(-1);
814 #else
815     fprintf(stderr,"Cannot stat file '%s' [%s].\n",filename,strerror(errno));
816     exit(EXIT_FAILURE);
817 #endif
818    }
819 
820  return(buf.st_size);
821 }
822 
823 
824 /*++++++++++++++++++++++++++++++++++++++
825   Get the size of a file from a file descriptor.
826 
827   offset_t SizeFileFD Returns the file size if OK or exits in case of an error.
828 
829   int fd The file descriptor to check.
830   ++++++++++++++++++++++++++++++++++++++*/
831 
SizeFileFD(int fd)832 offset_t SizeFileFD(int fd)
833 {
834  struct stat buf;
835 
836  if(fstat(fd,&buf))
837    {
838 #ifdef LIBROUTINO
839     return(-1);
840 #else
841     fprintf(stderr,"Cannot stat file descriptor '%d' [%s].\n",fd,strerror(errno));
842     exit(EXIT_FAILURE);
843 #endif
844    }
845 
846  return(buf.st_size);
847 }
848 
849 
850 /*++++++++++++++++++++++++++++++++++++++
851   Check if a file exists.
852 
853   int ExistsFile Returns 1 if the file exists and 0 if not.
854 
855   const char *filename The name of the file to check.
856   ++++++++++++++++++++++++++++++++++++++*/
857 
ExistsFile(const char * filename)858 int ExistsFile(const char *filename)
859 {
860  struct stat buf;
861 
862  if(stat(filename,&buf))
863     return(0);
864  else
865     return(1);
866 }
867 
868 
869 /*++++++++++++++++++++++++++++++++++++++
870   Close a file on disk (and flush the buffer).
871 
872   int CloseFileBuffered returns -1 (for similarity to the *OpenFileBuffered* functions).
873 
874   int fd The file descriptor to close.
875   ++++++++++++++++++++++++++++++++++++++*/
876 
CloseFileBuffered(int fd)877 int CloseFileBuffered(int fd)
878 {
879 #ifndef LIBROUTINO
880  logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
881 #endif
882 
883  if(!filebuffers[fd]->reading)
884     if(write(fd,filebuffers[fd]->buffer,filebuffers[fd]->pointer)!=(ssize_t)filebuffers[fd]->pointer)
885        return(-1);
886 
887  close(fd);
888 
889  free(filebuffers[fd]);
890  filebuffers[fd]=NULL;
891 
892 #if defined(_MSC_VER) || defined(__MINGW32__)
893 
894 #ifndef LIBROUTINO
895  logassert(fd<nopenedfiles && openedfiles[fd],"File descriptor has no record of opening - report a bug");
896 #endif
897 
898  if(openedfiles[fd]->delete)
899     unlink(openedfiles[fd]->filename);
900 
901  free(openedfiles[fd]);
902  openedfiles[fd]=NULL;
903 
904 #endif
905 
906  return(-1);
907 }
908 
909 
910 /*++++++++++++++++++++++++++++++++++++++
911   Open an existing file on disk for reading (in a simple mode).
912 
913   int OpenFile Returns the file descriptor if OK or exits in case of an error.
914 
915   const char *filename The name of the file to open.
916   ++++++++++++++++++++++++++++++++++++++*/
917 
OpenFile(const char * filename)918 int OpenFile(const char *filename)
919 {
920  int fd;
921 
922  /* Open the file */
923 
924 #if defined(_MSC_VER) || defined(__MINGW32__)
925  fd=open(filename,O_RDONLY|O_BINARY|O_RANDOM);
926 #else
927  fd=open(filename,O_RDONLY);
928 #endif
929 
930  if(fd<0)
931    {
932 #ifdef LIBROUTINO
933     return(-1);
934 #else
935     fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",filename,strerror(errno));
936     exit(EXIT_FAILURE);
937 #endif
938    }
939 
940 #if defined(_MSC_VER) || defined(__MINGW32__)
941  CreateOpenedFile(fd,filename);
942 #endif
943 
944  return(fd);
945 }
946 
947 
948 /*++++++++++++++++++++++++++++++++++++++
949   Close a file on disk (that was opened in simple mode).
950 
951   int fd The file descriptor to close.
952   ++++++++++++++++++++++++++++++++++++++*/
953 
CloseFile(int fd)954 void CloseFile(int fd)
955 {
956  close(fd);
957 
958 #if defined(_MSC_VER) || defined(__MINGW32__)
959 
960 #ifndef LIBROUTINO
961  logassert(fd<nopenedfiles && openedfiles[fd],"File descriptor has no record of opening - report a bug");
962 #endif
963 
964  if(openedfiles[fd]->delete)
965     unlink(openedfiles[fd]->filename);
966 
967  free(openedfiles[fd]);
968  openedfiles[fd]=NULL;
969 
970 #endif
971 }
972 
973 
974 /*++++++++++++++++++++++++++++++++++++++
975   Delete a file from disk.
976 
977   int DeleteFile Returns 0 if OK.
978 
979   const char *filename The name of the file to delete.
980   ++++++++++++++++++++++++++++++++++++++*/
981 
DeleteFile(const char * filename)982 int DeleteFile(const char *filename)
983 {
984 #if defined(_MSC_VER) || defined(__MINGW32__)
985 
986  int fd;
987 
988  for(fd=0;fd<nopenedfiles;fd++)
989     if(openedfiles[fd] && !strcmp(openedfiles[fd]->filename,filename))
990       {
991        openedfiles[fd]->delete=1;
992        return(0);
993       }
994 
995 #endif
996 
997  unlink(filename);
998 
999  return(0);
1000 }
1001 
1002 
1003 /*++++++++++++++++++++++++++++++++++++++
1004   Rename a file on disk.
1005 
1006   int RenameFile Returns 0 if OK.
1007 
1008   const char *oldfilename The old name of the file before renaming.
1009 
1010   const char *newfilename The new name of the file after renaming.
1011   ++++++++++++++++++++++++++++++++++++++*/
1012 
RenameFile(const char * oldfilename,const char * newfilename)1013 int RenameFile(const char *oldfilename,const char *newfilename)
1014 {
1015  rename(oldfilename,newfilename);
1016 
1017  return(0);
1018 }
1019 
1020 
1021 /*++++++++++++++++++++++++++++++++++++++
1022   Create a file buffer.
1023 
1024   int fd The file descriptor.
1025 
1026   int read_write A flag set to 1 for reading, -1 for writing and 0 for unbuffered.
1027   ++++++++++++++++++++++++++++++++++++++*/
1028 
CreateFileBuffer(int fd,int read_write)1029 static void CreateFileBuffer(int fd,int read_write)
1030 {
1031  if(nfilebuffers<=fd)
1032    {
1033     int i;
1034 
1035     filebuffers=(struct filebuffer**)realloc((void*)filebuffers,(fd+1)*sizeof(struct filebuffer*));
1036 
1037     for(i=nfilebuffers;i<=fd;i++)
1038        filebuffers[i]=NULL;
1039 
1040     nfilebuffers=fd+1;
1041    }
1042 
1043  if(read_write)
1044    {
1045     filebuffers[fd]=(struct filebuffer*)calloc(sizeof(struct filebuffer),1);
1046 
1047     filebuffers[fd]->reading=(read_write==1);
1048    }
1049 }
1050 
1051 
1052 #if defined(_MSC_VER) || defined(__MINGW32__)
1053 
1054 /*++++++++++++++++++++++++++++++++++++++
1055   Create an opened file record.
1056 
1057   int fd The file descriptor.
1058 
1059   const char *filename The name of the file.
1060   ++++++++++++++++++++++++++++++++++++++*/
1061 
CreateOpenedFile(int fd,const char * filename)1062 static void CreateOpenedFile(int fd,const char *filename)
1063 {
1064  if(nopenedfiles<=fd)
1065    {
1066     int i;
1067 
1068     openedfiles=(struct openedfile**)realloc((void*)openedfiles,(fd+1)*sizeof(struct openedfile*));
1069 
1070     for(i=nopenedfiles;i<=fd;i++)
1071        openedfiles[i]=NULL;
1072 
1073     nopenedfiles=fd+1;
1074    }
1075 
1076  openedfiles[fd]=(struct openedfile*)calloc(sizeof(struct openedfile),1);
1077 
1078  openedfiles[fd]->filename=strcpy(malloc(strlen(filename)+1),filename);
1079  openedfiles[fd]->delete=0;
1080 }
1081 
1082 #endif
1083