Leaked source code of windows server 2003
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.

533 lines
15 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. * 10-19-01 BWT If malloc_crt fails when allocating the return buffer in tmpnam,
  72. * return NULL and set errno to enomem. We've already set the
  73. * precedence that null can be returned if we're unable to get
  74. * the thread lock.
  75. * 12-11-01 BWT Replace _getptd with _getptd_noexit - failure to get a
  76. * unique tmpname buffer isn't fatal - return NULL/ENOMEM
  77. * and let the caller deal with it.
  78. *
  79. *******************************************************************************/
  80. #include <cruntime.h>
  81. #ifdef _POSIX_
  82. #include <unistd.h>
  83. #endif
  84. #include <errno.h>
  85. #include <process.h>
  86. #include <fcntl.h>
  87. #include <io.h>
  88. #include <mtdll.h>
  89. #include <share.h>
  90. #include <stdio.h>
  91. #include <stdlib.h>
  92. #include <string.h>
  93. #include <sys/types.h>
  94. #include <sys/stat.h>
  95. #include <file2.h>
  96. #include <internal.h>
  97. #include <tchar.h>
  98. #include <dbgint.h>
  99. /*
  100. * Buffers used by tmpnam() and tmpfile() to build filenames.
  101. */
  102. static _TSCHAR namebuf0[L_tmpnam] = { 0 }; /* used by tmpnam() */
  103. static _TSCHAR namebuf1[L_tmpnam] = { 0 }; /* used by tmpfile() */
  104. /*
  105. * Initializing function for namebuf0 and namebuf1.
  106. */
  107. #ifdef _UNICODE
  108. static void __cdecl winit_namebuf(int);
  109. #else
  110. static void __cdecl init_namebuf(int);
  111. #endif
  112. /*
  113. * Generator function that produces temporary filenames
  114. */
  115. #ifdef _UNICODE
  116. static int __cdecl wgenfname(wchar_t *);
  117. #else
  118. static int __cdecl genfname(char *);
  119. #endif
  120. /***
  121. *_TSCHAR *tmpnam(_TSCHAR *s) - generate temp file name
  122. *
  123. *Purpose:
  124. * Creates a file name that is unique in the directory specified by
  125. * _P_tmpdir in stdio.h. Places file name in string passed by user or
  126. * in static mem if pass NULL.
  127. *
  128. *Entry:
  129. * _TSCHAR *s - ptr to place to put temp name
  130. *
  131. *Exit:
  132. * returns pointer to constructed file name (s or address of static mem)
  133. * returns NULL if fails
  134. *
  135. *Exceptions:
  136. *
  137. *******************************************************************************/
  138. _TSCHAR * __cdecl _ttmpnam (
  139. _TSCHAR *s
  140. )
  141. {
  142. _TSCHAR *pfnam = NULL;
  143. #ifdef _MT
  144. _ptiddata ptd;
  145. if ( !_mtinitlocknum( _TMPNAM_LOCK ))
  146. return NULL;
  147. _mlock(_TMPNAM_LOCK);
  148. __try {
  149. #endif
  150. /*
  151. * Initialize namebuf0, if needed. Otherwise, call genfname() to
  152. * generate the next filename.
  153. */
  154. if ( *namebuf0 == 0 ) {
  155. #ifdef _UNICODE
  156. winit_namebuf(0);
  157. #else
  158. init_namebuf(0);
  159. #endif
  160. }
  161. #ifdef _UNICODE
  162. else if ( wgenfname(namebuf0) )
  163. #else
  164. else if ( genfname(namebuf0) )
  165. #endif
  166. goto tmpnam_err;
  167. /*
  168. * Generate a filename that doesn't already exist.
  169. */
  170. while ( _taccess(namebuf0, 0) == 0 )
  171. #ifdef _UNICODE
  172. if ( wgenfname(namebuf0) )
  173. #else
  174. if ( genfname(namebuf0) )
  175. #endif
  176. goto tmpnam_err;
  177. /*
  178. * Filename has successfully been generated.
  179. */
  180. if ( s == NULL )
  181. #ifdef _MT
  182. {
  183. /*
  184. * Use a per-thread buffer to hold the generated file name.
  185. * If there isn't one, and one cannot be created, just use
  186. * namebuf0.
  187. */
  188. ptd = _getptd_noexit();
  189. if (!ptd) {
  190. errno = ENOMEM;
  191. goto tmpnam_err;
  192. }
  193. #ifdef _UNICODE
  194. if ( (ptd->_wnamebuf0 != NULL) || ((ptd->_wnamebuf0 =
  195. _malloc_crt(L_tmpnam * sizeof(wchar_t))) != NULL) )
  196. {
  197. s = ptd->_wnamebuf0;
  198. wcscpy(s, namebuf0);
  199. }
  200. #else
  201. if ( (ptd->_namebuf0 != NULL) || ((ptd->_namebuf0 =
  202. _malloc_crt(L_tmpnam)) != NULL) )
  203. {
  204. s = ptd->_namebuf0;
  205. strcpy(s, namebuf0);
  206. }
  207. #endif
  208. else
  209. {
  210. errno = ENOMEM;
  211. goto tmpnam_err;
  212. }
  213. }
  214. #else
  215. s = namebuf0;
  216. #endif
  217. else
  218. _tcscpy(s, namebuf0);
  219. pfnam = s;
  220. /*
  221. * All errors come here.
  222. */
  223. tmpnam_err:
  224. #ifdef _MT
  225. ; }
  226. __finally {
  227. _munlock(_TMPNAM_LOCK);
  228. }
  229. #endif
  230. return pfnam;
  231. }
  232. #ifndef _UNICODE
  233. /***
  234. *FILE *tmpfile() - create a temporary file
  235. *
  236. *Purpose:
  237. * Creates a temporary file with the file mode "w+b". The file
  238. * will be automatically deleted when closed or the program terminates
  239. * normally.
  240. *
  241. *Entry:
  242. * None.
  243. *
  244. *Exit:
  245. * Returns stream pointer to opened file.
  246. * Returns NULL if fails
  247. *
  248. *Exceptions:
  249. *
  250. *******************************************************************************/
  251. FILE * __cdecl tmpfile (
  252. void
  253. )
  254. {
  255. FILE *stream;
  256. FILE *return_stream = NULL;
  257. int fh;
  258. #ifdef _MT
  259. int stream_lock_held = 0;
  260. if ( !_mtinitlocknum( _TMPNAM_LOCK ))
  261. return NULL;
  262. _mlock(_TMPNAM_LOCK);
  263. __try {
  264. #endif
  265. /*
  266. * Initialize namebuf1, if needed. Otherwise, call genfname() to
  267. * generate the next filename.
  268. */
  269. if ( *namebuf1 == 0 ) {
  270. init_namebuf(1);
  271. }
  272. else if ( genfname(namebuf1) )
  273. goto tmpfile_err;
  274. /*
  275. * Get a free stream.
  276. *
  277. * Note: In multi-thread models, the stream obtained below is locked!
  278. */
  279. if ( (stream = _getstream()) == NULL ) {
  280. errno = EMFILE;
  281. goto tmpfile_err;
  282. }
  283. #ifdef _MT
  284. stream_lock_held = 1;
  285. #endif
  286. /*
  287. * Create a temporary file.
  288. *
  289. * Note: The loop below will only create a new file. It will NOT
  290. * open and truncate an existing file. Either behavior is probably
  291. * legal under ANSI (4.9.4.3 says tmpfile "creates" the file, but
  292. * also says it is opened with mode "wb+"). However, the behavior
  293. * implemented below is compatible with prior versions of MS-C and
  294. * makes error checking easier.
  295. */
  296. #ifdef _POSIX_
  297. while ( ((fh = open(namebuf1,
  298. O_CREAT | O_EXCL | O_RDWR,
  299. S_IRUSR | S_IWUSR
  300. ))
  301. == -1) && (errno == EEXIST) )
  302. #else
  303. while ( ((fh = _sopen(namebuf1,
  304. _O_CREAT | _O_EXCL | _O_RDWR | _O_BINARY |
  305. _O_TEMPORARY,
  306. _SH_DENYNO,
  307. _S_IREAD | _S_IWRITE
  308. ))
  309. == -1) && (errno == EEXIST) )
  310. #endif
  311. if ( genfname(namebuf1) )
  312. break;
  313. /*
  314. * Check that the loop above did indeed create a temporary
  315. * file.
  316. */
  317. if ( fh == -1 )
  318. goto tmpfile_err;
  319. /*
  320. * Initialize stream
  321. */
  322. #ifdef _DEBUG
  323. if ( (stream->_tmpfname = _malloc_crt( (_tcslen( namebuf1 ) + 1) *
  324. sizeof(_TSCHAR) )) == NULL )
  325. #else /* ndef _DEBUG */
  326. if ( (stream->_tmpfname = _tcsdup( namebuf1 )) == NULL )
  327. #endif /* _DEBUG */
  328. {
  329. /* close the file, then branch to error handling */
  330. #ifdef _POSIX_
  331. close(fh);
  332. #else
  333. _close(fh);
  334. #endif
  335. goto tmpfile_err;
  336. }
  337. #ifdef _DEBUG
  338. _tcscpy( stream->_tmpfname, namebuf1 );
  339. #endif /* _DEBUG */
  340. stream->_cnt = 0;
  341. stream->_base = stream->_ptr = NULL;
  342. stream->_flag = _commode | _IORW;
  343. stream->_file = fh;
  344. return_stream = stream;
  345. /*
  346. * All errors branch to the label below.
  347. */
  348. tmpfile_err:
  349. #ifdef _MT
  350. ; }
  351. __finally {
  352. if ( stream_lock_held )
  353. _unlock_str(stream);
  354. _munlock(_TMPNAM_LOCK);
  355. }
  356. #endif
  357. return return_stream;
  358. }
  359. #endif /* _UNICODE */
  360. /***
  361. *static void init_namebuf(flag) - initializes the namebuf arrays
  362. *
  363. *Purpose:
  364. * Called once each for namebuf0 and namebuf1, to initialize
  365. * them.
  366. *
  367. *Entry:
  368. * int flag - flag set to 0 if namebuf0 is to be initialized,
  369. * non-zero (1) if namebuf1 is to be initialized.
  370. *Exit:
  371. *
  372. *Exceptions:
  373. *
  374. *******************************************************************************/
  375. #ifdef _UNICODE
  376. static void __cdecl winit_namebuf(
  377. #else
  378. static void __cdecl init_namebuf(
  379. #endif
  380. int flag
  381. )
  382. {
  383. _TSCHAR *p, *q;
  384. if ( flag == 0 )
  385. p = namebuf0;
  386. else
  387. p = namebuf1;
  388. /*
  389. * Put in the path prefix. Make sure it ends with a slash or
  390. * backslash character.
  391. */
  392. #ifdef _UNICODE
  393. wcscpy(p, _wP_tmpdir);
  394. #else
  395. strcpy(p, _P_tmpdir);
  396. #endif
  397. q = p + sizeof(_P_tmpdir) - 1; /* same as p + _tcslen(p) */
  398. #ifdef _POSIX_
  399. if ( *(q - 1) != _T('/') )
  400. *(q++) = _T('/');
  401. #else
  402. if ( (*(q - 1) != _T('\\')) && (*(q - 1) != _T('/')) )
  403. *(q++) = _T('\\');
  404. #endif
  405. /*
  406. * Append the leading character of the filename.
  407. */
  408. if ( flag )
  409. /* for tmpfile() */
  410. *(q++) = _T('t');
  411. else
  412. /* for tmpnam() */
  413. *(q++) = _T('s');
  414. /*
  415. * Append the process id, encoded in base 32. Note this makes
  416. * p back into a string again (i.e., terminated by a '\0').
  417. */
  418. #ifdef _POSIX_
  419. _ultot((unsigned long)getpid(), q, 32);
  420. #else
  421. _ultot((unsigned long)_getpid(), q, 32);
  422. #endif
  423. _tcscat(p, _T("."));
  424. }
  425. /***
  426. *static int genfname(_TSCHAR *fname) -
  427. *
  428. *Purpose:
  429. *
  430. *Entry:
  431. *
  432. *Exit:
  433. *
  434. *Exceptions:
  435. *
  436. *******************************************************************************/
  437. #ifdef _UNICODE
  438. static int __cdecl wgenfname (
  439. #else
  440. static int __cdecl genfname (
  441. #endif
  442. _TSCHAR *fname
  443. )
  444. {
  445. _TSCHAR *p;
  446. _TSCHAR pext[8]; // 7 positions for base 32 ulong + null terminator
  447. unsigned long extnum;
  448. p = _tcsrchr(fname, _T('.'));
  449. p++;
  450. if ( (extnum = _tcstoul(p, NULL, 32) + 1) >= (unsigned long)TMP_MAX )
  451. return -1;
  452. _tcscpy(p, _ultot(extnum, pext, 32));
  453. return 0;
  454. }
  455. #if !defined(_UNICODE) && !defined(CRTDLL)
  456. /***
  457. *void __inc_tmpoff(void) - force external reference for _tmpoff
  458. *
  459. *Purpose:
  460. * Forces an external reference to be generate for _tmpoff, which is
  461. * is defined in cinittmp.obj. This has the forces cinittmp.obj to be
  462. * pulled in, making a call to rmtmp part of the termination.
  463. *
  464. *Entry:
  465. *
  466. *Exit:
  467. *
  468. *Exceptions:
  469. *
  470. *******************************************************************************/
  471. extern int _tmpoff;
  472. void __inc_tmpoff(
  473. void
  474. )
  475. {
  476. _tmpoff++;
  477. }
  478. #endif /* _UNICODE */