Routino SVN Repository Browser

Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino

ViewVC logotype

Contents of /trunk/src/files.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1410 - (show annotations) (download) (as text)
Fri Jun 21 15:48:19 2013 UTC (11 years, 8 months ago) by amb
File MIME type: text/x-csrc
File size: 18134 byte(s)
Rename the functions for unbuffered file access to make this clear.

1 /***************************************
2 Functions to handle files.
3
4 Part of the Routino routing software.
5 ******************/ /******************
6 This file Copyright 2008-2013 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 #include <unistd.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <sys/stat.h>
30 #include <sys/mman.h>
31 #include <sys/types.h>
32
33 #include "files.h"
34
35
36 /*+ A structure to contain the list of memory mapped files. +*/
37 struct mmapinfo
38 {
39 const char *filename; /*+ The name of the file (the index of the list). +*/
40 int fd; /*+ The file descriptor used when it was opened. +*/
41 void *address; /*+ The address the file was mapped to. +*/
42 size_t length; /*+ The length of the file. +*/
43 };
44
45 /*+ The list of memory mapped files. +*/
46 static struct mmapinfo *mappedfiles;
47
48 /*+ The number of mapped files. +*/
49 static int nmappedfiles=0;
50
51
52 #define BUFFLEN 1024
53
54 /*+ A structure to contain the list of file buffers. +*/
55 struct filebuffer
56 {
57 int fd; /*+ The file descriptor used when it was opened. +*/
58 char buffer[BUFFLEN]; /*+ The data buffer. +*/
59 size_t pointer; /*+ The read/write pointer for the file buffer. +*/
60 size_t length; /*+ The read pointer for the file buffer. +*/
61 int reading; /*+ A flag to indicate if the file is for reading. +*/
62 };
63
64 /*+ The list of file buffers. +*/
65 static struct filebuffer **filebuffers=NULL;
66
67 /*+ The number of allocated file buffer pointers. +*/
68 static int nfilebuffers=0;
69
70
71 /* Local functions */
72
73 static void CreateFileBuffer(int fd,int read_write);
74
75
76 /*++++++++++++++++++++++++++++++++++++++
77 Return a filename composed of the dirname, prefix and name.
78
79 char *FileName Returns a pointer to memory allocated to the filename.
80
81 const char *dirname The directory name.
82
83 const char *prefix The file prefix.
84
85 const char *name The main part of the name.
86 ++++++++++++++++++++++++++++++++++++++*/
87
88 char *FileName(const char *dirname,const char *prefix, const char *name)
89 {
90 char *filename=(char*)malloc((dirname?strlen(dirname):0)+1+(prefix?strlen(prefix):0)+1+strlen(name)+1);
91
92 sprintf(filename,"%s%s%s%s%s",dirname?dirname:"",dirname?"/":"",prefix?prefix:"",prefix?"-":"",name);
93
94 return(filename);
95 }
96
97
98 /*++++++++++++++++++++++++++++++++++++++
99 Open a file read-only and map it into memory.
100
101 void *MapFile Returns the address of the file or exits in case of an error.
102
103 const char *filename The name of the file to open.
104 ++++++++++++++++++++++++++++++++++++++*/
105
106 void *MapFile(const char *filename)
107 {
108 int fd;
109 off_t size;
110 void *address;
111
112 /* Open the file and get its size */
113
114 fd=ReOpenFileUnbuffered(filename);
115
116 size=SizeFile(filename);
117
118 /* Map the file */
119
120 address=mmap(NULL,size,PROT_READ,MAP_SHARED,fd,0);
121
122 if(address==MAP_FAILED)
123 {
124 close(fd);
125
126 fprintf(stderr,"Cannot mmap file '%s' for reading [%s].\n",filename,strerror(errno));
127 exit(EXIT_FAILURE);
128 }
129
130 /* Store the information about the mapped file */
131
132 mappedfiles=(struct mmapinfo*)realloc((void*)mappedfiles,(nmappedfiles+1)*sizeof(struct mmapinfo));
133
134 mappedfiles[nmappedfiles].filename=filename;
135 mappedfiles[nmappedfiles].fd=fd;
136 mappedfiles[nmappedfiles].address=address;
137 mappedfiles[nmappedfiles].length=size;
138
139 nmappedfiles++;
140
141 return(address);
142 }
143
144
145 /*++++++++++++++++++++++++++++++++++++++
146 Open a file read-write and map it into memory.
147
148 void *MapFileWriteable Returns the address of the file or exits in case of an error.
149
150 const char *filename The name of the file to open.
151 ++++++++++++++++++++++++++++++++++++++*/
152
153 void *MapFileWriteable(const char *filename)
154 {
155 int fd;
156 off_t size;
157 void *address;
158
159 /* Open the file and get its size */
160
161 fd=ReOpenFileUnbufferedWriteable(filename);
162
163 size=SizeFile(filename);
164
165 /* Map the file */
166
167 address=mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
168
169 if(address==MAP_FAILED)
170 {
171 close(fd);
172
173 fprintf(stderr,"Cannot mmap file '%s' for reading and writing [%s].\n",filename,strerror(errno));
174 exit(EXIT_FAILURE);
175 }
176
177 /* Store the information about the mapped file */
178
179 mappedfiles=(struct mmapinfo*)realloc((void*)mappedfiles,(nmappedfiles+1)*sizeof(struct mmapinfo));
180
181 mappedfiles[nmappedfiles].filename=filename;
182 mappedfiles[nmappedfiles].fd=fd;
183 mappedfiles[nmappedfiles].address=address;
184 mappedfiles[nmappedfiles].length=size;
185
186 nmappedfiles++;
187
188 return(address);
189 }
190
191
192 /*++++++++++++++++++++++++++++++++++++++
193 Unmap a file and close it.
194
195 void *UnmapFile Returns NULL (for similarity to the MapFile function).
196
197 const void *address The address of the mapped file in memory.
198 ++++++++++++++++++++++++++++++++++++++*/
199
200 void *UnmapFile(const void *address)
201 {
202 int i;
203
204 for(i=0;i<nmappedfiles;i++)
205 if(mappedfiles[i].address==address)
206 break;
207
208 if(i==nmappedfiles)
209 {
210 fprintf(stderr,"The data at address %p was not mapped using MapFile().\n",address);
211 exit(EXIT_FAILURE);
212 }
213
214 /* Close the file */
215
216 CloseFileUnbuffered(mappedfiles[i].fd);
217
218 /* Unmap the file */
219
220 munmap(mappedfiles[i].address,mappedfiles[i].length);
221
222 /* Shuffle the list of files */
223
224 nmappedfiles--;
225
226 if(nmappedfiles>i)
227 memmove(&mappedfiles[i],&mappedfiles[i+1],(nmappedfiles-i)*sizeof(struct mmapinfo));
228
229 return(NULL);
230 }
231
232
233 /*++++++++++++++++++++++++++++++++++++++
234 Open a new file on disk for writing.
235
236 int OpenFileUnbufferedNew Returns the file descriptor if OK or exits in case of an error.
237
238 const char *filename The name of the file to create.
239 ++++++++++++++++++++++++++++++++++++++*/
240
241 int OpenFileUnbufferedNew(const char *filename)
242 {
243 int fd;
244
245 /* Open the file */
246
247 fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
248
249 if(fd<0)
250 {
251 fprintf(stderr,"Cannot open file '%s' for writing [%s].\n",filename,strerror(errno));
252 exit(EXIT_FAILURE);
253 }
254
255 CreateFileBuffer(fd,0);
256
257 return(fd);
258 }
259
260
261 /*++++++++++++++++++++++++++++++++++++++
262 Open a new file on disk for writing (with buffering).
263
264 int OpenFileBufferedNew Returns the file descriptor if OK or exits in case of an error.
265
266 const char *filename The name of the file to create.
267 ++++++++++++++++++++++++++++++++++++++*/
268
269 int OpenFileBufferedNew(const char *filename)
270 {
271 int fd;
272
273 fd=OpenFileUnbufferedNew(filename);
274
275 CreateFileBuffer(fd,-1);
276
277 return(fd);
278 }
279
280
281 /*++++++++++++++++++++++++++++++++++++++
282 Open a new or existing file on disk for appending.
283
284 int OpenFileUnbufferedAppend Returns the file descriptor if OK or exits in case of an error.
285
286 const char *filename The name of the file to create or open.
287 ++++++++++++++++++++++++++++++++++++++*/
288
289 int OpenFileUnbufferedAppend(const char *filename)
290 {
291 int fd;
292
293 /* Open the file */
294
295 fd=open(filename,O_WRONLY|O_CREAT|O_APPEND,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
296
297 if(fd<0)
298 {
299 fprintf(stderr,"Cannot open file '%s' for appending [%s].\n",filename,strerror(errno));
300 exit(EXIT_FAILURE);
301 }
302
303 CreateFileBuffer(fd,0);
304
305 return(fd);
306 }
307
308
309 /*++++++++++++++++++++++++++++++++++++++
310 Open a new or existing file on disk for appending (with buffering).
311
312 int OpenFileBufferedAppend Returns the file descriptor if OK or exits in case of an error.
313
314 const char *filename The name of the file to create or open.
315 ++++++++++++++++++++++++++++++++++++++*/
316
317 int OpenFileBufferedAppend(const char *filename)
318 {
319 int fd;
320
321 fd=OpenFileUnbufferedAppend(filename);
322
323 CreateFileBuffer(fd,-1);
324
325 return(fd);
326 }
327
328
329 /*++++++++++++++++++++++++++++++++++++++
330 Open an existing file on disk for reading.
331
332 int ReOpenFileUnbuffered Returns the file descriptor if OK or exits in case of an error.
333
334 const char *filename The name of the file to open.
335 ++++++++++++++++++++++++++++++++++++++*/
336
337 int ReOpenFileUnbuffered(const char *filename)
338 {
339 int fd;
340
341 /* Open the file */
342
343 fd=open(filename,O_RDONLY);
344
345 if(fd<0)
346 {
347 fprintf(stderr,"Cannot open file '%s' for reading [%s].\n",filename,strerror(errno));
348 exit(EXIT_FAILURE);
349 }
350
351 CreateFileBuffer(fd,0);
352
353 return(fd);
354 }
355
356
357 /*++++++++++++++++++++++++++++++++++++++
358 Open an existing file on disk for reading (with buffering).
359
360 int ReOpenFileBuffered Returns the file descriptor if OK or exits in case of an error.
361
362 const char *filename The name of the file to open.
363 ++++++++++++++++++++++++++++++++++++++*/
364
365 int ReOpenFileBuffered(const char *filename)
366 {
367 int fd;
368
369 fd=ReOpenFileUnbuffered(filename);
370
371 CreateFileBuffer(fd,1);
372
373 return(fd);
374 }
375
376
377 /*++++++++++++++++++++++++++++++++++++++
378 Open an existing file on disk for reading or writing.
379
380 int ReOpenFileUnbufferedWriteable Returns the file descriptor if OK or exits in case of an error.
381
382 const char *filename The name of the file to open.
383 ++++++++++++++++++++++++++++++++++++++*/
384
385 int ReOpenFileUnbufferedWriteable(const char *filename)
386 {
387 int fd;
388
389 /* Open the file */
390
391 fd=open(filename,O_RDWR);
392
393 if(fd<0)
394 {
395 fprintf(stderr,"Cannot open file '%s' for reading and writing [%s].\n",filename,strerror(errno));
396 exit(EXIT_FAILURE);
397 }
398
399 CreateFileBuffer(fd,0);
400
401 return(fd);
402 }
403
404
405 /*++++++++++++++++++++++++++++++++++++++
406 Write data to a file descriptor (via a buffer).
407
408 int WriteFileBuffered Returns 0 if OK or something else in case of an error.
409
410 int fd The file descriptor to write to.
411
412 const void *address The address of the data to be written.
413
414 size_t length The length of data to write.
415 ++++++++++++++++++++++++++++++++++++++*/
416
417 int WriteFileBuffered(int fd,const void *address,size_t length)
418 {
419 logassert(fd!=-1,"File descriptor is in error - report a bug");
420
421 logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
422
423 logassert(!filebuffers[fd]->reading,"File descriptor was not opened for writing - report a bug");
424
425 /* Write the data */
426
427 if((filebuffers[fd]->pointer+length)>BUFFLEN)
428 {
429 if(write(fd,filebuffers[fd]->buffer,filebuffers[fd]->pointer)!=(ssize_t)filebuffers[fd]->pointer)
430 return(-1);
431
432 filebuffers[fd]->pointer=0;
433 }
434
435 if(length>=BUFFLEN)
436 {
437 if(write(fd,address,length)!=(ssize_t)length)
438 return(-1);
439
440 return(0);
441 }
442
443 memcpy(filebuffers[fd]->buffer+filebuffers[fd]->pointer,address,length);
444
445 filebuffers[fd]->pointer+=length;
446
447 return(0);
448 }
449
450
451 /*++++++++++++++++++++++++++++++++++++++
452 Read data from a file descriptor (via a buffer).
453
454 int ReadFileBuffered Returns 0 if OK or something else in case of an error.
455
456 int fd The file descriptor to read from.
457
458 void *address The address the data is to be read into.
459
460 size_t length The length of data to read.
461 ++++++++++++++++++++++++++++++++++++++*/
462
463 int ReadFileBuffered(int fd,void *address,size_t length)
464 {
465 logassert(fd!=-1,"File descriptor is in error - report a bug");
466
467 logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
468
469 logassert(filebuffers[fd]->reading,"File descriptor was not opened for reading - report a bug");
470
471 /* Read the data */
472
473 if((filebuffers[fd]->pointer+length)>filebuffers[fd]->length)
474 if(filebuffers[fd]->pointer<filebuffers[fd]->length)
475 {
476 memcpy(address,filebuffers[fd]->buffer+filebuffers[fd]->pointer,filebuffers[fd]->length-filebuffers[fd]->pointer);
477
478 address+=filebuffers[fd]->length-filebuffers[fd]->pointer;
479 length-=filebuffers[fd]->length-filebuffers[fd]->pointer;
480
481 filebuffers[fd]->pointer=0;
482 filebuffers[fd]->length=0;
483 }
484
485 if(length>=BUFFLEN)
486 {
487 if(read(fd,address,length)!=(ssize_t)length)
488 return(-1);
489
490 return(0);
491 }
492
493 if(filebuffers[fd]->pointer==filebuffers[fd]->length)
494 {
495 filebuffers[fd]->length=read(fd,filebuffers[fd]->buffer,BUFFLEN);
496 filebuffers[fd]->pointer=0;
497 }
498
499 if(filebuffers[fd]->length==0)
500 return(-1);
501
502 memcpy(address,filebuffers[fd]->buffer+filebuffers[fd]->pointer,length);
503
504 filebuffers[fd]->pointer+=length;
505
506 return(0);
507 }
508
509
510 /*++++++++++++++++++++++++++++++++++++++
511 Seek to a position in a file descriptor.
512
513 int SeekFileUnbuffered Returns 0 if OK or something else in case of an error.
514
515 int fd The file descriptor to seek within.
516
517 off_t position The position to seek to.
518 ++++++++++++++++++++++++++++++++++++++*/
519
520 int SeekFileUnbuffered(int fd,off_t position)
521 {
522 logassert(fd!=-1,"File descriptor is in error - report a bug");
523
524 logassert(fd>=nfilebuffers || !filebuffers[fd],"File descriptor has a buffer - report a bug");
525
526 /* Seek the data */
527
528 if(lseek(fd,position,SEEK_SET)!=position)
529 return(-1);
530
531 return(0);
532 }
533
534
535 /*++++++++++++++++++++++++++++++++++++++
536 Seek to a position in a file descriptor that uses a buffer.
537
538 int SeekFileBuffered Returns 0 if OK or something else in case of an error.
539
540 int fd The file descriptor to seek within.
541
542 off_t position The position to seek to.
543 ++++++++++++++++++++++++++++++++++++++*/
544
545 int SeekFileBuffered(int fd,off_t position)
546 {
547 logassert(fd!=-1,"File descriptor is in error - report a bug");
548
549 logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
550
551 /* Seek the data - doesn't need to be highly optimised */
552
553 if(!filebuffers[fd]->reading)
554 if(write(fd,filebuffers[fd]->buffer,filebuffers[fd]->pointer)!=(ssize_t)filebuffers[fd]->pointer)
555 return(-1);
556
557 filebuffers[fd]->pointer=0;
558 filebuffers[fd]->length=0;
559
560 if(lseek(fd,position,SEEK_SET)!=position)
561 return(-1);
562
563 return(0);
564 }
565
566
567 /*++++++++++++++++++++++++++++++++++++++
568 Skip forward by an offset in a file descriptor that uses a buffer.
569
570 int SkipFileBuffered Returns 0 if OK or something else in case of an error.
571
572 int fd The file descriptor to skip within.
573
574 off_t skip The amount to skip forward.
575 ++++++++++++++++++++++++++++++++++++++*/
576
577 int SkipFileBuffered(int fd,off_t skip)
578 {
579 logassert(fd!=-1,"File descriptor is in error - report a bug");
580
581 logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
582
583 logassert(filebuffers[fd]->reading,"File descriptor was not opened for reading - report a bug");
584
585 /* Skip the data - needs to be optimised */
586
587 if((filebuffers[fd]->pointer+skip)>filebuffers[fd]->length)
588 {
589 skip-=filebuffers[fd]->length-filebuffers[fd]->pointer;
590
591 filebuffers[fd]->pointer=0;
592 filebuffers[fd]->length=0;
593
594 if(lseek(fd,skip,SEEK_CUR)==-1)
595 return(-1);
596 }
597 else
598 filebuffers[fd]->pointer+=skip;
599
600 return(0);
601 }
602
603
604 /*++++++++++++++++++++++++++++++++++++++
605 Get the size of a file.
606
607 off_t SizeFile Returns the file size if OK or exits in case of an error.
608
609 const char *filename The name of the file to check.
610 ++++++++++++++++++++++++++++++++++++++*/
611
612 off_t SizeFile(const char *filename)
613 {
614 struct stat buf;
615
616 if(stat(filename,&buf))
617 {
618 fprintf(stderr,"Cannot stat file '%s' [%s].\n",filename,strerror(errno));
619 exit(EXIT_FAILURE);
620 }
621
622 return(buf.st_size);
623 }
624
625
626 /*++++++++++++++++++++++++++++++++++++++
627 Check if a file exists.
628
629 int ExistsFile Returns 1 if the file exists and 0 if not.
630
631 const char *filename The name of the file to check.
632 ++++++++++++++++++++++++++++++++++++++*/
633
634 int ExistsFile(const char *filename)
635 {
636 struct stat buf;
637
638 if(stat(filename,&buf))
639 return(0);
640 else
641 return(1);
642 }
643
644
645 /*++++++++++++++++++++++++++++++++++++++
646 Close a file on disk.
647
648 int CloseFileUnbuffered returns -1 (for similarity to the *OpenFileUnbuffered* functions).
649
650 int fd The file descriptor to close.
651 ++++++++++++++++++++++++++++++++++++++*/
652
653 int CloseFileUnbuffered(int fd)
654 {
655 logassert(fd>=nfilebuffers || !filebuffers[fd],"File descriptor has a buffer - report a bug");
656
657 close(fd);
658
659 return(-1);
660 }
661
662
663 /*++++++++++++++++++++++++++++++++++++++
664 Close a file on disk (and flush the buffer).
665
666 int CloseFileBuffered returns -1 (for similarity to the *OpenFileBuffered* functions).
667
668 int fd The file descriptor to close.
669 ++++++++++++++++++++++++++++++++++++++*/
670
671 int CloseFileBuffered(int fd)
672 {
673 logassert(fd<nfilebuffers && filebuffers[fd],"File descriptor has no buffer - report a bug");
674
675 if(!filebuffers[fd]->reading)
676 write(fd,filebuffers[fd]->buffer,filebuffers[fd]->pointer);
677
678 close(fd);
679
680 free(filebuffers[fd]);
681
682 filebuffers[fd]=NULL;
683
684 return(-1);
685 }
686
687
688 /*++++++++++++++++++++++++++++++++++++++
689 Delete a file from disk.
690
691 int DeleteFile Returns 0 if OK.
692
693 const char *filename The name of the file to delete.
694 ++++++++++++++++++++++++++++++++++++++*/
695
696 int DeleteFile(const char *filename)
697 {
698 unlink(filename);
699
700 return(0);
701 }
702
703
704 /*++++++++++++++++++++++++++++++++++++++
705 Rename a file on disk.
706
707 int RenameFile Returns 0 if OK.
708
709 const char *oldfilename The old name of the file before renaming.
710
711 const char *newfilename The new name of the file after renaming.
712 ++++++++++++++++++++++++++++++++++++++*/
713
714 int RenameFile(const char *oldfilename,const char *newfilename)
715 {
716 rename(oldfilename,newfilename);
717
718 return(0);
719 }
720
721
722 /*++++++++++++++++++++++++++++++++++++++
723 Create a file buffer.
724
725 int fd The file descriptor.
726
727 int read_write A flag set to 1 for reading, -1 for writing and 0 for unbuffered.
728 ++++++++++++++++++++++++++++++++++++++*/
729
730 static void CreateFileBuffer(int fd,int read_write)
731 {
732 if(nfilebuffers<=fd)
733 {
734 int i;
735
736 filebuffers=(struct filebuffer**)realloc((void*)filebuffers,(fd+1)*sizeof(struct filebuffer*));
737
738 for(i=nfilebuffers;i<=fd;i++)
739 filebuffers[i]=NULL;
740
741 nfilebuffers=fd+1;
742 }
743
744 if(read_write)
745 {
746 filebuffers[fd]=(struct filebuffer*)calloc(sizeof(struct filebuffer),1);
747
748 filebuffers[fd]->reading=(read_write==1);
749 }
750 }

Properties

Name Value
cvs:description File handling functions.