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
16 KiB

  1. /***
  2. *osfinfo.c - Win32 _osfhnd[] support routines
  3. *
  4. * Copyright (c) 1990-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Defines the internally used routine _alloc_osfhnd()
  8. * and the user visible routine _get_osfhandle().
  9. *
  10. *Revision History:
  11. * 11-16-90 GJF What can I say? The custom heap business was getting
  12. * a little slow...
  13. * 12-03-90 GJF Fixed my syntax errors.
  14. * 12-06-90 SRW Changed to use _osfile and _osfhnd instead of _osfinfo
  15. * 12-28-90 SRW Added cast of void * to char * for Mips C Compiler
  16. * 02-18-91 SRW Fixed bug in _alloc_osfhnd with setting FOPEN bit
  17. * (only caller should do that) [_WIN32_]
  18. * 02-18-91 SRW Fixed bug in _alloc_osfhnd with checking against
  19. * _NFILE_ instead of _nfile [_WIN32_]
  20. * 02-18-91 SRW Added debug output to _alloc_osfhnd if out of
  21. * file handles. [_WIN32_]
  22. * 02-25-91 SRW Renamed _get_free_osfhnd to be _alloc_osfhnd [_WIN32_]
  23. * 02-25-91 SRW Exposed _get_osfhandle and _open_osfhandle [_WIN32_]
  24. * 08-08-91 GJF Use ANSI-fied form of constant names.
  25. * 11-25-91 GJF Lock fh before checking whether it's free.
  26. * 12-31-91 GJF Improved multi-thread lock usage [_WIN32_].
  27. * 02-13-92 GJF Replaced _nfile with _nhandle
  28. * 07-15-92 GJF Fixed setting of flags in _open_osfhnd.
  29. * 02-19-93 GJF If GetFileType fails in _open_osfhandle, don't unlock
  30. * fh (it wasn't locked)!
  31. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  32. * 09-06-94 CFW Replace MTHREAD with _MT.
  33. * 01-04-95 GJF _WIN32_ -> _WIN32
  34. * 02-15-95 GJF Appended Mac version of source file (somewhat cleaned
  35. * up), with appropriate #ifdef-s.
  36. * 06-02-95 GJF Only call SetStdHandle for console apps.
  37. * 06-12-95 GJF Revised to use __pioinfo[].
  38. * 06-29-95 GJF Have _lock_fhandle ensure the lock is initialized.
  39. * 02-17-96 SKS Fix error in file handle locking code
  40. * 07-09-96 GJF Replaced defined(_WIN32) with !defined(_MAC) and
  41. * defined(_M_M68K) || defined(_M_MPPC) with
  42. * defined(_MAC). Removed DLL_FOR_WIN32S
  43. * 08-29-97 GJF Check for and propagate _O_NOINHERIT in
  44. * _open_osfhandle.
  45. * 02-10-98 GJF Changes for Win64: changed everything that holds HANDLE
  46. * values to intptr_t.
  47. * 05-17-99 PML Remove all Macintosh support.
  48. * 10-14-99 PML Replace InitializeCriticalSection with wrapper function
  49. * __crtInitCritSecAndSpinCount
  50. * 02-20-01 PML vs7#172586 Avoid _RT_LOCK by preallocating all locks
  51. * that will be required, and returning failure back on
  52. * inability to allocate a lock.
  53. *
  54. *******************************************************************************/
  55. #include <cruntime.h>
  56. #include <oscalls.h>
  57. #include <errno.h>
  58. #include <internal.h>
  59. #include <fcntl.h>
  60. #include <malloc.h>
  61. #include <msdos.h>
  62. #include <mtdll.h>
  63. #include <stdlib.h>
  64. #include <dbgint.h>
  65. /***
  66. *int _alloc_osfhnd() - get free _ioinfo struct
  67. *
  68. *Purpose:
  69. * Finds the first free entry in the arrays of ioinfo structs and
  70. * returns the index of that entry (which is the CRT file handle to the
  71. * caller) to the caller.
  72. *
  73. *Entry:
  74. * none
  75. *
  76. *Exit:
  77. * returns index of the entry, if successful
  78. * return -1, if no free entry is available or out of memory
  79. *
  80. * MULTITHREAD NOTE: IF SUCCESSFUL, THE HANDLE IS LOCKED WHEN IT IS
  81. * RETURNED TO THE CALLER!
  82. *
  83. *Exceptions:
  84. *
  85. *******************************************************************************/
  86. int __cdecl _alloc_osfhnd(
  87. void
  88. )
  89. {
  90. int fh = -1; /* file handle */
  91. int i;
  92. ioinfo *pio;
  93. #ifdef _MT
  94. if (!_mtinitlocknum(_OSFHND_LOCK))
  95. return -1;
  96. #endif
  97. _mlock(_OSFHND_LOCK); /* lock the __pioinfo[] array */
  98. /*
  99. * Search the arrays of ioinfo structs, in order, looking for the
  100. * first free entry. The compound index of this free entry is the
  101. * return value. Here, the compound index of the ioinfo struct
  102. * *(__pioinfo[i] + j) is k = i * IOINFO_ARRAY_ELTS + j, and k = 0,
  103. * 1, 2,... is the order of the search.
  104. */
  105. for ( i = 0 ; i < IOINFO_ARRAYS ; i++ ) {
  106. /*
  107. * If __pioinfo[i] is non-empty array, search it looking for
  108. * the first free entry. Otherwise, allocate a new array and use
  109. * its first entry.
  110. */
  111. if ( __pioinfo[i] != NULL ) {
  112. /*
  113. * Search for an available entry.
  114. */
  115. for ( pio = __pioinfo[i] ;
  116. pio < __pioinfo[i] + IOINFO_ARRAY_ELTS ;
  117. pio++ )
  118. {
  119. if ( (pio->osfile & FOPEN) == 0 ) {
  120. #ifdef _MT
  121. /*
  122. * Make sure the lock is initialized.
  123. */
  124. if ( pio->lockinitflag == 0 ) {
  125. _mlock( _LOCKTAB_LOCK );
  126. if ( pio->lockinitflag == 0 ) {
  127. if ( !__crtInitCritSecAndSpinCount( &(pio->lock), _CRT_SPINCOUNT )) {
  128. /*
  129. * Lock initialization failed. Release
  130. * held locks and return failure.
  131. */
  132. _munlock( _LOCKTAB_LOCK );
  133. _munlock( _OSFHND_LOCK );
  134. return -1;
  135. }
  136. pio->lockinitflag++;
  137. }
  138. _munlock( _LOCKTAB_LOCK );
  139. }
  140. EnterCriticalSection( &(pio->lock) );
  141. /*
  142. * Check for the case where another thread has
  143. * managed to grab the handle out from under us.
  144. */
  145. if ( (pio->osfile & FOPEN) != 0 ) {
  146. LeaveCriticalSection( &(pio->lock) );
  147. continue;
  148. }
  149. #endif
  150. pio->osfhnd = (intptr_t)INVALID_HANDLE_VALUE;
  151. fh = i * IOINFO_ARRAY_ELTS + (int)(pio - __pioinfo[i]);
  152. break;
  153. }
  154. }
  155. /*
  156. * Check if a free entry has been found.
  157. */
  158. if ( fh != -1 )
  159. break;
  160. }
  161. else {
  162. /*
  163. * Allocate and initialize another array of ioinfo structs.
  164. */
  165. if ( (pio = _malloc_crt( IOINFO_ARRAY_ELTS * sizeof(ioinfo) ))
  166. != NULL )
  167. {
  168. /*
  169. * Update __pioinfo[] and _nhandle
  170. */
  171. __pioinfo[i] = pio;
  172. _nhandle += IOINFO_ARRAY_ELTS;
  173. for ( ; pio < __pioinfo[i] + IOINFO_ARRAY_ELTS ; pio++ ) {
  174. pio->osfile = 0;
  175. pio->osfhnd = (intptr_t)INVALID_HANDLE_VALUE;
  176. pio->pipech = 10;
  177. #ifdef _MT
  178. pio->lockinitflag = 0;
  179. #endif
  180. }
  181. /*
  182. * The first element of the newly allocated array of ioinfo
  183. * structs, *(__pioinfo[i]), is our first free entry.
  184. */
  185. fh = i * IOINFO_ARRAY_ELTS;
  186. #ifdef _MT
  187. if ( !_lock_fhandle( fh ) ) {
  188. /*
  189. * The lock initialization failed, return the failure
  190. */
  191. fh = -1;
  192. }
  193. #endif
  194. }
  195. break;
  196. }
  197. }
  198. _munlock(_OSFHND_LOCK); /* unlock the __pioinfo[] table */
  199. #ifdef DEBUG
  200. if ( fh == -1 ) {
  201. DbgPrint( "WINCRT: only %d open files allowed\n", _nhandle );
  202. }
  203. #endif
  204. /*
  205. * return the index of the previously free table entry, if one was
  206. * found. return -1 otherwise.
  207. */
  208. return( fh );
  209. }
  210. /***
  211. *int _set_osfhnd(int fh, long value) - set Win32 HANDLE value
  212. *
  213. *Purpose:
  214. * If fh is in range and if _osfhnd(fh) is marked with
  215. * INVALID_HANDLE_VALUE then set _osfhnd(fh) to the passed value.
  216. *
  217. *Entry:
  218. * int fh - CRT file handle
  219. * long value - new Win32 HANDLE value for this handle
  220. *
  221. *Exit:
  222. * Returns zero if successful.
  223. * Returns -1 and sets errno to EBADF otherwise.
  224. *
  225. *Exceptions:
  226. *
  227. *******************************************************************************/
  228. int __cdecl _set_osfhnd (
  229. int fh,
  230. intptr_t value
  231. )
  232. {
  233. if ( ((unsigned)fh < (unsigned)_nhandle) &&
  234. (_osfhnd(fh) == (intptr_t)INVALID_HANDLE_VALUE)
  235. ) {
  236. if ( __app_type == _CONSOLE_APP ) {
  237. switch (fh) {
  238. case 0:
  239. SetStdHandle( STD_INPUT_HANDLE, (HANDLE)value );
  240. break;
  241. case 1:
  242. SetStdHandle( STD_OUTPUT_HANDLE, (HANDLE)value );
  243. break;
  244. case 2:
  245. SetStdHandle( STD_ERROR_HANDLE, (HANDLE)value );
  246. break;
  247. }
  248. }
  249. _osfhnd(fh) = value;
  250. return(0);
  251. } else {
  252. errno = EBADF; /* bad handle */
  253. _doserrno = 0L; /* not an OS error */
  254. return -1;
  255. }
  256. }
  257. /***
  258. *int _free_osfhnd(int fh) - mark osfhnd field of ioinfo struct as free
  259. *
  260. *Purpose:
  261. * If fh is in range, the corrsponding ioinfo struct is marked as
  262. * being open, and the osfhnd field is NOT set to INVALID_HANDLE_VALUE,
  263. * then mark it with INVALID_HANDLE_VALUE.
  264. *
  265. *Entry:
  266. * int fh - CRT file handle
  267. *
  268. *Exit:
  269. * Returns zero if successful.
  270. * Returns -1 and sets errno to EBADF otherwise.
  271. *
  272. *Exceptions:
  273. *
  274. *******************************************************************************/
  275. int __cdecl _free_osfhnd (
  276. int fh /* user's file handle */
  277. )
  278. {
  279. if ( ((unsigned)fh < (unsigned)_nhandle) &&
  280. (_osfile(fh) & FOPEN) &&
  281. (_osfhnd(fh) != (intptr_t)INVALID_HANDLE_VALUE) )
  282. {
  283. if ( __app_type == _CONSOLE_APP ) {
  284. switch (fh) {
  285. case 0:
  286. SetStdHandle( STD_INPUT_HANDLE, NULL );
  287. break;
  288. case 1:
  289. SetStdHandle( STD_OUTPUT_HANDLE, NULL );
  290. break;
  291. case 2:
  292. SetStdHandle( STD_ERROR_HANDLE, NULL );
  293. break;
  294. }
  295. }
  296. _osfhnd(fh) = (intptr_t)INVALID_HANDLE_VALUE;
  297. return(0);
  298. } else {
  299. errno = EBADF; /* bad handle */
  300. _doserrno = 0L; /* not an OS error */
  301. return -1;
  302. }
  303. }
  304. /***
  305. *long _get_osfhandle(int fh) - get Win32 HANDLE value
  306. *
  307. *Purpose:
  308. * If fh is in range and marked open, return _osfhnd(fh).
  309. *
  310. *Entry:
  311. * int fh - CRT file handle
  312. *
  313. *Exit:
  314. * Returns the Win32 HANDLE successful.
  315. * Returns -1 and sets errno to EBADF otherwise.
  316. *
  317. *Exceptions:
  318. *
  319. *******************************************************************************/
  320. intptr_t __cdecl _get_osfhandle (
  321. int fh /* user's file handle */
  322. )
  323. {
  324. if ( ((unsigned)fh < (unsigned)_nhandle) && (_osfile(fh) & FOPEN) )
  325. return( _osfhnd(fh) );
  326. else {
  327. errno = EBADF; /* bad handle */
  328. _doserrno = 0L; /* not an OS error */
  329. return -1;
  330. }
  331. }
  332. /***
  333. *int _open_osfhandle(long osfhandle, int flags) - open C Runtime file handle
  334. *
  335. *Purpose:
  336. * This function allocates a free C Runtime file handle and associates
  337. * it with the Win32 HANDLE specified by the first parameter.
  338. *
  339. *Entry:
  340. * long osfhandle - Win32 HANDLE to associate with C Runtime file handle.
  341. * int flags - flags to associate with C Runtime file handle.
  342. *
  343. *Exit:
  344. * returns index of entry in fh, if successful
  345. * return -1, if no free entry is found
  346. *
  347. *Exceptions:
  348. *
  349. *******************************************************************************/
  350. int __cdecl _open_osfhandle(
  351. intptr_t osfhandle,
  352. int flags
  353. )
  354. {
  355. int fh;
  356. char fileflags; /* _osfile flags */
  357. DWORD isdev; /* device indicator in low byte */
  358. /* copy relevant flags from second parameter */
  359. fileflags = 0;
  360. if ( flags & _O_APPEND )
  361. fileflags |= FAPPEND;
  362. if ( flags & _O_TEXT )
  363. fileflags |= FTEXT;
  364. if ( flags & _O_NOINHERIT )
  365. fileflags |= FNOINHERIT;
  366. /* find out what type of file (file/device/pipe) */
  367. isdev = GetFileType((HANDLE)osfhandle);
  368. if (isdev == FILE_TYPE_UNKNOWN) {
  369. /* OS error */
  370. _dosmaperr( GetLastError() ); /* map error */
  371. return -1;
  372. }
  373. /* is isdev value to set flags */
  374. if (isdev == FILE_TYPE_CHAR)
  375. fileflags |= FDEV;
  376. else if (isdev == FILE_TYPE_PIPE)
  377. fileflags |= FPIPE;
  378. /* attempt to allocate a C Runtime file handle */
  379. if ( (fh = _alloc_osfhnd()) == -1 ) {
  380. errno = EMFILE; /* too many open files */
  381. _doserrno = 0L; /* not an OS error */
  382. return -1; /* return error to caller */
  383. }
  384. /*
  385. * the file is open. now, set the info in _osfhnd array
  386. */
  387. _set_osfhnd(fh, osfhandle);
  388. fileflags |= FOPEN; /* mark as open */
  389. _osfile(fh) = fileflags; /* set osfile entry */
  390. _unlock_fh(fh); /* unlock handle */
  391. return fh; /* return handle */
  392. }
  393. #ifdef _MT
  394. /***
  395. *void _lock_fhandle(int fh) - lock file handle
  396. *
  397. *Purpose:
  398. * Assert the lock associated with the passed file handle.
  399. *
  400. *Entry:
  401. * int fh - CRT file handle
  402. *
  403. *Exit:
  404. * Returns FALSE if the attempt to initialize the lock fails. This can
  405. * only happen the first time the lock is taken, so the return status only
  406. * needs to be checked on the first such attempt, which is always in
  407. * _alloc_osfhnd (except for inherited or standard handles, and the lock
  408. * is allocated manually in _ioinit for those).
  409. *
  410. *Exceptions:
  411. *
  412. *******************************************************************************/
  413. int __cdecl _lock_fhandle (
  414. int fh
  415. )
  416. {
  417. ioinfo *pio = _pioinfo(fh);
  418. /*
  419. * Make sure the lock has been initialized.
  420. */
  421. if ( pio->lockinitflag == 0 ) {
  422. _mlock( _LOCKTAB_LOCK );
  423. if ( pio->lockinitflag == 0 ) {
  424. if ( !__crtInitCritSecAndSpinCount( &(pio->lock), _CRT_SPINCOUNT )) {
  425. /*
  426. * Failed to initialize the lock, so return failure code.
  427. */
  428. _munlock( _LOCKTAB_LOCK );
  429. return FALSE;
  430. }
  431. pio->lockinitflag++;
  432. }
  433. _munlock( _LOCKTAB_LOCK);
  434. }
  435. EnterCriticalSection( &(_pioinfo(fh)->lock) );
  436. return TRUE;
  437. }
  438. /***
  439. *void _unlock_fhandle(int fh) - unlock file handle
  440. *
  441. *Purpose:
  442. * Release the lock associated with passed file handle.
  443. *
  444. *Entry:
  445. * int fh - CRT file handle
  446. *
  447. *Exit:
  448. *
  449. *Exceptions:
  450. *
  451. *******************************************************************************/
  452. void __cdecl _unlock_fhandle (
  453. int fh
  454. )
  455. {
  456. LeaveCriticalSection( &(_pioinfo(fh)->lock) );
  457. }
  458. #endif /* _MT */