VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin/mscfakes.c@ 3387

Last change on this file since 3387 was 3387, checked in by bird, 4 years ago

mscfakes.c: Don't pass zero to SetFileAttributes.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use