4 * Implementation of an (approximately) POSIX conforming mkstemp(3)
5 * function; invocation is via an inline wrapper, defined in stdlib.h,
6 * which delegates to the library routine defined herein.
10 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
11 * Copyright (C) 2013, 2014, MinGW.org Project.
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the "Software"),
16 * to deal in the Software without restriction, including without limitation
17 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 * and/or sell copies of the Software, and to permit persons to whom the
19 * Software is furnished to do so, subject to the following conditions:
21 * The above copyright notice, this permission notice, and the following
22 * disclaimer shall be included in all copies or substantial portions of
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
31 * DEALINGS IN THE SOFTWARE.
40 /* Candidate names for the temporary file are generated, based on a
41 * cryptographically secure random character sequence; this externally
42 * implemented character sequence generator is shared by mkstemp(3)
45 extern char *__mingw_crypto_tmpname( char * );
47 int __mingw_mkstemp( int setmode, char *template )
49 /* Implementation of the low-level functional support for mkstemp(3);
50 * this provides the formal function implementation, including support
51 * for adjustment of its behaviour w.r.t. temporary file persistence.
53 * By default, temporary files will persist until explicitly deleted;
54 * POSIX prescribes that temporary files are to be created with the
55 * following attributes, (with O_BINARY added, to ensure there is
56 * no undue influence from "helpful" text mode transformations):
58 static int omode = _O_CREAT | _O_EXCL | _O_RDWR | _O_BINARY;
61 /* On POSIX platforms, programmers may adopt an idiom such as:
63 * if( mkstemp( template ) >= 0 )
64 * { unlink( template );
68 * to ensure that a temporary file does NOT persist after it is
69 * closed; MS-Windows does not allow such use of unlink(2), while
70 * the file remains open. Thus, MS-Windows programmers must take
71 * extra care, to close and unlink temporary files AFTER use, if
72 * similar behaviour is desired.
74 * To mitigate this MS-Windows limitation, we provide support for
75 * an alternative, MinGW specific idiom:
79 * _MKSTEMP_SETMODE( _O_TEMPORARY );
80 * if( mkstemp( template ) >= 0 )
85 * to achieve a similar effect to that of the above POSIX idiom.
87 return omode = (omode & ~_O_TEMPORARY) | (setmode & _O_TEMPORARY);
90 { /* Formal MinGW implementation of the mkstemp(3) function; to begin,
91 * we assume that it may fail, and record an invalid file descriptor
92 * for return in such eventuality.
96 /* Check that the caller gave us a viable template...
98 if( template == NULL )
100 /* ...bailing out, if nothing at all...
105 { /* ...but assume that anything at all is potentially viable;
106 * set up a retry limit, and estimate the storage requirement
107 * for a working scratch buffer.
110 size_t bufsiz = 1 + strlen( template );
112 /* Until we either get a valid file descriptor, or we exhaust
113 * the retry limit while attempting to get one...
115 while( (fd < 0) && (retry-- > 0) )
117 /* ...set up the scratch buffer, copy the template into it,
118 * then transform to get a cryptographically secure candidate
119 * file name for the temporary file; (each retry cycle will
120 * generate a randomly differing candidate file name)...
122 char filename[bufsiz];
123 if( __mingw_crypto_tmpname( strcpy( filename, template ) ) == NULL )
125 /* ...bailing out, on any unsuccessful attempt to generate
126 * the candidate name; (this is most likely to occur during
127 * the first cycle, due to a malformed template; if we can
128 * successfully generate the first candidate, successive
129 * attempts are unlikely to fail).
135 { /* We got a usable candidate file name; attempt to open it
138 if( (fd = open( filename, omode, _S_IREAD | _S_IWRITE )) >= 0 )
140 * ...and, on success, update the template to reflect the
141 * name of the file we've opened, and we are done...
143 strcpy( template, filename );
145 /* ...but, if we failed for any reason other than that a file
146 * with the candidate name already exists...
148 else if( errno != EEXIST )
150 * ...then, any retry will most likely also fail, so we may
151 * as well just give up now.
157 /* Finally, whether we succeeded in opening any temporary file, or we
158 * ultimately gave up in disgust, we return the prevailing state of the
159 * file descriptor we attempted to assign.
165 /* $RCSfile$: end of file */