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.

325 lines
10 KiB

  1. /***
  2. *tempnam.c - generate unique file name
  3. *
  4. * Copyright (c) 1986-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. *Revision History:
  9. * ??-??-?? TC initial version
  10. * 04-17-86 JMB changed directory of last resort from \tmp to tmp.
  11. * eliminated use of L_tmpnam (it was incoorectly defined
  12. * in stdio.h and should not be used in tempnam; see
  13. * System V definition of tempnam.
  14. * 04-23-86 TC changed last try directory from tmp to current directory
  15. * 04-29-86 JMB bug fix: pfxlength was being set from strlen(pfx)
  16. * even if pfx was NULL. Fixed to set pfxlength to zero
  17. * if pfx is NULL, strlen(pfx) otherwise.
  18. * 05-28-86 TC changed stat's to access's, and optimized code a bit
  19. * 12-01-86 JMB added support for Kanji file names until KANJI switch
  20. * 12-15-86 JMB free malloced memory if (++_tmpoff == first)
  21. * 07-15-87 JCR Re-init _tempoff based on length of pfx (fixes infinate
  22. * loop bug; also, tempnam() now uses _tempoff instead of
  23. * _tmpoff (used by tmpnam()).
  24. * 10-16-87 JCR Fixed bug in _tempoff re-init code if pfx is NULL.
  25. * 11-09-87 JCR Multi-thread version
  26. * 12-11-87 JCR Added "_LOAD_DS" to declaration
  27. * 05-27-88 PHG Merged DLL and normal versions
  28. * 06-09-89 GJF Propagated MT's change of 05-17-89 (Kanji)
  29. * 02-16-90 GJF Fixed copyright and indents
  30. * 03-19-90 GJF Replaced _LOAD_DS and _CALLTYPE1 and added #include
  31. * <cruntime.h>.
  32. * 03-26-90 GJF Added #include <io.h>.
  33. * 08-13-90 SBM Compiles cleanly with -W3, replaced explicit register
  34. * declarations by REGn references
  35. * 10-03-90 GJF New-style function declarator.
  36. * 01-21-91 GJF ANSI naming.
  37. * 08-19-91 JCR Allow quotes in TMP variable path
  38. * 08-27-91 JCR ANSI naming
  39. * 08-25-92 GJF Don't build for POSIX.
  40. * 11-30-92 KRS Generalize KANJI support to MBCS. Port 16-bit bug fix.
  41. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  42. * 12-07-93 CFW Wide char enable.
  43. * 01-10-95 CFW Debug CRT allocs.
  44. * 01-23-95 CFW Debug: tempnam return freed by user.
  45. * 02-21-95 GJF Appended Mac version of source file (somewhat cleaned
  46. * up), with appropriate #ifdef-s. Also replaced WPRFLAG
  47. * with _UNICODE.
  48. * 03-10-95 CFW Made _tempnam() parameters const.
  49. * 03-14-95 JCF Made pfin _TSCHAR for the Mac.
  50. * 07-30-96 GJF Allow longer file names and changed the way we ensure
  51. * a file name is not too long. In particular, this
  52. * corrects the absurdly long loop (appeared infinite to
  53. * to users) which occurred when the user supplied prefix
  54. * was too long. Also, cleaned up the format a bit.
  55. * 03-04-98 GJF Exception-safe locking.
  56. * 01-04-99 GJF Changes for 64-bit size_t.
  57. * 05-17-99 PML Remove all Macintosh support.
  58. * 12-10-00 PML Fix double-free of qptr when _stripquote succeeds but
  59. * result isn't a valid directory (vs7#5416).
  60. * 02-20-01 PML vs7#172586 Avoid _RT_LOCK by preallocating all locks
  61. * that will be required, and returning failure back on
  62. * inability to allocate a lock.
  63. * 07-07-01 BWT Initialize 's' in tempnam - in case the done2 branch is taken,
  64. * 's' must be something reasonable.
  65. *
  66. *******************************************************************************/
  67. #ifndef _POSIX_
  68. #include <cruntime.h>
  69. #include <sys/types.h>
  70. #include <sys/stat.h>
  71. #include <io.h>
  72. #include <stdio.h>
  73. #include <stdlib.h>
  74. #include <errno.h>
  75. #include <malloc.h>
  76. #include <string.h>
  77. #include <internal.h>
  78. #include <mtdll.h>
  79. #include <tchar.h>
  80. #include <dbgint.h>
  81. #ifdef _MBCS
  82. #include <mbstring.h>
  83. #endif
  84. /* local tchar */
  85. #ifdef _UNICODE
  86. #define _tP_tmpdir _wP_tmpdir
  87. #else
  88. #define _tP_tmpdir _P_tmpdir
  89. #endif
  90. #ifdef _UNICODE
  91. static wchar_t * _wstripquote (wchar_t *);
  92. #else
  93. static char * _stripquote (char *);
  94. #endif
  95. /***
  96. *_TSCHAR *_tempnam(dir, prefix) - create unique file name
  97. *
  98. *Purpose:
  99. * Create a file name that is unique in the specified directory.
  100. * The semantics of directory specification is as follows:
  101. * Use the directory specified by the TMP environment variable
  102. * if that exists, else use the dir argument if non-NULL, else
  103. * use _P_tmpdir if that directory exists, else use the current
  104. * working directory), else return NULL.
  105. *
  106. *Entry:
  107. * _TSCHAR *dir - directory to be used for temp file if TMP env var
  108. * not set
  109. * _TSCHAR *prefix - user provided prefix for temp file name
  110. *
  111. *Exit:
  112. * returns ptr to constructed file name if successful
  113. * returns NULL if unsuccessful
  114. *
  115. *Exceptions:
  116. *
  117. *******************************************************************************/
  118. _TSCHAR * __cdecl _ttempnam (
  119. const _TSCHAR *dir,
  120. const _TSCHAR *pfx
  121. )
  122. {
  123. REG1 _TSCHAR *ptr;
  124. REG2 unsigned int pfxlength = 0;
  125. _TSCHAR *s = NULL;
  126. _TSCHAR *pfin;
  127. unsigned int first;
  128. unsigned int bufsz;
  129. _TSCHAR * qptr = NULL; /* ptr to TMP path with quotes stripped out */
  130. #ifdef _MT
  131. if ( !_mtinitlocknum( _TMPNAM_LOCK ))
  132. return NULL;
  133. #endif
  134. /* try TMP path */
  135. if ( ( ptr = _tgetenv( _T("TMP") ) ) && ( _taccess( ptr, 0 ) != -1 ) )
  136. dir = ptr;
  137. /* try stripping quotes out of TMP path */
  138. #ifdef _UNICODE
  139. else if ( (ptr != NULL) && (qptr = _wstripquote(ptr)) &&
  140. #else
  141. else if ( (ptr != NULL) && (qptr = _stripquote(ptr)) &&
  142. #endif
  143. (_taccess(qptr, 0) != -1 ) )
  144. dir = qptr;
  145. /* TMP path not available, use alternatives */
  146. else if (!( dir != NULL && ( _taccess( dir, 0 ) != -1 ) ) )
  147. /* do not "simplify" this depends on side effects!! */
  148. {
  149. if ( _taccess( _tP_tmpdir, 0 ) != -1 )
  150. dir = _tP_tmpdir;
  151. else
  152. dir = _T(".");
  153. }
  154. if (pfx)
  155. pfxlength = (unsigned)_tcslen(pfx);
  156. if ( ((bufsz = (unsigned)_tcslen(dir) + pfxlength + 12) > FILENAME_MAX) ||
  157. ((s = malloc(bufsz * sizeof(_TSCHAR))) == NULL) )
  158. /* the 12 above allows for a backslash, 10 char temp string and
  159. a null terminator */
  160. {
  161. goto done2;
  162. }
  163. *s = _T('\0');
  164. _tcscat( s, dir );
  165. pfin = (_TSCHAR *)&(dir[ _tcslen( dir ) - 1 ]);
  166. #ifdef _MBCS
  167. if (*pfin == '\\') {
  168. if (pfin != _mbsrchr(dir,'\\'))
  169. /* *pfin is second byte of a double-byte char */
  170. strcat( s, "\\" );
  171. }
  172. else if (*pfin != '/')
  173. strcat( s, "\\" );
  174. #else
  175. if ( ( *pfin != _T('\\') ) && ( *pfin != _T('/') ) )
  176. {
  177. _tcscat( s, _T("\\") );
  178. }
  179. #endif
  180. if ( pfx != NULL )
  181. {
  182. _tcscat( s, pfx );
  183. }
  184. ptr = &s[_tcslen( s )];
  185. /*
  186. Re-initialize _tempoff if necessary. If we don't re-init _tempoff, we
  187. can get into an infinate loop (e.g., (a) _tempoff is a big number on
  188. entry, (b) prefix is a long string (e.g., 8 chars) and all tempfiles
  189. with that prefix exist, (c) _tempoff will never equal first and we'll
  190. loop forever).
  191. [NOTE: To avoid a conflict that causes the same bug as that discussed
  192. above, _tempnam() uses _tempoff; tmpnam() uses _tmpoff]
  193. */
  194. #ifdef _MT
  195. _mlock(_TMPNAM_LOCK); /* Lock access to _old_pfxlen and _tempoff */
  196. __try {
  197. #endif
  198. if (_old_pfxlen < pfxlength)
  199. _tempoff = 1;
  200. _old_pfxlen = pfxlength;
  201. first = _tempoff;
  202. do {
  203. if ( (++_tempoff - first) > TMP_MAX ) {
  204. free(s);
  205. s = NULL;
  206. goto done1;
  207. }
  208. /* the maximum length string returned by _ultot is 10 chars
  209. (assuming 32-bit unsigned long) so there is enough room in
  210. the tail of s (pointed to by ptr) for it */
  211. _ultot( (unsigned long)_tempoff, ptr, 10 );
  212. }
  213. while ( (_taccess( s, 0 ) == 0 ) || (errno == EACCES) );
  214. /* Common return */
  215. done1:
  216. #ifdef _MT
  217. ; }
  218. __finally {
  219. _munlock(_TMPNAM_LOCK); /* release tempnam lock */
  220. }
  221. #endif
  222. done2:
  223. _free_crt(qptr); /* free temp ptr, if non-NULL */
  224. return(s);
  225. }
  226. /***
  227. *_stripquote() - Strip quotes out of a string
  228. *
  229. *Purpose:
  230. * This routine strips quotes out of a string. This is necessary
  231. * in the case where a file/path name has embedded quotes (i.e.,
  232. * new file system.)
  233. *
  234. * For example,
  235. * c:\tmp\"a b c"\d --> c:\tmp\a b d\d
  236. *
  237. * NOTE: This routine makes a copy of the string since it may be
  238. * passed a pointer to an environment variable that shouldn't be
  239. * changed. It is up to the caller to free up the memory (if the
  240. * return value is non-NULL).
  241. *
  242. *Entry:
  243. * _TSCHAR * ptr = pointer to string
  244. *
  245. *Exit:
  246. * _TSCHAR * ptr = pointer to copy of string with quotes gone.
  247. * NULL = no quotes in string.
  248. *
  249. *Exceptions:
  250. *
  251. *******************************************************************************/
  252. #ifdef _UNICODE
  253. static wchar_t * _wstripquote (
  254. #else
  255. static char * _stripquote (
  256. #endif
  257. _TSCHAR * src
  258. )
  259. {
  260. _TSCHAR * dst;
  261. _TSCHAR * ret;
  262. unsigned int q = 0;
  263. /* get a buffer for the new string */
  264. if ((dst = _malloc_crt((_tcslen(src)+1) * sizeof(_TSCHAR))) == NULL)
  265. return(NULL);
  266. /* copy the string stripping out the quotes */
  267. ret = dst; /* save base ptr */
  268. while (*src) {
  269. if (*src == _T('\"')) {
  270. src++; q++;
  271. }
  272. else
  273. *dst++ = *src++;
  274. }
  275. if (q) {
  276. *dst = _T('\0'); /* final nul */
  277. return(ret);
  278. }
  279. else {
  280. _free_crt(ret);
  281. return(NULL);
  282. }
  283. }
  284. #endif /* _POSIX_ */