_WCRTLINK FILE *tmpfile( void ) /* create a temporary file */ { char tmpfnext; int fd; FILE *fp; char name[L_tmpnam]; char *ptr; ptr = __tmpdir( name ); strcpy( ptr, _TMPFNAME ); for( tmpfnext = 'a'; ; tmpfnext++ ) { ptr[_TMPFCHAR] = tmpfnext; fd = open( name, O_RDWR | O_CREAT | O_EXCL | O_TEMP, 0666 ); if( fd != -1 ) break; if( errno != EEXIST ) return( NULL ); if( tmpfnext == 'z' ) tmpfnext = 'A' - 1; if( tmpfnext == 'Z' ) return( NULL ); } fp = fdopen( fd, "wb+" ); if( fp != NULL ) { /* fp->_flag |= _TMPFIL; -- Don't turn the TMPFIL bit on... we're going to remove the filename from the file system right away. This is allowed under POSIX. The file will be deleted as soon as it's closed */ _FP_TMPFCHAR(fp) = tmpfnext; } else { close( fd ); } remove( name ); return( fp ); }
void __RmTmpFile( FILE *fp ) { char name[PATH_MAX + _TMPFNAME_LENGTH + 1]; /* 02-aug-90 */ __MkTmpFile( name, _FP_TMPFCHAR(fp) ); remove( name ); }
_WCRTLINK FILE *tmpfile( void ) /* create a temporary file */ { int hdl; int old_errno; int our_errno; char suffix1; char suffix2; FILE *fp; char name1[PATH_MAX + _TMPFNAME_LENGTH + 1]; char name2[PATH_MAX + _TMPFNAME_LENGTH + 1]; old_errno = _RWD_errno; suffix1 = 0; for( ;; ) { // Part I for( ;; ) { __MkTmpFile( name1, suffix1 ); // if a file by this name does not exist if( access( name1, F_OK ) != 0 ) { // then let's try to create it hdl = sopen( name1, OPEN_MODE, OPENMODE_DENY_COMPAT, PMODE ); // if we created it then continue with part II if( hdl != -1 ) break; _RWD_errno = EAGAIN; } suffix1++; // give up after _TMP_INIT_CHAR tries JBS 99/10/26 if( suffix1 >= _TMP_INIT_CHAR ) return NULL; } close( hdl ); // Part II /* we now have a empty file. Let's try to rename it rename should be an atomic operation in the operating system so if it succeeds we can be sure no one else has this file. Consider the following sequence: task1: access x.y => file does not exist task2: access x.y => file does not exist task1: fopen x.y => succeeds task2: fopen x.y => succeeds (now have both tasks with x.y open) task1: rename x.y to y.y => succeeds, can use this file task2: rename x.y to y.y => fails (because x.y no longer exists) task2: start over again to get a new file name task2: succeeds second time around since no more race condition with task1. */ suffix2 = _RWD_tmpfnext; // only one of these per process for( ;; ) { if( suffix2 == suffix1 ) { suffix2++; } __MkTmpFile( name2, suffix2 ); if( rename( name1, name2 ) == 0 ) { // if rename worked // The file is now ours. Let's try to open it. fp = fopen( name2, "wb+" ); if( fp != NULL ) { fp->_flag |= _TMPFIL; _FP_TMPFCHAR(fp) = suffix2; _RWD_errno = old_errno; return( fp ); } // We couldn't open it, probably because we have run out of handles. // Remove the renamed file. our_errno = _RWD_errno; remove( name2 ); _RWD_errno = our_errno; return( NULL ); } // The rename didn't work or we couldn't open the renamed file. // One of two possibilities: // (1) The "to" name already exists. // (2) Another process renamed it away from us. // Check for case (2). // Quit if "from" file is gone and start over. if( access( name1, F_OK ) != 0 ) break; // Must be case (1). Try another "to" name. ++suffix2; if( suffix2 == 0 ) { suffix2 = _TMP_INIT_CHAR; } _RWD_tmpfnext = suffix2; // update for all processes } } }