forked from KolibriOS/kolibrios
update CLib
git-svn-id: svn://kolibrios.org@614 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
171
programs/develop/open watcom/trunk/clib/streamio/tmpfl.c
Normal file
171
programs/develop/open watcom/trunk/clib/streamio/tmpfl.c
Normal file
@@ -0,0 +1,171 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Open Watcom Project
|
||||
*
|
||||
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
|
||||
*
|
||||
* ========================================================================
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original
|
||||
* Code as defined in and that are subject to the Sybase Open Watcom
|
||||
* Public License version 1.0 (the 'License'). You may not use this file
|
||||
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
|
||||
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
|
||||
* provided with the Original Code and Modifications, and is also
|
||||
* available at www.sybase.com/developer/opensource.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
|
||||
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
|
||||
* NON-INFRINGEMENT. Please see the License for the specific language
|
||||
* governing rights and limitations under the License.
|
||||
*
|
||||
* ========================================================================
|
||||
*
|
||||
* Description: Platform independent tmpfile() implementation.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include "variety.h"
|
||||
#include "rtinit.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <fcntl.h>
|
||||
#include <direct.h>
|
||||
#include <string.h>
|
||||
#include <process.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "rtdata.h"
|
||||
#include "tmpfname.h"
|
||||
#include "seterrno.h"
|
||||
#include "openmode.h"
|
||||
|
||||
#define OPEN_MODE (O_RDWR | O_CREAT | O_BINARY)
|
||||
#define PMODE (S_IREAD | S_IWRITE)
|
||||
|
||||
/* Netware doesn't define these */
|
||||
/* Symbolic constants for the access() function */
|
||||
|
||||
#if !defined( F_OK )
|
||||
#define R_OK 4 /* Test for read permission */
|
||||
#define W_OK 2 /* Test for write permission */
|
||||
#define X_OK 1 /* Test for execute permission */
|
||||
#define F_OK 0 /* Test for existence of file */
|
||||
#endif
|
||||
|
||||
extern void __MkTmpFile( char *buf, int num );
|
||||
extern void __RmTmpFile( FILE *fp );
|
||||
extern void (*__RmTmpFileFn)( FILE *fp );
|
||||
|
||||
char __tmpfnext = _TMP_INIT_CHAR;
|
||||
|
||||
_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;
|
||||
__set_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;
|
||||
__set_errno( old_errno );
|
||||
return( fp );
|
||||
}
|
||||
// We couldn't open it, probably because we have run out of handles.
|
||||
// Remove the renamed file.
|
||||
our_errno = errno;
|
||||
remove( name2 );
|
||||
__set_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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* tmpfil() pulls in a lot of overhead that many programs do not need. But */
|
||||
/* since temp files are removed on program shutdown, the code to remove */
|
||||
/* them would always get linked in even if the program never heard of temp */
|
||||
/* files. Since we know that temporary files can _only_ be created through */
|
||||
/* tmpfile(), we can have a dummy __RmTmpFile() by default and use the */
|
||||
/* real thing only if tmpfil() was called. */
|
||||
void __Init_Tmpfl( void )
|
||||
{
|
||||
// Just assign the function address
|
||||
__RmTmpFileFn = __RmTmpFile;
|
||||
}
|
||||
|
||||
AXI( __Init_Tmpfl, INIT_PRIORITY_RUNTIME )
|
Reference in New Issue
Block a user