1 //////////////////////////////////////////////////////////////////////////////////////////
2 //   w32util.c        Windows porting functions
3 //////////////////////////////////////////////////////////////////////////////////////////
4 // (c) Copyright "Fish" (David B. Trout), 2005-2009. Released under the Q Public License
5 // (http://www.hercules-390.org/herclic.html) as modifications to Hercules.
6 //////////////////////////////////////////////////////////////////////////////////////////
7 //
8 //                       IMPORTANT PROGRAMMING NOTE!
9 //
10 //   Please see the "VERY IMPORTANT SPECIAL NOTE" comments accompanying the
11 //   select, fdopen, etc, #undef's in the Windows Socket Handling section!!
12 //
13 //////////////////////////////////////////////////////////////////////////////////////////
14 
15 
16 #include "hstdinc.h"
17 
18 #define _W32UTIL_C_
19 #define _HUTIL_DLL_
20 
21 #include "hercules.h"
22 
23 #if defined( _MSVC_ )
24 
25 ///////////////////////////////////////////////////////////////////////////////
26 // Support for disabling of CRT Invalid Parameter Handler...
27 
28 #if defined( _MSVC_ ) && defined( _MSC_VER ) && ( _MSC_VER >= 1400 )
29 
DummyCRTInvalidParameterHandler(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t pReserved)30 static void DummyCRTInvalidParameterHandler
31 (
32     const wchar_t*  expression,
33     const wchar_t*  function,
34     const wchar_t*  file,
35     unsigned int    line,
36     uintptr_t       pReserved
37 )
38 {
39     // Do nothing to cause CRT to simply ignore the invalid parameter
40     // and to instead just pass back the return code to the caller.
41 }
42 
43 static _invalid_parameter_handler  old_iph  = NULL;
44 static int                         prev_rm  = 0;
45 
46 // This function's sole purpose is to bypass Microsoft's default handling of
47 // invalid parameters being passed to CRT functions, which ends up causing
48 // two completely different assertion dialogs to appear for each problem
49 
DisableInvalidParameterHandling()50 DLL_EXPORT void DisableInvalidParameterHandling()
51 {
52     if ( old_iph ) return;
53     old_iph = _set_invalid_parameter_handler( DummyCRTInvalidParameterHandler );
54 #if defined(DEBUG) || defined(_DEBUG)
55     prev_rm = _CrtSetReportMode( _CRT_ASSERT, 0 );
56 #endif
57 }
58 
EnableInvalidParameterHandling()59 DLL_EXPORT void EnableInvalidParameterHandling()
60 {
61     if ( !old_iph ) return;
62     _set_invalid_parameter_handler( old_iph ); old_iph = NULL;
63 #if defined(DEBUG) || defined(_DEBUG)
64     _CrtSetReportMode( _CRT_ASSERT, prev_rm );
65 #endif
66 }
67 
68 #endif // defined( _MSVC_ ) && defined( _MSC_VER ) && ( _MSC_VER >= 1400 )
69 
70 //////////////////////////////////////////////////////////////////////////////////////////
71 
72 struct ERRNOTAB
73 {
74     DWORD  dwLastError;     // Win32 error from GetLastError()
75     int    nErrNo;          // corresponding 'errno' value
76 };
77 
78 typedef struct ERRNOTAB  ERRNOTAB;
79 
80 // PROGRAMMING NOTE: we only need to translate values which
81 // are in the same range as existing defined errno values. If
82 // the Win32 GetLastError() value is outside the defined errno
83 // value range, then we just use the raw GetLastError() value.
84 
85 // The current 'errno' value range is 0 - 43, so only those
86 // GetLastError() values (defined in winerror.h) which are 43
87 // or less need to be remapped.
88 
89 ERRNOTAB  w32_errno_tab[] =
90 {
91     { ERROR_TOO_MANY_OPEN_FILES, EMFILE },
92     { ERROR_ACCESS_DENIED,       EACCES },
93     { ERROR_INVALID_HANDLE,      EBADF  },
94     { ERROR_NOT_ENOUGH_MEMORY,   ENOMEM },
95     { ERROR_OUTOFMEMORY,         ENOMEM },
96     { ERROR_INVALID_DRIVE,       ENOENT },
97     { ERROR_WRITE_PROTECT,       EACCES },
98     { ERROR_NOT_READY,           EIO    },
99     { ERROR_CRC,                 EIO    },
100     { ERROR_WRITE_FAULT,         EIO    },
101     { ERROR_READ_FAULT,          EIO    },
102     { ERROR_GEN_FAILURE,         EIO    },
103     { ERROR_SHARING_VIOLATION,   EACCES },
104 };
105 
106 #define NUM_ERRNOTAB_ENTRIES  (sizeof(w32_errno_tab)/sizeof(w32_errno_tab[0]))
107 
108 //////////////////////////////////////////////////////////////////////////////////////////
109 // Translates a Win32 '[WSA]GetLastError()' value into a 'errno' value (if possible
110 // and/or if needed) that can then be used in the below 'w32_strerror' string function...
111 
w32_trans_w32error(const DWORD dwLastError)112 DLL_EXPORT int w32_trans_w32error( const DWORD dwLastError )
113 {
114     int i; for ( i=0; i < NUM_ERRNOTAB_ENTRIES; i++ )
115         if ( dwLastError == w32_errno_tab[i].dwLastError )
116             return w32_errno_tab[i].nErrNo;
117     return (int) dwLastError;
118 }
119 
120 //////////////////////////////////////////////////////////////////////////////////////////
121 // ("unsafe" version -- use "safer" 'w32_strerror_r' instead if possible)
122 
w32_strerror(int errnum)123 DLL_EXPORT char* w32_strerror( int errnum )
124 {
125     static char szMsgBuff[ 256 ]; // (s/b plenty big enough)
126     w32_strerror_r( errnum, szMsgBuff, sizeof(szMsgBuff) );
127     return szMsgBuff;
128 }
129 
130 //////////////////////////////////////////////////////////////////////////////////////////
131 // Handles both regular 'errno' values as well as [WSA]GetLastError() values too...
132 
w32_strerror_r(int errnum,char * buffer,size_t buffsize)133 DLL_EXPORT int w32_strerror_r( int errnum, char* buffer, size_t buffsize )
134 {
135     // Route all 'errno' values outside the normal CRT (C Runtime) error
136     // message table range to the Win32 'w32_w32errmsg' function instead.
137     // Otherwise simply use the CRT's error message table directly...
138 
139     if ( !buffer || !buffsize ) return -1;
140 
141     if ( errnum >= 0 && errnum < _sys_nerr )
142     {
143         // Use CRT's error message table directly...
144         strlcpy( buffer, _sys_errlist[ errnum ], buffsize );
145     }
146     else
147     {
148         // 'errno' value is actually a Win32 [WSA]GetLastError value...
149         w32_w32errmsg( errnum, buffer, buffsize );
150     }
151 
152     return 0;
153 }
154 
155 //////////////////////////////////////////////////////////////////////////////////////////
156 // Return Win32 error message text associated with an error number value
157 // as returned by a call to either GetLastError() or WSAGetLastError()...
158 
w32_w32errmsg(int errnum,char * pszBuffer,size_t nBuffSize)159 DLL_EXPORT char* w32_w32errmsg( int errnum, char* pszBuffer, size_t nBuffSize )
160 {
161     DWORD dwBytesReturned = 0;
162     DWORD dwBuffSize = (DWORD)nBuffSize;
163 
164     ASSERT( pszBuffer && nBuffSize );
165 
166     dwBytesReturned = FormatMessageA
167     (
168         0
169             | FORMAT_MESSAGE_FROM_SYSTEM
170             | FORMAT_MESSAGE_IGNORE_INSERTS
171         ,
172         NULL,
173         errnum,
174         MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
175         pszBuffer,
176         dwBuffSize,
177         NULL
178     );
179 
180     ASSERT( dwBytesReturned );
181 
182     // (remove trailing whitespace)
183     {
184         char* p = pszBuffer + dwBytesReturned - 1;
185         while ( p >= pszBuffer && isspace(*p) ) p--;
186         *++p = 0;
187     }
188 
189     return pszBuffer;
190 }
191 
192 //////////////////////////////////////////////////////////////////////////////////////////
193 // Large File Support...
194 
195 #if (_MSC_VER < 1400)
196 
197 //----------------------------------------------------------------------------------------
198 
199 #if defined( _POSIX_ )
200   // (promote/demote long to/from __int64)
201   #define FPOS_T_TO_INT64(pos)      ((__int64)(pos))
202   #define INT64_TO_FPOS_T(i64,pos)  ((pos) = (long)(i64))
203   #if _INTEGRAL_MAX_BITS < 64
204     #pragma message( MSVC_MESSAGE_LINENUM "warning: fseek/ftell use offset arguments of insufficient size" )
205   #endif
206 #else
207   #if !__STDC__ && _INTEGRAL_MAX_BITS >= 64
208     // (already __int64!)
209     #define FPOS_T_TO_INT64(pos)      (pos)
210     #define INT64_TO_FPOS_T(i64,pos)  ((pos) = (i64))
211   #else
212     // (construct an __int64 from fpos_t structure members and vice-versa)
213     #define FPOS_T_TO_INT64(pos)      ((__int64)(((unsigned __int64)(pos).hipart << 32) | \
214                                                   (unsigned __int64)(pos).lopart))
215     #define INT64_TO_FPOS_T(i64,pos)  ((pos).hipart = (int)((i64) >> 32), \
216                                        (pos).lopart = (unsigned int)(i64))
217   #endif
218 #endif
219 
220 //----------------------------------------------------------------------------------------
221 
w32_ftelli64(FILE * stream)222 DLL_EXPORT __int64 w32_ftelli64 ( FILE* stream )
223 {
224     fpos_t pos; if ( fgetpos( stream, &pos ) != 0 )
225     return -1; else return FPOS_T_TO_INT64( pos );
226 }
227 
228 //----------------------------------------------------------------------------------------
229 
w32_fseeki64(FILE * stream,__int64 offset,int origin)230 DLL_EXPORT int w32_fseeki64 ( FILE* stream, __int64 offset, int origin )
231 {
232     __int64  offset_from_beg;
233     fpos_t   pos;
234 
235     if (SEEK_CUR == origin)
236     {
237         if ( (offset_from_beg = w32_ftelli64( stream )) < 0 )
238             return -1;
239         offset_from_beg += offset;
240     }
241     else if (SEEK_END == origin)
242     {
243         struct stat fst;
244         if ( fstat( fileno( stream ), &fst ) != 0 )
245             return -1;
246         offset_from_beg = (__int64)fst.st_size + offset;
247     }
248     else if (SEEK_SET == origin)
249     {
250         offset_from_beg = offset;
251     }
252     else
253     {
254         errno = EINVAL;
255         return -1;
256     }
257 
258     INT64_TO_FPOS_T( offset_from_beg, pos );
259     return fsetpos( stream, &pos );
260 }
261 
262 //----------------------------------------------------------------------------------------
263 
w32_ftrunc64(int fd,__int64 new_size)264 DLL_EXPORT int w32_ftrunc64 ( int fd, __int64 new_size )
265 {
266     HANDLE  hFile;
267     int rc = 0, save_errno;
268     __int64 old_pos, old_size;
269 
270     if ( new_size < 0 )
271     {
272         errno = EINVAL;
273         return -1;
274     }
275 
276     hFile  = (HANDLE)  _get_osfhandle( fd );
277 
278     if ( (HANDLE) -1 == hFile )
279     {
280         errno = EBADF;  // (probably not a valid opened file descriptor)
281         return -1;
282     }
283 
284     // The value of the seek pointer shall not be modified by a call to ftruncate().
285 
286     if ( ( old_pos = _telli64( fd ) ) < 0 )
287         return -1;
288 
289     // PROGRAMMING NOTE: from here on, all errors
290     // need to goto error_return to restore the original
291     // seek pointer...
292 
293     if ( ( old_size = _lseeki64( fd, 0, SEEK_END ) ) < 0 )
294     {
295         rc = -1;
296         goto error_return;
297     }
298 
299     // pad with zeros out to new_size if needed
300 
301     rc = 0;  // (think positively)
302 
303     if ( new_size > old_size )
304     {
305 #define            ZEROPAD_BUFFSIZE  ( 128 * 1024 )
306         BYTE zeros[ZEROPAD_BUFFSIZE];
307         size_t write_amount = sizeof(zeros);
308         memset( zeros, 0, sizeof(zeros) );
309 
310         do
311         {
312             write_amount = min( sizeof(zeros), ( new_size - old_size ) );
313 
314             if ( !WriteFile( hFile, zeros, write_amount, NULL, NULL ) )
315             {
316                 errno = (int) GetLastError();
317                 rc = -1;
318                 break;
319             }
320         }
321         while ( ( old_size += write_amount ) < new_size );
322 
323         save_errno = errno;
324         ASSERT( old_size == new_size || rc < 0 );
325         errno = save_errno;
326     }
327 
328     if ( rc < 0 )
329         goto error_return;
330 
331     // set the new file size (eof)
332 
333     if ( _lseeki64( fd, new_size, SEEK_SET ) < 0 )
334     {
335         rc = -1;
336         goto error_return;
337     }
338 
339     if ( !SetEndOfFile( hFile ) )
340     {
341         errno = (int) GetLastError();
342         rc = -1;
343         goto error_return;
344     }
345 
346     rc = 0; // success!
347 
348 error_return:
349 
350     // restore the original seek pointer and return
351 
352     save_errno = errno;
353     _lseeki64( fd, old_pos, SEEK_SET );
354     errno = save_errno;
355 
356     return rc;
357 }
358 
359 #endif // (_MSC_VER < 1400)
360 
361 //////////////////////////////////////////////////////////////////////////////////////////
362 
363 #if !defined( HAVE_FORK )
364 
fork(void)365 DLL_EXPORT pid_t  fork( void )
366 {
367     errno = ENOTSUP;
368     return -1;          // *** NOT SUPPORTED ***
369 }
370 
371 #endif
372 
373 //////////////////////////////////////////////////////////////////////////////////////////
374 
375 #if !defined( HAVE_SCHED_YIELD )
376 
sched_yield(void)377 DLL_EXPORT int sched_yield ( void )
378 {
379     Sleep(0);
380     return 0;
381 }
382 
383 #endif
384 
385 //////////////////////////////////////////////////////////////////////////////////////////
386 // Win32's runtime library functions are reentrant as long as you link
387 // with one of the multi-threaded libraries (i.e. LIBCMT, MSVCRT, etc.)
388 
389 #if !defined( HAVE_STRTOK_R )
390 
strtok_r(char * s,const char * sep,char ** lasts)391 DLL_EXPORT char* strtok_r ( char* s, const char* sep, char** lasts )
392 {
393     UNREFERENCED( lasts );
394     return strtok( s, sep );
395 }
396 
397 #endif
398 
399 //////////////////////////////////////////////////////////////////////////////////////////
400 // Can't use "HAVE_SLEEP" since Win32's "Sleep" causes HAVE_SLEEP to
401 // be erroneously #defined due to autoconf AC_CHECK_FUNCS case issues...
402 
403 //#if !defined( HAVE_SLEEP )
404 
sleep(unsigned seconds)405 DLL_EXPORT unsigned sleep ( unsigned seconds )
406 {
407     Sleep( seconds * 1000 );
408     return 0;
409 }
410 
411 //#endif
412 
413 //////////////////////////////////////////////////////////////////////////////////////////
414 // high resolution sleep
415 
416 #if !defined( HAVE_NANOSLEEP ) || !defined( HAVE_USLEEP )
417 
w32_nanosleep(const struct timespec * rqtp)418 static int w32_nanosleep ( const struct timespec* rqtp )
419 {
420     /*
421     DESCRIPTION
422 
423         The nanosleep() function shall cause the current thread
424         to be suspended from execution until either the time interval
425         specified by the rqtp argument has elapsed or a signal is
426         delivered to the calling thread, and its action is to invoke
427         a signal-catching function or to terminate the process. The
428         suspension time may be longer than requested because the argument
429         value is rounded up to an integer multiple of the sleep resolution
430         or because of the scheduling of other activity by the system.
431         But, except for the case of being interrupted by a signal, the
432         suspension time shall not be less than the time specified by rqtp,
433         as measured by the system clock CLOCK_REALTIME.
434 
435         The use of the nanosleep() function has no effect on the action
436         or blockage of any signal.
437 
438     RETURN VALUE
439 
440         If the nanosleep() function returns because the requested time
441         has elapsed, its return value shall be zero.
442 
443         If the nanosleep() function returns because it has been interrupted
444         by a signal, it shall return a value of -1 and set errno to indicate
445         the interruption. If the rmtp argument is non-NULL, the timespec
446         structure referenced by it is updated to contain the amount of time
447         remaining in the interval (the requested time minus the time actually
448         slept). If the rmtp argument is NULL, the remaining time is not returned.
449 
450         If nanosleep() fails, it shall return a value of -1 and set errno
451         to indicate the error.
452 
453     ERRORS
454 
455         The nanosleep() function shall fail if:
456 
457         [EINTR]   The nanosleep() function was interrupted by a signal.
458 
459         [EINVAL]  The rqtp argument specified a nanosecond value less than zero
460                   or greater than or equal to 1000 million.
461     */
462 
463     static BOOL    bDidInit    = FALSE;
464     static HANDLE  hTimer      = NULL;
465     LARGE_INTEGER  liDueTime;
466 
467     // Create the waitable timer if needed...
468 
469     if (unlikely( !bDidInit ))
470     {
471         bDidInit = TRUE;
472 
473         VERIFY( ( hTimer = CreateWaitableTimer( NULL, TRUE, NULL ) ) != NULL );
474     }
475 
476     // Check passed parameters...
477 
478     if (unlikely(!rqtp
479         || rqtp->tv_nsec < 0
480         || rqtp->tv_nsec >= 1000000000
481     ))
482     {
483         errno = EINVAL;
484         return -1;
485     }
486 
487     // Note: Win32 waitable timers: parameter is #of 100-nanosecond intervals.
488     //       Positive values indicate absolute UTC time. Negative values indicate
489     //       relative time. The actual timer accuracy depends on the capability
490     //       of your hardware.
491 
492     liDueTime.QuadPart = -(                 // (negative means relative)
493         (((__int64)rqtp->tv_sec * 10000000))
494         +
495         (((__int64)rqtp->tv_nsec + 99) / 100)
496     );
497 
498     // Set the waitable timer...
499 
500     VERIFY( SetWaitableTimer( hTimer, &liDueTime, 0, NULL, NULL, FALSE ) );
501 
502     // Wait for the waitable timer to expire...
503 
504     VERIFY( WaitForSingleObject( hTimer, INFINITE ) == WAIT_OBJECT_0 );
505 
506     return 0;
507 }
508 
509 #endif
510 
511 //////////////////////////////////////////////////////////////////////////////////////////
512 // nanosleep - high resolution sleep
513 
514 #if !defined( HAVE_NANOSLEEP )
515 
nanosleep(const struct timespec * rqtp,struct timespec * rmtp)516 DLL_EXPORT int nanosleep ( const struct timespec* rqtp, struct timespec* rmtp )
517 {
518     if (unlikely(rmtp))
519     {
520         rmtp->tv_sec  = 0;
521         rmtp->tv_nsec = 0;
522     }
523 
524     return w32_nanosleep ( rqtp );
525 }
526 
527 #endif
528 
529 //////////////////////////////////////////////////////////////////////////////////////////
530 // usleep - suspend execution for an interval
531 
532 #if !defined( HAVE_USLEEP )
533 
usleep(useconds_t useconds)534 DLL_EXPORT int usleep ( useconds_t useconds )
535 {
536     //  "The useconds argument shall be less than one million. If the value of
537     //   useconds is 0, then the call has no effect."
538 
539     //  "Implementations may place limitations on the granularity of timer values.
540     //   For each interval timer, if the requested timer value requires a finer
541     //   granularity than the implementation supports, the actual timer value shall
542     //   be rounded up to the next supported value."
543 
544     //  "Upon successful completion, usleep() shall return 0; otherwise, it shall
545     //   return -1 and set errno to indicate the error."
546 
547     //  "The usleep() function may fail if:
548     //
549     //     [EINVAL]     The time interval specified
550     //                  one million or more microseconds"
551 
552     struct timespec rqtp;
553 
554     if (unlikely( useconds < 0 || useconds >= 1000000 ))
555     {
556         errno = EINVAL;
557         return -1;
558     }
559 
560     rqtp.tv_sec  = 0;
561     rqtp.tv_nsec = useconds * 1000;
562 
563     return w32_nanosleep ( &rqtp );
564 }
565 
566 #endif
567 
568 //////////////////////////////////////////////////////////////////////////////////////////
569 // gettimeofday...
570 
571 #if !defined( HAVE_GETTIMEOFDAY )
572 
573 // Number of 100-nanosecond units from 1 Jan 1601 to 1 Jan 1970
574 
575 #define  EPOCH_BIAS  116444736000000000ULL
576 
577 // Helper function to convert Windows system-time value to microseconds...
578 
FileTimeToMicroseconds(const FILETIME * pFT)579 static LARGE_INTEGER FileTimeToMicroseconds( const FILETIME* pFT )
580 {
581     LARGE_INTEGER  liWork;  // (work area)
582 
583     // Copy value to be converted to work area
584 
585     liWork.HighPart = pFT->dwHighDateTime;
586     liWork.LowPart  = pFT->dwLowDateTime;
587 
588     // Convert to 100-nanosecond units since 1 Jan 1970
589 
590     liWork.QuadPart -= EPOCH_BIAS;
591 
592     // Convert to microseconds since 1 Jan 1970
593 
594     liWork.QuadPart /= (LONGLONG) 10;
595 
596     return liWork;
597 }
598 
gettimeofday(struct timeval * pTV,void * pTZ)599 DLL_EXPORT int gettimeofday ( struct timeval* pTV, void* pTZ )
600 {
601     LARGE_INTEGER          liCurrentHPCValue;       // (high-performance-counter tick count)
602     static LARGE_INTEGER   liStartingHPCValue;      // (high-performance-counter tick count)
603     static LARGE_INTEGER   liStartingSystemTime;    // (time of last resync in microseconds)
604     static struct timeval  tvPrevSyncVal = {0,0};   // (time of last resync as timeval)
605     static struct timeval  tvPrevRetVal  = {0,0};   // (previously returned value)
606     static double          dHPCTicksPerMicrosecond; // (just what it says)
607     static BOOL            bInSync = FALSE;         // (work flag)
608 
609     UNREFERENCED(pTZ);
610 
611     // One-time (and periodic!) initialization...
612 
613     if (unlikely( !bInSync ))
614     {
615         FILETIME       ftStartingSystemTime;
616         LARGE_INTEGER  liHPCTicksPerSecond;
617 
618         // The "GetSystemTimeAsFileTime" function obtains the current system date
619         // and time. The information is in Coordinated Universal Time (UTC) format.
620 
621         GetSystemTimeAsFileTime( &ftStartingSystemTime );
622         VERIFY( QueryPerformanceCounter( &liStartingHPCValue ) );
623 
624         VERIFY( QueryPerformanceFrequency( &liHPCTicksPerSecond ) );
625         dHPCTicksPerMicrosecond = (double) liHPCTicksPerSecond.QuadPart / 1000000.0;
626 
627         liStartingSystemTime = FileTimeToMicroseconds( &ftStartingSystemTime );
628 
629         tvPrevSyncVal.tv_sec = 0;       // (to force init further below)
630         tvPrevSyncVal.tv_usec = 0;      // (to force init further below)
631 
632         bInSync = TRUE;
633     }
634 
635     // The following check for user error must FOLLOW the above initialization
636     // code block so the above initialization code block ALWAYS gets executed!
637 
638     if (unlikely( !pTV ))
639         return EFAULT;
640 
641     // Query current high-performance counter value...
642 
643     VERIFY( QueryPerformanceCounter( &liCurrentHPCValue ) );
644 
645     // Calculate elapsed HPC ticks...
646 
647     liCurrentHPCValue.QuadPart -= liStartingHPCValue.QuadPart;
648 
649     // Convert to elapsed microseconds...
650 
651     liCurrentHPCValue.QuadPart = (LONGLONG)
652         ( (double) liCurrentHPCValue.QuadPart / dHPCTicksPerMicrosecond );
653 
654     // Add to starting system time...
655 
656     liCurrentHPCValue.QuadPart += liStartingSystemTime.QuadPart;
657 
658     // Build results...
659 
660     pTV->tv_sec   =  (long)(liCurrentHPCValue.QuadPart / 1000000);
661     pTV->tv_usec  =  (long)(liCurrentHPCValue.QuadPart % 1000000);
662 
663     // Re-sync to system clock every so often to prevent clock drift
664     // since high-performance timer updated independently from clock.
665 
666 #define  RESYNC_GTOD_EVERY_SECS  30
667 
668     // (initialize time of previous 'sync')
669 
670     if (unlikely( !tvPrevSyncVal.tv_sec ))
671     {
672         tvPrevSyncVal.tv_sec  = pTV->tv_sec;
673         tvPrevSyncVal.tv_usec = pTV->tv_usec;
674     }
675 
676     // (is is time to resync again?)
677 
678     if (unlikely( (pTV->tv_sec - tvPrevSyncVal.tv_sec ) > RESYNC_GTOD_EVERY_SECS ))
679     {
680         bInSync = FALSE;    // (force resync)
681         return gettimeofday( pTV, NULL );
682     }
683 
684     // Ensure that each call returns a unique, ever-increasing value...
685 
686     if (unlikely( !tvPrevRetVal.tv_sec ))
687     {
688         tvPrevRetVal.tv_sec  = pTV->tv_sec;
689         tvPrevRetVal.tv_usec = pTV->tv_usec;
690     }
691 
692     if (unlikely
693     (0
694         ||      pTV->tv_sec  <  tvPrevRetVal.tv_sec
695         || (1
696             &&  pTV->tv_sec  == tvPrevRetVal.tv_sec
697             &&  pTV->tv_usec <= tvPrevRetVal.tv_usec
698            )
699     ))
700     {
701         pTV->tv_sec  = tvPrevRetVal.tv_sec;
702         pTV->tv_usec = tvPrevRetVal.tv_usec + 1;
703 
704         if (unlikely(pTV->tv_usec >= 1000000))
705         {
706             pTV->tv_sec  += pTV->tv_usec / 1000000;
707             pTV->tv_usec  = pTV->tv_usec % 1000000;
708         }
709     }
710 
711     // Save previously returned value for next time...
712 
713     tvPrevRetVal.tv_sec  = pTV->tv_sec;
714     tvPrevRetVal.tv_usec = pTV->tv_usec;
715 
716     // Done!
717 
718     return 0;       // (always unless user error)
719 }
720 
721 #endif
722 
723 //////////////////////////////////////////////////////////////////////////////////////////
724 // scandir...
725 
726 #if !defined( HAVE_SCANDIR )
727 
728 // (fishfix: fix benign "passing incompatible pointer type" compiler warning..)
729 typedef int (*PFN_QSORT_COMPARE_FUNC)( const void* elem1, const void* elem2 );
730 
731 // Found the following on Koders.com ...  (http://www.koders.com/) ...
732 
733 /*
734    Copyright (c) 2000 Petter Reinholdtsen
735 
736    Permission is hereby granted, free of charge, to any person
737    obtaining a copy of this software and associated documentation
738    files (the "Software"), to deal in the Software without
739    restriction, including without limitation the rights to use, copy,
740    modify, merge, publish, distribute, sublicense, and/or sell copies
741    of the Software, and to permit persons to whom the Software is
742    furnished to do so, subject to the following conditions:
743 
744    The above copyright notice and this permission notice shall be
745    included in all copies or substantial portions of the Software.
746 
747    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
748    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
749    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
750    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
751    BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
752    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
753    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
754    SOFTWARE.
755 */
scandir(const char * dir,struct dirent *** namelist,int (* filter)(const struct dirent *),int (* compar)(const struct dirent **,const struct dirent **))756 DLL_EXPORT int scandir
757 (
758   const char *dir,
759   struct dirent ***namelist,
760   int (*filter)(const struct dirent *),
761   int (*compar)(const struct dirent **, const struct dirent **)
762 )
763 {
764   WIN32_FIND_DATA file_data;
765   HANDLE handle;
766   int count, pos;
767   struct dirent **names;
768   char *pattern;
769 
770   /* 3 for "*.*", 1 for "\", 1 for zero termination */
771   pattern = (char*)malloc(strlen(dir) + 3 +1 +1);
772   strcpy(pattern, dir);
773   if (pattern[ strlen(pattern) - 1] != '\\')
774     strcat(pattern, "\\");
775   strcat(pattern, "*.*");
776 
777   /* 1st pass thru is just to count them */
778   handle = FindFirstFile(pattern, &file_data);
779   if (handle == INVALID_HANDLE_VALUE)
780     {
781       free(pattern);
782       return -1;
783     }
784 
785   count = 0;
786   while (1)
787     {
788       count++;
789       if (!FindNextFile(handle, &file_data))
790         break;
791     }
792   FindClose(handle);
793 
794   /* Now we know how many, we can alloc & make 2nd pass to copy them */
795   names = (struct dirent**)malloc(sizeof(struct dirent*) * count);
796   memset(names, 0, sizeof(*names));
797   handle = FindFirstFile(pattern, &file_data);
798   if (handle == INVALID_HANDLE_VALUE)
799     {
800       free(pattern);
801       free(names);
802       return -1;
803     }
804 
805   /* Now let caller filter them if requested */
806   pos = 0;
807   while (1)
808     {
809       int rtn;
810       struct dirent current;
811 
812       strcpy(current.d_name, file_data.cFileName);
813 
814       if (!filter || filter(&current))
815         {
816           struct dirent *copyentry = malloc(sizeof(struct dirent));
817           strcpy(copyentry->d_name, current.d_name);
818           names[pos] = copyentry;
819           pos++;
820         }
821 
822       rtn = FindNextFile(handle, &file_data);
823       if (!rtn || rtn==ERROR_NO_MORE_FILES)
824         break;
825     }
826 
827   free(pattern);
828   /* Now sort them */
829   if (compar)
830     // (fishfix: fix benign "passing incompatible pointer type" compiler warning..)
831     qsort(names, pos, sizeof(names[0]), (PFN_QSORT_COMPARE_FUNC)compar);
832   *namelist = names;
833   return pos;
834 }
835 
836 #endif
837 
838 //////////////////////////////////////////////////////////////////////////////////////////
839 
840 #if !defined( HAVE_ALPHASORT )
841 
alphasort(const struct dirent ** a,const struct dirent ** b)842 DLL_EXPORT int alphasort ( const struct dirent **a, const struct dirent **b )
843 {
844     return  strfilenamecmp ( (*a)->d_name, (*b)->d_name );
845 }
846 
847 #endif
848 
849 //////////////////////////////////////////////////////////////////////////////////////////
850 // "Poor man's" getrusage...
851 
852 #if !defined(HAVE_SYS_RESOURCE_H)
853 
DoGetRUsage(HANDLE hProcess,struct rusage * r_usage)854 static int DoGetRUsage( HANDLE hProcess, struct rusage* r_usage )
855 {
856     FILETIME  ftCreation;   // When the process was created(*)
857     FILETIME  ftExit;       // When the process exited(*)
858 
859     // (*) Windows standard FILETIME format: date/time expressed as the
860     //     amount of time that has elapsed since midnight January 1, 1601.
861 
862     FILETIME  ftKernel;     // CPU time spent in kernel mode (in #of 100-nanosecond units)
863     FILETIME  ftUser;       // CPU time spent in user   mode (in #of 100-nanosecond units)
864 
865     LARGE_INTEGER  liWork;  // (work area)
866 
867     if ( !GetProcessTimes( hProcess, &ftCreation, &ftExit, &ftKernel, &ftUser ) )
868     {
869         ftCreation.dwHighDateTime = ftCreation.dwLowDateTime = 0;
870         ftExit    .dwHighDateTime = ftExit    .dwLowDateTime = 0;
871         ftKernel  .dwHighDateTime = ftKernel  .dwLowDateTime = 0;
872         ftUser    .dwHighDateTime = ftUser    .dwLowDateTime = 0;
873     }
874 
875     // Kernel time...
876 
877     liWork.HighPart = ftKernel.dwHighDateTime;
878     liWork.LowPart  = ftKernel.dwLowDateTime;
879 
880     liWork.QuadPart /= 10;  // (convert to microseconds)
881 
882     r_usage->ru_stime.tv_sec  = (long)(liWork.QuadPart / 1000000);
883     r_usage->ru_stime.tv_usec = (long)(liWork.QuadPart % 1000000);
884 
885     // User time...
886 
887     liWork.HighPart = ftUser.dwHighDateTime;
888     liWork.LowPart  = ftUser.dwLowDateTime;
889 
890     liWork.QuadPart /= 10;  // (convert to microseconds)
891 
892     r_usage->ru_utime.tv_sec  = (long)(liWork.QuadPart / 1000000);
893     r_usage->ru_utime.tv_usec = (long)(liWork.QuadPart % 1000000);
894 
895     return 0;
896 }
897 
getrusage(int who,struct rusage * r_usage)898 DLL_EXPORT int getrusage ( int who, struct rusage* r_usage )
899 {
900     if ( !r_usage )
901     {
902         errno = EFAULT;
903         return -1;
904     }
905 
906     if ( RUSAGE_SELF == who )
907         return DoGetRUsage( GetCurrentProcess(), r_usage );
908 
909     if ( RUSAGE_CHILDREN != who )
910     {
911         errno = EINVAL;
912         return -1;
913     }
914 
915     // RUSAGE_CHILDREN ...
916 
917     {
918         DWORD           dwOurProcessId  = GetCurrentProcessId();
919         HANDLE          hProcessSnap    = NULL;
920         PROCESSENTRY32  pe32;
921         HANDLE          hChildProcess;
922         struct rusage   child_usage;
923 
924         memset( &pe32, 0, sizeof(pe32) );
925 
926         // Take a snapshot of all active processes...
927 
928         hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
929 
930         if ( INVALID_HANDLE_VALUE == hProcessSnap )
931             return DoGetRUsage( INVALID_HANDLE_VALUE, r_usage );
932 
933         pe32.dwSize = sizeof( PROCESSENTRY32 );
934 
935         //  Walk the snapshot...
936 
937         if ( !Process32First( hProcessSnap, &pe32 ) )
938         {
939             CloseHandle( hProcessSnap );
940             return DoGetRUsage( INVALID_HANDLE_VALUE, r_usage );
941         }
942 
943         r_usage->ru_stime.tv_sec = r_usage->ru_stime.tv_usec = 0;
944         r_usage->ru_utime.tv_sec = r_usage->ru_utime.tv_usec = 0;
945 
946         // Locate all children of the current process
947         // and accumulate their process times together...
948 
949         do
950         {
951             if ( pe32.th32ParentProcessID != dwOurProcessId )
952                 continue;
953 
954             hChildProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID );
955             DoGetRUsage( hChildProcess, &child_usage );
956             CloseHandle( hChildProcess );
957 
958             VERIFY( timeval_add( &child_usage.ru_stime, &r_usage->ru_stime ) == 0 );
959             VERIFY( timeval_add( &child_usage.ru_utime, &r_usage->ru_utime ) == 0 );
960         }
961         while ( Process32Next( hProcessSnap, &pe32 ) );
962 
963         VERIFY( CloseHandle( hProcessSnap ) );
964     }
965 
966     return 0;
967 }
968 
969 #endif
970 
971 //////////////////////////////////////////////////////////////////////////////////////////
972 
973 #if !defined( HAVE_GETLOGIN_R )
974 
getlogin_r(char * name,size_t namesize)975 DLL_EXPORT int getlogin_r ( char* name, size_t namesize )
976 {
977     DWORD  dwSize = (DWORD)namesize;
978 
979     if ( !name )
980         return EFAULT;
981 
982     if ( namesize < 2 || namesize > ( LOGIN_NAME_MAX + 1 ) )
983         return EINVAL;
984 
985     return ( GetUserName( name, &dwSize ) ? 0 : ERANGE );
986 }
987 
988 #endif
989 
990 //////////////////////////////////////////////////////////////////////////////////////////
991 
992 #if !defined( HAVE_GETLOGIN )
993 
getlogin(void)994 DLL_EXPORT char* getlogin ( void )
995 {
996     static char login_name [ LOGIN_NAME_MAX + 1 ];
997 
998     int rc;
999 
1000     if ( ( rc = getlogin_r ( login_name, sizeof(login_name) ) ) == 0 )
1001         return login_name;
1002 
1003     errno = rc;
1004     return NULL;
1005 }
1006 
1007 #endif
1008 
1009 //////////////////////////////////////////////////////////////////////////////////////////
1010 
1011 #if !defined( HAVE_REALPATH )
1012 
realpath(const char * file_name,char * resolved_name)1013 DLL_EXPORT char* realpath ( const char* file_name, char* resolved_name )
1014 {
1015     char* retval;
1016 
1017     if ( !file_name || !resolved_name )
1018     {
1019         errno = EINVAL;
1020         return NULL;
1021     }
1022 
1023     // PROGRAMMING NOTE: unfortunately there's no possible way to implement an accurate
1024     // Win32 port of realpath in regard to the errno values returned whenever there's an
1025     // error. The errno values that are set whenever realpath fails are quite precise,
1026     // telling you exactly what went wrong (name too long, invalid directory component,
1027     // etc), whereas _fullpath only returns success/failure with absolutely no indication
1028     // as to WHY it failed. To further complicate matters, there's no real "generic" type
1029     // of errno value we can choose to return to the caller should _fullpath fail either,
1030     // so for this implementation we purposely return EIO (i/o error) if _fullpath fails
1031     // for any reason. That may perhaps be somewhat misleading (since the actual cause of
1032     // the failure was probably not because of an i/o error), but returning any of the
1033     // OTHER possible realpath errno values would be even MORE misleading in my opinion.
1034 
1035     if ( !(retval = _fullpath( resolved_name, file_name, PATH_MAX ) ) )
1036         errno = EIO;
1037 
1038     return retval;
1039 }
1040 
1041 #endif
1042 
1043 //////////////////////////////////////////////////////////////////////////////////////////
1044 // Returns outpath as a host filesystem compatible filename path.
1045 // This is a Cygwin-to-MSVC transitional period helper function.
1046 // On non-Windows platforms it simply copies inpath to outpath.
1047 // On Windows it converts inpath of the form "/cygdrive/x/foo.bar"
1048 // to outpath in the form "x:/foo.bar" for Windows compatibility.
1049 
hostpath(BYTE * outpath,const BYTE * inpath,size_t buffsize)1050 DLL_EXPORT BYTE *hostpath( BYTE *outpath, const BYTE *inpath, size_t buffsize )
1051 {
1052     // The possibilities:
1053 
1054     //   a. Linux/Cygwin absolute:
1055     //      /dir/foo.bar
1056 
1057     //   b. Linux/Cygwin relative:
1058     //      ../dir/foo.bar
1059     //      ./dir/foo.bar
1060     //      ../../.././dir/foo.bar
1061     //      (etc)
1062 
1063     //   c. Windows relative:
1064     //      ./dir\foo.bar
1065     //      ../dir\foo.bar
1066     //      ..\dir\foo.bar
1067     //      .\dir\foo.bar
1068     //      ..\dir/foo.bar
1069     //      .\dir/foo.bar
1070     //      ../..\../.\dir/foo.bar
1071     //      (etc)
1072 
1073     //   d. Windows absolute
1074     //      x:/dir/foo.bar
1075     //      x:\dir\foo.bar
1076     //      x:/dir\foo.bar
1077     //      x:\dir/foo.bar
1078 
1079     // For case a we check for special Cygwin format "/cygdrive/x/..."
1080     // and convert it to "normalized" (forward-slash) case d format.
1081     // (Note that the slashes in this case MUST be forward slashes
1082     // or else the special Cygwin path format will not be detected!)
1083 
1084     // Case b we treat the same as case c.
1085 
1086     // For case c we simply convert all backslashes to forward slashes
1087     // since Windows supports both.
1088 
1089     // For case d we do nothing since it is already a Windows path
1090     // (other than normalize all backward slashes to forward slashes
1091     // since Windows supports both)
1092 
1093     // NOTE that we do NOT attempt to convert relative paths to absolute
1094     // paths! The caller is responsible for doing that themselves after
1095     // calling this function if so desired.
1096 
1097     if (outpath && buffsize)
1098         *outpath = 0;
1099 
1100     if (inpath && *inpath && outpath && buffsize > 1)
1101     {
1102         size_t inlen = strlen(inpath);
1103 
1104         if (1
1105             && inlen >= 11
1106             && strncasecmp(inpath,"/cygdrive/",10) == 0
1107             && isalpha(inpath[10])
1108         )
1109         {
1110             *outpath++ = inpath[10];
1111             buffsize--;
1112             if (buffsize > 1)
1113             {
1114                 *outpath++ = ':';
1115                 buffsize--;
1116             }
1117             inpath += 11;
1118         }
1119 
1120         while (*inpath && --buffsize)
1121         {
1122             BYTE c = *inpath++;
1123             if (c == '\\') c = '/';
1124             *outpath++ = c;
1125         }
1126         *outpath = 0;
1127     }
1128     return outpath;
1129 }
1130 
1131 //////////////////////////////////////////////////////////////////////////////////////////
1132 // Poor man's  "fcntl( fd, F_GETFL )"...
1133 // (only returns access-mode flags and not any others)
1134 
get_file_accmode_flags(int fd)1135 DLL_EXPORT int get_file_accmode_flags( int fd )
1136 {
1137     // PROGRAMMING NOTE: we unfortunately CANNOT use Microsoft's "_fstat" here
1138     // since it seems to always return the actual file's ATTRIBUTE permissions
1139     // and not the ACCESS MODE permissions specified when the file was opened!
1140 
1141     HANDLE  hFile;
1142     BOOL    bCanRead;
1143     BOOL    bCanWrite;
1144     DWORD   dwNumBytesToReadOrWrite;
1145     DWORD   dwNumBytesReadOrWritten;
1146     char    read_write_buffer;
1147 
1148     // TECHNIQUE: check whether or not we can "read" and/or "write" to the file
1149     // and return appropriate access-mode flags accordingly. Note that we do not
1150     // actually read nor write from/to the file per se, since we specify ZERO BYTES
1151     // for our "number of bytes to read/write" argument. This is valid under Win32
1152     // and does not modify the file position and so is safe to do. All it does is
1153     // return the appropriate success/failure return code (e.g. ERROR_ACCESS_DENIED)
1154     // depending on whether the file was opened with the proper access permissions.
1155 
1156     hFile  = (HANDLE)  _get_osfhandle( fd );
1157 
1158     if ( (HANDLE) -1 == hFile )
1159     {
1160         errno = EBADF;      // (probably not a valid opened file descriptor)
1161         return -1;
1162     }
1163 
1164     dwNumBytesToReadOrWrite = 0;  // ZERO!!! (we don't wish to modify the file!)
1165 
1166     VERIFY( ( bCanRead = ReadFile ( hFile, &read_write_buffer, dwNumBytesToReadOrWrite, &dwNumBytesReadOrWritten, NULL ) )
1167         || ERROR_ACCESS_DENIED == GetLastError() );
1168 
1169     VERIFY( ( bCanWrite = WriteFile ( hFile, &read_write_buffer, dwNumBytesToReadOrWrite, &dwNumBytesReadOrWritten, NULL ) )
1170         || ERROR_ACCESS_DENIED == GetLastError() );
1171 
1172     // For reference, 'fcntl.h' defines the flags as follows:
1173     //
1174     //  #define   _O_RDONLY    0
1175     //  #define   _O_WRONLY    1
1176     //  #define   _O_RDWR      2
1177 
1178     if (  bCanRead  &&  bCanWrite ) return _O_RDWR;
1179     if (  bCanRead  && !bCanWrite ) return _O_RDONLY;
1180     if ( !bCanRead  &&  bCanWrite ) return _O_WRONLY;
1181 
1182     ASSERT( FALSE );    // (HUH?! Can neither read NOR write to the file?!)
1183     errno = EBADF;      // (maybe they closed it before we could test it??)
1184     return -1;          // (oh well)
1185 }
1186 
1187 //////////////////////////////////////////////////////////////////////////////////////////
1188 // Retrieve directory where process was loaded from...
1189 // (returns >0 == success, 0 == failure)
1190 
get_process_directory(char * dirbuf,size_t bufsiz)1191 DLL_EXPORT int get_process_directory( char* dirbuf, size_t bufsiz )
1192 {
1193     char process_exec_dirbuf[MAX_PATH];
1194     char* p;
1195     DWORD dwDirBytes =
1196         GetModuleFileName(GetModuleHandle(NULL),process_exec_dirbuf,MAX_PATH);
1197     if (!dwDirBytes || dwDirBytes >= MAX_PATH)
1198         return 0;
1199     p = strrchr(process_exec_dirbuf,'\\'); if (p) *(p+1) = 0;
1200     strlcpy(dirbuf,process_exec_dirbuf,bufsiz);
1201     return strlen(dirbuf) ? 1 : 0;
1202 }
1203 
1204 //////////////////////////////////////////////////////////////////////////////////////////
1205 // Expand environment variables... (e.g. %SystemRoot%, etc); 0==success
1206 
expand_environ_vars(const char * inbuff,char * outbuff,DWORD outbufsiz)1207 DLL_EXPORT int expand_environ_vars( const char* inbuff, char* outbuff, DWORD outbufsiz )
1208 {
1209     // If the function succeeds, the return value is the number of TCHARs
1210     // stored in the destination buffer, including the terminating null character.
1211     // If the destination buffer is too small to hold the expanded string, the
1212     // return value is the required buffer size, in TCHARs. If the function fails,
1213     // the return value is zero.
1214 
1215     DWORD dwOutLen = ExpandEnvironmentStrings( inbuff, outbuff, outbufsiz );
1216     return ( ( dwOutLen && dwOutLen < outbufsiz ) ? 0 : -1 );
1217 }
1218 
1219 //////////////////////////////////////////////////////////////////////////////////////////
1220 // Initialize Hercules HOSTINFO structure
1221 
w32_init_hostinfo(HOST_INFO * pHostInfo)1222 DLL_EXPORT void w32_init_hostinfo( HOST_INFO* pHostInfo )
1223 {
1224     CRITICAL_SECTION  cs;
1225     OSVERSIONINFO     vi;
1226     SYSTEM_INFO       si;
1227     char*             psz;
1228     DWORD             dw;
1229 
1230     dw = sizeof(pHostInfo->nodename)-1;
1231     GetComputerName( pHostInfo->nodename, &dw );
1232     pHostInfo->nodename[sizeof(pHostInfo->nodename)-1] = 0;
1233 
1234     vi.dwOSVersionInfoSize = sizeof(vi);
1235 
1236     VERIFY( GetVersionEx( &vi ) );
1237 
1238     switch ( vi.dwPlatformId )
1239     {
1240         case VER_PLATFORM_WIN32_WINDOWS: psz = "9X"; break;
1241         case VER_PLATFORM_WIN32_NT:      psz = "NT"; break;
1242         default:                         psz = "??"; break;
1243     }
1244 
1245 #if defined(__MINGW32_VERSION)
1246  #define HWIN32_SYSNAME         "MINGW32"
1247 #else
1248  #define HWIN32_SYSNAME         "Windows"
1249 #endif
1250 
1251     _snprintf(
1252         pHostInfo->sysname, sizeof(
1253         pHostInfo->sysname)-1,        HWIN32_SYSNAME "_%s",  psz );
1254         pHostInfo->sysname[ sizeof(
1255         pHostInfo->sysname)-1] = 0;
1256 
1257     _snprintf(
1258         pHostInfo->release, sizeof(
1259         pHostInfo->release)-1,        "%d",  vi.dwMajorVersion );
1260         pHostInfo->release[ sizeof(
1261         pHostInfo->release)-1] = 0;
1262 
1263     _snprintf(
1264         pHostInfo->version, sizeof(
1265         pHostInfo->version)-1,        "%d",  vi.dwMinorVersion );
1266         pHostInfo->version[ sizeof(
1267         pHostInfo->version)-1] = 0;
1268 
1269     GetSystemInfo( &si );
1270 
1271     switch ( si.wProcessorArchitecture )
1272     {
1273         case PROCESSOR_ARCHITECTURE_INTEL:
1274         {
1275             int n;
1276 
1277             if      ( si.wProcessorLevel < 3 ) n = 3;
1278             else if ( si.wProcessorLevel > 9 ) n = 6;
1279             else                               n = si.wProcessorLevel;
1280 
1281             _snprintf(
1282                 pHostInfo->machine, sizeof(
1283                 pHostInfo->machine)-1,        "i%d86",  n );
1284                 pHostInfo->machine[ sizeof(
1285                 pHostInfo->machine)-1] = 0;
1286         }
1287         break;
1288 
1289 // The following are missing from MinGW's supplied version of <winnt.h>
1290 
1291 #define PROCESSOR_ARCHITECTURE_MSIL             8
1292 #define PROCESSOR_ARCHITECTURE_AMD64            9
1293 #define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64    10
1294 
1295         case PROCESSOR_ARCHITECTURE_IA64:          strlcpy( pHostInfo->machine, "IA64"          , sizeof(pHostInfo->machine) ); break;
1296         case PROCESSOR_ARCHITECTURE_AMD64:         strlcpy( pHostInfo->machine, "AMD64"         , sizeof(pHostInfo->machine) ); break;
1297         case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: strlcpy( pHostInfo->machine, "IA32_ON_WIN64" , sizeof(pHostInfo->machine) ); break;
1298         case PROCESSOR_ARCHITECTURE_ALPHA:         strlcpy( pHostInfo->machine, "ALPHA"         , sizeof(pHostInfo->machine) ); break;
1299         case PROCESSOR_ARCHITECTURE_MIPS:          strlcpy( pHostInfo->machine, "MIPS"          , sizeof(pHostInfo->machine) ); break;
1300         default:                                   strlcpy( pHostInfo->machine, "???"           , sizeof(pHostInfo->machine) ); break;
1301     }
1302 
1303     pHostInfo->num_procs = si.dwNumberOfProcessors;
1304 
1305     InitializeCriticalSection( &cs );
1306 
1307     if ( !TryEnterCriticalSection( &cs ) )
1308         pHostInfo->trycritsec_avail = 0;
1309     else
1310     {
1311         pHostInfo->trycritsec_avail = 1;
1312         LeaveCriticalSection( &cs );
1313     }
1314 
1315     DeleteCriticalSection( &cs );
1316 }
1317 
1318 //////////////////////////////////////////////////////////////////////////////////////////
1319 // The function that creates us is responsible for initializing the below values
1320 // (as well as de-initialzing them too!)
1321 
1322 static DWORD   dwThreadId       = 0;        // (Win32 thread-id of below thread)
1323 static HANDLE  hThread          = NULL;     // (Win32 handle of below thread)
1324 static HANDLE  hGotStdIn        = NULL;     // (signaled to get next char)
1325 static HANDLE  hStdInAvailable  = NULL;     // (signaled when char avail)
1326 static HANDLE  hStdIn           = NULL;     // (Win32 stdin handle)
1327 static char    chStdIn          = 0;        // (the next char read from stdin)
1328 
1329 // Win32 worker thread that reads from stdin. It needs to be a thread because the
1330 // "ReadFile" on stdin 'hangs' (blocks) until there's actually some data to read
1331 // or the handle is closed, whichever comes first. Note that we only read one char
1332 // at a time. This may perhaps be slightly inefficient but it makes for a simpler
1333 // implementation and besides, we don't really expect huge gobs of data coming in.
1334 
ReadStdInW32Thread(LPVOID lpParameter)1335 static DWORD WINAPI ReadStdInW32Thread( LPVOID lpParameter )
1336 {
1337     DWORD   dwBytesRead  = 0;
1338 
1339     UNREFERENCED( lpParameter );
1340 
1341     SET_THREAD_NAME ("ReadStdInW32Thread");
1342 
1343     for (;;)
1344     {
1345         WaitForSingleObject( hGotStdIn, INFINITE );
1346 
1347         if ( !ReadFile( hStdIn, &chStdIn, 1, &dwBytesRead, NULL ) )
1348         {
1349             char  szErrMsg[256];
1350             DWORD dwLastError = GetLastError();
1351 
1352             if ( ERROR_BROKEN_PIPE == dwLastError || sysblk.shutdown )
1353                 break; // (shutting down; time to exit)
1354 
1355             w32_w32errmsg( dwLastError, szErrMsg, sizeof(szErrMsg) );
1356 
1357             logmsg
1358             (
1359                 _("HHCDG008W ReadFile(hStdIn) failed! dwLastError=%d (0x%08.8X): %s\n")
1360 
1361                 ,dwLastError
1362                 ,dwLastError
1363                 ,szErrMsg
1364             );
1365 
1366             continue;
1367         }
1368 
1369         ASSERT( 1 == dwBytesRead );
1370 
1371         ResetEvent( hGotStdIn );
1372         SetEvent( hStdInAvailable );
1373     }
1374 
1375     return 0;
1376 }
1377 
1378 //////////////////////////////////////////////////////////////////////////////////////////
1379 // Function to read the next character from stdin. Similar to 'getch' but allows
1380 // one to specify a maximum timeout value and thus doesn't block forever. Returns
1381 // 0 or 1: 0 == timeout (zero characters read), 1 == success (one character read),
1382 // or -1 == error (pCharBuff NULL). The worker thread is created on the 1st call.
1383 
1384 DLL_EXPORT
w32_get_stdin_char(char * pCharBuff,int wait_millisecs)1385 int w32_get_stdin_char( char* pCharBuff, int wait_millisecs )
1386 {
1387     if ( !pCharBuff )
1388     {
1389         errno = EINVAL;
1390         return -1;
1391     }
1392 
1393     *pCharBuff = 0;
1394 
1395     if ( !dwThreadId )
1396     {
1397         hStdIn          = GetStdHandle( STD_INPUT_HANDLE );
1398         hStdInAvailable = CreateEvent(NULL,TRUE,FALSE,NULL);
1399         hGotStdIn       = CreateEvent(NULL,TRUE,TRUE,NULL); // (initially signaled)
1400 
1401         hThread = (HANDLE) _beginthreadex
1402         (
1403             NULL,               // pointer to security attributes
1404             64*1024,            // initial thread stack size in bytes
1405             ReadStdInW32Thread, // pointer to thread function
1406             NULL,               // argument for new thread
1407             0,                  // creation flags
1408             &dwThreadId         // pointer to receive thread ID
1409         );
1410 
1411         ASSERT(1
1412             &&  hStdIn           &&  INVALID_HANDLE_VALUE != hStdIn
1413             &&  hStdInAvailable  &&  INVALID_HANDLE_VALUE != hStdInAvailable
1414             &&  hGotStdIn        &&  INVALID_HANDLE_VALUE != hGotStdIn
1415             &&  hThread          &&  INVALID_HANDLE_VALUE != hThread
1416         );
1417     }
1418 
1419     if ( WAIT_TIMEOUT == WaitForSingleObject( hStdInAvailable, wait_millisecs ) )
1420         return 0;
1421 
1422     *pCharBuff = chStdIn;               // (save the next char right away)
1423     ResetEvent( hStdInAvailable );      // (reset OUR flag for next time)
1424     SetEvent( hGotStdIn );              // (allow thread to read next char)
1425     return 1;
1426 }
1427 
1428 /****************************************************************************************\
1429  *                                                                                      *
1430  *   (BEGIN)     S O C K E T    H A N D L I N G    F U N C T I O N S      (BEGIN)       *
1431  *                                                                                      *
1432 \****************************************************************************************/
1433 
1434 //               *****    VERY IMPORTANT SPECIAL NOTE!  *****
1435 
1436 //  Because "hmacros.h" #defines 'xxxx' to 'w32_xxxx' (to route the call to us),
1437 //  we now need to #undef it here to allow us to call the actual 'xxxx' function
1438 //  if we need to. All xxxx calls from here on will call the true Windows version.
1439 //  To call the w32_xxxx function instead, simply call it directly yourself.
1440 
1441 #undef  socket      // (so we can call the actual Windows version if we need to)
1442 #undef  select      // (so we can call the actual Windows version if we need to)
1443 #undef  fdopen      // (so we can call the actual Windows version if we need to)
1444 #undef  fwrite      // (so we can call the actual Windows version if we need to)
1445 #undef  fprintf     // (so we can call the actual Windows version if we need to)
1446 #undef  fclose      // (so we can call the actual Windows version if we need to)
1447 
1448 //////////////////////////////////////////////////////////////////////////////////////////
1449 /*
1450             INITIALIZE / DE-INITIALIZE SOCKETS PACKAGE
1451 
1452     The WSAStartup function must be the first Windows Sockets
1453     function called by an application or DLL. It allows an application
1454     or DLL to specify the version of Windows Sockets required
1455     and retrieve details of the specific Windows Sockets implementation.
1456     The application or DLL can only issue further Windows Sockets
1457     functions after successfully calling WSAStartup.
1458 
1459     Once an application or DLL has made a successful WSAStartup call,
1460     it can proceed to make other Windows Sockets calls as needed.
1461     When it has finished using the services of the WS2_32.DLL, the
1462     application or DLL must call WSACleanup to allow the WS2_32.DLL
1463     to free any resources for the application.
1464 
1465                        ***  IMPORTANT  ***
1466 
1467     An application must call one WSACleanup call for every successful
1468     WSAStartup call to allow third-party DLLs to make use of a WS2_32.DLL
1469     on behalf of an application. This means, for example, that if an
1470     application calls WSAStartup three times, it must call WSACleanup
1471     three times. The first two calls to WSACleanup do nothing except
1472     decrement an internal counter; the final WSACleanup call for the task
1473     does all necessary resource deallocation for the task.
1474 
1475 */
socket_init(void)1476 DLL_EXPORT int socket_init ( void )
1477 {
1478     /*
1479     In order to support future Windows Sockets implementations
1480     and applications that can have functionality differences
1481     from the current version of Windows Sockets, a negotiation
1482     takes place in WSAStartup.
1483 
1484     The caller of WSAStartup and the WS2_32.DLL indicate to each
1485     other the highest version that they can support, and each
1486     confirms that the other's highest version is acceptable.
1487 
1488     Upon entry to WSAStartup, the WS2_32.DLL examines the version
1489     requested by the application. If this version is equal to or
1490     higher than the lowest version supported by the DLL, the call
1491     succeeds and the DLL returns in wHighVersion the highest
1492     version it supports and in wVersion the minimum of its high
1493     version and wVersionRequested.
1494 
1495     The WS2_32.DLL then assumes that the application will use
1496     wVersion If the wVersion parameter of the WSADATA structure
1497     is unacceptable to the caller, it should call WSACleanup and
1498     either search for another WS2_32.DLL or fail to initialize.
1499     */
1500 
1501     WSADATA  sSocketPackageInfo;
1502     WORD     wVersionRequested    = MAKEWORD(1,1);
1503 
1504     return
1505     (
1506         WSAStartup( wVersionRequested, &sSocketPackageInfo ) == 0 ?
1507         0 : -1
1508     );
1509 }
1510 
1511 //////////////////////////////////////////////////////////////////////////////////////////
1512 // De-initialize Windows Sockets package...
1513 
socket_deinit(void)1514 DLL_EXPORT int socket_deinit ( void )
1515 {
1516     // PROGRAMMING NOTE: regardless of the comments in the socket_init function above
1517     // regarding the need to always call WSACleanup for every WSAStartup call, it's not
1518     // really necessary in our particular case because we're not designed to continue
1519     // running after shutting down socket handling (which is really what the WSACleanup
1520     // function is designed for). That is to say, the WSACleanup function is designed
1521     // so a program can inform the operating system that it's finished using the socket
1522     // DLL (thus allowing it to free up all of the resources currently being used by
1523     // the process and allow the DLL to be unmapped from the process'es address space)
1524     // but not exit (i.e. continue running). In our case however, our entire process
1525     // is exiting (i.e. we're NOT going to continue running), and when a process exits,
1526     // all loaded DLLs are automatically notified by the operating system to allow them
1527     // to automatically free all resources for the process in question. Thus since we
1528     // are exiting we don't really need to call WSACleanup since whatever "cleanup" it
1529     // would do is going to get done *anyway* by virtue of our going away. Besides that,
1530     // WSACleanup appears to "hang" when it's called while socket resources are still
1531     // being used (which is true in our case since we're not designed (yet!) to cleanly
1532     // shutdown all of our socket-using threads before exiting). THUS (sorry to ramble)
1533     // we in fact probably SHOULDN'T be calling WSACleanup here (and besides, bypassing
1534     // it seems to resolve our hangs at shutdown whenever there's still a thread running
1535     // that doing sockets shit).
1536 
1537 #if 0 // (see above)
1538     return
1539     (
1540         WSACleanup() == 0 ?
1541         0 : -1
1542     );
1543 #else
1544     return 0;       // (not needed? see PROGRAMING NOTE above!)
1545 #endif
1546 }
1547 
1548 //////////////////////////////////////////////////////////////////////////////////////////
1549 // Retrieve unique host id
1550 
gethostid(void)1551 DLL_EXPORT long gethostid( void )
1552 {
1553     char             szHostName[ WSADESCRIPTION_LEN ];
1554     struct hostent*  pHostent = NULL;
1555     return (gethostname( szHostName, sizeof(szHostName) ) == 0
1556         && (pHostent = gethostbyname( szHostName )) != NULL) ?
1557         (long)(*(pHostent->h_addr)) : 0;
1558 }
1559 
1560 //////////////////////////////////////////////////////////////////////////////////////////
1561 
w32_socket(int af,int type,int protocol)1562 DLL_EXPORT int w32_socket( int af, int type, int protocol )
1563 {
1564     ///////////////////////////////////////////////////////////////////////////////
1565     //
1566     //                         PROGRAMMING NOTE
1567     //
1568     // We need to request that all sockets we create [via the 'socket()' API]
1569     // be created WITHOUT the "OVERLAPPED" attribute so that our 'fgets()', etc,
1570     // calls (which end up calling the "ReadFile()", etc, Win32 API) work as
1571     // expected.
1572     //
1573     // Note that the "overlapped" attribute for a socket is completely different
1574     // from its non-blocking vs. blocking mode. All sockets are created, by default,
1575     // as blocking mode sockets, but WITH the "overlapped" attribute set. Thus all
1576     // sockets are actually asynchonous by default. (The winsock DLL(s) handle the
1577     // blocking mode separately programmatically internally even though the socket
1578     // is actually an asynchronous Win32 "file").
1579     //
1580     // Thus we need to specifically request that our [blocking mode] sockets be
1581     // created WITHOUT the Win32 "OVERLAPPED" attribute (so that when we call the
1582     // C runtime read/write/etc functions, the C runtime's ReadFile/WriteFile calls
1583     // work (which they don't (they fail with error 87 ERROR_INVALID_PARAMETER)
1584     // when called on a Win32 "file" handle created with the OVERLAPPED attribute
1585     // but without an OVERLAPPED structure pased in the ReadFile/WriteFile call
1586     // (which the C runtime functions don't use)). You follow?).
1587     //
1588     // See KB (Knowledge Base) article 181611 for more information:
1589     //
1590     //        "Socket overlapped I/O versus blocking/non-blocking mode"
1591     //            (http://support.microsoft.com/?kbid=181611)
1592     //
1593     //  ---------------------------------------------------------------------
1594     //   "However, you can call the setsockopt API with SO_OPENTYPE option
1595     //   on any socket handle -- including an INVALID_SOCKET -- to change
1596     //   the overlapped attributes for all successive socket calls in the
1597     //   same thread. The default SO_OPENTYPE option value is 0, which sets
1598     //   the overlapped attribute. All non-zero option values make the socket
1599     //   synchronous and make it so that you cannot use a completion function."
1600     //  ---------------------------------------------------------------------
1601     //
1602     // The documentation for the "SOL_SOCKET" SO_OPENTYPE socket option contains
1603     // the folowing advice/warning however:
1604     //
1605     //
1606     //    "Once set, subsequent sockets created will be non-overlapped.
1607     //     This option should not be used; use WSASocket and leave the
1608     //     WSA_FLAG_OVERLAPPED turned off."
1609     //
1610     //
1611     // So we'll use WSASocket instead as suggested.
1612     //
1613     ///////////////////////////////////////////////////////////////////////////////
1614 
1615     // The last parameter is where one would normally specify the WSA_FLAG_OVERLAPPED
1616     // option, but we're specifying '0' because we want our sockets to be synchronous
1617     // and not asynchronous so the C runtime functions can successfully perform ReadFile
1618     // and WriteFile on them...
1619 
1620     SOCKET sock = WSASocket( af, type, protocol, NULL, 0, 0 );
1621 
1622     if ( INVALID_SOCKET == sock )
1623     {
1624         errno = WSAGetLastError();
1625         sock = (SOCKET) -1;
1626     }
1627 
1628     return ( (int) sock );
1629 }
1630 
1631 //////////////////////////////////////////////////////////////////////////////////////////
1632 // Determine whether a file descriptor is a socket or not...
1633 // (returns 1==true if it's a socket, 0==false otherwise)
1634 
socket_is_socket(int sfd)1635 DLL_EXPORT int socket_is_socket( int sfd )
1636 {
1637     u_long dummy;
1638     return WSAHtonl( (SOCKET) sfd, 666, &dummy ) == 0 ? 1 : 0;
1639 }
1640 
1641 //////////////////////////////////////////////////////////////////////////////////////////
1642 // Set the SO_KEEPALIVE option and timeout values for a
1643 // socket connection to detect when client disconnects */
1644 
socket_keepalive(int sfd,int idle_time,int probe_interval,int probe_count)1645 DLL_EXPORT void socket_keepalive( int sfd, int idle_time, int probe_interval, int probe_count )
1646 {
1647     DWORD   dwBytesReturned;            // (not used)
1648 
1649     struct tcp_keepalive  ka;
1650 
1651     ka.onoff              = TRUE;
1652     ka.keepalivetime      = idle_time       * 1000;
1653     ka.keepaliveinterval  = probe_interval  * 1000;
1654     UNREFERENCED(probe_count);
1655 
1656     // It either works or it doesn't <shrug>
1657 
1658     // PROGRAMMING NOTE: the 'dwBytesReturned' value must apparently always be
1659     // specified in order for this call to work at all. If you don't specify it,
1660     // even though the call succeeds (does not return an error), the automatic
1661     // keep-alive polling does not occur!
1662 
1663     if (0 != WSAIoctl
1664     (
1665         (SOCKET)sfd,                    // [in]  Descriptor identifying a socket
1666         SIO_KEEPALIVE_VALS,             // [in]  Control code of operation to perform
1667         &ka,                            // [in]  Pointer to the input buffer
1668         sizeof(ka),                     // [in]  Size of the input buffer, in bytes
1669         NULL,                           // [out] Pointer to the output buffer
1670         0,                              // [in]  Size of the output buffer, in bytes
1671         &dwBytesReturned,               // [out] Pointer to actual number of bytes of output
1672         NULL,                           // [in]  Pointer to a WSAOVERLAPPED structure
1673                                         //       (ignored for nonoverlapped sockets)
1674         NULL                            // [in]  Pointer to the completion routine called
1675                                         //       when the operation has been completed
1676                                         //       (ignored for nonoverlapped sockets)
1677     ))
1678     {
1679         DWORD dwLastError = WSAGetLastError();
1680         TRACE("*** WSAIoctl(SIO_KEEPALIVE_VALS) failed; rc %d: %s\n",
1681             dwLastError, w32_strerror(dwLastError) );
1682         ASSERT(1); // (in case we're debugging)
1683     }
1684 }
1685 
1686 //////////////////////////////////////////////////////////////////////////////////////////
1687 // The inet_aton() function converts the specified string,
1688 // in the Internet standard dot notation, to a network address,
1689 // and stores the address in the structure provided.
1690 //
1691 // The inet_aton() function returns 1 if the address is successfully converted,
1692 // or 0 if the conversion failed.
1693 
1694 #if !defined( HAVE_INET_ATON )
1695 
inet_aton(const char * cp,struct in_addr * addr)1696 DLL_EXPORT int inet_aton( const char* cp, struct in_addr* addr )
1697 {
1698     // Return success as long as both args are not NULL *and*
1699     // the result is not INADDR_NONE (0xFFFFFFFF), -OR- if it
1700     // is [INADDR_NONE], [we return success] if that is the
1701     // actual expected value of the conversion...
1702 
1703     return
1704     (
1705         (1
1706             &&  cp      // (must not be NULL)
1707             &&  addr    // (must not be NULL)
1708             &&  (0
1709                     ||  INADDR_NONE != ( addr->s_addr = inet_addr( cp ) )
1710                     ||  strcmp( cp, "255.255.255.255" ) == 0
1711                 )
1712         )
1713         ? 1 : 0         //  1 == success,   0 == failure
1714     );
1715 }
1716 
1717 #endif // !defined( HAVE_INET_ATON )
1718 
1719 //////////////////////////////////////////////////////////////////////////////////////////
1720 // All internal calls to Windows's 'FD_ISSET' or 'FD_SET' macros MUST use the below
1721 // macros instead and NOT the #defined 'FD_ISSET' or 'FD_SET' macros! The #defined
1722 // 'FD_ISSET' and 'FD_SET' macros are coded (in hmacros.h) to route the calls to the
1723 // internal 'w32_FD_SET' and 'w32_FD_ISSET' functions further below!
1724 
1725 #define  ORIGINAL_FD_ISSET    __WSAFDIsSet
1726 
1727 #define  ORIGINAL_FD_SET( fd, pSet )                      \
1728     do                                                    \
1729     {                                                     \
1730         unsigned int i;                                   \
1731         for (i=0; i < ((fd_set*)(pSet))->fd_count; i++)   \
1732             if (((fd_set*)(pSet))->fd_array[i] == (fd))   \
1733                 break;                                    \
1734         if (i == ((fd_set*)(pSet))->fd_count              \
1735             && ((fd_set*)(pSet))->fd_count < FD_SETSIZE)  \
1736         {                                                 \
1737             ((fd_set*)(pSet))->fd_array[i] = (fd);        \
1738             ((fd_set*)(pSet))->fd_count++;                \
1739         }                                                 \
1740     }                                                     \
1741     while (0)
1742 
1743 //////////////////////////////////////////////////////////////////////////////////////////
1744 // FD_SET:   (   FD_SET(fd,pSet)   )
1745 //
1746 // Will need to override and route to  "w32_FD_SET"
1747 //
1748 // Do '_get_osfhandle'.
1749 //
1750 // If '_get_osfhandle' error, then it's either already a HANDLE (SOCKET probably),
1751 // or else a bona fide invalid file descriptor or invalid SOCKET handle, so do a
1752 // normal FD_SET.
1753 //
1754 // Otherwise ('_get_osfhandle' success), then it WAS a file descriptor
1755 // but we now have it's HANDLE, so do the FD_SET on the returned HANDLE.
1756 //
1757 // Thus we ensure all entries added to set are HANDLES
1758 // (or SOCKETS which are considered to be HANDLES too)
1759 
w32_FD_SET(int fd,fd_set * pSet)1760 DLL_EXPORT void w32_FD_SET( int fd, fd_set* pSet )
1761 {
1762     SOCKET hSocket;
1763 
1764     if (0
1765         || socket_is_socket( fd )
1766         || (SOCKET) -1 == ( hSocket = (SOCKET) _get_osfhandle( fd ) )
1767     )
1768         hSocket = (SOCKET) fd;
1769 
1770     ORIGINAL_FD_SET( hSocket, pSet );   // (add HANDLE/SOCKET to specified set)
1771 }
1772 
1773 //////////////////////////////////////////////////////////////////////////////////////////
1774 // FD_ISSET:   (   FD_ISSET(fd,pSet)   )
1775 //
1776 // Will need to override and route to  "w32_FD_ISSET".
1777 //
1778 // (Note: all entries in sets should already be HANDLES
1779 //   due to previously mentioned FD_SET override)
1780 //
1781 // If socket, do normal FD_ISSET.
1782 // Otherwise do our IsEventSet().
1783 
w32_FD_ISSET(int fd,fd_set * pSet)1784 DLL_EXPORT int w32_FD_ISSET( int fd, fd_set* pSet )
1785 {
1786     int     i;
1787     HANDLE  hFile;
1788 
1789     if ( socket_is_socket( fd ) )                       // (is it already a SOCKET?)
1790         return ORIGINAL_FD_ISSET( (SOCKET)fd, pSet );   // (yes, do normal FD_ISSET)
1791 
1792     hFile = (HANDLE) _get_osfhandle( fd );
1793 
1794     for ( i=0; i < (int)pSet->fd_count; i++ )
1795         if ( pSet->fd_array[i] == (SOCKET) hFile )      // (is this the file?)
1796             return IsEventSet( hFile );                 // (yes, return whether ready (signaled) or not)
1797 
1798     return 0;   // (file not a member of the specified set)
1799 }
1800 //////////////////////////////////////////////////////////////////////////////////////////
1801 // Win32 "socketpair()" and "pipe()" functionality...
1802 
1803 #if !defined( HAVE_SOCKETPAIR )
1804 
socketpair(int domain,int type,int protocol,int socket_vector[2])1805 DLL_EXPORT int socketpair( int domain, int type, int protocol, int socket_vector[2] )
1806 {
1807     // PROGRAMMING NOTE: we do NOT support type AF_UNIX socketpairs on Win32.
1808     //                   we *ONLY* support AF_INET, IPPROTO_IP, SOCK_STREAM.
1809 
1810     SOCKET temp_listen_socket;
1811     struct sockaddr_in  localhost_addr;
1812     int    len = sizeof(localhost_addr);
1813 
1814     /* FIXME ISW ? In some situations, it seems the sockaddr_in structure */
1815     /*         returned by getsockname() isn't appropriate for use        */
1816     /*         by connect(). We therefore use another sockaddr_in for the */
1817     /*         sole purpose of fetching the automatic port number issued  */
1818     /*         during the bind() operation.                               */
1819     /* NOTE : This is a workaround. The actual root cause for this        */
1820     /*        problem is presently unknown because it is hard to reproduce*/
1821 
1822     struct sockaddr_in tempaddr;
1823     int talen = sizeof(tempaddr);
1824 
1825     // Technique: create a pair of sockets bound to each other by first creating a
1826     // temporary listening socket bound to the localhost loopback address (127.0.0.1)
1827     // and then having the other socket connect to it...
1828 
1829     //  "Upon successful completion, 0 shall be returned; otherwise,
1830     //   -1 shall be returned and errno set to indicate the error."
1831 
1832     if ( AF_INET     != domain   ) { errno = WSAEAFNOSUPPORT;    return -1; }
1833     if ( SOCK_STREAM != type     ) { errno = WSAEPROTONOSUPPORT; return -1; }
1834     if ( IPPROTO_IP  != protocol ) { errno = WSAEPROTOTYPE;      return -1; }
1835 
1836     socket_vector[0] = socket_vector[1] = INVALID_SOCKET;
1837 
1838     if ( INVALID_SOCKET == (temp_listen_socket = socket( AF_INET, SOCK_STREAM, 0 )) )
1839     {
1840         errno = (int)WSAGetLastError();
1841         return -1;
1842     }
1843 
1844     memset( &localhost_addr, 0, len   );
1845     memset( &tempaddr,       0, talen );
1846 
1847     localhost_addr.sin_family       = AF_INET;
1848     localhost_addr.sin_port         = htons( 0 );
1849     localhost_addr.sin_addr.s_addr  = htonl( INADDR_LOOPBACK );
1850 
1851     if (0
1852         || SOCKET_ERROR   == bind( temp_listen_socket, (SOCKADDR*) &localhost_addr, len )
1853         || SOCKET_ERROR   == listen( temp_listen_socket, 1 )
1854         || SOCKET_ERROR   == getsockname( temp_listen_socket, (SOCKADDR*) &tempaddr, &talen )
1855         || INVALID_SOCKET == (SOCKET)( socket_vector[1] = socket( AF_INET, SOCK_STREAM, 0 ) )
1856     )
1857     {
1858         int nLastError = (int)WSAGetLastError();
1859         closesocket( temp_listen_socket );
1860         errno = nLastError;
1861         return -1;
1862     }
1863 
1864     /* Get the temporary port number assigned automatically */
1865     /* by bind(127.0.0.1/0)                                 */
1866 
1867     localhost_addr.sin_port = tempaddr.sin_port;
1868 
1869     if (0
1870         || SOCKET_ERROR   == connect( socket_vector[1], (SOCKADDR*) &localhost_addr, len )
1871         || INVALID_SOCKET == (SOCKET)( socket_vector[0] = accept( temp_listen_socket, (SOCKADDR*) &localhost_addr, &len ) )
1872     )
1873     {
1874         int nLastError = (int)WSAGetLastError();
1875         closesocket( socket_vector[1] );
1876                      socket_vector[1] = INVALID_SOCKET;
1877         closesocket( temp_listen_socket );
1878         errno = nLastError;
1879         return -1;
1880     }
1881 
1882     closesocket( temp_listen_socket );
1883     return 0;
1884 }
1885 
1886 #endif // !defined( HAVE_SOCKETPAIR )
1887 
1888 //////////////////////////////////////////////////////////////////////////////////////////
1889 // Set socket to blocking or non-blocking mode...
1890 
socket_set_blocking_mode(int sfd,int blocking_mode)1891 DLL_EXPORT int socket_set_blocking_mode( int sfd, int blocking_mode )
1892 {
1893     u_long non_blocking_option = !blocking_mode;
1894 
1895     if ( SOCKET_ERROR != ioctlsocket( sfd, FIONBIO, &non_blocking_option) )
1896         return 0;
1897 
1898     switch (WSAGetLastError())
1899     {
1900     case WSAENETDOWN: errno = ENETDOWN; break;
1901     case WSAENOTSOCK: errno = ENOTSOCK; break;
1902     case WSAEFAULT:   errno = EFAULT;   break;
1903     default:          errno = ENOSYS;   break;
1904     }
1905 
1906     return -1;
1907 }
1908 
1909 //////////////////////////////////////////////////////////////////////////////////////////
1910 // select:
1911 //
1912 // Will need to override and route to  "w32_select"
1913 //
1914 // w32_select:
1915 //
1916 // Check if all entries (in all sets) are sockets or not
1917 //
1918 // (Note: all entries in sets should already be HANDLES
1919 //   due to previously mentioned FD_SET override)
1920 //
1921 // If all sockets, then do normal 'select'.
1922 //
1923 // If all non-sockets, then do 'WaitForMultipleObjects' instead.
1924 //
1925 // if mixed, then EBADF (one or more bad file descriptors)
1926 
1927 static void SelectSet       // (helper function)
1928 (
1929     fd_set*  pSet,
1930     BOOL*    pbSocketFound,
1931     BOOL*    pbNonSocketFound,
1932     DWORD*   pdwHandles,
1933     HANDLE*  parHandles
1934 );
1935 
w32_select(int nfds,fd_set * pReadSet,fd_set * pWriteSet,fd_set * pExceptSet,const struct timeval * pTimeVal,const char * pszSourceFile,int nLineNumber)1936 DLL_EXPORT int w32_select
1937 (
1938     int                    nfds,
1939     fd_set*                pReadSet,
1940     fd_set*                pWriteSet,
1941     fd_set*                pExceptSet,
1942     const struct timeval*  pTimeVal,
1943     const char*            pszSourceFile,
1944     int                    nLineNumber
1945 )
1946 {
1947     HANDLE   arHandles[ 2 * FD_SETSIZE ];   // (max read + write set size)
1948     DWORD    dwHandles                 = 0;
1949 
1950     BOOL     bSocketFound              = FALSE;
1951     BOOL     bNonSocketFound           = FALSE;
1952 
1953     BOOL     bExceptSetSocketFound     = FALSE;
1954     BOOL     bExceptSetNonSocketFound  = FALSE;
1955 
1956     DWORD    dwWaitMilliSeconds        = 0;
1957     DWORD    dwWaitRetCode             = 0;
1958 
1959     UNREFERENCED( nfds );
1960 
1961     // Quick check for 'timer.c' call wherein all passed fd_set pointers are NULL...
1962 
1963     if ( !pReadSet && !pWriteSet && !pExceptSet )
1964     {
1965         ASSERT( pTimeVal );     // (why else would we be called?!)
1966 
1967         if ( !pTimeVal )
1968         {
1969             logmsg( "** Win32 porting error: invalid call to 'w32_select' from %s(%d): NULL args\n",
1970                 pszSourceFile, nLineNumber );
1971             errno = EINVAL;
1972             return -1;
1973         }
1974 
1975         // Sleep for the specified time period...
1976 
1977         if ( !pTimeVal->tv_sec && !pTimeVal->tv_usec )
1978             sched_yield();
1979         else
1980         {
1981             if ( pTimeVal->tv_sec )
1982                 sleep( pTimeVal->tv_sec );
1983 
1984             if ( pTimeVal->tv_usec )
1985                 usleep( pTimeVal->tv_usec );
1986         }
1987 
1988         return 0;
1989     }
1990 
1991     // Check for mixed sets and build HANDLE array...
1992     // (Note: we don't support except sets for non-sockets)
1993 
1994     SelectSet( pReadSet,   &bSocketFound,          &bNonSocketFound,          &dwHandles, arHandles );
1995     SelectSet( pWriteSet,  &bSocketFound,          &bNonSocketFound,          &dwHandles, arHandles );
1996     SelectSet( pExceptSet, &bExceptSetSocketFound, &bExceptSetNonSocketFound, NULL,       NULL      );
1997 
1998     if (0
1999         || ( bSocketFound    && ( bNonSocketFound || bExceptSetNonSocketFound ) )
2000         || ( bNonSocketFound && ( bSocketFound    || bExceptSetSocketFound    ) )
2001     )
2002     {
2003         logmsg( "** Win32 porting error: invalid call to 'w32_select' from %s(%d): mixed set(s)\n",
2004             pszSourceFile, nLineNumber );
2005         errno = EBADF;
2006         return -1;
2007     }
2008 
2009     if ( bExceptSetNonSocketFound )
2010     {
2011         logmsg( "** Win32 porting error: invalid call to 'w32_select' from %s(%d): non-socket except set\n",
2012             pszSourceFile, nLineNumber );
2013         errno = EBADF;
2014         return -1;
2015     }
2016 
2017     // If all SOCKETs, do a normal 'select'...
2018 
2019     if ( bSocketFound )
2020         return select( nfds, pReadSet, pWriteSet, pExceptSet, pTimeVal );
2021 
2022     // Otherwise they're all HANDLEs, so do a WaitForMultipleObjects...
2023 
2024     if ( !pTimeVal )
2025         dwWaitMilliSeconds = INFINITE;
2026     else
2027     {
2028         dwWaitMilliSeconds  = (   pTimeVal->tv_sec          * 1000 );
2029         dwWaitMilliSeconds += ( ( pTimeVal->tv_usec + 500 ) / 1000 );
2030     }
2031 
2032     if ( !dwHandles )
2033     {
2034         // Just sleep for the specified interval...
2035         Sleep( dwWaitMilliSeconds );
2036         return 0;   // (timeout)
2037     }
2038 
2039     dwWaitRetCode = WaitForMultipleObjects( dwHandles, arHandles, FALSE, dwWaitMilliSeconds );
2040 
2041     if ( WAIT_TIMEOUT == dwWaitRetCode )
2042         return 0;
2043 
2044     // NOTE: we don't support returning the actual total number of handles
2045     // that are ready; instead, we return 1 as long as ANY handle is ready...
2046 
2047     if ( dwWaitRetCode >= WAIT_OBJECT_0 && dwWaitRetCode < ( WAIT_OBJECT_0 + dwHandles ) )
2048         return 1;
2049 
2050     // Something went wrong...
2051 
2052     ASSERT( FALSE );    // (in case this is a debug build)
2053     errno = ENOSYS;     // (system call failure)
2054     return -1;
2055 }
2056 
2057 //////////////////////////////////////////////////////////////////////////////////////////
2058 // internal helper function to pre-process a 'select' set...
2059 
SelectSet(fd_set * pSet,BOOL * pbSocketFound,BOOL * pbNonSocketFound,DWORD * pdwHandles,HANDLE * parHandles)2060 static void SelectSet
2061 (
2062     fd_set*  pSet,
2063     BOOL*    pbSocketFound,
2064     BOOL*    pbNonSocketFound,
2065     DWORD*   pdwHandles,
2066     HANDLE*  parHandles
2067 )
2068 {
2069     unsigned int i;
2070 
2071     if ( !pSet ) return;
2072 
2073     for (i=0; i < pSet->fd_count && i < FD_SETSIZE; i++)
2074     {
2075         if ( socket_is_socket( pSet->fd_array[i] ) )
2076         {
2077             *pbSocketFound = TRUE;
2078             continue;
2079         }
2080 
2081         *pbNonSocketFound = TRUE;
2082 
2083         // If parHandles is NULL, then we're
2084         // only interested in the BOOLean flags...
2085 
2086         if ( !parHandles ) continue;
2087         ASSERT( *pdwHandles < ( 2 * FD_SETSIZE ) );
2088         *( parHandles + *pdwHandles ) = (HANDLE) pSet->fd_array[i];
2089         *pdwHandles++;
2090     }
2091 }
2092 
2093 //////////////////////////////////////////////////////////////////////////////////////////
2094 
2095 struct MODE_TRANS
2096 {
2097     const char*  old_mode;
2098     const char*  new_mode;
2099     int          new_flags;
2100 };
2101 
2102 typedef struct MODE_TRANS MODE_TRANS;
2103 
w32_fdopen(int their_fd,const char * their_mode)2104 DLL_EXPORT FILE* w32_fdopen( int their_fd, const char* their_mode )
2105 {
2106     int new_fd, new_flags = 0;
2107     const char* new_mode = NULL;
2108     MODE_TRANS* pModeTransTab;
2109     MODE_TRANS  mode_trans_tab[] =
2110     {
2111         { "r",   "rbc",  _O_RDONLY                        | _O_BINARY },
2112         { "r+",  "r+bc", _O_RDWR                          | _O_BINARY },
2113         { "r+b", "r+bc", _O_RDWR                          | _O_BINARY },
2114         { "rb+", "r+bc", _O_RDWR                          | _O_BINARY },
2115 
2116         { "w",   "wbc",  _O_WRONLY | _O_CREAT | _O_TRUNC  | _O_BINARY },
2117         { "w+",  "w+bc", _O_RDWR   | _O_CREAT | _O_TRUNC  | _O_BINARY },
2118         { "w+b", "w+bc", _O_RDWR   | _O_CREAT | _O_TRUNC  | _O_BINARY },
2119         { "wb+", "w+bc", _O_RDWR   | _O_CREAT | _O_TRUNC  | _O_BINARY },
2120 
2121         { "a",   "abc",  _O_WRONLY | _O_CREAT | _O_APPEND | _O_BINARY },
2122         { "a+",  "a+bc", _O_RDWR   | _O_CREAT | _O_APPEND | _O_BINARY },
2123         { "a+b", "a+bc", _O_RDWR   | _O_CREAT | _O_APPEND | _O_BINARY },
2124         { "ab+", "a+bc", _O_RDWR   | _O_CREAT | _O_APPEND | _O_BINARY },
2125 
2126         { NULL, NULL, 0 }
2127     };
2128 
2129     ASSERT( their_mode );
2130 
2131     // (we're only interested in socket calls)
2132 
2133     if ( !socket_is_socket( their_fd ) )
2134         return _fdopen( their_fd, their_mode );
2135 
2136     // The passed "file descriptor" is actually a SOCKET handle...
2137 
2138     // Translate their original mode to our new mode
2139     // and determine what flags we should use in our
2140     // call to _open_osfhandle()...
2141 
2142     if ( their_mode )
2143         for (pModeTransTab = mode_trans_tab; pModeTransTab->old_mode; pModeTransTab++)
2144             if ( strcmp( their_mode, pModeTransTab->old_mode ) == 0 )
2145             {
2146                 new_mode  = pModeTransTab->new_mode;
2147                 new_flags = pModeTransTab->new_flags;
2148                 break;
2149             }
2150 
2151     if ( !new_mode )
2152     {
2153         errno = EINVAL;
2154         return NULL;
2155     }
2156 
2157     // Allocate a CRT file descriptor integer for this SOCKET...
2158 
2159     if ( ( new_fd = _open_osfhandle( their_fd, new_flags ) ) < 0 )
2160         return NULL;  // (errno already set)
2161 
2162     // Now we should be able to do the actual fdopen...
2163 
2164     return _fdopen( new_fd, new_mode );
2165 }
2166 
2167 //////////////////////////////////////////////////////////////////////////////////////////
2168 // fwrite
2169 
w32_fwrite(const void * buff,size_t size,size_t count,FILE * stream)2170 DLL_EXPORT size_t w32_fwrite ( const void* buff, size_t size, size_t count, FILE* stream )
2171 {
2172     int rc;
2173     SOCKET sock;
2174 
2175     ASSERT( buff && (size * count) && stream );
2176 
2177     {
2178         int sd = fileno( stream );
2179         if ( !socket_is_socket( sd ) )
2180             return fwrite( buff, size, count, stream );
2181         sock = (SOCKET) _get_osfhandle( sd );
2182     }
2183 
2184     if ( ( rc = send( sock, buff, (int)(size * count), 0 ) ) == SOCKET_ERROR )
2185     {
2186         errno = WSAGetLastError();
2187         return -1;
2188     }
2189     return ( rc / size );
2190 }
2191 
2192 //////////////////////////////////////////////////////////////////////////////////////////
2193 // fprintf
2194 
w32_fprintf(FILE * stream,const char * format,...)2195 DLL_EXPORT int w32_fprintf( FILE* stream, const char* format, ... )
2196 {
2197     char* buff = NULL;
2198     int bytes = 0, rc;
2199     va_list vl;
2200     SOCKET sock;
2201 
2202     ASSERT( stream && format );
2203 
2204     va_start( vl, format );
2205 
2206     {
2207         int sd = fileno( stream );
2208         if ( !socket_is_socket( sd ) )
2209             return vfprintf( stream, format, vl );
2210         sock = (SOCKET) _get_osfhandle( sd );
2211     }
2212 
2213     do
2214     {
2215         free( buff );
2216 
2217         if ( !( buff = malloc( bytes += 1000 ) ) )
2218         {
2219             errno = ENOMEM;
2220             return -1;
2221         }
2222     }
2223     while ( ( rc = vsnprintf( buff, bytes, format, vl ) ) < 0 );
2224 
2225     rc = send( sock, buff, bytes = rc, 0 );
2226 
2227     free( buff );
2228 
2229     if ( SOCKET_ERROR == rc )
2230     {
2231         errno = WSAGetLastError();
2232         return -1;
2233     }
2234     return rc;
2235 }
2236 
2237 //////////////////////////////////////////////////////////////////////////////////////////
2238 // fclose
2239 
w32_fclose(FILE * stream)2240 DLL_EXPORT int w32_fclose ( FILE* stream )
2241 {
2242     int sd, rc, err;
2243     SOCKET sock;
2244 
2245     ASSERT( stream );
2246 
2247     sd = fileno( stream );
2248 
2249     if ( !socket_is_socket( sd ) )
2250         return fclose( stream );
2251 
2252     // (SOCKETs get special handling)
2253 
2254     sock = (SOCKET) _get_osfhandle( sd );
2255 
2256     // Flush the data, close the socket, then deallocate
2257     // the crt's file descriptor for it by calling fclose.
2258 
2259     // Note that the fclose will fail since the closesocket
2260     // has already closed the o/s handle, but we don't care;
2261     // all we care about is the crt deallocating its file
2262     // descriptor for it...
2263 
2264     fflush( stream );               // (flush buffers)
2265     shutdown( sock, SD_BOTH);       // (try to be graceful)
2266     rc  = closesocket( sock );      // (close socket)
2267     err = WSAGetLastError();        // (save retcode)
2268     fclose( stream );               // (ignore likely error)
2269 
2270     if ( SOCKET_ERROR == rc )       // (closesocket error?)
2271     {
2272         errno = err;                // (yes, return error)
2273         return EOF;                 // (failed)
2274     }
2275     return 0;                       // (success)
2276 }
2277 
2278 /****************************************************************************************\
2279            (END)           (Socket Handling Functions)            (END)
2280 \****************************************************************************************/
2281 
2282 // Create a child process with redirected standard file HANDLEs...
2283 //
2284 // For more information, see KB article 190351 "HOWTO: Spawn Console Processes
2285 // with Redirected Standard Handles" http://support.microsoft.com/?kbid=190351
2286 
2287 #define  PIPEBUFSIZE              (1024)            // SHOULD be big enough!!
2288 #define  HOLDBUFSIZE              (PIPEBUFSIZE*2)   // twice pipe buffer size
2289 #define  PIPE_THREAD_STACKSIZE    (64*1024)         // 64K should be plenty!!
2290 
2291 #define  MSG_TRUNCATED_MSG        "...(truncated)\n"
2292 
2293 char*    buffer_overflow_msg      = NULL;   // used to trim received message
2294 size_t   buffer_overflow_msg_len  = 0;      // length of above truncation msg
2295 
2296 //////////////////////////////////////////////////////////////////////////////////////////
2297 // Fork control...
2298 
2299 typedef struct _PIPED_PROCESS_CTL
2300 {
2301     char*               pszBuffer;          // ptr to current logmsgs buffer
2302     size_t              nAllocSize;         // allocated size of logmsgs buffer
2303     size_t              nStrLen;            // amount used - 1 (because of NULL)
2304     CRITICAL_SECTION    csLock;             // lock for accessing above buffer
2305 }
2306 PIPED_PROCESS_CTL;
2307 
2308 typedef struct _PIPED_THREAD_CTL
2309 {
2310     HANDLE              hStdXXX;            // stdout or stderr handle
2311     PIPED_PROCESS_CTL*  pPipedProcessCtl;   // ptr to process control
2312 }
2313 PIPED_THREAD_CTL;
2314 
2315 //////////////////////////////////////////////////////////////////////////////////////////
2316 // "Poor man's" fork...
2317 
2318 UINT WINAPI w32_read_piped_process_stdxxx_output_thread ( void* pThreadParm ); // (fwd ref)
2319 
w32_poor_mans_fork(char * pszCommandLine,int * pnWriteToChildStdinFD)2320 DLL_EXPORT pid_t w32_poor_mans_fork ( char* pszCommandLine, int* pnWriteToChildStdinFD )
2321 {
2322     HANDLE hChildReadFromStdin;         // child's stdin  pipe HANDLE (inherited from us)
2323     HANDLE hChildWriteToStdout;         // child's stdout pipe HANDLE (inherited from us)
2324     HANDLE hChildWriteToStderr;         // child's stderr pipe HANDLE (inherited from us)
2325 
2326     HANDLE hOurWriteToStdin;            // our HANDLE to write-end of child's stdin pipe
2327     HANDLE hOurReadFromStdout;          // our HANDLE to read-end of child's stdout pipe
2328     HANDLE hOurReadFromStderr;          // our HANDLE to read-end of child's stderr pipe
2329 
2330     HANDLE hOurProcess;                 // (temporary for creating pipes)
2331     HANDLE hPipeReadHandle;             // (temporary for creating pipes)
2332     HANDLE hPipeWriteHandle;            // (temporary for creating pipes)
2333 
2334     HANDLE hWorkerThread;               // (worker thread to monitor child's pipe)
2335     DWORD  dwThreadId;                  // (worker thread to monitor child's pipe)
2336 
2337     STARTUPINFO          siStartInfo;   // (info passed to CreateProcess)
2338     PROCESS_INFORMATION  piProcInfo;    // (info returned by CreateProcess)
2339     SECURITY_ATTRIBUTES  saAttr;        // (suckurity? we dunt need no stinkin suckurity!)
2340 
2341     char* pszNewCommandLine;            // (because we build pvt copy for CreateProcess)
2342     BOOL  bSuccess;                     // (work)
2343     int   rc;                           // (work)
2344     size_t len;                         // (work)
2345 
2346     PIPED_PROCESS_CTL*  pPipedProcessCtl        = NULL;
2347     PIPED_THREAD_CTL*   pPipedStdOutThreadCtl   = NULL;
2348     PIPED_THREAD_CTL*   pPipedStdErrThreadCtl   = NULL;
2349 
2350     //////////////////////////////////////////////////
2351     // Initialize fields...
2352 
2353     buffer_overflow_msg         = MSG_TRUNCATED_MSG;
2354     buffer_overflow_msg_len     = strlen( buffer_overflow_msg );
2355     saAttr.nLength              = sizeof(SECURITY_ATTRIBUTES);
2356     saAttr.lpSecurityDescriptor = NULL; // (we dunt need no stinkin suckurity!)
2357     saAttr.bInheritHandle       = TRUE; // (allows our inheritable HANDLEs
2358                                         // to be inherited by child)
2359     hOurProcess = GetCurrentProcess();  // (for creating pipes)
2360 
2361     //////////////////////////////////////////////////
2362     // Only create a stdin pipe if caller will be providing the child's stdin data...
2363 
2364     if (!pnWriteToChildStdinFD)         // (will caller be providing child's stdin?)
2365     {
2366         // PROGRAMMING NOTE: KB article 190351 "HOWTO: Spawn Console Processes with
2367         // Redirected Standard Handles" http://support.microsoft.com/?kbid=190351
2368         // is WRONG! (or at the very least quite misleading!)
2369 
2370         // It states that for those stdio handles you do NOT wish to redirect, you
2371         // should use "GetStdHandle(STD_xxx_HANDLE)", but that ONLY works when you
2372         // have a console to begin with! (which Hercules would NOT have when started
2373         // via HercGUI for example (since it specifies "DETACHED_PROCESS" (i.e. no
2374         // console) whenever it starts it via its own CreateProcess call).
2375 
2376         // If you wish to only redirect *some* (but NOT *all*) stdio handles in your
2377         // CreateProcess call, the ONLY way to properly do so (regardless of whether
2378         // you have a console or not) is by specifying NULL. Specifying NULL for your
2379         // stdio handle tells CreateProcess to use the default value for that HANDLE.
2380 
2381         hChildReadFromStdin = NULL;     // (no stdin redirection; use default)
2382     }
2383     else
2384     {
2385         // Create Stdin pipe for sending data to child...
2386 
2387         VERIFY(CreatePipe(&hChildReadFromStdin, &hPipeWriteHandle, &saAttr, PIPEBUFSIZE));
2388 
2389         // Create non-inheritable duplcate of pipe handle for our own private use...
2390 
2391         VERIFY(DuplicateHandle
2392         (
2393             hOurProcess, hPipeWriteHandle,      // (handle to be duplicated)
2394             hOurProcess, &hOurWriteToStdin,     // (non-inheritable duplicate)
2395             0,
2396             FALSE,                              // (prevents child from inheriting it)
2397             DUPLICATE_SAME_ACCESS
2398         ));
2399         VERIFY(CloseHandle(hPipeWriteHandle));  // (MUST close so child won't hang!)
2400     }
2401 
2402     //////////////////////////////////////////////////
2403     // Pipe child's Stdout output back to us...
2404 
2405     VERIFY(CreatePipe(&hPipeReadHandle, &hChildWriteToStdout, &saAttr, PIPEBUFSIZE));
2406 
2407     // Create non-inheritable duplcate of pipe handle for our own private use...
2408 
2409     VERIFY(DuplicateHandle
2410     (
2411         hOurProcess, hPipeReadHandle,       // (handle to be duplicated)
2412         hOurProcess, &hOurReadFromStdout,   // (non-inheritable duplicate)
2413         0,
2414         FALSE,                              // (prevents child from inheriting it)
2415         DUPLICATE_SAME_ACCESS
2416     ));
2417     VERIFY(CloseHandle(hPipeReadHandle));   // (MUST close so child won't hang!)
2418 
2419     //////////////////////////////////////////////////
2420     // Pipe child's Stderr output back to us...
2421 
2422     VERIFY(CreatePipe(&hPipeReadHandle, &hChildWriteToStderr, &saAttr, PIPEBUFSIZE));
2423 
2424     // Create non-inheritable duplcate of pipe handle for our own private use...
2425 
2426     VERIFY(DuplicateHandle
2427     (
2428         hOurProcess, hPipeReadHandle,       // (handle to be duplicated)
2429         hOurProcess, &hOurReadFromStderr,   // (non-inheritable duplicate)
2430         0,
2431         FALSE,                              // (prevents child from inheriting it)
2432         DUPLICATE_SAME_ACCESS
2433     ));
2434     VERIFY(CloseHandle(hPipeReadHandle));   // (MUST close so child won't hang!)
2435 
2436     //////////////////////////////////////////////////
2437     // Prepare for creation of child process...
2438 
2439     ZeroMemory(&piProcInfo,  sizeof(PROCESS_INFORMATION));
2440     ZeroMemory(&siStartInfo, sizeof(STARTUPINFO        ));
2441 
2442     siStartInfo.cb         = sizeof(STARTUPINFO);   // (size of structure)
2443     siStartInfo.dwFlags    = STARTF_USESTDHANDLES;  // (use redirected std HANDLEs)
2444     siStartInfo.hStdInput  = hChildReadFromStdin;   // (use redirected std HANDLEs)
2445     siStartInfo.hStdOutput = hChildWriteToStdout;   // (use redirected std HANDLEs)
2446     siStartInfo.hStdError  = hChildWriteToStderr;   // (use redirected std HANDLEs)
2447 
2448     // Build the command-line for the system to create the child process with...
2449 
2450     len = strlen(pszCommandLine) + 1;
2451     pszNewCommandLine = malloc( len );
2452     strlcpy( pszNewCommandLine, pszCommandLine, len );
2453 
2454     //////////////////////////////////////////////////
2455     // Now actually create the child process...
2456     //////////////////////////////////////////////////
2457 
2458     bSuccess = CreateProcess
2459     (
2460         NULL,                   // name of executable module = from command-line
2461         pszNewCommandLine,      // command line with arguments
2462 
2463         NULL,                   // process security attributes = use defaults
2464         NULL,                   // primary thread security attributes = use defaults
2465 
2466         TRUE,                   // HANDLE inheritance flag = allow
2467                                 // (required when STARTF_USESTDHANDLES flag is used)
2468 
2469         0,  //  NOTE!  >>>--->  // UNDOCUMENTED SECRET! MUST BE ZERO! Can't be "CREATE_NO_WINDOW"
2470                                 // nor "DETACHED_PROCESS", etc, or else it sometimes doesn't work
2471                                 // or else a console window appears! ("ipconfig" being one such
2472                                 // example). THIS IS NOT DOCUMENTED *ANYWHERE* IN ANY MICROSOFT
2473                                 // DOCUMENTATION THAT I COULD FIND! I only stumbled across it by
2474                                 // sheer good fortune in a news group post after some intensive
2475                                 // Googling and have experimentally verified it works as desired.
2476 
2477         NULL,                   // environment block ptr = make a copy from parent's
2478         NULL,                   // initial working directory = same as parent's
2479 
2480         &siStartInfo,           // input STARTUPINFO pointer
2481         &piProcInfo             // output PROCESS_INFORMATION
2482     );
2483 
2484     rc = GetLastError();                        // (save return code)
2485 
2486     // Close the HANDLEs we don't need...
2487 
2488     if (pnWriteToChildStdinFD)
2489     VERIFY(CloseHandle(hChildReadFromStdin));   // (MUST close so child won't hang!)
2490     VERIFY(CloseHandle(hChildWriteToStdout));   // (MUST close so child won't hang!)
2491     VERIFY(CloseHandle(hChildWriteToStderr));   // (MUST close so child won't hang!)
2492 
2493            CloseHandle(piProcInfo.hThread);     // (we don't need this one)
2494 
2495     free(pszNewCommandLine);                    // (not needed anymore)
2496 
2497     // Check results...
2498 
2499     if (!bSuccess)
2500     {
2501         TRACE("*** CreateProcess() failed! rc = %d : %s\n",
2502             rc,w32_strerror(rc));
2503 
2504         if (pnWriteToChildStdinFD)
2505         VERIFY(CloseHandle(hOurWriteToStdin));
2506         VERIFY(CloseHandle(hOurReadFromStdout));
2507         VERIFY(CloseHandle(hOurReadFromStderr));
2508 
2509         errno = rc;
2510         return -1;
2511     }
2512 
2513     // Allocate/intialize control blocks for piped process/thread control...
2514 
2515     // If we were passed a pnWriteToChildStdinFD pointer, then the caller
2516     // is in charge of the process and will handle message capturing/logging
2517     // (such as is done with the print-to-pipe facility).
2518 
2519     // Otherwise (pnWriteToChildStdinFD is NULL) the caller wishes for us
2520     // to capture the piped process's o/p, so we pass a PIPED_PROCESS_CTL
2521     // structure to the stdout/stderr monitoring threads. This structure
2522     // contains a pointer to a buffer where they can accumulate messages.
2523 
2524     // Then once the process exits WE will then issue the "logmsg". This
2525     // is necessary in order to "capture" the process's o/p since the logmsg
2526     // capture facility is designed to capture o/p for a specific thread,
2527     // where that thread is US! (else if we let the monitoring thread issue
2528     // the logmsg's, they'll never get captured since they don't have the
2529     // same thread-id as the thread that started the capture, which was us!
2530     // (actually it was the caller, but we're the same thread as they are!)).
2531 
2532     pPipedStdOutThreadCtl = malloc( sizeof(PIPED_THREAD_CTL) );
2533     pPipedStdErrThreadCtl = malloc( sizeof(PIPED_THREAD_CTL) );
2534 
2535     pPipedStdOutThreadCtl->hStdXXX = hOurReadFromStdout;
2536     pPipedStdErrThreadCtl->hStdXXX = hOurReadFromStderr;
2537 
2538     if ( !pnWriteToChildStdinFD )
2539     {
2540         pPipedProcessCtl = malloc( sizeof(PIPED_PROCESS_CTL) );
2541 
2542         pPipedStdOutThreadCtl->pPipedProcessCtl = pPipedProcessCtl;
2543         pPipedStdErrThreadCtl->pPipedProcessCtl = pPipedProcessCtl;
2544 
2545         InitializeCriticalSection( &pPipedProcessCtl->csLock );
2546         pPipedProcessCtl->nAllocSize =         1;    // (purposely small for debugging)
2547         pPipedProcessCtl->pszBuffer  = malloc( 1 );  // (purposely small for debugging)
2548         *pPipedProcessCtl->pszBuffer = 0;            // (null terminate string buffer)
2549         pPipedProcessCtl->nStrLen    = 0;            // (no msgs yet)
2550     }
2551     else
2552     {
2553         pPipedStdOutThreadCtl->pPipedProcessCtl = NULL;
2554         pPipedStdErrThreadCtl->pPipedProcessCtl = NULL;
2555     }
2556 
2557     //////////////////////////////////////////////////
2558     // Create o/p pipe monitoring worker threads...
2559     //////////////////////////////////////////////////
2560     // Stdout...
2561 
2562     hWorkerThread = (HANDLE) _beginthreadex
2563     (
2564         NULL,                                       // pointer to security attributes = use defaults
2565         PIPE_THREAD_STACKSIZE,                      // initial thread stack size
2566         w32_read_piped_process_stdxxx_output_thread,
2567         pPipedStdOutThreadCtl,                      // thread argument
2568         0,                                          // special creation flags = none needed
2569         &dwThreadId                                 // pointer to receive thread ID
2570     );
2571     rc = GetLastError();                            // (save return code)
2572 
2573     if (!hWorkerThread || INVALID_HANDLE_VALUE == hWorkerThread)
2574     {
2575         TRACE("*** _beginthreadex() failed! rc = %d : %s\n",
2576             rc,w32_strerror(rc));
2577 
2578         if (pnWriteToChildStdinFD)
2579         VERIFY(CloseHandle(hOurWriteToStdin));
2580         VERIFY(CloseHandle(hOurReadFromStdout));
2581         VERIFY(CloseHandle(hOurReadFromStderr));
2582 
2583         if ( !pnWriteToChildStdinFD )
2584         {
2585             DeleteCriticalSection( &pPipedProcessCtl->csLock );
2586             free( pPipedProcessCtl->pszBuffer );
2587             free( pPipedProcessCtl );
2588         }
2589         free( pPipedStdOutThreadCtl );
2590         free( pPipedStdErrThreadCtl );
2591 
2592         errno = rc;
2593         return -1;
2594     }
2595     else
2596         VERIFY(CloseHandle(hWorkerThread));         // (not needed anymore)
2597 
2598     SET_THREAD_NAME_ID(dwThreadId,"w32_read_piped_process_stdOUT_output_thread");
2599 
2600     //////////////////////////////////////////////////
2601     // Stderr...
2602 
2603     hWorkerThread = (HANDLE) _beginthreadex
2604     (
2605         NULL,                                       // pointer to security attributes = use defaults
2606         PIPE_THREAD_STACKSIZE,                      // initial thread stack size
2607         w32_read_piped_process_stdxxx_output_thread,
2608         pPipedStdErrThreadCtl,                      // thread argument
2609         0,                                          // special creation flags = none needed
2610         &dwThreadId                                 // pointer to receive thread ID
2611     );
2612     rc = GetLastError();                            // (save return code)
2613 
2614     if (!hWorkerThread || INVALID_HANDLE_VALUE == hWorkerThread)
2615     {
2616         TRACE("*** _beginthreadex() failed! rc = %d : %s\n",
2617             rc,w32_strerror(rc));
2618 
2619         if (pnWriteToChildStdinFD)
2620         VERIFY(CloseHandle(hOurWriteToStdin));
2621         VERIFY(CloseHandle(hOurReadFromStdout));
2622         VERIFY(CloseHandle(hOurReadFromStderr));
2623 
2624         if ( !pnWriteToChildStdinFD )
2625         {
2626             DeleteCriticalSection( &pPipedProcessCtl->csLock );
2627             free( pPipedProcessCtl->pszBuffer );
2628             free( pPipedProcessCtl );
2629         }
2630         free( pPipedStdOutThreadCtl );
2631         free( pPipedStdErrThreadCtl );
2632 
2633         errno = rc;
2634         return -1;
2635     }
2636     else
2637         VERIFY(CloseHandle(hWorkerThread));     // (not needed anymore)
2638 
2639     SET_THREAD_NAME_ID(dwThreadId,"w32_read_piped_process_stdERR_output_thread");
2640 
2641     // Piped process capture handling...
2642 
2643     if ( !pnWriteToChildStdinFD )
2644     {
2645         // We're in control of the process...
2646         // Wait for it to exit...
2647 
2648         WaitForSingleObject( piProcInfo.hProcess, INFINITE );
2649         CloseHandle( piProcInfo.hProcess );
2650 
2651         // Now print ALL captured messages AT ONCE (if any)...
2652 
2653         while (pPipedProcessCtl->nStrLen && isspace( pPipedProcessCtl->pszBuffer[ pPipedProcessCtl->nStrLen - 1 ] ))
2654             pPipedProcessCtl->nStrLen--;
2655         if (pPipedProcessCtl->nStrLen)
2656         {
2657             pPipedProcessCtl->pszBuffer[ pPipedProcessCtl->nStrLen ] = 0;  // (null terminate)
2658             logmsg( "%s", pPipedProcessCtl->pszBuffer );
2659         }
2660 
2661         // Free resources...
2662 
2663         DeleteCriticalSection( &pPipedProcessCtl->csLock );
2664         free( pPipedProcessCtl->pszBuffer );
2665         free( pPipedProcessCtl );
2666     }
2667     else
2668     {
2669         // Caller is in control of the process...
2670 
2671         CloseHandle( piProcInfo.hProcess );
2672 
2673         // Return a C run-time file descriptor
2674         // for the write-to-child-stdin HANDLE...
2675 
2676         *pnWriteToChildStdinFD = _open_osfhandle( (intptr_t) hOurWriteToStdin, 0 );
2677     }
2678 
2679     // Success!
2680 
2681     return piProcInfo.dwProcessId;      // (return process-id to caller)
2682 }
2683 
2684 //////////////////////////////////////////////////////////////////////////////////////////
2685 // Thread to read message data from the child process's stdxxx o/p pipe...
2686 
2687 void w32_parse_piped_process_stdxxx_data ( PIPED_PROCESS_CTL* pPipedProcessCtl, char* holdbuff, int* pnHoldAmount );
2688 
w32_read_piped_process_stdxxx_output_thread(void * pThreadParm)2689 UINT  WINAPI  w32_read_piped_process_stdxxx_output_thread ( void* pThreadParm )
2690 {
2691     PIPED_THREAD_CTL*   pPipedStdXXXThreadCtl   = NULL;
2692     PIPED_PROCESS_CTL*  pPipedProcessCtl        = NULL;
2693 
2694     HANDLE    hOurReadFromStdxxx  = NULL;
2695     DWORD     nAmountRead         = 0;
2696     int       nHoldAmount         = 0;
2697     BOOL      oflow               = FALSE;
2698     unsigned  nRetcode            = 0;
2699 
2700     char   readbuff [ PIPEBUFSIZE ];
2701     char   holdbuff [ HOLDBUFSIZE ];
2702 
2703     // Extract parms
2704 
2705     pPipedStdXXXThreadCtl = (PIPED_THREAD_CTL*) pThreadParm;
2706 
2707     pPipedProcessCtl    = pPipedStdXXXThreadCtl->pPipedProcessCtl;
2708     hOurReadFromStdxxx  = pPipedStdXXXThreadCtl->hStdXXX;
2709 
2710     free( pPipedStdXXXThreadCtl );      // (prevent memory leak)
2711 
2712     // Begin work...
2713 
2714     for (;;)
2715     {
2716         if (!ReadFile(hOurReadFromStdxxx, readbuff, PIPEBUFSIZE-1, &nAmountRead, NULL))
2717         {
2718             if (ERROR_BROKEN_PIPE == (nRetcode = GetLastError()))
2719                 nRetcode = 0;
2720             // (else keep value returned from GetLastError())
2721             break;
2722         }
2723         *(readbuff+nAmountRead) = 0;
2724 
2725         if (!nAmountRead) break;    // (pipe closed (i.e. broken pipe); time to exit)
2726 
2727         if ((nHoldAmount + nAmountRead) >= (HOLDBUFSIZE-1))
2728         {
2729             // OVERFLOW! append "truncated" string and force end-of-msg...
2730 
2731             oflow = TRUE;
2732             memcpy( holdbuff + nHoldAmount, readbuff, HOLDBUFSIZE - nHoldAmount);
2733             strcpy(                         readbuff, buffer_overflow_msg);
2734             nAmountRead =                   (DWORD)buffer_overflow_msg_len;
2735             nHoldAmount =  HOLDBUFSIZE  -   nAmountRead - 1;
2736         }
2737 
2738         // Append new data to end of hold buffer...
2739 
2740         memcpy(holdbuff+nHoldAmount,readbuff,nAmountRead);
2741         nHoldAmount += nAmountRead;
2742         *(holdbuff+nHoldAmount) = 0;
2743 
2744         // Pass all existing data to parsing function...
2745 
2746         w32_parse_piped_process_stdxxx_data( pPipedProcessCtl, holdbuff, &nHoldAmount );
2747 
2748         if (oflow) ASSERT(!nHoldAmount); oflow = FALSE;
2749     }
2750 
2751     // Finish up...
2752 
2753     CloseHandle( hOurReadFromStdxxx );      // (prevent HANDLE leak)
2754 
2755     return nRetcode;
2756 }
2757 
2758 //////////////////////////////////////////////////////////////////////////////////////////
2759 // Parse piped child's stdout/stderr o/p data into individual newline delimited
2760 // messages for displaying on the Hercules hardware console...
2761 
w32_parse_piped_process_stdxxx_data(PIPED_PROCESS_CTL * pPipedProcessCtl,char * holdbuff,int * pnHoldAmount)2762 void w32_parse_piped_process_stdxxx_data ( PIPED_PROCESS_CTL* pPipedProcessCtl, char* holdbuff, int* pnHoldAmount )
2763 {
2764     // This function executes in the context of the worker thread that calls it.
2765 
2766     char* pbeg;                         // ptr to start of message
2767     char* pend;                         // find end of message (MUST NOT BE MODIFIED!)
2768     char* pmsgend;                      // work ptr to end of message
2769                                         // 'pend' variable MUST NOT BE MODIFIED
2770     int nlen;                           // work length of one message
2771     int ntotlen;                        // accumulated length of all parsed messages
2772 
2773     // A worker thread that monitors a child's Stdout o/p has received a message
2774     // and is calling this function to determine what, if anything, to do with it.
2775 
2776     // (Note: the worker thread that calls us ensures holdbuff is null terminated)
2777 
2778     pbeg = holdbuff;                    // ptr to start of message
2779     pend = strchr(pbeg,'\n');           // find end of message (MUST NOT BE MODIFIED!)
2780     if (!pend) return;                  // we don't we have a complete message yet
2781     ntotlen = 0;                        // accumulated length of all parsed messages
2782 
2783     // Parse the message...
2784 
2785     do
2786     {
2787         nlen = (pend-pbeg);             // get length of THIS message
2788         ntotlen += nlen + 1;            // keep track of all that we see
2789 
2790         // Remove trailing newline character and any other trailing blanks...
2791 
2792         // (Note: we MUST NOT MODIFY the 'pend' variable. It should always
2793         // point to where the newline character was found so we can start
2794         // looking for the next message (if there is one) where this message
2795         // ended).
2796 
2797         *pend = 0;                      // (change newline character to null)
2798         pmsgend = pend;                 // (start removing blanks from here)
2799 
2800         while (--pmsgend >= pbeg && isspace(*pmsgend)) {*pmsgend = 0; --nlen;}
2801 
2802         // If we were passed a PIPED_PROCESS_CTL pointer, then the root thread
2803         // wants us to just capture the o/p and IT will issue the logmsg within
2804         // its own thread. Otherwise root thread isn't interested in capturing
2805         // and thus we must issue the individual logmsg's ourselves...
2806 
2807         if (!pPipedProcessCtl)
2808         {
2809             logmsg("%s\n",pbeg);    // send all child's msgs to Herc console
2810         }
2811         else
2812         {
2813             size_t  nNewStrLen, nAllocSizeNeeded;   // (work)
2814 
2815             EnterCriticalSection( &pPipedProcessCtl->csLock );
2816 
2817             nNewStrLen        = strlen( pbeg );
2818             nAllocSizeNeeded  = ((((pPipedProcessCtl->nStrLen + nNewStrLen + 2) / 4096) + 1) * 4096);
2819 
2820             if ( nAllocSizeNeeded > pPipedProcessCtl->nAllocSize )
2821             {
2822                 pPipedProcessCtl->nAllocSize = nAllocSizeNeeded;
2823                 pPipedProcessCtl->pszBuffer  = realloc( pPipedProcessCtl->pszBuffer, nAllocSizeNeeded );
2824                 ASSERT( pPipedProcessCtl->pszBuffer );
2825             }
2826 
2827             if (nNewStrLen)
2828             {
2829                 memcpy( pPipedProcessCtl->pszBuffer + pPipedProcessCtl->nStrLen, pbeg, nNewStrLen );
2830                 pPipedProcessCtl->nStrLen += nNewStrLen;
2831             }
2832 
2833             *(pPipedProcessCtl->pszBuffer + pPipedProcessCtl->nStrLen) = '\n';
2834             pPipedProcessCtl->nStrLen++;
2835             *(pPipedProcessCtl->pszBuffer + pPipedProcessCtl->nStrLen) = '\0';
2836 
2837             ASSERT( pPipedProcessCtl->nStrLen <= pPipedProcessCtl->nAllocSize );
2838 
2839             LeaveCriticalSection( &pPipedProcessCtl->csLock );
2840         }
2841 
2842         // 'pend' should still point to the end of this message (where newline was)
2843 
2844         pbeg = (pend + 1);              // point to beg of next message (if any)
2845 
2846         if (pbeg >= (holdbuff + *pnHoldAmount))   // past end of data?
2847         {
2848             pbeg = pend;                // re-point back to our null
2849             ASSERT(*pbeg == 0);         // sanity check
2850             break;                      // we're done with this batch
2851         }
2852 
2853         pend = strchr(pbeg,'\n');       // is there another message?
2854     }
2855     while (pend);                       // while messages remain...
2856 
2857     if (ntotlen > *pnHoldAmount)        // make sure we didn't process too much
2858     {
2859         TRACE("*** ParseStdxxxMsg logic error! ***\n");
2860         ASSERT(FALSE);                  // oops!
2861     }
2862 
2863     // 'Remove' the messages that we parsed from the caller's hold buffer by
2864     // sliding the remainder to the left (i.e. left justifying the remainder
2865     // in their hold buffer) and then telling them how much data now remains
2866     // in their hold buffer.
2867 
2868     // IMPORTANT PROGRAMMING NOTE! We must use memmove here and not strcpy!
2869     // strcpy doesn't work correctly for overlapping source and destination.
2870     // If there's 100 bytes remaining and we just want to slide it left by 1
2871     // byte (just as an illustrative example), strcpy screws up. This is more
2872     // than likely because strcpy is trying to be as efficient as possible and
2873     // is grabbing multiple bytes at a time from the source string and plonking
2874     // them down into the destination string, thus wiping out part of our source
2875     // string. Thus, we MUST use memmove here and NOT strcpy.
2876 
2877     if ((*pnHoldAmount = (int)strlen(pbeg)) > 0)   // new amount of data remaining
2878         memmove(holdbuff,pbeg,*pnHoldAmount);      // slide left justify remainder
2879 }
2880 
2881 //////////////////////////////////////////////////////////////////////////////////////////
2882 // The following is documented in Microsoft's Visual Studio developer documentation...
2883 
2884 #define  MS_VC_EXCEPTION   0x406D1388       // (special value)
2885 
2886 typedef struct tagTHREADNAME_INFO
2887 {
2888     DWORD   dwType;         // must be 0x1000
2889     LPCSTR  pszName;        // pointer to name (in same addr space)
2890     DWORD   dwThreadID;     // thread ID (-1 caller thread)
2891     DWORD   dwFlags;        // reserved for future use, must be zero
2892 }
2893 THREADNAME_INFO;
2894 
w32_set_thread_name(TID tid,char * name)2895 DLL_EXPORT void w32_set_thread_name( TID tid, char* name )
2896 {
2897     THREADNAME_INFO info;
2898 
2899     if (!name) return;              // (ignore premature calls)
2900 
2901     info.dwType     = 0x1000;
2902     info.pszName    = name;         // (should really be LPCTSTR)
2903     info.dwThreadID = tid;          // (-1 == current thread, else tid)
2904     info.dwFlags    = 0;
2905 
2906     __try
2907     {
2908         RaiseException( MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(DWORD), (const ULONG_PTR*)&info );
2909     }
2910     __except ( EXCEPTION_CONTINUE_EXECUTION )
2911     {
2912         /* (do nothing) */
2913     }
2914 }
2915 
2916 //////////////////////////////////////////////////////////////////////////////////////////
2917 // Hercules file open
2918 // w32_hopen is called instead of hopen in MSVC environment (see hercwind.h)
2919 // Its purpose is to prevent a file from being opened for output by two
2920 // Hercules instances at the same time.
2921 // _SH_DENYRW prevents all access to the file from other processes;
2922 // _SH_DENYWR permits other processes to read the file but not to write;
2923 // _SH_SECURE opens the file in _SH_DENYRW mode if oflag specifies write
2924 // access, or _SH_DENYWR mode if oflag specifies read-only.
w32_hopen(const char * path,int oflag,...)2925 DLL_EXPORT int w32_hopen( const char* path, int oflag, ... )
2926 {
2927     int shflag = (oflag & _O_RDWR) ? _SH_DENYRW : _SH_DENYWR;
2928     int pmode = 0;
2929     if (oflag & _O_CREAT)
2930     {
2931         va_list vargs;
2932         va_start( vargs, oflag );
2933         pmode = va_arg( vargs, int );
2934     }
2935     return _sopen( path, oflag, shflag, pmode );
2936 }
2937 
2938 //////////////////////////////////////////////////////////////////////////////////////////
2939 
2940 #endif // defined( _MSVC_ )
2941