home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / dup2.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  8KB  |  299 lines

  1. /***
  2. *dup2.c - Duplicate file handles
  3. *
  4. *       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       defines _dup2() - duplicate file handles
  8. *
  9. *******************************************************************************/
  10.  
  11. #ifndef _MAC
  12.  
  13.  
  14. #include <cruntime.h>
  15. #include <io.h>
  16. #include <oscalls.h>
  17. #include <msdos.h>
  18. #include <mtdll.h>
  19. #include <errno.h>
  20. #include <stdlib.h>
  21. #include <internal.h>
  22. #include <malloc.h>
  23. #include <dbgint.h>
  24.  
  25. static int __cdecl extend_ioinfo_arrays(int);
  26.  
  27. /***
  28. *int _dup2(fh1, fh2) - force handle 2 to refer to handle 1
  29. *
  30. *Purpose:
  31. *       Forces file handle 2 to refer to the same file as file
  32. *       handle 1.  If file handle 2 referred to an open file, that file
  33. *       is closed.
  34. *
  35. *       Multi-thread: We must hold 2 lowio locks at the same time
  36. *       to ensure multi-thread integrity.  In order to prevent deadlock,
  37. *       we always get the lower file handle lock first.  Order of unlocking
  38. *       does not matter.  If you modify this routine, make sure you don't
  39. *       cause any deadlocks! Scary stuff, kids!!
  40. *
  41. *Entry:
  42. *       int fh1 - file handle to duplicate
  43. *       int fh2 - file handle to assign to file handle 1
  44. *
  45. *Exit:
  46. *       returns 0 if successful, -1 (and sets errno) if fails.
  47. *
  48. *Exceptions:
  49. *
  50. *******************************************************************************/
  51.  
  52. int __cdecl _dup2 (
  53.         int fh1,
  54.         int fh2
  55.         )
  56. {
  57.         ULONG dosretval;                /* o.s. return code */
  58.         long new_osfhandle;
  59.  
  60.         /* validate file handles */
  61.         if ( ((unsigned)fh1 >= (unsigned)_nhandle) ||
  62.              !(_osfile(fh1) & FOPEN) ||
  63.              ((unsigned)fh2 >= _NHANDLE_) )
  64.         {
  65.                 /* handle out of range */
  66.                 errno = EBADF;
  67.                 _doserrno = 0;  /* not an OS error */
  68.                 return -1;
  69.         }
  70.  
  71.         /*
  72.          * Make sure there is an ioinfo struct corresponding to fh2.
  73.          */
  74.         if ( (fh2 >= _nhandle) && (extend_ioinfo_arrays(fh2) != 0) ) {
  75.                 errno = ENOMEM;
  76.                 return -1;
  77.         }
  78.  
  79.  
  80. #ifdef _MT
  81.         /* get the two file handle locks; in order to prevent deadlock,
  82.            get the lowest handle lock first. */
  83.         if ( fh1 < fh2 ) {
  84.                 _lock_fh(fh1);
  85.                 _lock_fh(fh2);
  86.         }
  87.         else if ( fh1 > fh2 ) {
  88.                 _lock_fh(fh2);
  89.                 _lock_fh(fh1);
  90.         }
  91.  
  92.         /*
  93.          * Re-test and take care of case of unopened source handle. This is
  94.          * necessary only in the multi-thread case where the file have been
  95.          * closed by another thread before the lock was asserted, but after
  96.          * the initial test above.
  97.          */
  98.         if ( !(_osfile(fh1) & FOPEN) ) {
  99.                 /*
  100.                  * Source handle isn't open, release locks and bail out with
  101.                  * an error. Note that the DuplicateHandle API will not
  102.                  * detect this error since it implies that _osfhnd(fh1) ==
  103.                  * INVALID_HANDLE_VALUE, and this is a legal HANDLE value
  104.                  * (it's the HANDLE for the current process).
  105.                  */
  106.                 _unlock_fh(fh1);
  107.                 _unlock_fh(fh2);
  108.                 errno = EBADF;
  109.                 _doserrno = 0;  /* not an OS error */
  110.                 return -1;
  111.         }
  112. #endif  /* _MT */
  113.  
  114.         /*
  115.          * Take of the case of equal handles.
  116.          */
  117.         if ( fh1 == fh2 ) {
  118.                 /*
  119.                  * Since fh1 is known to be open, return 0 indicating success.
  120.                  * This is in conformance with the POSIX specification for
  121.                  * dup2.
  122.                  */
  123.                 _unlock_fh(fh1);
  124.                 _unlock_fh(fh2);
  125.                 return 0;
  126.         }
  127.  
  128.         /*
  129.          * if fh2 is open, close it.
  130.          */
  131.         if ( _osfile(fh2) & FOPEN )
  132.                 /*
  133.                  * close the handle. ignore the possibility of an error - an
  134.                  * error simply means that an OS handle value may remain bound
  135.                  * for the duration of the process.  Use _close_lk as we
  136.                  * already own lock
  137.                  */
  138.                 (void) _close_lk(fh2);
  139.  
  140.  
  141.         /* Duplicate source file onto target file */
  142.  
  143.         if ( !(DuplicateHandle(GetCurrentProcess(),
  144.                                (HANDLE)_get_osfhandle(fh1),
  145.                                GetCurrentProcess(),
  146.                                (PHANDLE)&new_osfhandle,
  147.                                0L,
  148.                                TRUE,
  149.                                DUPLICATE_SAME_ACCESS)) )
  150.         {
  151.  
  152.                 dosretval = GetLastError();
  153.         }
  154.         else {
  155.                 _set_osfhnd(fh2, new_osfhandle);
  156.                 dosretval = 0;
  157.         }
  158.  
  159.         if (dosretval) {
  160.                 _dosmaperr(dosretval);
  161.                 _unlock_fh(fh1);
  162.                 _unlock_fh(fh2);
  163.                 return -1;
  164.         }
  165.  
  166.         /* copy the _osfile information, with the FNOINHERIT bit cleared */
  167.         _osfile(fh2) = _osfile(fh1) & ~FNOINHERIT;
  168.  
  169.         /* unlock file handles */
  170.         _unlock_fh(fh1);
  171.         _unlock_fh(fh2);
  172.  
  173.         return 0;
  174. }
  175.  
  176.  
  177. /***
  178. *static int extend_ioinfo_arrays( int fh ) - extend ioinfo arrays to fh
  179. *
  180. *Purpose:
  181. *       Allocate and initialize arrays of ioinfo structs,filling in
  182. *       __pioinfo[],until there is an ioinfo struct corresponding to fh.
  183. *
  184. *       Note: It is assumed the fh < _NHANDLE_!
  185. *
  186. *Entry:
  187. *       int fh  - C file handle corresponding to ioinfo
  188. *
  189. *Exit:
  190. *       returns 0 if successful, -1
  191. *
  192. *Exceptions:
  193. *
  194. *******************************************************************************/
  195.  
  196. static int __cdecl extend_ioinfo_arrays(
  197.         int fh
  198.         )
  199. {
  200.         ioinfo *pio;
  201.         int i;
  202.  
  203.         /*
  204.          * Walk __pioinfo[], allocating an array of ioinfo structs for each
  205.          * empty entry, until there is an ioinfo struct corresponding to fh.
  206.          */
  207.         for ( i = 0 ; fh >= _nhandle ; i++ ) {
  208.  
  209.             if ( __pioinfo[i] == NULL ) {
  210.  
  211.                 if ( (pio = _malloc_crt( IOINFO_ARRAY_ELTS * sizeof(ioinfo) ))
  212.                      != NULL )
  213.                 {
  214.                     __pioinfo[i] = pio;
  215.                     _nhandle += IOINFO_ARRAY_ELTS;
  216.  
  217.                     for ( ; pio < __pioinfo[i] + IOINFO_ARRAY_ELTS ; pio++ ) {
  218.                         pio->osfile = 0;
  219.                         pio->osfhnd = (long)INVALID_HANDLE_VALUE;
  220.                         pio->pipech = 10;
  221. #ifdef _MT
  222.                         pio->lockinitflag = 0;
  223. #endif  /* _MT */
  224.                     }
  225.                 }
  226.                 else {
  227.                     /*
  228.                      * Couldn't allocate another array, return failure.
  229.                      */
  230.                     return -1;
  231.                 }
  232.             }
  233.         }
  234.  
  235.         return 0;
  236. }
  237.  
  238.  
  239. #else  /* _MAC */
  240.  
  241.  
  242. #include <cruntime.h>
  243. #include <errno.h>
  244. #include <io.h>
  245. #include <internal.h>
  246. #include <stdlib.h>
  247. #include <msdos.h>
  248.  
  249. /***
  250. *int _dup2(fh1, fh2) - force handle 2 to refer to handle 1
  251. *
  252. *Purpose:
  253. *       Forces file handle 2 to refer to the same file as file
  254. *       handle 1.  If file handle 2 referred to an open file, that file
  255. *       is closed.
  256. *
  257. *
  258. *Entry:
  259. *       int fh1 - file handle to duplicate
  260. *       int fh2 - file handle to assign to file handle 1
  261. *
  262. *Exit:
  263. *       returns 0 if successful, -1 (and sets errno) if fails.
  264. *
  265. *Exceptions:
  266. *
  267. *******************************************************************************/
  268.  
  269. int __cdecl _dup2 (
  270.         int fh1,
  271.         int fh2
  272.         )
  273. {
  274.  
  275.         if ((unsigned int)fh2 > (unsigned int)_nfile)
  276.         {
  277.                 errno = EBADF;
  278.                 _macerrno = 0;
  279.                 return -1;
  280.         }
  281.  
  282.         if (_osfile[fh2] & FOPEN)
  283.         {
  284.                 _close(fh2);
  285.         }
  286.  
  287.         if (__dupx(fh1, fh2) == fh2)
  288.         {
  289.                 return 0;
  290.         }
  291.         else
  292.         {
  293.                 return -1;
  294.         }
  295. }
  296.  
  297.  
  298. #endif  /* _MAC */
  299.