Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /****************************************************************************
  2. *
  3. *                            Open Watcom Project
  4. *
  5. *    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
  6. *
  7. *  ========================================================================
  8. *
  9. *    This file contains Original Code and/or Modifications of Original
  10. *    Code as defined in and that are subject to the Sybase Open Watcom
  11. *    Public License version 1.0 (the 'License'). You may not use this file
  12. *    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
  13. *    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
  14. *    provided with the Original Code and Modifications, and is also
  15. *    available at www.sybase.com/developer/opensource.
  16. *
  17. *    The Original Code and all software distributed under the License are
  18. *    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  19. *    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
  20. *    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
  21. *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
  22. *    NON-INFRINGEMENT. Please see the License for the specific language
  23. *    governing rights and limitations under the License.
  24. *
  25. *  ========================================================================
  26. *
  27. * Description:  Platform independent tmpfile() implementation.
  28. *
  29. ****************************************************************************/
  30.  
  31.  
  32. #include "variety.h"
  33. #include "rtinit.h"
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <stddef.h>
  37. #include <fcntl.h>
  38. #include <direct.h>
  39. #include <string.h>
  40. #include <process.h>
  41. #include <unistd.h>
  42. #include <errno.h>
  43. #include "rtdata.h"
  44. #include "tmpfname.h"
  45. #include "seterrno.h"
  46. #include "openmode.h"
  47.  
  48. #define OPEN_MODE   (O_RDWR | O_CREAT | O_BINARY)
  49. #define PMODE       (S_IREAD | S_IWRITE)
  50.  
  51. /* Netware doesn't define these */
  52. /* Symbolic constants for the access() function */
  53.  
  54. #if !defined( F_OK )
  55. #define R_OK    4       /*  Test for read permission    */
  56. #define W_OK    2       /*  Test for write permission   */
  57. #define X_OK    1       /*  Test for execute permission */
  58. #define F_OK    0       /*  Test for existence of file  */
  59. #endif
  60.  
  61. extern void     __MkTmpFile( char *buf, int num );
  62. extern void     __RmTmpFile( FILE *fp );
  63. extern void     (*__RmTmpFileFn)( FILE *fp );
  64.  
  65. char __tmpfnext = _TMP_INIT_CHAR;
  66.  
  67. _WCRTLINK FILE *tmpfile( void )         /* create a temporary file */
  68. {
  69.     int         hdl;
  70.     int         old_errno;
  71.     int         our_errno;
  72.     char        suffix1;
  73.     char        suffix2;
  74.     FILE        *fp;
  75.     char        name1[PATH_MAX + _TMPFNAME_LENGTH + 1];
  76.     char        name2[PATH_MAX + _TMPFNAME_LENGTH + 1];
  77.  
  78.     old_errno = _RWD_errno;
  79.     suffix1 = 0;
  80.     for( ;; ) {
  81.         // Part I
  82.         for( ;; ) {
  83.             __MkTmpFile( name1, suffix1 );
  84.             // if a file by this name does not exist
  85.             if( access( name1, F_OK ) != 0 ) {
  86.  
  87.                 // then let's try to create it
  88.                 hdl = sopen( name1, OPEN_MODE, OPENMODE_DENY_COMPAT, PMODE );
  89.  
  90.                 // if we created it then continue with part II
  91.                 if( hdl != -1 ) break;
  92.                 __set_errno( EAGAIN );
  93.             }
  94.             suffix1++;
  95.             // give up after _TMP_INIT_CHAR tries  JBS 99/10/26
  96.             if( suffix1 >= _TMP_INIT_CHAR ) return NULL;
  97.         }
  98.         close( hdl );
  99.  
  100.         // Part II
  101.         /* we now have a empty file. Let's try to rename it
  102.            rename should be an atomic operation in the operating system
  103.            so if it succeeds we can be sure no one else has this file.
  104.            Consider the following sequence:
  105.  
  106.            task1: access x.y => file does not exist
  107.            task2: access x.y => file does not exist
  108.            task1: fopen  x.y => succeeds
  109.            task2: fopen  x.y => succeeds (now have both tasks with x.y open)
  110.            task1: rename x.y to y.y => succeeds, can use this file
  111.            task2: rename x.y to y.y => fails (because x.y no longer exists)
  112.            task2: start over again to get a new file name
  113.            task2: succeeds second time around since no more race condition
  114.                   with task1.
  115.          */
  116.         suffix2 = _RWD_tmpfnext;    // only one of these per process
  117.         for( ;; ) {
  118.             if( suffix2 == suffix1 ) {
  119.                 suffix2++;
  120.             }
  121.             __MkTmpFile( name2, suffix2 );
  122.  
  123.             if( rename( name1, name2 ) == 0 ) { // if rename worked
  124.  
  125.                 // The file is now ours. Let's try to open it.
  126.                 fp = fopen( name2, "wb+" );
  127.                 if( fp != NULL ) {
  128.                     fp->_flag |= _TMPFIL;
  129.                     _FP_TMPFCHAR(fp) = suffix2;
  130.                     __set_errno( old_errno );
  131.                     return( fp );
  132.                 }
  133.                 // We couldn't open it, probably because we have run out of handles.
  134.                 // Remove the renamed file.
  135.                 our_errno = errno;
  136.                 remove( name2 );
  137.                 __set_errno( our_errno );
  138.                 return( NULL );
  139.             }
  140.             // The rename didn't work or we couldn't open the renamed file.
  141.             // One of two possibilities:
  142.             // (1) The "to" name already exists.
  143.             // (2) Another process renamed it away from us.
  144.  
  145.             // Check for case (2).
  146.             // Quit if "from" file is gone and start over.
  147.             if( access( name1, F_OK ) != 0 ) break;
  148.  
  149.             // Must be case (1). Try another "to" name.
  150.             ++suffix2;
  151.             if( suffix2 == 0 ) {
  152.                 suffix2 = _TMP_INIT_CHAR;
  153.             }
  154.             _RWD_tmpfnext = suffix2;    // update for all processes
  155.         }
  156.     }
  157. }
  158.  
  159. /* tmpfil() pulls in a lot of overhead that many programs do not need. But */
  160. /* since temp files are removed on program shutdown, the code to remove    */
  161. /* them would always get linked in even if the program never heard of temp */
  162. /* files. Since we know that temporary files can _only_ be created through */
  163. /* tmpfile(), we can have a dummy __RmTmpFile() by default and use the     */
  164. /* real thing only if tmpfil() was called.                                 */
  165. void __Init_Tmpfl( void )
  166. {
  167.     // Just assign the function address
  168.     __RmTmpFileFn = __RmTmpFile;
  169. }
  170.  
  171. AXI( __Init_Tmpfl, INIT_PRIORITY_RUNTIME )
  172.