/* This is an example implementation of tmpfile() fit for use with POSIX kernels. */ struct _PDCLIB_file_t * tmpfile( void ) { FILE * rc; /* This is the chosen way to get high-quality randomness. Replace as appropriate. */ FILE * randomsource = fopen( "/proc/sys/kernel/random/uuid", "rb" ); char filename[ L_tmpnam ]; _PDCLIB_fd_t fd; if ( randomsource == NULL ) { return NULL; } for ( ;; ) { /* Get a filename candidate. What constitutes a valid filename and where temporary files are usually located is platform-dependent, which is one reason why this function is located in the platform overlay. The other reason is that a *good* implementation should use high-quality randomness instead of a pseudo-random sequence to generate the filename candidate, which is *also* platform-dependent. */ unsigned int random; fscanf( randomsource, "%u", &random ); sprintf( filename, "/tmp/%u.tmp", random ); /* Check if file of this name exists. Note that fopen() is a very weak check, which does not take e.g. access permissions into account (file might exist but not readable). Replace with something more appropriate. */ fd = open( filename, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR ); if ( fd != -1 ) { break; } close( fd ); } fclose( randomsource ); /* See fopen(). */ if ( ( rc = calloc( 1, sizeof( struct _PDCLIB_file_t ) + _PDCLIB_UNGETCBUFSIZE + L_tmpnam + BUFSIZ ) ) == NULL ) { /* No memory to set up FILE structure */ close( fd ); return NULL; } rc->status = _PDCLIB_filemode( "wb+" ) | _IOLBF | _PDCLIB_DELONCLOSE; rc->handle = fd; rc->ungetbuf = (unsigned char *)rc + sizeof( struct _PDCLIB_file_t ); rc->filename = (char *)rc->ungetbuf + _PDCLIB_UNGETCBUFSIZE; rc->buffer = rc->filename + L_tmpnam; strcpy( rc->filename, filename ); rc->bufsize = BUFSIZ; rc->bufidx = 0; rc->ungetidx = 0; rc->next = _PDCLIB_filelist; _PDCLIB_filelist = rc; return rc; }
#include <stdio.h> #include <stdlib.h> #ifndef REGTEST #include "_PDCLIB_io.h" #include "_PDCLIB_glue.h" #include <string.h> #include <errno.h> extern FILE * _PDCLIB_filelist; FILE * fopen( const char * _PDCLIB_restrict filename, const char * _PDCLIB_restrict mode ) { int imode = _PDCLIB_filemode( mode ); if( imode == 0 || filename == NULL ) return NULL; _PDCLIB_fd_t fd; const _PDCLIB_fileops_t * ops; if(!_PDCLIB_open( &fd, &ops, filename, imode )) { return NULL; } FILE * f = _PDCLIB_fvopen( fd, ops, imode, filename ); if(!f) { int saveErrno = errno; ops->close(fd); errno = saveErrno;
int main( void ) { #ifndef REGTEST TESTCASE( _PDCLIB_filemode( "r" ) == _PDCLIB_FREAD ); TESTCASE( _PDCLIB_filemode( "w" ) == _PDCLIB_FWRITE ); TESTCASE( _PDCLIB_filemode( "a" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE ) ); TESTCASE( _PDCLIB_filemode( "r+" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW ) ); TESTCASE( _PDCLIB_filemode( "w+" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW ) ); TESTCASE( _PDCLIB_filemode( "a+" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FRW ) ); TESTCASE( _PDCLIB_filemode( "rb" ) == ( _PDCLIB_FREAD | _PDCLIB_FBIN ) ); TESTCASE( _PDCLIB_filemode( "wb" ) == ( _PDCLIB_FWRITE | _PDCLIB_FBIN ) ); TESTCASE( _PDCLIB_filemode( "ab" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FBIN ) ); TESTCASE( _PDCLIB_filemode( "r+b" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW | _PDCLIB_FBIN ) ); TESTCASE( _PDCLIB_filemode( "w+b" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) ); TESTCASE( _PDCLIB_filemode( "a+b" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) ); TESTCASE( _PDCLIB_filemode( "rb+" ) == ( _PDCLIB_FREAD | _PDCLIB_FRW | _PDCLIB_FBIN ) ); TESTCASE( _PDCLIB_filemode( "wb+" ) == ( _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) ); TESTCASE( _PDCLIB_filemode( "ab+" ) == ( _PDCLIB_FAPPEND | _PDCLIB_FWRITE | _PDCLIB_FRW | _PDCLIB_FBIN ) ); TESTCASE( _PDCLIB_filemode( "x" ) == 0 ); TESTCASE( _PDCLIB_filemode( "r++" ) == 0 ); TESTCASE( _PDCLIB_filemode( "wbb" ) == 0 ); TESTCASE( _PDCLIB_filemode( "a+bx" ) == 0 ); #endif return TEST_RESULTS; }