00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <sys/types.h>
00028 #include <sys/stat.h>
00029 #include <fcntl.h>
00030 #include <unistd.h>
00031 #include <sys/mman.h>
00032 #include <errno.h>
00033 #include <assert.h>
00034
00035 #include "libdefs.h"
00036 #include "vacopy.h"
00037 #include "error.h"
00038 #include "fileutils.h"
00039 #include "options.h"
00040
00041 #if fid_WORDSIZE == 64
00042 #define FILETOOLARGEERROR(ERR,FNAME)\
00043 fid_error_throw(ERR,"File \"%s\" is too large to be handled by "\
00044 PACKAGE ". The maximum file size is limited to %lu bytes "\
00045 "in this version.",(FNAME),(unsigned long)fid_FILE_MAXSIZE)
00046 #else
00047 #define FILETOOLARGEERROR(ERR,FNAME)\
00048 fid_error_throw(ERR,"File \"%s\" is too large to be handled by "\
00049 PACKAGE ". The maximum file size is limited to %lu bytes. "\
00050 "Please consider compiling and using a 64 bit version.",\
00051 (FNAME),(unsigned long)fid_FILE_MAXSIZE)
00052 #endif
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 static int map_file(fid_Mappedfile *mfile, const char *filename,
00085 int writable, int create, size_t initial_size,
00086 fid_Error *error)
00087 {
00088 struct stat buf;
00089 int all_ok;
00090
00091 assert(mfile != NULL);
00092 assert(filename != NULL);
00093
00094 mfile->content=NULL;
00095 mfile->occupied=mfile->allocated=0;
00096 mfile->fd=0;
00097 mfile->filename=NULL;
00098
00099 if(create)
00100 {
00101 assert(initial_size > 0);
00102 if(initial_size > fid_FILE_MAXSIZE)
00103 {
00104 FILETOOLARGEERROR(error,filename);
00105 return -1;
00106 }
00107 writable=1;
00108 }
00109
00110 if((mfile->filename=strdup(filename)) == NULL)
00111 {
00112 fid_OUTOFMEM(error);
00113 }
00114 else
00115 {
00116 if(create)
00117 {
00118 mfile->fd=open(mfile->filename,O_CREAT|O_TRUNC|O_RDWR,
00119 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
00120 }
00121 else
00122 {
00123 mfile->fd=open(mfile->filename,writable?O_RDWR:O_RDONLY,0);
00124 }
00125
00126 if(mfile->fd == -1)
00127 {
00128 fid_error_throw(error,"Could not open file \"%s\".",mfile->filename);
00129 }
00130 else
00131 {
00132 all_ok=0;
00133 if(create)
00134 {
00135 mfile->occupied=0;
00136 mfile->allocated=initial_size;
00137 if(ftruncate(mfile->fd,(off_t)mfile->allocated) == 0)
00138 {
00139 all_ok=1;
00140 }
00141 else
00142 {
00143 fid_error_throw(error,"Could not create file \"%s\" of size "
00144 "%lu bytes.",mfile->filename,
00145 (unsigned long)mfile->allocated);
00146 }
00147 }
00148 else if(fstat(mfile->fd,&buf) == 0)
00149 {
00150 if(S_ISREG(buf.st_mode) || S_ISLNK(buf.st_mode))
00151 {
00152 if(buf.st_size <= (off_t)fid_FILE_MAXSIZE)
00153 {
00154 mfile->allocated=mfile->occupied=(size_t)buf.st_size;
00155 all_ok=1;
00156 }
00157 else
00158 {
00159 FILETOOLARGEERROR(error,filename);
00160 }
00161 }
00162 else
00163 {
00164 fid_error_throw(error,"Path \"%s\" is not a file.",mfile->filename);
00165 }
00166 }
00167 else
00168 {
00169 fid_error_throw(error,"Could not read file \"%s\".",mfile->filename);
00170 }
00171
00172 if(all_ok)
00173 {
00174 mfile->mmap_prot=PROT_READ|(writable?PROT_WRITE:0);
00175 mfile->mmap_flags=writable?MAP_SHARED:MAP_PRIVATE;
00176 if((mfile->content=
00177 (unsigned char *)mmap(NULL,mfile->allocated,
00178 mfile->mmap_prot,mfile->mmap_flags,
00179 mfile->fd,(off_t)0)) != MAP_FAILED)
00180 {
00181
00182 return 0;
00183 }
00184 else
00185 {
00186 fid_error_throw(error,"Could not map file \"%s\" into memory.",
00187 mfile->filename);
00188 mfile->content=NULL;
00189 }
00190 }
00191
00192
00193 (void)close(mfile->fd);
00194
00195 if(create)
00196 {
00197
00198
00199
00200
00201 (void)remove(mfile->filename);
00202 }
00203 }
00204 free(mfile->filename);
00205 }
00206 mfile->content=NULL;
00207 mfile->occupied=mfile->allocated=0;
00208 return -1;
00209 }
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226 int fid_file_map(fid_Mappedfile *mfile, const char *filename, int writable,
00227 int may_prefetch, fid_Error *error)
00228 {
00229 int retval;
00230
00231 if((retval=map_file(mfile,filename,writable,0,0,error)) == 0 && may_prefetch)
00232 {
00233 fid_options_parse();
00234 if(fid_options_prefetch)
00235 {
00236
00237 fid_file_prefetch(mfile,fid_options_smart_prefetch);
00238 }
00239 }
00240 return retval;
00241 }
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 int fid_file_new(fid_Mappedfile *mfile, const char *filename, fid_Error *error)
00260 {
00261 return map_file(mfile,filename,1,1,fid_MAPPEDFILE_GROWSIZE,error);
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 int fid_file_allocate(fid_Mappedfile *mfile, const char *filename,
00281 size_t size, fid_Error *error)
00282 {
00283 return map_file(mfile,filename,1,1,size,error);
00284 }
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309 void fid_file_fake(fid_Mappedfile *mfile, void *block, size_t size)
00310 {
00311 assert(block != NULL);
00312 assert(size > 0);
00313
00314 mfile->content=(unsigned char *)block;
00315 mfile->allocated=mfile->occupied=size;
00316 mfile->fd=-1;
00317 mfile->filename=NULL;
00318 mfile->mmap_prot=PROT_READ;
00319 mfile->mmap_flags=MAP_PRIVATE;
00320 }
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340 int fid_file_grow_by_size(fid_Mappedfile *mfile, size_t size,
00341 fid_Error *error)
00342 {
00343 size_t oldsize;
00344
00345 assert(mfile != NULL);
00346 assert(mfile->content != NULL);
00347 assert(mfile->occupied <= mfile->allocated);
00348
00349 if(!fid_MAPPEDFILE_IS_WRITABLE(mfile))
00350 {
00351 fid_error_throw(error,"Cannot enlarge read-only file \"%s\".",
00352 mfile->filename);
00353 return -1;
00354 }
00355
00356 if(size > fid_FILE_MAXSIZE || mfile->allocated+size > fid_FILE_MAXSIZE)
00357 {
00358 fid_error_throw(error,"Cannot enlarge file \"%s\" by %lu "
00359 "bytes, maximum file size of %lu exceeded.",
00360 mfile->filename,(unsigned long)size,
00361 (unsigned long)fid_FILE_MAXSIZE);
00362 return -1;
00363 }
00364
00365
00366 oldsize=mfile->allocated;
00367 mfile->allocated+=size;
00368 assert(mfile->allocated <= fid_FILE_MAXSIZE);
00369
00370 if(ftruncate(mfile->fd,(off_t)mfile->allocated) == 0)
00371 {
00372 #ifndef S_SPLINT_S
00373 (void)msync((caddr_t)mfile->content,oldsize,MS_ASYNC);
00374 #endif
00375 (void)munmap((caddr_t)mfile->content,oldsize);
00376 if((mfile->content=
00377 (unsigned char *)mmap(NULL,mfile->allocated,mfile->mmap_prot,
00378 mfile->mmap_flags,mfile->fd,(off_t)0)) != MAP_FAILED)
00379 {
00380 return 0;
00381 }
00382 else
00383 {
00384 fid_error_throw(error,"Could not re-map file \"%s\".",mfile->filename);
00385 mfile->content=NULL;
00386 }
00387 }
00388 else
00389 {
00390 fid_error_throw(error,"Could not set size of file \"%s\" to %lu bytes.",
00391 mfile->filename,(unsigned long)mfile->allocated);
00392 }
00393
00394 return -1;
00395 }
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 int fid_file_ensure_free_space(fid_Mappedfile *mfile, size_t size,
00418 fid_Error *error)
00419 {
00420 size_t reqsize;
00421
00422 assert(mfile != NULL);
00423 assert(mfile->content != NULL);
00424 assert(mfile->occupied <= mfile->allocated);
00425
00426 if(!fid_MAPPEDFILE_IS_WRITABLE(mfile))
00427 {
00428 fid_error_throw(error,"Cannot enlarge read-only file \"%s\".",
00429 mfile->filename);
00430 return -1;
00431 }
00432
00433 if(size <= fid_FILE_MAXSIZE &&
00434 (reqsize=mfile->occupied+size) <= fid_FILE_MAXSIZE)
00435 {
00436 if(reqsize > mfile->allocated)
00437 {
00438
00439
00440 return fid_file_grow_by_size(mfile,size+fid_MAPPEDFILE_GROWSIZE,error);
00441 }
00442 else
00443 {
00444 return 0;
00445 }
00446 }
00447 fid_error_throw(error,"Need %lu more bytes in file \"%s\", "
00448 "but maximum file size of %lu would be "
00449 "exceeded then.",(unsigned long)size,mfile->filename,
00450 (unsigned long)fid_FILE_MAXSIZE);
00451 return -1;
00452 }
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464 static void truncate_file(fid_Mappedfile *mfile)
00465 {
00466 int dummy;
00467
00468 assert(mfile != NULL);
00469 assert(mfile->content != NULL);
00470
00471 if(fid_MAPPEDFILE_IS_WRITABLE(mfile) && mfile->allocated > mfile->occupied)
00472 {
00473 dummy=ftruncate(mfile->fd,(off_t)mfile->occupied);
00474 (void)lseek(mfile->fd,(off_t)0,SEEK_END);
00475 }
00476 }
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 int fid_file_write(fid_Mappedfile *mfile, fid_Error *error, const char *fmt,
00502 ...)
00503 {
00504 int bufsize, retval=0;
00505 va_list ap, copy;
00506 #ifdef ENABLE_VSNPRINTF_WORKAROUND
00507 char dummy;
00508 #endif
00509
00510 assert(mfile != NULL);
00511
00512 if(fmt == NULL)
00513 {
00514
00515 return 0;
00516 }
00517
00518 va_start(ap,fmt);
00519 #ifndef S_SPLINT_S
00520 va_copy(copy,ap);
00521 #endif
00522 bufsize=vsnprintf(
00523 #ifdef ENABLE_VSNPRINTF_WORKAROUND
00524 &dummy,1,
00525 #else
00526 NULL,0,
00527 #endif
00528 fmt,copy)+1;
00529 va_end(copy);
00530 if(bufsize > 1)
00531 {
00532
00533 fid_MAPPEDFILE_CHECKSPACE(mfile,bufsize,bufsize+1024,error,retval=-1;);
00534 if(retval == 0)
00535 {
00536 #ifndef S_SPLINT_S
00537 va_copy(copy,ap);
00538 #endif
00539 (void)vsnprintf((char *)mfile->content+mfile->occupied,(size_t)bufsize,
00540 fmt,copy);
00541 va_end(copy);
00542 mfile->occupied+=bufsize-1;
00543 }
00544 }
00545 va_end(ap);
00546 return retval;
00547 }
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564 int fid_file_make_readonly(fid_Mappedfile *mfile, fid_Error *error)
00565 {
00566 struct stat buf;
00567
00568 assert(mfile != NULL);
00569 assert(mfile->content != NULL);
00570
00571 if(!fid_MAPPEDFILE_IS_WRITABLE(mfile))
00572 {
00573
00574 #ifdef DEBUG
00575 fprintf(stderr,"%s(): file is read-only already, doing nothing.\n",
00576 __func__);
00577 #endif
00578 return 0;
00579 }
00580
00581
00582 #ifndef S_SPLINT_S
00583 (void)msync((caddr_t)mfile->content,mfile->allocated,MS_ASYNC);
00584 #endif
00585 (void)munmap((caddr_t)mfile->content,mfile->allocated);
00586 truncate_file(mfile);
00587 mfile->allocated=mfile->occupied;
00588 mfile->mmap_prot=PROT_READ;
00589 mfile->mmap_flags=MAP_PRIVATE;
00590 mfile->content=NULL;
00591
00592 if(close(mfile->fd) == 0)
00593 {
00594 if((mfile->fd=open(mfile->filename,O_RDONLY)) != -1)
00595 {
00596 if(fstat(mfile->fd,&buf) == 0)
00597 {
00598 if(buf.st_size == (off_t)mfile->allocated)
00599 {
00600 if(buf.st_size == 0)
00601 {
00602
00603 return 0;
00604 }
00605
00606 if((mfile->content=
00607 (unsigned char *)mmap(NULL,mfile->allocated,
00608 mfile->mmap_prot,mfile->mmap_flags,
00609 mfile->fd,(off_t)0)) != MAP_FAILED)
00610 {
00611 return 0;
00612 }
00613 fid_error_throw(error,
00614 "Could not make file \"%s\" read-only (mmap failed).",
00615 mfile->filename);
00616 mfile->content=NULL;
00617 }
00618 else
00619 {
00620 fid_error_throw(error,
00621 "Could not make file \"%s\" read-only (file size "
00622 "changed unexpectedly).",mfile->filename);
00623 }
00624 }
00625 else
00626 {
00627 fid_error_throw(error,
00628 "Could not make file \"%s\" read-only (fstat failed).",
00629 mfile->filename);
00630 }
00631 (void)close(mfile->fd);
00632 }
00633 else
00634 {
00635 fid_error_throw(error,
00636 "Could not make file \"%s\" read-only (open failed).",
00637 mfile->filename);
00638 }
00639 }
00640 else
00641 {
00642 fid_error_throw(error,
00643 "Could not make file \"%s\" read-only (close failed).",
00644 mfile->filename);
00645 }
00646
00647 return -1;
00648 }
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674 int fid_file_dump_to_file(const fid_Mappedfile *mfile, const char *filename,
00675 fid_Error *error)
00676 {
00677 int fd, errnum;
00678 const unsigned char *data;
00679 size_t remaining;
00680 ssize_t written;
00681 #ifdef FID_MAX_WRITE_SIZE
00682 size_t write_now;
00683 #endif
00684
00685 assert(mfile != NULL);
00686 assert(mfile->content != NULL);
00687 assert(filename != NULL);
00688
00689 if((fd=open(filename,O_CREAT|O_TRUNC|O_RDWR,
00690 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) == -1)
00691 {
00692 fid_error_throw(error,"Could not create file \"%s\".",filename);
00693 return -1;
00694 }
00695
00696 data=mfile->content;
00697 remaining=mfile->occupied;
00698 while(remaining > 0)
00699 {
00700 #ifdef FID_MAX_WRITE_SIZE
00701 if((write_now=remaining) > FID_MAX_WRITE_SIZE) write_now=FID_MAX_WRITE_SIZE;
00702 #endif
00703
00704 errno=0;
00705 written=write(fd,data,
00706 #ifdef FID_MAX_WRITE_SIZE
00707 write_now
00708 #else
00709 remaining
00710 #endif
00711 );
00712 errnum=errno;
00713
00714 if(written != -1)
00715 {
00716 data+=written;
00717 assert(remaining >= (size_t)written);
00718 remaining-=written;
00719 assert(data <= mfile->content+mfile->occupied);
00720 }
00721
00722 if(errnum != 0 && errnum != EINTR)
00723 {
00724
00725 fid_error_throw_errno(error,errnum,"write()");
00726 fid_error_throw(error,"Could not write to file \"%s\".",filename);
00727 break;
00728 }
00729 }
00730
00731 (void)close(fd);
00732
00733 if(remaining > 0)
00734 {
00735
00736 (void)remove(filename);
00737 return -1;
00738 }
00739
00740 return 0;
00741 }
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753 void fid_file_cleanup(fid_Mappedfile *mfile)
00754 {
00755 assert(mfile != NULL);
00756 if(mfile->content == NULL || mfile->fd == -1 || mfile->filename == NULL)
00757 {
00758 return;
00759 }
00760
00761 (void)munmap((caddr_t)mfile->content,mfile->allocated);
00762 (void)close(mfile->fd);
00763 (void)remove(mfile->filename);
00764 free(mfile->filename);
00765 mfile->content=NULL;
00766 mfile->occupied=mfile->allocated=0;
00767 }
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798 static int file_already_prefetched(const fid_Mappedfile *mfile,
00799 size_t minsize, int pgsize)
00800 {
00801 #ifdef HAVE_MINCORE
00802 #ifdef MINCORE_SIGNED_CHAR
00803 char vec;
00804 #else
00805 unsigned char vec;
00806 #endif
00807 double frac;
00808 size_t offset, i, count;
00809
00810 if(mfile->occupied < minsize)
00811 {
00812
00813 return 0;
00814 }
00815
00816 count=0;
00817 frac=(double)mfile->occupied/100.0;
00818 for(i=0; i < 100; ++i)
00819 {
00820 offset=pgsize*(((size_t)((double)i*frac))/pgsize);
00821 assert(offset < mfile->occupied);
00822 assert((offset%(size_t)pgsize) == 0);
00823 if(mincore((caddr_t)mfile->content+offset,(size_t)1,&vec) != 0)
00824 {
00825 fprintf(stderr,"%s(): mincore() failed\n",__func__);
00826 return 0;
00827 }
00828 if((vec&MINCORE_INCORE) != 0)
00829 {
00830 if(++count >= 90)
00831 {
00832 return 1;
00833 }
00834 }
00835 }
00836 #endif
00837
00838 return 0;
00839 }
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869 void fid_file_prefetch(const fid_Mappedfile *mfile, int smart)
00870 {
00871 const unsigned char *ptr, *maxptr;
00872 volatile unsigned char value;
00873 static int increment=0;
00874 static size_t minsize=0;
00875
00876 if(mfile == NULL || mfile->content == NULL)
00877 {
00878 return;
00879 }
00880
00881 if(increment <= 0)
00882 {
00883 if(increment == 0)
00884 {
00885 #ifdef HAVE_GETPAGESIZE
00886 increment=getpagesize();
00887 #elif defined HAVE_SYSCONF
00888 increment=(int)sysconf(_SC_PAGE_SIZE);
00889 #else
00890
00891 abort();
00892 #endif
00893 if(increment <= 0)
00894 {
00895 fprintf(stderr,
00896 #ifdef HAVE_GETPAGESIZE
00897 "getpagesize()"
00898 #elif defined HAVE_SYSCONF
00899 "sysconf(_SC_PAGE_SIZE)"
00900 #endif
00901 " returned %d\n",increment);
00902 increment=-1;
00903 return;
00904 }
00905 minsize=(size_t)64*(size_t)increment;
00906 }
00907 else
00908 {
00909 return;
00910 }
00911 }
00912
00913 if(smart && file_already_prefetched(mfile,minsize,increment))
00914 {
00915 return;
00916 }
00917
00918 ptr=mfile->content;
00919 maxptr=ptr+mfile->occupied;
00920 while(ptr < maxptr)
00921 {
00922 value=*ptr;
00923 ptr+=increment;
00924 }
00925 }
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940 void fid_file_unmap(fid_Mappedfile *mfile)
00941 {
00942 assert(mfile != NULL);
00943 if(mfile->content == NULL)
00944 {
00945 return;
00946 }
00947 assert(mfile->content != MAP_FAILED || mfile->fd == -1);
00948 assert(mfile->allocated >= mfile->occupied);
00949
00950 if(mfile->fd != -1)
00951 {
00952
00953 assert(mfile->filename != NULL);
00954
00955 #ifndef S_SPLINT_S
00956 (void)msync((caddr_t)mfile->content,mfile->allocated,MS_ASYNC);
00957 #endif
00958 (void)munmap((caddr_t)mfile->content,mfile->allocated);
00959 truncate_file(mfile);
00960 (void)close(mfile->fd);
00961 free(mfile->filename);
00962 }
00963 else
00964 {
00965
00966 free(mfile->content);
00967 }
00968
00969 mfile->content=NULL;
00970 mfile->occupied=mfile->allocated=0;
00971 }
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985 int fid_filenamebuffer_init(fid_Filenamebuffer *fnamebuf, const char *filename,
00986 fid_Error *error)
00987 {
00988 size_t baselength;
00989
00990 assert(fnamebuf != NULL);
00991 assert(filename != NULL);
00992
00993 baselength=strlen(filename);
00994 if((fnamebuf->buffer=(char *)malloc(sizeof(char)*(baselength+5))) == NULL)
00995 {
00996 fid_OUTOFMEM(error);
00997 return -1;
00998 }
00999 memcpy(fnamebuf->buffer,filename,baselength);
01000 fnamebuf->bufptr=fnamebuf->buffer+baselength;
01001 *fnamebuf->bufptr='.';
01002 ++fnamebuf->bufptr;
01003 return 0;
01004 }
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022 int fid_filenamebuffer_init_local(fid_Filenamebuffer *fnamebuf,
01023 fid_Filenamebuffer **extbuffer,
01024 const char *filename, fid_Error *error)
01025 {
01026 assert(fnamebuf != NULL);
01027 assert(extbuffer != NULL);
01028 assert(filename != NULL);
01029
01030 if(*extbuffer == NULL)
01031 {
01032 *extbuffer=fnamebuf;
01033 return (fid_filenamebuffer_init(fnamebuf,filename,error) == -1)?-1:1;
01034 }
01035 return 0;
01036 }
01037
01038
01039
01040
01041
01042
01043
01044
01045 void fid_filenamebuffer_free(fid_Filenamebuffer *fnamebuf)
01046 {
01047 assert(fnamebuf != NULL);
01048 assert(fnamebuf->buffer != NULL);
01049 assert(fnamebuf->bufptr != NULL);
01050 free(fnamebuf->buffer);
01051 }
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066 char *fid_filename_create(const char *basefilename, const char *fileext,
01067 fid_Error *error)
01068 {
01069 fid_Filenamebuffer fnamebuf;
01070
01071 assert(basefilename != NULL);
01072 assert(fileext != NULL);
01073 assert(strlen(fileext) == (size_t)3);
01074
01075 if(fid_filenamebuffer_init(&fnamebuf,basefilename,error) == 0)
01076 {
01077 memcpy(fnamebuf.bufptr,fileext,(size_t)4);
01078 return fnamebuf.buffer;
01079 }
01080 else
01081 {
01082 return NULL;
01083 }
01084 }
01085
01086