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.

294 lines
9.3 KiB

  1. /***
  2. *dup2.c - Duplicate file handles
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * defines _dup2() - duplicate file handles
  8. *
  9. *Revision History:
  10. * 06-09-89 PHG Module created, based on asm version
  11. * 03-12-90 GJF Made calling type _CALLTYPE2 (for now), added #include
  12. * <cruntime.h> and fixed the copyright. Also, cleaned up
  13. * the formatting a bit.
  14. * 04-03-90 GJF Now _CALLTYPE1.
  15. * 07-24-90 SBM Removed '32' from API names
  16. * 08-14-90 SBM Compiles cleanly with -W3
  17. * 09-28-90 GJF New-style function declarator.
  18. * 12-04-90 GJF Appended Win32 version onto the source with #ifdef-s.
  19. * It is enough different that there is little point in
  20. * trying to more closely merge the two versions.
  21. * 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
  22. * 12-06-90 SRW Changed to use _osfile and _osfhnd instead of _osfinfo
  23. * 01-16-91 GJF ANSI naming.
  24. * 02-07-91 SRW Changed to call _get_osfhandle [_WIN32_]
  25. * 02-18-91 SRW Changed to call _free_osfhnd [_WIN32_]
  26. * 02-25-91 SRW Renamed _get_free_osfhnd to be _alloc_osfhnd [_WIN32_]
  27. * 02-13-92 GJF Replaced _nfile by _nhandle for Win32.
  28. * 09-04-92 GJF Check for unopened fh1 and gracefully handle fh1 ==
  29. * fh2.
  30. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  31. * 09-06-94 CFW Remove Cruiser support.
  32. * 09-06-94 CFW Replace MTHREAD with _MT.
  33. * 12-03-94 SKS Clean up OS/2 references
  34. * 01-04-95 GJF _WIN32_ -> _WIN32
  35. * 02-15-95 GJF Appended Mac version of source file (somewhat cleaned
  36. * up), with appropriate #ifdef-s.
  37. * 06-11-95 GJF Replaced _osfile[] with _osfile() (macro referencing
  38. * field in ioinfo struct).
  39. * 06-26-95 GJF Added support to grow the ioinfo arrays in order to
  40. * ensure an ioinfo struct exists for fh2.
  41. * 05-16-96 GJF Clear FNOINHERIT (new) bit on _osfile. Also, detab-ed.
  42. * 07-08-96 GJF Replaced defined(_WIN32) with !defined(_MAC), and
  43. * defined(_M_M68K) || defined(_M_MPPC) with
  44. * defined(_MAC). Removed DLL_FOR_WIN32S. Also, cleaned
  45. * up the format a bit.
  46. * 12-17-97 GJF Exception-safe locking.
  47. * 02-07-98 GJF Changes for Win64: use intptr_t for anything holding
  48. * a HANDLE value.
  49. * 05-17-99 PML Remove all Macintosh support.
  50. *
  51. *******************************************************************************/
  52. #include <cruntime.h>
  53. #include <io.h>
  54. #include <oscalls.h>
  55. #include <msdos.h>
  56. #include <mtdll.h>
  57. #include <errno.h>
  58. #include <stdlib.h>
  59. #include <internal.h>
  60. #include <malloc.h>
  61. #include <dbgint.h>
  62. static int __cdecl extend_ioinfo_arrays(int);
  63. #ifdef _MT
  64. static int __cdecl _dup2_lk(int, int);
  65. #endif
  66. /***
  67. *int _dup2(fh1, fh2) - force handle 2 to refer to handle 1
  68. *
  69. *Purpose:
  70. * Forces file handle 2 to refer to the same file as file
  71. * handle 1. If file handle 2 referred to an open file, that file
  72. * is closed.
  73. *
  74. * Multi-thread: We must hold 2 lowio locks at the same time
  75. * to ensure multi-thread integrity. In order to prevent deadlock,
  76. * we always get the lower file handle lock first. Order of unlocking
  77. * does not matter. If you modify this routine, make sure you don't
  78. * cause any deadlocks! Scary stuff, kids!!
  79. *
  80. *Entry:
  81. * int fh1 - file handle to duplicate
  82. * int fh2 - file handle to assign to file handle 1
  83. *
  84. *Exit:
  85. * returns 0 if successful, -1 (and sets errno) if fails.
  86. *
  87. *Exceptions:
  88. *
  89. *******************************************************************************/
  90. int __cdecl _dup2 (
  91. int fh1,
  92. int fh2
  93. )
  94. {
  95. #ifdef _MT
  96. int retcode;
  97. #else
  98. ULONG dosretval; /* o.s. return code */
  99. intptr_t new_osfhandle;
  100. #endif
  101. /* validate file handles */
  102. if ( ((unsigned)fh1 >= (unsigned)_nhandle) ||
  103. !(_osfile(fh1) & FOPEN) ||
  104. ((unsigned)fh2 >= _NHANDLE_) )
  105. {
  106. /* handle out of range */
  107. errno = EBADF;
  108. _doserrno = 0; /* not an OS error */
  109. return -1;
  110. }
  111. /*
  112. * Make sure there is an ioinfo struct corresponding to fh2.
  113. */
  114. if ( (fh2 >= _nhandle) && (extend_ioinfo_arrays(fh2) != 0) ) {
  115. errno = ENOMEM;
  116. return -1;
  117. }
  118. #ifdef _MT
  119. /* get the two file handle locks; in order to prevent deadlock,
  120. get the lowest handle lock first. */
  121. if ( fh1 < fh2 ) {
  122. _lock_fh(fh1);
  123. _lock_fh(fh2);
  124. }
  125. else if ( fh1 > fh2 ) {
  126. _lock_fh(fh2);
  127. _lock_fh(fh1);
  128. }
  129. __try {
  130. retcode = _dup2_lk(fh1, fh2);
  131. }
  132. __finally {
  133. _unlock_fh(fh1);
  134. _unlock_fh(fh2);
  135. }
  136. return retcode;
  137. }
  138. static int __cdecl _dup2_lk (
  139. int fh1,
  140. int fh2
  141. )
  142. {
  143. ULONG dosretval; /* o.s. return code */
  144. intptr_t new_osfhandle;
  145. /*
  146. * Re-test and take care of case of unopened source handle. This is
  147. * necessary only in the multi-thread case where the file have been
  148. * closed by another thread before the lock was asserted, but after
  149. * the initial test above.
  150. */
  151. if ( !(_osfile(fh1) & FOPEN) ) {
  152. /*
  153. * Source handle isn't open, bail out with an error.
  154. * Note that the DuplicateHandle API will not detect this
  155. * error since it implies that _osfhnd(fh1) ==
  156. * INVALID_HANDLE_VALUE, and this is a legal HANDLE value
  157. * (it's the HANDLE for the current process).
  158. */
  159. errno = EBADF;
  160. _doserrno = 0; /* not an OS error */
  161. return -1;
  162. }
  163. #endif /* _MT */
  164. /*
  165. * Take of the case of equal handles.
  166. */
  167. if ( fh1 == fh2 )
  168. /*
  169. * Since fh1 is known to be open, return 0 indicating success.
  170. * This is in conformance with the POSIX specification for
  171. * dup2.
  172. */
  173. return 0;
  174. /*
  175. * if fh2 is open, close it.
  176. */
  177. if ( _osfile(fh2) & FOPEN )
  178. /*
  179. * close the handle. ignore the possibility of an error - an
  180. * error simply means that an OS handle value may remain bound
  181. * for the duration of the process. Use _close_lk as we
  182. * already own lock
  183. */
  184. (void) _close_lk(fh2);
  185. /* Duplicate source file onto target file */
  186. if ( !(DuplicateHandle(GetCurrentProcess(),
  187. (HANDLE)_get_osfhandle(fh1),
  188. GetCurrentProcess(),
  189. (PHANDLE)&new_osfhandle,
  190. 0L,
  191. TRUE,
  192. DUPLICATE_SAME_ACCESS)) )
  193. {
  194. dosretval = GetLastError();
  195. }
  196. else {
  197. _set_osfhnd(fh2, new_osfhandle);
  198. dosretval = 0;
  199. }
  200. if (dosretval) {
  201. _dosmaperr(dosretval);
  202. return -1;
  203. }
  204. /* copy the _osfile information, with the FNOINHERIT bit cleared */
  205. _osfile(fh2) = _osfile(fh1) & ~FNOINHERIT;
  206. return 0;
  207. }
  208. /***
  209. *static int extend_ioinfo_arrays( int fh ) - extend ioinfo arrays to fh
  210. *
  211. *Purpose:
  212. * Allocate and initialize arrays of ioinfo structs,filling in
  213. * __pioinfo[],until there is an ioinfo struct corresponding to fh.
  214. *
  215. * Note: It is assumed the fh < _NHANDLE_!
  216. *
  217. *Entry:
  218. * int fh - C file handle corresponding to ioinfo
  219. *
  220. *Exit:
  221. * returns 0 if successful, -1
  222. *
  223. *Exceptions:
  224. *
  225. *******************************************************************************/
  226. static int __cdecl extend_ioinfo_arrays(
  227. int fh
  228. )
  229. {
  230. ioinfo *pio;
  231. int i;
  232. /*
  233. * Walk __pioinfo[], allocating an array of ioinfo structs for each
  234. * empty entry, until there is an ioinfo struct corresponding to fh.
  235. */
  236. for ( i = 0 ; fh >= _nhandle ; i++ ) {
  237. if ( __pioinfo[i] == NULL ) {
  238. if ( (pio = _malloc_crt( IOINFO_ARRAY_ELTS * sizeof(ioinfo) ))
  239. != NULL )
  240. {
  241. __pioinfo[i] = pio;
  242. _nhandle += IOINFO_ARRAY_ELTS;
  243. for ( ; pio < __pioinfo[i] + IOINFO_ARRAY_ELTS ; pio++ ) {
  244. pio->osfile = 0;
  245. pio->osfhnd = (intptr_t)INVALID_HANDLE_VALUE;
  246. pio->pipech = 10;
  247. #ifdef _MT
  248. pio->lockinitflag = 0;
  249. #endif
  250. }
  251. }
  252. else {
  253. /*
  254. * Couldn't allocate another array, return failure.
  255. */
  256. return -1;
  257. }
  258. }
  259. }
  260. return 0;
  261. }