Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

519 lines
14 KiB

  1. /***
  2. *tmpfile.c - create unique file name or file
  3. *
  4. * Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * defines tmpnam() and tmpfile().
  8. *
  9. *Revision History:
  10. * ??-??-?? TC initial version
  11. * 04-17-86 JMB tmpnam - brought semantics in line with System V
  12. * definition as follows: 1) if tmpnam paramter is NULL,
  13. * store name in static buffer (do NOT use malloc); (2)
  14. * use P_tmpdir as the directory prefix to the temp file
  15. * name (do NOT use current working directory)
  16. * 05-26-87 JCR fixed bug where tmpnam was modifying errno
  17. * 08-10-87 JCR Added code to support P_tmpdir with or without trailing
  18. * '\'.
  19. * 11-09-87 JCR Multi-thread support
  20. * 12-11-87 JCR Added "_LOAD_DS" to declaration
  21. * 01-22-88 JCR Added per thread static namebuf area (mthread bug fix)
  22. * 05-27-88 PHG Merged DLL/normal versions
  23. * 11-14-88 GJF _openfile() now takes a file sharing flag, also some
  24. * cleanup (now specific to the 386)
  25. * 06-06-89 JCR 386 mthread support
  26. * 11-28-89 JCR Added check to _tmpnam so it can't loop forever
  27. * 02-16-90 GJF Fixed copyright and indents
  28. * 03-19-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include
  29. * <cruntime.h> and removed #include <register.h>.
  30. * 03-26-90 GJF Added #include <io.h>.
  31. * 10-03-90 GJF New-style function declarators.
  32. * 01-21-91 GJF ANSI naming.
  33. * 07-22-91 GJF Multi-thread support for Win32 [_WIN32_].
  34. * 03-17-92 GJF Completely rewrote Win32 version.
  35. * 03-27-92 DJM POSIX support.
  36. * 05-02-92 SRW Use _O_TEMPORARY flag for tmpfile routine.
  37. * 05-04-92 GJF Force cinittmp.obj in for Win32.
  38. * 08-26-92 GJF Fixed POSIX build.
  39. * 08-28-92 GJF Oops, forgot about getpid...
  40. * 11-06-92 GJF Use '/' for POSIX, '\\' otherwise, as the path
  41. * separator. Also, backed out JHavens' bug fix of 6-14,
  42. * which was itself a bug (albeit a less serious one).
  43. * 02-26-93 GJF Put in per-thread buffers, purged Cruiser support.
  44. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  45. * 04-07-93 SKS Replace access() with ANSI-conforming _access()
  46. * 04-22-93 GJF Fixed bug in multi-thread - multiple threads calling
  47. * tmpnam would get the same names. Also, went to static
  48. * namebufX buffers since failing due to a failed malloc
  49. * would violate ANSI.
  50. * 04-29-93 GJF Multi-thread bug in tmpnam() - forgot to copy the
  51. * generated name to the per-thread buffer.
  52. * 12-07-93 CFW Wide char enable.
  53. * 04-01-94 GJF #ifdef-ed out __inc_tmpoff for msvcrt*.dll, it's
  54. * unnecessary.
  55. * 04-22-94 GJF Made definitions of namebuf0 and namebuf1 conditional
  56. * on DLL_FOR_WIN32S.
  57. * 01-10-95 CFW Debug CRT allocs.
  58. * 01-18-95 GJF Must replace _tcsdup with _malloc_crt/_tcscpy for
  59. * _DEBUG build.
  60. * 02-21-95 GJF Appended Mac version of source file (somewhat cleaned
  61. * up), with appropriate #ifdef-s. Also replaced WPRFLAG
  62. * with _UNICODE.
  63. * 03-07-95 GJF _[un]lock_str macros now take FILE * arg.
  64. * 08-08-97 GJF Removed initialized-but-unused local variable from
  65. * tmpfile(). Also, detab-ed.
  66. * 03-03-98 GJF Exception-safe locking.
  67. * 05-13-99 PML Remove Win32s
  68. * 05-17-99 PML Remove all Macintosh support.
  69. * 10-06-99 PML Set errno EMFILE when out of streams.
  70. * 07-03-01 BWT Fix genfname to use the correct buffer size to encode a dword (7 bytes + NULL).
  71. *
  72. *******************************************************************************/
  73. #include <cruntime.h>
  74. #ifdef _POSIX_
  75. #include <unistd.h>
  76. #endif
  77. #include <errno.h>
  78. #include <process.h>
  79. #include <fcntl.h>
  80. #include <io.h>
  81. #include <mtdll.h>
  82. #include <share.h>
  83. #include <stdio.h>
  84. #include <stdlib.h>
  85. #include <string.h>
  86. #include <sys/types.h>
  87. #include <sys/stat.h>
  88. #include <file2.h>
  89. #include <internal.h>
  90. #include <tchar.h>
  91. #include <dbgint.h>
  92. /*
  93. * Buffers used by tmpnam() and tmpfile() to build filenames.
  94. */
  95. static _TSCHAR namebuf0[L_tmpnam] = { 0 }; /* used by tmpnam() */
  96. static _TSCHAR namebuf1[L_tmpnam] = { 0 }; /* used by tmpfile() */
  97. /*
  98. * Initializing function for namebuf0 and namebuf1.
  99. */
  100. #ifdef _UNICODE
  101. static void __cdecl winit_namebuf(int);
  102. #else
  103. static void __cdecl init_namebuf(int);
  104. #endif
  105. /*
  106. * Generator function that produces temporary filenames
  107. */
  108. #ifdef _UNICODE
  109. static int __cdecl wgenfname(wchar_t *);
  110. #else
  111. static int __cdecl genfname(char *);
  112. #endif
  113. /***
  114. *_TSCHAR *tmpnam(_TSCHAR *s) - generate temp file name
  115. *
  116. *Purpose:
  117. * Creates a file name that is unique in the directory specified by
  118. * _P_tmpdir in stdio.h. Places file name in string passed by user or
  119. * in static mem if pass NULL.
  120. *
  121. *Entry:
  122. * _TSCHAR *s - ptr to place to put temp name
  123. *
  124. *Exit:
  125. * returns pointer to constructed file name (s or address of static mem)
  126. * returns NULL if fails
  127. *
  128. *Exceptions:
  129. *
  130. *******************************************************************************/
  131. _TSCHAR * __cdecl _ttmpnam (
  132. _TSCHAR *s
  133. )
  134. {
  135. _TSCHAR *pfnam = NULL;
  136. #ifdef _MT
  137. _ptiddata ptd;
  138. if ( !_mtinitlocknum( _TMPNAM_LOCK ))
  139. return NULL;
  140. _mlock(_TMPNAM_LOCK);
  141. __try {
  142. #endif
  143. /*
  144. * Initialize namebuf0, if needed. Otherwise, call genfname() to
  145. * generate the next filename.
  146. */
  147. if ( *namebuf0 == 0 ) {
  148. #ifdef _UNICODE
  149. winit_namebuf(0);
  150. #else
  151. init_namebuf(0);
  152. #endif
  153. }
  154. #ifdef _UNICODE
  155. else if ( wgenfname(namebuf0) )
  156. #else
  157. else if ( genfname(namebuf0) )
  158. #endif
  159. goto tmpnam_err;
  160. /*
  161. * Generate a filename that doesn't already exist.
  162. */
  163. while ( _taccess(namebuf0, 0) == 0 )
  164. #ifdef _UNICODE
  165. if ( wgenfname(namebuf0) )
  166. #else
  167. if ( genfname(namebuf0) )
  168. #endif
  169. goto tmpnam_err;
  170. /*
  171. * Filename has successfully been generated.
  172. */
  173. if ( s == NULL )
  174. #ifdef _MT
  175. {
  176. /*
  177. * Use a per-thread buffer to hold the generated file name.
  178. * If there isn't one, and one cannot be created, just use
  179. * namebuf0.
  180. */
  181. ptd = _getptd();
  182. #ifdef _UNICODE
  183. if ( (ptd->_wnamebuf0 != NULL) || ((ptd->_wnamebuf0 =
  184. _malloc_crt(L_tmpnam * sizeof(wchar_t))) != NULL) )
  185. {
  186. s = ptd->_wnamebuf0;
  187. wcscpy(s, namebuf0);
  188. }
  189. #else
  190. if ( (ptd->_namebuf0 != NULL) || ((ptd->_namebuf0 =
  191. _malloc_crt(L_tmpnam)) != NULL) )
  192. {
  193. s = ptd->_namebuf0;
  194. strcpy(s, namebuf0);
  195. }
  196. #endif
  197. else
  198. s = namebuf0;
  199. }
  200. #else
  201. s = namebuf0;
  202. #endif
  203. else
  204. _tcscpy(s, namebuf0);
  205. pfnam = s;
  206. /*
  207. * All errors come here.
  208. */
  209. tmpnam_err:
  210. #ifdef _MT
  211. ; }
  212. __finally {
  213. _munlock(_TMPNAM_LOCK);
  214. }
  215. #endif
  216. return pfnam;
  217. }
  218. #ifndef _UNICODE
  219. /***
  220. *FILE *tmpfile() - create a temporary file
  221. *
  222. *Purpose:
  223. * Creates a temporary file with the file mode "w+b". The file
  224. * will be automatically deleted when closed or the program terminates
  225. * normally.
  226. *
  227. *Entry:
  228. * None.
  229. *
  230. *Exit:
  231. * Returns stream pointer to opened file.
  232. * Returns NULL if fails
  233. *
  234. *Exceptions:
  235. *
  236. *******************************************************************************/
  237. FILE * __cdecl tmpfile (
  238. void
  239. )
  240. {
  241. FILE *stream;
  242. FILE *return_stream = NULL;
  243. int fh;
  244. #ifdef _MT
  245. int stream_lock_held = 0;
  246. if ( !_mtinitlocknum( _TMPNAM_LOCK ))
  247. return NULL;
  248. _mlock(_TMPNAM_LOCK);
  249. __try {
  250. #endif
  251. /*
  252. * Initialize namebuf1, if needed. Otherwise, call genfname() to
  253. * generate the next filename.
  254. */
  255. if ( *namebuf1 == 0 ) {
  256. init_namebuf(1);
  257. }
  258. else if ( genfname(namebuf1) )
  259. goto tmpfile_err;
  260. /*
  261. * Get a free stream.
  262. *
  263. * Note: In multi-thread models, the stream obtained below is locked!
  264. */
  265. if ( (stream = _getstream()) == NULL ) {
  266. errno = EMFILE;
  267. goto tmpfile_err;
  268. }
  269. #ifdef _MT
  270. stream_lock_held = 1;
  271. #endif
  272. /*
  273. * Create a temporary file.
  274. *
  275. * Note: The loop below will only create a new file. It will NOT
  276. * open and truncate an existing file. Either behavior is probably
  277. * legal under ANSI (4.9.4.3 says tmpfile "creates" the file, but
  278. * also says it is opened with mode "wb+"). However, the behavior
  279. * implemented below is compatible with prior versions of MS-C and
  280. * makes error checking easier.
  281. */
  282. #ifdef _POSIX_
  283. while ( ((fh = open(namebuf1,
  284. O_CREAT | O_EXCL | O_RDWR,
  285. S_IRUSR | S_IWUSR
  286. ))
  287. == -1) && (errno == EEXIST) )
  288. #else
  289. while ( ((fh = _sopen(namebuf1,
  290. _O_CREAT | _O_EXCL | _O_RDWR | _O_BINARY |
  291. _O_TEMPORARY,
  292. _SH_DENYNO,
  293. _S_IREAD | _S_IWRITE
  294. ))
  295. == -1) && (errno == EEXIST) )
  296. #endif
  297. if ( genfname(namebuf1) )
  298. break;
  299. /*
  300. * Check that the loop above did indeed create a temporary
  301. * file.
  302. */
  303. if ( fh == -1 )
  304. goto tmpfile_err;
  305. /*
  306. * Initialize stream
  307. */
  308. #ifdef _DEBUG
  309. if ( (stream->_tmpfname = _malloc_crt( (_tcslen( namebuf1 ) + 1) *
  310. sizeof(_TSCHAR) )) == NULL )
  311. #else /* ndef _DEBUG */
  312. if ( (stream->_tmpfname = _tcsdup( namebuf1 )) == NULL )
  313. #endif /* _DEBUG */
  314. {
  315. /* close the file, then branch to error handling */
  316. #ifdef _POSIX_
  317. close(fh);
  318. #else
  319. _close(fh);
  320. #endif
  321. goto tmpfile_err;
  322. }
  323. #ifdef _DEBUG
  324. _tcscpy( stream->_tmpfname, namebuf1 );
  325. #endif /* _DEBUG */
  326. stream->_cnt = 0;
  327. stream->_base = stream->_ptr = NULL;
  328. stream->_flag = _commode | _IORW;
  329. stream->_file = fh;
  330. return_stream = stream;
  331. /*
  332. * All errors branch to the label below.
  333. */
  334. tmpfile_err:
  335. #ifdef _MT
  336. ; }
  337. __finally {
  338. if ( stream_lock_held )
  339. _unlock_str(stream);
  340. _munlock(_TMPNAM_LOCK);
  341. }
  342. #endif
  343. return return_stream;
  344. }
  345. #endif /* _UNICODE */
  346. /***
  347. *static void init_namebuf(flag) - initializes the namebuf arrays
  348. *
  349. *Purpose:
  350. * Called once each for namebuf0 and namebuf1, to initialize
  351. * them.
  352. *
  353. *Entry:
  354. * int flag - flag set to 0 if namebuf0 is to be initialized,
  355. * non-zero (1) if namebuf1 is to be initialized.
  356. *Exit:
  357. *
  358. *Exceptions:
  359. *
  360. *******************************************************************************/
  361. #ifdef _UNICODE
  362. static void __cdecl winit_namebuf(
  363. #else
  364. static void __cdecl init_namebuf(
  365. #endif
  366. int flag
  367. )
  368. {
  369. _TSCHAR *p, *q;
  370. if ( flag == 0 )
  371. p = namebuf0;
  372. else
  373. p = namebuf1;
  374. /*
  375. * Put in the path prefix. Make sure it ends with a slash or
  376. * backslash character.
  377. */
  378. #ifdef _UNICODE
  379. wcscpy(p, _wP_tmpdir);
  380. #else
  381. strcpy(p, _P_tmpdir);
  382. #endif
  383. q = p + sizeof(_P_tmpdir) - 1; /* same as p + _tcslen(p) */
  384. #ifdef _POSIX_
  385. if ( *(q - 1) != _T('/') )
  386. *(q++) = _T('/');
  387. #else
  388. if ( (*(q - 1) != _T('\\')) && (*(q - 1) != _T('/')) )
  389. *(q++) = _T('\\');
  390. #endif
  391. /*
  392. * Append the leading character of the filename.
  393. */
  394. if ( flag )
  395. /* for tmpfile() */
  396. *(q++) = _T('t');
  397. else
  398. /* for tmpnam() */
  399. *(q++) = _T('s');
  400. /*
  401. * Append the process id, encoded in base 32. Note this makes
  402. * p back into a string again (i.e., terminated by a '\0').
  403. */
  404. #ifdef _POSIX_
  405. _ultot((unsigned long)getpid(), q, 32);
  406. #else
  407. _ultot((unsigned long)_getpid(), q, 32);
  408. #endif
  409. _tcscat(p, _T("."));
  410. }
  411. /***
  412. *static int genfname(_TSCHAR *fname) -
  413. *
  414. *Purpose:
  415. *
  416. *Entry:
  417. *
  418. *Exit:
  419. *
  420. *Exceptions:
  421. *
  422. *******************************************************************************/
  423. #ifdef _UNICODE
  424. static int __cdecl wgenfname (
  425. #else
  426. static int __cdecl genfname (
  427. #endif
  428. _TSCHAR *fname
  429. )
  430. {
  431. _TSCHAR *p;
  432. _TSCHAR pext[8]; // 7 positions for base 32 ulong + null terminator
  433. unsigned long extnum;
  434. p = _tcsrchr(fname, _T('.'));
  435. p++;
  436. if ( (extnum = _tcstoul(p, NULL, 32) + 1) >= (unsigned long)TMP_MAX )
  437. return -1;
  438. _tcscpy(p, _ultot(extnum, pext, 32));
  439. return 0;
  440. }
  441. #if !defined(_UNICODE) && !defined(CRTDLL)
  442. /***
  443. *void __inc_tmpoff(void) - force external reference for _tmpoff
  444. *
  445. *Purpose:
  446. * Forces an external reference to be generate for _tmpoff, which is
  447. * is defined in cinittmp.obj. This has the forces cinittmp.obj to be
  448. * pulled in, making a call to rmtmp part of the termination.
  449. *
  450. *Entry:
  451. *
  452. *Exit:
  453. *
  454. *Exceptions:
  455. *
  456. *******************************************************************************/
  457. extern int _tmpoff;
  458. void __inc_tmpoff(
  459. void
  460. )
  461. {
  462. _tmpoff++;
  463. }
  464. #endif /* _UNICODE */