source: trunk/src/kmk/kmkbuiltin/mscfakes.c@ 3072

Last change on this file since 3072 was 3060, checked in by bird, 8 years ago

kmk,lib: ported kmk_touch to windows (nt).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.8 KB
Line 
1/* $Id: mscfakes.c 3060 2017-09-21 15:11:07Z bird $ */
2/** @file
3 * Fake Unix stuff for MSC.
4 */
5
6/*
7 * Copyright (c) 2005-2015 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
8 *
9 * This file is part of kBuild.
10 *
11 * kBuild is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * kBuild is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
23 *
24 */
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#include "config.h"
30#include <assert.h>
31#include <stdarg.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <errno.h>
36#include <io.h>
37#include <fcntl.h>
38#include <sys/stat.h>
39#include <sys/timeb.h>
40#include "err.h"
41#include "mscfakes.h"
42
43#include "nt/ntutimes.h"
44#undef utimes
45#undef lutimes
46
47#define timeval windows_timeval
48#include <Windows.h>
49#undef timeval
50
51
52/*******************************************************************************
53* Internal Functions *
54*******************************************************************************/
55static BOOL isPipeFd(int fd);
56
57
58/**
59 * Makes corrections to a directory path that ends with a trailing slash.
60 *
61 * @returns temporary buffer to free.
62 * @param ppszPath The path pointer. This is updated when necessary.
63 * @param pfMustBeDir This is set if it must be a directory, otherwise it's cleared.
64 */
65static char *
66msc_fix_path(const char **ppszPath, int *pfMustBeDir)
67{
68 const char *pszPath = *ppszPath;
69 const char *psz;
70 char *pszNew;
71 *pfMustBeDir = 0;
72
73 /*
74 * Skip any compusory trailing slashes
75 */
76 if (pszPath[0] == '/' || pszPath[0] == '\\')
77 {
78 if ( (pszPath[1] == '/' || pszPath[1] == '\\')
79 && pszPath[2] != '/'
80 && pszPath[2] != '\\')
81 /* unc */
82 pszPath += 2;
83 else
84 /* root slash(es) */
85 pszPath++;
86 }
87 else if ( isalpha(pszPath[0])
88 && pszPath[1] == ':')
89 {
90 if (pszPath[2] == '/' || pszPath[2] == '\\')
91 /* drive w/ slash */
92 pszPath += 3;
93 else
94 /* drive relative path. */
95 pszPath += 2;
96 }
97 /* else: relative path, no skipping necessary. */
98
99 /*
100 * Any trailing slashes to drop off?
101 */
102 psz = strchr(pszPath, '\0');
103 if (pszPath <= psz)
104 return NULL;
105 if ( psz[-1] != '/'
106 || psz[-1] != '\\')
107 return NULL;
108
109 /* figure how many, make a copy and strip them off. */
110 while ( psz > pszPath
111 && ( psz[-1] == '/'
112 || psz[-1] == '\\'))
113 psz--;
114 pszNew = strdup(pszPath);
115 pszNew[psz - pszPath] = '\0';
116
117 *pfMustBeDir = 1;
118 *ppszPath = pszNew; /* use this one */
119 return pszNew;
120}
121
122
123int
124birdSetErrno(unsigned dwErr)
125{
126 switch (dwErr)
127 {
128 default:
129 case ERROR_INVALID_FUNCTION: errno = EINVAL; break;
130 case ERROR_FILE_NOT_FOUND: errno = ENOENT; break;
131 case ERROR_PATH_NOT_FOUND: errno = ENOENT; break;
132 case ERROR_TOO_MANY_OPEN_FILES: errno = EMFILE; break;
133 case ERROR_ACCESS_DENIED: errno = EACCES; break;
134 case ERROR_INVALID_HANDLE: errno = EBADF; break;
135 case ERROR_ARENA_TRASHED: errno = ENOMEM; break;
136 case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break;
137 case ERROR_INVALID_BLOCK: errno = ENOMEM; break;
138 case ERROR_BAD_ENVIRONMENT: errno = E2BIG; break;
139 case ERROR_BAD_FORMAT: errno = ENOEXEC; break;
140 case ERROR_INVALID_ACCESS: errno = EINVAL; break;
141 case ERROR_INVALID_DATA: errno = EINVAL; break;
142 case ERROR_INVALID_DRIVE: errno = ENOENT; break;
143 case ERROR_CURRENT_DIRECTORY: errno = EACCES; break;
144 case ERROR_NOT_SAME_DEVICE: errno = EXDEV; break;
145 case ERROR_NO_MORE_FILES: errno = ENOENT; break;
146 case ERROR_LOCK_VIOLATION: errno = EACCES; break;
147 case ERROR_BAD_NETPATH: errno = ENOENT; break;
148 case ERROR_NETWORK_ACCESS_DENIED: errno = EACCES; break;
149 case ERROR_BAD_NET_NAME: errno = ENOENT; break;
150 case ERROR_FILE_EXISTS: errno = EEXIST; break;
151 case ERROR_CANNOT_MAKE: errno = EACCES; break;
152 case ERROR_FAIL_I24: errno = EACCES; break;
153 case ERROR_INVALID_PARAMETER: errno = EINVAL; break;
154 case ERROR_NO_PROC_SLOTS: errno = EAGAIN; break;
155 case ERROR_DRIVE_LOCKED: errno = EACCES; break;
156 case ERROR_BROKEN_PIPE: errno = EPIPE; break;
157 case ERROR_DISK_FULL: errno = ENOSPC; break;
158 case ERROR_INVALID_TARGET_HANDLE: errno = EBADF; break;
159 case ERROR_WAIT_NO_CHILDREN: errno = ECHILD; break;
160 case ERROR_CHILD_NOT_COMPLETE: errno = ECHILD; break;
161 case ERROR_DIRECT_ACCESS_HANDLE: errno = EBADF; break;
162 case ERROR_NEGATIVE_SEEK: errno = EINVAL; break;
163 case ERROR_SEEK_ON_DEVICE: errno = EACCES; break;
164 case ERROR_DIR_NOT_EMPTY: errno = ENOTEMPTY; break;
165 case ERROR_NOT_LOCKED: errno = EACCES; break;
166 case ERROR_BAD_PATHNAME: errno = ENOENT; break;
167 case ERROR_MAX_THRDS_REACHED: errno = EAGAIN; break;
168 case ERROR_LOCK_FAILED: errno = EACCES; break;
169 case ERROR_ALREADY_EXISTS: errno = EEXIST; break;
170 case ERROR_FILENAME_EXCED_RANGE: errno = ENOENT; break;
171 case ERROR_NESTING_NOT_ALLOWED: errno = EAGAIN; break;
172#ifdef EMLINK
173 case ERROR_TOO_MANY_LINKS: errno = EMLINK; break;
174#endif
175 }
176
177 return -1;
178}
179
180char *dirname(char *path)
181{
182 /** @todo later */
183 return path;
184}
185
186
187int lchmod(const char *pszPath, mode_t mode)
188{
189 int rc = 0;
190 int fMustBeDir;
191 char *pszPathFree = msc_fix_path(&pszPath, &fMustBeDir);
192
193 /*
194 * Get the current attributes
195 */
196 DWORD fAttr = GetFileAttributes(pszPath);
197 if (fAttr == INVALID_FILE_ATTRIBUTES)
198 rc = birdSetErrno(GetLastError());
199 else if (fMustBeDir & !(fAttr & FILE_ATTRIBUTE_DIRECTORY))
200 {
201 errno = ENOTDIR;
202 rc = -1;
203 }
204 else
205 {
206 /*
207 * Modify the attributes and try set them.
208 */
209 if (mode & _S_IWRITE)
210 fAttr &= ~FILE_ATTRIBUTE_READONLY;
211 else
212 fAttr |= FILE_ATTRIBUTE_READONLY;
213 if (!SetFileAttributes(pszPath, fAttr))
214 rc = birdSetErrno(GetLastError());
215 }
216
217 if (pszPathFree)
218 {
219 int saved_errno = errno;
220 free(pszPathFree);
221 errno = saved_errno;
222 }
223 return rc;
224}
225
226
227int msc_chmod(const char *pszPath, mode_t mode)
228{
229 int rc = 0;
230 int fMustBeDir;
231 char *pszPathFree = msc_fix_path(&pszPath, &fMustBeDir);
232
233 /*
234 * Get the current attributes.
235 */
236 DWORD fAttr = GetFileAttributes(pszPath);
237 if (fAttr == INVALID_FILE_ATTRIBUTES)
238 rc = birdSetErrno(GetLastError());
239 else if (fMustBeDir & !(fAttr & FILE_ATTRIBUTE_DIRECTORY))
240 {
241 errno = ENOTDIR;
242 rc = -1;
243 }
244 else if (fAttr & FILE_ATTRIBUTE_REPARSE_POINT)
245 {
246 errno = ENOSYS; /** @todo resolve symbolic link / rewrite to NtSetInformationFile. */
247 rc = -1;
248 }
249 else
250 {
251 /*
252 * Modify the attributes and try set them.
253 */
254 if (mode & _S_IWRITE)
255 fAttr &= ~FILE_ATTRIBUTE_READONLY;
256 else
257 fAttr |= FILE_ATTRIBUTE_READONLY;
258 if (!SetFileAttributes(pszPath, fAttr))
259 rc = birdSetErrno(GetLastError());
260 }
261
262 if (pszPathFree)
263 {
264 int saved_errno = errno;
265 free(pszPathFree);
266 errno = saved_errno;
267 }
268 return rc;
269}
270
271
272typedef BOOL (WINAPI *PFNCREATEHARDLINKA)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES);
273int link(const char *pszDst, const char *pszLink)
274{
275 static PFNCREATEHARDLINKA s_pfnCreateHardLinkA = NULL;
276 static int s_fTried = FALSE;
277
278 /* The API was introduced in Windows 2000, so resolve it dynamically. */
279 if (!s_pfnCreateHardLinkA)
280 {
281 if (!s_fTried)
282 {
283 HMODULE hmod = LoadLibrary("KERNEL32.DLL");
284 if (hmod)
285 *(FARPROC *)&s_pfnCreateHardLinkA = GetProcAddress(hmod, "CreateHardLinkA");
286 s_fTried = TRUE;
287 }
288 if (!s_pfnCreateHardLinkA)
289 {
290 errno = ENOSYS;
291 return -1;
292 }
293 }
294
295 if (s_pfnCreateHardLinkA(pszLink, pszDst, NULL))
296 return 0;
297 return birdSetErrno(GetLastError());
298}
299
300
301int mkdir_msc(const char *path, mode_t mode)
302{
303 int rc = (mkdir)(path);
304 if (rc)
305 {
306 size_t len = strlen(path);
307 if (len > 0 && (path[len - 1] == '/' || path[len - 1] == '\\'))
308 {
309 char *str = strdup(path);
310 while (len > 0 && (str[len - 1] == '/' || str[len - 1] == '\\'))
311 str[--len] = '\0';
312 rc = (mkdir)(str);
313 free(str);
314 }
315 }
316 return rc;
317}
318
319int rmdir_msc(const char *path)
320{
321 int rc = (rmdir)(path);
322 if (rc)
323 {
324 size_t len = strlen(path);
325 if (len > 0 && (path[len - 1] == '/' || path[len - 1] == '\\'))
326 {
327 char *str = strdup(path);
328 while (len > 0 && (str[len - 1] == '/' || str[len - 1] == '\\'))
329 str[--len] = '\0';
330 rc = (rmdir)(str);
331 free(str);
332 }
333 }
334 return rc;
335}
336
337
338static int doname(char *pszX, char *pszEnd)
339{
340 static char s_szChars[] = "Xabcdefghijklmnopqrstuwvxyz1234567890";
341 int rc = 0;
342 do
343 {
344 char ch;
345
346 pszEnd++;
347 ch = *(strchr(s_szChars, *pszEnd) + 1);
348 if (ch)
349 {
350 *pszEnd = ch;
351 return 0;
352 }
353 *pszEnd = 'a';
354 } while (pszEnd != pszX);
355 return 1;
356}
357
358
359int mkstemp(char *temp)
360{
361 char *pszX = strchr(temp, 'X');
362 char *pszEnd = strchr(pszX, '\0');
363 int cTries = 1000;
364 while (--cTries > 0)
365 {
366 int fd;
367 if (doname(pszX, pszEnd))
368 return -1;
369 fd = open(temp, _O_EXCL | _O_CREAT | _O_BINARY | _O_RDWR, 0777);
370 if (fd >= 0)
371 return fd;
372 }
373 return -1;
374}
375
376
377/** Unix to DOS. */
378static char *fix_slashes(char *psz)
379{
380 char *pszRet = psz;
381 for (; *psz; psz++)
382 if (*psz == '/')
383 *psz = '\\';
384 return pszRet;
385}
386
387
388/** Calcs the SYMBOLIC_LINK_FLAG_DIRECTORY flag for CreatesymbolcLink. */
389static DWORD is_directory(const char *pszPath, const char *pszRelativeTo)
390{
391 size_t cchPath = strlen(pszPath);
392 struct stat st;
393 if (cchPath > 0 && pszPath[cchPath - 1] == '\\' || pszPath[cchPath - 1] == '/')
394 return 1; /* SYMBOLIC_LINK_FLAG_DIRECTORY */
395
396 if (stat(pszPath, &st))
397 {
398 size_t cchRelativeTo = strlen(pszRelativeTo);
399 char *psz = malloc(cchPath + cchRelativeTo + 4);
400 memcpy(psz, pszRelativeTo, cchRelativeTo);
401 memcpy(psz + cchRelativeTo, "\\", 1);
402 memcpy(psz + cchRelativeTo + 1, pszPath, cchPath + 1);
403 if (stat(pszPath, &st))
404 st.st_mode = _S_IFREG;
405 free(psz);
406 }
407
408 return (st.st_mode & _S_IFMT) == _S_IFDIR ? 1 : 0;
409}
410
411
412int symlink(const char *pszDst, const char *pszLink)
413{
414 static BOOLEAN (WINAPI *s_pfnCreateSymbolicLinkA)(LPCSTR, LPCSTR, DWORD) = 0;
415 static BOOL s_fTried = FALSE;
416
417 if (!s_fTried)
418 {
419 HMODULE hmod = LoadLibrary("KERNEL32.DLL");
420 if (hmod)
421 *(FARPROC *)&s_pfnCreateSymbolicLinkA = GetProcAddress(hmod, "CreateSymbolicLinkA");
422 s_fTried = TRUE;
423 }
424
425 if (s_pfnCreateSymbolicLinkA)
426 {
427 char *pszDstCopy = fix_slashes(strdup(pszDst));
428 char *pszLinkCopy = fix_slashes(strdup(pszLink));
429 BOOLEAN fRc = s_pfnCreateSymbolicLinkA(pszLinkCopy, pszDstCopy,
430 is_directory(pszDstCopy, pszLinkCopy));
431 DWORD err = GetLastError();
432 free(pszDstCopy);
433 free(pszLinkCopy);
434 if (fRc)
435 return 0;
436 switch (err)
437 {
438 case ERROR_NOT_SUPPORTED: errno = ENOSYS; break;
439 case ERROR_ALREADY_EXISTS:
440 case ERROR_FILE_EXISTS: errno = EEXIST; break;
441 case ERROR_DIRECTORY: errno = ENOTDIR; break;
442 case ERROR_ACCESS_DENIED:
443 case ERROR_PRIVILEGE_NOT_HELD: errno = EPERM; break;
444 default: errno = EINVAL; break;
445 }
446 return -1;
447 }
448
449 errno = ENOSYS;
450 err(1, "symlink() is not implemented on windows!");
451 return -1;
452}
453
454
455#if _MSC_VER < 1400
456int snprintf(char *buf, size_t size, const char *fmt, ...)
457{
458 int cch;
459 va_list args;
460 va_start(args, fmt);
461 cch = vsprintf(buf, fmt, args);
462 va_end(args);
463 return cch;
464}
465#endif
466
467
468/* We override the libc write function (in our modules only, unfortunately) so
469 we can kludge our way around a ENOSPC problem observed on build servers
470 capturing STDOUT and STDERR via pipes. Apparently this may happen when the
471 pipe buffer is full, even with the mscfake_init hack in place.
472
473 XXX: Probably need to hook into fwrite as well. */
474ssize_t msc_write(int fd, const void *pvSrc, size_t cbSrc)
475{
476 ssize_t cbRet;
477 if (cbSrc < UINT_MAX / 4)
478 {
479#ifndef MSC_WRITE_TEST
480 cbRet = _write(fd, pvSrc, (unsigned int)cbSrc);
481#else
482 cbRet = -1; errno = ENOSPC;
483#endif
484 if (cbRet < 0)
485 {
486 /* ENOSPC on pipe kludge. */
487 int cbLimit;
488 int cSinceLastSuccess;
489
490 if (cbSrc == 0)
491 return 0;
492 if (errno != ENOSPC)
493 return -1;
494#ifndef MSC_WRITE_TEST
495 if (!isPipeFd(fd))
496 {
497 errno = ENOSPC;
498 return -1;
499 }
500#endif
501
502 /* Likely a full pipe buffer, try write smaller amounts and do some
503 sleeping inbetween each unsuccessful one. */
504 cbLimit = cbSrc / 4;
505 if (cbLimit < 4)
506 cbLimit = 4;
507 else if (cbLimit > 512)
508 cbLimit = 512;
509 cSinceLastSuccess = 0;
510 cbRet = 0;
511#ifdef MSC_WRITE_TEST
512 cbLimit = 4;
513#endif
514
515 while (cbSrc > 0)
516 {
517 unsigned int cbAttempt = cbSrc > cbLimit ? (int)cbLimit : (int)cbSrc;
518 ssize_t cbActual = _write(fd, pvSrc, cbAttempt);
519 if (cbActual > 0)
520 {
521 assert(cbActual <= (ssize_t)cbAttempt);
522 pvSrc = (char *)pvSrc + cbActual;
523 cbSrc -= cbActual;
524 cbRet += cbActual;
525#ifndef MSC_WRITE_TEST
526 if (cbLimit < 32)
527 cbLimit = 32;
528#endif
529 cSinceLastSuccess = 0;
530 }
531 else if (errno != ENOSPC)
532 return -1;
533 else
534 {
535 /* Delay for about 30 seconds, then just give up. */
536 cSinceLastSuccess++;
537 if (cSinceLastSuccess > 1860)
538 return -1;
539 if (cSinceLastSuccess <= 2)
540 Sleep(0);
541 else if (cSinceLastSuccess <= 66)
542 {
543 if (cbLimit >= 8)
544 cbLimit /= 2; /* Just in case the pipe buffer is very very small. */
545 Sleep(1);
546 }
547 else
548 Sleep(16);
549 }
550 }
551 }
552 }
553 else
554 {
555 /*
556 * Type limit exceeded. Split the job up.
557 */
558 cbRet = 0;
559 while (cbSrc > 0)
560 {
561 size_t cbToWrite = cbSrc > UINT_MAX / 4 ? UINT_MAX / 4 : cbSrc;
562 ssize_t cbWritten = msc_write(fd, pvSrc, cbToWrite);
563 if (cbWritten > 0)
564 {
565 pvSrc = (char *)pvSrc + (size_t)cbWritten;
566 cbSrc -= (size_t)cbWritten;
567 cbRet += (size_t)cbWritten;
568 }
569 else if (cbWritten == 0 || cbRet > 0)
570 break;
571 else
572 return -1;
573 }
574 }
575 return cbRet;
576}
577
578ssize_t writev(int fd, const struct iovec *vector, int count)
579{
580 int size = 0;
581 int i;
582 for (i = 0; i < count; i++)
583 {
584 int cb = msc_write(fd, vector[i].iov_base, (int)vector[i].iov_len);
585 if (cb < 0)
586 return cb;
587 size += cb;
588 }
589 return size;
590}
591
592
593intmax_t strtoimax(const char *nptr, char **endptr, int base)
594{
595 if (*nptr != '-')
596 return _strtoui64(nptr, endptr, base);
597 return -(intmax_t)_strtoui64(nptr + 1, endptr, base);
598}
599
600
601uintmax_t strtoumax(const char *nptr, char **endptr, int base)
602{
603 return _strtoui64(nptr, endptr, base);
604}
605
606
607int asprintf(char **strp, const char *fmt, ...)
608{
609 int rc;
610 va_list va;
611 va_start(va, fmt);
612 rc = vasprintf(strp, fmt, va);
613 va_end(va);
614 return rc;
615}
616
617
618int vasprintf(char **strp, const char *fmt, va_list va)
619{
620 int rc;
621 char *psz;
622 size_t cb = 1024;
623
624 *strp = NULL;
625 for (;;)
626 {
627 va_list va2;
628
629 psz = malloc(cb);
630 if (!psz)
631 return -1;
632
633#ifdef va_copy
634 va_copy(va2, va);
635 rc = vsnprintf(psz, cb, fmt, va2);
636 va_end(vaCopy);
637#else
638 va2 = va;
639 rc = vsnprintf(psz, cb, fmt, va2);
640#endif
641 if (rc < 0 || (size_t)rc < cb)
642 break;
643 cb *= 2;
644 free(psz);
645 }
646
647 *strp = psz;
648 return rc;
649}
650
651
652int utimes(const char *pszPath, const struct timeval *paTimes)
653{
654 BirdTimeVal_T aTimes[2];
655 aTimes[0].tv_sec = paTimes[0].tv_sec;
656 aTimes[0].tv_usec = paTimes[0].tv_usec;
657 aTimes[1].tv_sec = paTimes[1].tv_sec;
658 aTimes[1].tv_usec = paTimes[1].tv_usec;
659 return birdUtimes(pszPath, aTimes);
660}
661
662
663int lutimes(const char *pszPath, const struct timeval *paTimes)
664{
665 BirdTimeVal_T aTimes[2];
666 aTimes[0].tv_sec = paTimes[0].tv_sec;
667 aTimes[0].tv_usec = paTimes[0].tv_usec;
668 aTimes[1].tv_sec = paTimes[1].tv_sec;
669 aTimes[1].tv_usec = paTimes[1].tv_usec;
670 return birdUtimes(pszPath, aTimes);
671}
672
673
674int gettimeofday(struct timeval *pNow, void *pvIgnored)
675{
676 struct __timeb64 Now;
677 int rc = _ftime64_s(&Now);
678 if (rc == 0)
679 {
680 pNow->tv_sec = Now.time;
681 pNow->tv_usec = Now.millitm * 1000;
682 return 0;
683 }
684 errno = rc;
685 return -1;
686}
687
688
689struct tm *localtime_r(const __time64_t *pNow, struct tm *pResult)
690{
691 int rc = _localtime64_s(pResult, pNow);
692 if (rc == 0)
693 return pResult;
694 errno = rc;
695 return NULL;
696}
697
698
699__time64_t timegm(struct tm *pNow)
700{
701 return _mkgmtime64(pNow);
702}
703
704
705/**
706 * Checks if the given file descriptor is a pipe or not.
707 *
708 * @returns TRUE if pipe, FALSE if not.
709 * @param fd The libc file descriptor number.
710 */
711static BOOL isPipeFd(int fd)
712{
713 /* Is pipe? */
714 HANDLE hFile = (HANDLE)_get_osfhandle(fd);
715 if (hFile != INVALID_HANDLE_VALUE)
716 {
717 DWORD fType = GetFileType(hFile);
718 fType &= ~FILE_TYPE_REMOTE;
719 if (fType == FILE_TYPE_PIPE)
720 return TRUE;
721 }
722 return FALSE;
723}
724
725
726/**
727 * This is a kludge to make pipe handles blocking.
728 *
729 * @returns TRUE if it's now blocking, FALSE if not a pipe or we failed to fix
730 * the blocking mode.
731 * @param fd The libc file descriptor number.
732 */
733static BOOL makePipeBlocking(int fd)
734{
735 if (isPipeFd(fd))
736 {
737 /* Try fix it. */
738 HANDLE hFile = (HANDLE)_get_osfhandle(fd);
739 DWORD fState = 0;
740 if (GetNamedPipeHandleState(hFile, &fState, NULL, NULL, NULL, NULL, 0))
741 {
742 fState &= ~PIPE_NOWAIT;
743 fState |= PIPE_WAIT;
744 if (SetNamedPipeHandleState(hFile, &fState, NULL, NULL))
745 return TRUE;
746 }
747 }
748 return FALSE;
749}
750
751
752/**
753 * Initializes the msc fake stuff.
754 * @returns 0 on success (non-zero would indicate failure, see rterr.h).
755 */
756int mscfake_init(void)
757{
758 /*
759 * Kludge against _write returning ENOSPC on non-blocking pipes.
760 */
761 makePipeBlocking(STDOUT_FILENO);
762 makePipeBlocking(STDERR_FILENO);
763
764 return 0;
765}
766
767/*
768 * Do this before main is called.
769 */
770#pragma section(".CRT$XIA", read)
771#pragma section(".CRT$XIU", read)
772#pragma section(".CRT$XIZ", read)
773typedef int (__cdecl *PFNCRTINIT)(void);
774static __declspec(allocate(".CRT$XIU")) PFNCRTINIT g_MscFakeInitVectorEntry = mscfake_init;
775
Note: See TracBrowser for help on using the repository browser.