]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/compat.cpp
017c5443ca254eb784a3a7b627c946e830d87306
[bacula/bacula] / bacula / src / win32 / compat / compat.cpp
1 //                              -*- Mode: C++ -*-
2 // compat.cpp -- compatibilty layer to make bacula-fd run
3 //               natively under windows
4 //
5 // Copyright transferred from Raider Solutions, Inc to
6 //   Kern Sibbald and John Walker by express permission.
7 //
8 // Copyright (C) 2004 Kern Sibbald and John Walker
9 //
10 //   This program is free software; you can redistribute it and/or
11 //   modify it under the terms of the GNU General Public License as
12 //   published by the Free Software Foundation; either version 2 of
13 //   the License, or (at your option) any later version.
14 //
15 //   This program is distributed in the hope that it will be useful,
16 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
17 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 //   General Public License for more details.
19 //
20 //   You should have received a copy of the GNU General Public
21 //   License along with this program; if not, write to the Free
22 //   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23 //   MA 02111-1307, USA.
24 //
25 // Author          : Christopher S. Hull
26 // Created On      : Sat Jan 31 15:55:00 2004
27 // $Id$
28
29 #include <stdio.h>
30
31 #include "compat.h"
32 #include "pthread.h"
33
34 #define USE_WIN32_COMPAT_IO 1
35
36 extern void d_msg(const char *file, int line, int level, const char *fmt,...);
37 extern DWORD   g_platform_id;
38
39 // from CYGWIN (should be diff between Jan 1 1601 and Jan 1 1970
40 #ifdef HAVE_MINGW
41 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000UL //Not sure it works
42 #else
43 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
44 #endif
45
46 #define WIN32_FILETIME_SCALE  10000000             // 100ns/second
47
48 extern "C" void
49 cygwin_conv_to_win32_path(const char *name, char *win32_name)
50 {
51     const char *fname = name;
52     while (*name) {
53         /* Check for Unix separator and convert to Win32 */
54         if (*name == '/') {
55             *win32_name++ = '\\';     /* convert char */
56         /* If Win32 separated that is "quoted", remove quote */
57         } else if (*name == '\\' && name[1] == '\\') {
58             *win32_name++ = '\\';
59             name++;                   /* skip first \ */
60         } else {
61             *win32_name++ = *name;    /* copy character */
62         }
63         name++;
64     }
65     /* Strip any trailing slash, if we stored something */
66     if (*fname != 0 && win32_name[-1] == '\\') {
67         win32_name[-1] = 0;
68     } else {
69         *win32_name = 0;
70     }
71 }
72
73
74 void
75 wchar_win32_path(const char *name, WCHAR *win32_name)
76 {
77     const char *fname = name;
78     while (*name) {
79         /* Check for Unix separator and convert to Win32 */
80         if (*name == '/') {
81             *win32_name++ = '\\';     /* convert char */
82         /* If Win32 separated that is "quoted", remove quote */
83         } else if (*name == '\\' && name[1] == '\\') {
84             *win32_name++ = '\\';
85             name++;                   /* skip first \ */
86         } else {
87             *win32_name++ = *name;    /* copy character */
88         }
89         name++;
90     }
91     /* Strip any trailing slash, if we stored something */
92     if (*fname != 0 && win32_name[-1] == '\\') {
93         win32_name[-1] = 0;
94     } else {
95         *win32_name = 0;
96     }
97 }
98
99 int
100 umask(int)
101 {
102     return 0;
103 }
104
105 int
106 chmod(const char *, mode_t)
107 {
108     return 0;
109 }
110
111 int
112 chown(const char *k, uid_t, gid_t)
113 {
114     return 0;
115 }
116
117 int
118 lchown(const char *k, uid_t, gid_t)
119 {
120     return 0;
121 }
122
123
124
125 long int
126 random(void)
127 {
128     return rand();
129 }
130
131 void
132 srandom(unsigned int seed)
133 {
134     srand(seed);
135 }
136 // /////////////////////////////////////////////////////////////////
137 // convert from Windows concept of time to Unix concept of time
138 // /////////////////////////////////////////////////////////////////
139 void
140 cvt_utime_to_ftime(const time_t  &time, FILETIME &wintime)
141 {
142     uint64_t mstime = time;
143     mstime *= WIN32_FILETIME_SCALE;
144     mstime += WIN32_FILETIME_ADJUST;
145
146     #ifdef HAVE_MINGW
147     wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL);
148     #else
149     wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
150     #endif
151     wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
152 }
153
154 time_t
155 cvt_ftime_to_utime(const FILETIME &time)
156 {
157     uint64_t mstime = time.dwHighDateTime;
158     mstime <<= 32;
159     mstime |= time.dwLowDateTime;
160
161     mstime -= WIN32_FILETIME_ADJUST;
162     mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
163
164     return (time_t) (mstime & 0xffffffff);
165 }
166
167 static const char *
168 errorString(void)
169 {
170     LPVOID lpMsgBuf;
171
172     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
173                   FORMAT_MESSAGE_FROM_SYSTEM |
174                   FORMAT_MESSAGE_IGNORE_INSERTS,
175                   NULL,
176                   GetLastError(),
177                   MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
178                   (LPTSTR) &lpMsgBuf,
179                   0,
180                   NULL);
181
182     return (const char *) lpMsgBuf;
183 }
184
185 #ifndef HAVE_MINGW
186
187 static int
188 statDir(const char *file, struct stat *sb)
189 {
190     WIN32_FIND_DATA info;       // window's file info
191
192     if (file[1] == ':' && file[2] == 0) {
193         d_msg(__FILE__, __LINE__, 99, "faking ROOT attrs(%s).\n", file);
194         sb->st_mode = S_IFDIR;
195         sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
196         time(&sb->st_ctime);
197         time(&sb->st_mtime);
198         time(&sb->st_atime);
199         return 0;
200     }
201     HANDLE h = FindFirstFile(file, &info);
202
203     if (h == INVALID_HANDLE_VALUE) {
204         const char *err = errorString();
205         d_msg(__FILE__, __LINE__, 99, "FindFirstFile(%s):%s\n", file, err);
206         LocalFree((void *)err);
207         errno = GetLastError();
208         return -1;
209     }
210
211     sb->st_mode = 0777;               /* start with everything */
212     if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
213         sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
214     if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
215         sb->st_mode &= ~S_IRWXO; /* remove everything for other */
216     if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
217         sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
218     sb->st_mode |= S_IFDIR;
219
220     sb->st_size = info.nFileSizeHigh;
221     sb->st_size <<= 32;
222     sb->st_size |= info.nFileSizeLow;
223     sb->st_blksize = 4096;
224     sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
225
226     sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
227     sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
228     sb->st_ctime = cvt_ftime_to_utime(info.ftLastWriteTime);
229     FindClose(h);
230
231     return 0;
232 }
233
234 static int
235 stat2(const char *file, struct stat *sb)
236 {
237     BY_HANDLE_FILE_INFORMATION info;
238     HANDLE h;
239     int rval = 0;
240     char tmpbuf[1024];
241     cygwin_conv_to_win32_path(file, tmpbuf);
242
243     DWORD attr = GetFileAttributes(tmpbuf);
244
245     if (attr == -1) {
246         const char *err = errorString();
247         d_msg(__FILE__, __LINE__, 99,
248               "GetFileAttrubtes(%s): %s\n", tmpbuf, err);
249         LocalFree((void *)err);
250         errno = GetLastError();
251         return -1;
252     }
253
254     if (attr & FILE_ATTRIBUTE_DIRECTORY)
255         return statDir(tmpbuf, sb);
256
257     h = CreateFile(tmpbuf, GENERIC_READ,
258                    FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
259
260     if (h == INVALID_HANDLE_VALUE) {
261         const char *err = errorString();
262         d_msg(__FILE__, __LINE__, 99,
263               "Cannot open file for stat (%s):%s\n", tmpbuf, err);
264         LocalFree((void *)err);
265         rval = -1;
266         errno = GetLastError();
267         goto error;
268     }
269
270     if (!GetFileInformationByHandle(h, &info)) {
271         const char *err = errorString();
272         d_msg(__FILE__, __LINE__, 99,
273               "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
274         LocalFree((void *)err);
275         rval = -1;
276         errno = GetLastError();
277         goto error;
278     }
279
280     sb->st_dev = info.dwVolumeSerialNumber;
281     sb->st_ino = info.nFileIndexHigh;
282     sb->st_ino <<= 32;
283     sb->st_ino |= info.nFileIndexLow;
284     sb->st_nlink = (short)info.nNumberOfLinks;
285
286     sb->st_mode = 0777;               /* start with everything */
287     if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
288         sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
289     if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
290         sb->st_mode &= ~S_IRWXO; /* remove everything for other */
291     if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
292         sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
293     sb->st_mode |= S_IFREG;
294
295     sb->st_size = info.nFileSizeHigh;
296     sb->st_size <<= 32;
297     sb->st_size |= info.nFileSizeLow;
298     sb->st_blksize = 4096;
299     sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
300     sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
301     sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
302     sb->st_ctime = cvt_ftime_to_utime(info.ftLastWriteTime);
303
304 error:
305     CloseHandle(h);
306     return rval;
307 }
308
309 int
310 stat(const char *file, struct stat *sb)
311 {
312     WIN32_FILE_ATTRIBUTE_DATA data;
313     errno = 0;
314
315
316     memset(sb, 0, sizeof(*sb));
317
318     if (g_platform_id == VER_PLATFORM_WIN32_WINDOWS)
319         return stat2(file, sb);
320
321     // otherwise we're on NT
322 #if 0
323     WCHAR buf[32767];
324     buf[0] = '\\';
325     buf[1] = '\\';
326     buf[2] = '?';
327     buf[3] = '\\';
328
329     wchar_win32_path(file, buf+4);
330
331     if (!GetFileAttributesExW((WCHAR *)buf, GetFileExInfoStandard, &data))
332         return stat2(file, sb);
333 #else
334     if (!GetFileAttributesEx(file, GetFileExInfoStandard, &data))
335         return stat2(file, sb);
336 #endif
337
338     sb->st_mode = 0777;               /* start with everything */
339     if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
340         sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
341     if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
342         sb->st_mode &= ~S_IRWXO; /* remove everything for other */
343     if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
344         sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
345
346     if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
347         sb->st_mode |= S_IFDIR;
348     else
349         sb->st_mode |= S_IFREG;
350
351     sb->st_nlink = 1;
352     sb->st_size = data.nFileSizeHigh;
353     sb->st_size <<= 32;
354     sb->st_size |= data.nFileSizeLow;
355     sb->st_blksize = 4096;
356     sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
357     sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
358     sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
359     sb->st_ctime = cvt_ftime_to_utime(data.ftLastWriteTime);
360     return 0;
361 }
362
363 #endif //HAVE_MINGW
364
365 int
366 lstat(const char *file, struct stat *sb)
367 {
368     return stat(file, sb);
369 }
370
371 void
372 sleep(int sec)
373 {
374     Sleep(sec * 1000);
375 }
376
377 int
378 geteuid(void)
379 {
380     return 0;
381 }
382
383 int
384 execvp(const char *, char *[]) {
385     return -1;
386 }
387
388
389 int
390 fork(void)
391 {
392     return -1;
393 }
394
395 int
396 pipe(int[])
397 {
398     return -1;
399 }
400
401 int
402 waitpid(int, int*, int)
403 {
404     return -1;
405 }
406
407 int
408 readlink(const char *, char *, int)
409 {
410     return -1;
411 }
412
413
414 #ifndef HAVE_MINGW
415 int
416 strcasecmp(const char *s1, const char *s2)
417 {
418     register int ch1, ch2;
419
420     if (s1==s2)
421         return 0;       /* strings are equal if same object. */
422     else if (!s1)
423         return -1;
424     else if (!s2)
425         return 1;
426     do
427     {
428         ch1 = *s1;
429         ch2 = *s2;
430         s1++;
431         s2++;
432     } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
433
434   return(ch1 - ch2);
435 }
436 #endif //HAVE_MINGW
437
438 int
439 strncasecmp(const char *s1, const char *s2, int len)
440 {
441     register int ch1, ch2;
442
443     if (s1==s2)
444         return 0;       /* strings are equal if same object. */
445     else if (!s1)
446         return -1;
447     else if (!s2)
448         return 1;
449     do
450     {
451         ch1 = *s1;
452         ch2 = *s2;
453         s1++;
454         s2++;
455     } while (len-- && ch1 != 0 && tolower(ch1) == tolower(ch2));
456
457     return(ch1 - ch2);
458 }
459
460 int
461 gettimeofday(struct timeval *tv, struct timezone *)
462 {
463     SYSTEMTIME now;
464     FILETIME tmp;
465     GetSystemTime(&now);
466
467     if (tv == NULL) return -1;
468     if (!SystemTimeToFileTime(&now, &tmp)) return -1;
469
470     int64_t _100nsec = tmp.dwHighDateTime;
471     _100nsec <<= 32;
472     _100nsec |= tmp.dwLowDateTime;
473     _100nsec -= WIN32_FILETIME_ADJUST;
474
475     tv->tv_sec =(long) (_100nsec / 10000000);
476     tv->tv_usec = (long) ((_100nsec % 10000000)/10);
477     return 0;
478
479 }
480
481 int
482 syslog(int, const char *, const char *)
483 {
484     return 0;
485 }
486
487 struct passwd *
488 getpwuid(uid_t)
489 {
490     return NULL;
491 }
492
493 struct group *
494 getgrgid(uid_t)
495 {
496     return NULL;
497 }
498
499 // implement opendir/readdir/closedir on top of window's API
500 typedef struct _dir
501 {
502     WIN32_FIND_DATA data;       // window's file info
503     const char *spec;           // the directory we're traversing
504     HANDLE      dirh;           // the search handle
505     BOOL        valid;          // the info in data field is valid
506     UINT32      offset;         // pseudo offset for d_off
507 } _dir;
508
509 DIR *
510 opendir(const char *path)
511 {
512     int max_len = strlen(path) + 16;
513     _dir *rval = NULL;
514     if (path == NULL) return NULL;
515
516     rval = (_dir *)malloc(sizeof(_dir));
517     if (rval == NULL) return NULL;
518     char *tspec = (char *)malloc(max_len);
519     if (tspec == NULL) goto err1;
520
521     if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS) {
522         // allow path to be 32767 bytes
523         tspec[0] = '\\';
524         tspec[1] = '\\';
525         tspec[2] = '?';
526         tspec[3] = '\\';
527         tspec[4] = 0;
528         cygwin_conv_to_win32_path(path, tspec+4);
529     } else {
530         cygwin_conv_to_win32_path(path, tspec);
531     }
532
533     strncat(tspec, "\\*", max_len);
534     rval->spec = tspec;
535
536     rval->dirh = FindFirstFile(rval->spec, &rval->data);
537     d_msg(__FILE__, __LINE__,
538           99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
539           path, rval->spec, rval->dirh);
540
541     rval->offset = 0;
542     if (rval->dirh == INVALID_HANDLE_VALUE)
543         goto err;
544     rval->valid = 1;
545     d_msg(__FILE__, __LINE__,
546           99, "\tFirstFile=%s\n", rval->data.cFileName);
547     return (DIR *)rval;
548 err:
549     free((void *)rval->spec);
550 err1:
551     free(rval);
552     return NULL;
553 }
554
555 int
556 closedir(DIR *dirp)
557 {
558     _dir *dp = (_dir *)dirp;
559     FindClose(dp->dirh);
560     free((void *)dp->spec);
561     free((void *)dp);
562     return 0;
563 }
564
565 /*
566   typedef struct _WIN32_FIND_DATA {
567     DWORD dwFileAttributes;
568     FILETIME ftCreationTime;
569     FILETIME ftLastAccessTime;
570     FILETIME ftLastWriteTime;
571     DWORD nFileSizeHigh;
572     DWORD nFileSizeLow;
573     DWORD dwReserved0;
574     DWORD dwReserved1;
575     TCHAR cFileName[MAX_PATH];
576     TCHAR cAlternateFileName[14];
577 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
578 */
579
580 static int
581 copyin(struct dirent &dp, const char *fname)
582 {
583     dp.d_ino = 0;
584     dp.d_reclen = 0;
585     char *cp = dp.d_name;
586     while (*fname) {
587         *cp++ = *fname++;
588         dp.d_reclen++;
589     }
590         *cp = 0;
591     return dp.d_reclen;
592 }
593
594 int
595 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
596 {
597
598     _dir *dp = (_dir *)dirp;
599     if (dp->valid) {
600         entry->d_off = dp->offset;
601         dp->offset += copyin(*entry, dp->data.cFileName);
602         *result = entry;              /* return entry address */
603         d_msg(__FILE__, __LINE__,
604               99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
605               dirp, entry->d_name, entry->d_reclen, entry->d_off);
606     } else {
607 //      d_msg(__FILE__, __LINE__, 99, "readdir_r !valid\n");
608         return -1;
609     }
610     dp->valid = FindNextFile(dp->dirh, &dp->data);
611     return 0;
612 }
613
614 int
615 inet_aton(const char *a, struct in_addr *inp)
616 {
617
618     const char *cp = a;
619     uint32_t acc = 0, tmp = 0;
620     int dotc = 0;
621     if (!isdigit(*a)) return 0;
622     while (*cp) {
623         if (isdigit(*cp))
624             tmp = (tmp * 10) + (*cp -'0');
625         else if (*cp == '.') {
626             if (tmp > 255) return 0;
627             acc = (acc << 8) + tmp;
628             dotc++;
629         }
630         else return 0;
631     }
632
633     if (dotc != 3) return 0;
634     inp->s_addr = acc;
635     return 1;
636 }
637
638 int
639 nanosleep(const struct timespec *req, struct timespec *rem)
640 {
641     if (rem)
642         rem->tv_sec = rem->tv_nsec = 0;
643     Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
644     return 0;
645 }
646
647 void
648 init_signals(void terminate(int sig))
649 {
650
651 }
652
653 void
654 init_stack_dump(void)
655 {
656
657 }
658
659
660 long
661 pathconf(const char *path, int name)
662 {
663     switch(name) {
664     case _PC_PATH_MAX :
665         if (strncmp(path, "\\\\?\\", 4) == 0)
666             return 32767;
667     case _PC_NAME_MAX :
668         return 255;
669     }
670
671     return -1;
672 }
673
674 int
675 WSA_Init(void)
676 {
677     WORD wVersionRequested = MAKEWORD( 1, 1);
678     WSADATA wsaData;
679
680     int err = WSAStartup(wVersionRequested, &wsaData);
681
682
683     if (err != 0)
684     {
685         printf("Can not start Windows Sockets\n");
686         return -1;
687     }
688
689     return 0;
690 }
691
692
693 int
694 win32_chdir(const char *dir)
695 {
696     if (0 == SetCurrentDirectory(dir)) return -1;
697     return 0;
698 }
699
700 char *
701 win32_getcwd(char *buf, int maxlen)
702 {
703    int n =  GetCurrentDirectory(maxlen, buf);
704
705    if (n == 0 || n > maxlen) return NULL;
706
707    if (n+1 > maxlen) return NULL;
708    if (n != 3) {
709        buf[n] = '\\';
710        buf[n+1] = 0;
711    }
712
713    return buf;
714 }
715
716 #include "mswinver.h"
717
718 char WIN_VERSION_LONG[64];
719 char WIN_VERSION[32];
720
721 class winver {
722 public:
723     winver(void);
724 };
725
726 static winver INIT;                     // cause constructor to be called before main()
727
728 #include "bacula.h"
729 #include "jcr.h"
730
731 winver::winver(void)
732 {
733     const char *version = "";
734     const char *platform = "";
735     OSVERSIONINFO osvinfo;
736     osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
737
738     // Get the current OS version
739     if (!GetVersionEx(&osvinfo)) {
740         version = "Unknown";
741         platform = "Unknown";
742     }
743     else
744         switch (_mkversion(osvinfo.dwPlatformId, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion))
745         {
746         case MS_WINDOWS_95: (version =  "Windows 95"); break;
747         case MS_WINDOWS_98: (version =  "Windows 98"); break;
748         case MS_WINDOWS_ME: (version =  "Windows ME"); break;
749         case MS_WINDOWS_NT4:(version =  "Windows NT 4.0"); platform = "NT"; break;
750         case MS_WINDOWS_2K: (version =  "Windows 2000");platform = "NT"; break;
751         case MS_WINDOWS_XP: (version =  "Windows XP");platform = "NT"; break;
752         case MS_WINDOWS_S2003: (version =  "Windows Server 2003");platform = "NT"; break;
753         default: version = "Windows ??"; break;
754         }
755
756     bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
757     snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %d.%d.%d",
758              platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
759
760 #if 0
761     HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
762     CloseHandle(h);
763 #endif
764 #if 0
765     BPIPE *b = open_bpipe("ls -l", 10, "r");
766     char buf[1024];
767     while (!feof(b->rfd)) {
768         fgets(buf, sizeof(buf), b->rfd);
769     }
770     close_bpipe(b);
771 #endif
772 }
773
774 BOOL CreateChildProcess(VOID);
775 VOID WriteToPipe(VOID);
776 VOID ReadFromPipe(VOID);
777 VOID ErrorExit(LPTSTR);
778 VOID ErrMsg(LPTSTR, BOOL);
779
780
781 const char *
782 getArgv0(const char *cmdline)
783 {
784     const char *cp = cmdline;
785
786     while (*cp && !isspace(*cp)) cp++;
787
788     int len = cp - cmdline;
789     char *rval = (char *)malloc(len+1);
790
791     cp = cmdline;
792     char *rp = rval;
793     while (len--)
794         *rp++ = *cp++;
795
796     *rp = 0;
797     return rval;
798 }
799
800 HANDLE
801 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
802 {
803     PROCESS_INFORMATION piProcInfo;
804     STARTUPINFO siStartInfo;
805     BOOL bFuncRetn = FALSE;
806
807     // Set up members of the PROCESS_INFORMATION structure.
808
809     ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
810
811     // Set up members of the STARTUPINFO structure.
812
813     ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
814     siStartInfo.cb = sizeof(STARTUPINFO);
815     // setup new process to use supplied handles for stdin,stdout,stderr
816     // if supplied handles are not used the send a copy of our STD_HANDLE
817     // as appropriate
818     siStartInfo.dwFlags = STARTF_USESTDHANDLES;
819
820     if (in != INVALID_HANDLE_VALUE)
821         siStartInfo.hStdInput = in;
822     else
823         siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
824
825     if (out != INVALID_HANDLE_VALUE)
826         siStartInfo.hStdOutput = out;
827     else
828         siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
829     if (err != INVALID_HANDLE_VALUE)
830         siStartInfo.hStdError = err;
831     else
832         siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
833     // Create the child process.
834
835     char cmdLine[1024];
836     char exeFile[1024];
837     // retrive the first compont of the command line which should be the
838     // executable
839     const char *exeName = getArgv0(cmdline);
840     // check to see if absolute path was passed to us already?
841     if (exeName[1] != ':'
842         || (strchr(cmdline, '/') == NULL
843             && strchr(cmdline, '\\') == NULL))
844     {
845         // only command name so perform search of PATH to find
846         char *file;
847         DWORD rval = SearchPath(NULL,
848                                 exeName,
849                                 ".exe",
850                                 sizeof(exeFile),
851                                 exeFile,
852                                 &file);
853         if (rval == 0)
854             return INVALID_HANDLE_VALUE;
855         if (rval > sizeof(exeFile))
856             return INVALID_HANDLE_VALUE;
857
858     }
859     else
860         strcpy(exeFile, exeName);
861
862     // exeFile now has absolute path to program to execute.
863     free((void *)exeName);
864     // copy original command line to pass to create process
865     strcpy(cmdLine, cmdline);
866     // try to execute program
867     bFuncRetn = CreateProcess(exeFile,
868                               cmdLine, // command line
869                               NULL, // process security attributes
870                               NULL, // primary thread security attributes
871                               TRUE, // handles are inherited
872                               0, // creation flags
873                               NULL, // use parent's environment
874                               NULL, // use parent's current directory
875                               &siStartInfo, // STARTUPINFO pointer
876                               &piProcInfo); // receives PROCESS_INFORMATION
877
878     if (bFuncRetn == 0) {
879         ErrorExit("CreateProcess failed\n");
880         return INVALID_HANDLE_VALUE;
881     }
882     // we don't need a handle on the process primary thread so we close
883     // this now.
884     CloseHandle(piProcInfo.hThread);
885
886     return piProcInfo.hProcess;
887 }
888
889
890 void
891 ErrorExit (LPTSTR lpszMessage)
892 {
893     d_msg(__FILE__, __LINE__, 0, "%s", lpszMessage);
894 }
895
896
897 /*
898 typedef struct s_bpipe {
899    pid_t worker_pid;
900    time_t worker_stime;
901    int wait;
902    btimer_t *timer_id;
903    FILE *rfd;
904    FILE *wfd;
905 } BPIPE;
906 */
907
908 static void
909 CloseIfValid(HANDLE handle)
910 {
911     if (handle != INVALID_HANDLE_VALUE)
912         CloseHandle(handle);
913 }
914
915 #ifndef HAVE_MINGW
916 BPIPE *
917 open_bpipe(char *prog, int wait, const char *mode)
918 {
919     HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
920         hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
921         hInputFile;
922
923     SECURITY_ATTRIBUTES saAttr;
924
925     BOOL fSuccess;
926
927     hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
928         hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
929         hInputFile = INVALID_HANDLE_VALUE;
930
931     BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
932     memset((void *)bpipe, 0, sizeof(BPIPE));
933
934     int mode_read = (mode[0] == 'r');
935     int mode_write = (mode[0] == 'w' || mode[1] == 'w');
936
937
938     // Set the bInheritHandle flag so pipe handles are inherited.
939
940     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
941     saAttr.bInheritHandle = TRUE;
942     saAttr.lpSecurityDescriptor = NULL;
943
944     if (mode_read) {
945
946         // Create a pipe for the child process's STDOUT.
947         if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
948             ErrorExit("Stdout pipe creation failed\n");
949             goto cleanup;
950         }
951         // Create noninheritable read handle and close the inheritable read
952         // handle.
953
954         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
955                                    GetCurrentProcess(), &hChildStdoutRdDup , 0,
956                                    FALSE,
957                                    DUPLICATE_SAME_ACCESS);
958         if ( !fSuccess ) {
959             ErrorExit("DuplicateHandle failed");
960             goto cleanup;
961         }
962
963         CloseHandle(hChildStdoutRd);
964     }
965
966     if (mode_write) {
967
968         // Create a pipe for the child process's STDIN.
969
970         if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
971             ErrorExit("Stdin pipe creation failed\n");
972             goto cleanup;
973         }
974
975         // Duplicate the write handle to the pipe so it is not inherited.
976         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
977                                    GetCurrentProcess(), &hChildStdinWrDup,
978                                    0,
979                                    FALSE,                  // not inherited
980                                    DUPLICATE_SAME_ACCESS);
981         if (!fSuccess) {
982             ErrorExit("DuplicateHandle failed");
983             goto cleanup;
984         }
985
986         CloseHandle(hChildStdinWr);
987     }
988     // spawn program with redirected handles as appropriate
989     bpipe->worker_pid = (pid_t)
990         CreateChildProcess(prog, // commandline
991                            hChildStdinRd, // stdin HANDLE
992                            hChildStdoutWr, // stdout HANDLE
993                            hChildStdoutWr);// stderr HANDLE
994
995     if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
996         goto cleanup;
997
998     bpipe->wait = wait;
999     bpipe->worker_stime = time(NULL);
1000
1001     if (mode_read) {
1002         CloseHandle(hChildStdoutWr); // close our write side so when
1003                                      // process terminates we can
1004                                      // detect eof.
1005         // ugly but convert WIN32 HANDLE to FILE*
1006         int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY);
1007         bpipe->rfd = _fdopen(rfd, "r");
1008     }
1009     if (mode_write) {
1010         CloseHandle(hChildStdinRd); // close our read side so as not
1011                                     // to interfre with child's copy
1012         // ugly but convert WIN32 HANDLE to FILE*
1013         int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY);
1014         bpipe->wfd = _fdopen(wfd, "w");
1015     }
1016
1017     if (wait > 0) {
1018         bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
1019     }
1020
1021     return bpipe;
1022
1023 cleanup:
1024
1025     CloseIfValid(hChildStdoutRd);
1026     CloseIfValid(hChildStdoutRdDup);
1027     CloseIfValid(hChildStdinWr);
1028     CloseIfValid(hChildStdinWrDup);
1029
1030     free((void *) bpipe);
1031
1032     return NULL;
1033 }
1034
1035 #endif //HAVE_MINGW
1036
1037 int
1038 kill(int pid, int signal)
1039 {
1040     int rval = 0;
1041     if (!TerminateProcess((HANDLE)pid, (UINT) signal))
1042         rval = -1;
1043     CloseHandle((HANDLE)pid);
1044     return rval;
1045 }
1046
1047 #ifndef HAVE_MINGW
1048
1049 int
1050 close_bpipe(BPIPE *bpipe)
1051 {
1052     int rval = 0;
1053     if (bpipe->rfd) fclose(bpipe->rfd);
1054     if (bpipe->wfd) fclose(bpipe->wfd);
1055
1056     if (bpipe->wait) {
1057         int remaining_wait = bpipe->wait;
1058         do
1059         {
1060             DWORD exitCode;
1061             if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode))
1062             {
1063                 const char *err = errorString();
1064                 rval = GetLastError();
1065                 d_msg(__FILE__, __LINE__, 0,
1066                       "GetExitCode error %s\n", err);
1067                 LocalFree((void *)err);
1068                 break;
1069             }
1070
1071             if (exitCode == STILL_ACTIVE) {
1072                 bmicrosleep(1, 0);             /* wait one second */
1073                 remaining_wait--;
1074             }
1075             else break;
1076         } while(remaining_wait);
1077     }
1078
1079     if (bpipe->timer_id) {
1080         stop_child_timer(bpipe->timer_id);
1081     }
1082     free((void *)bpipe);
1083     return rval;
1084 }
1085
1086 int
1087 close_wpipe(BPIPE *bpipe)
1088 {
1089     int stat = 1;
1090
1091     if (bpipe->wfd) {
1092         fflush(bpipe->wfd);
1093         if (fclose(bpipe->wfd) != 0) {
1094             stat = 0;
1095       }
1096         bpipe->wfd = NULL;
1097     }
1098     return stat;
1099 }
1100
1101 #include "findlib/find.h"
1102
1103 int
1104 utime(const char *fname, struct utimbuf *times)
1105 {
1106     FILETIME acc, mod;
1107     char tmpbuf[1024];
1108
1109     cygwin_conv_to_win32_path(fname, tmpbuf);
1110
1111     cvt_utime_to_ftime(times->actime, acc);
1112     cvt_utime_to_ftime(times->modtime, mod);
1113
1114     HANDLE h = CreateFile(tmpbuf,
1115                           FILE_WRITE_ATTRIBUTES,
1116                           FILE_SHARE_WRITE,
1117                           NULL,
1118                           OPEN_EXISTING,
1119                           0,
1120                           NULL);
1121
1122     if (h == INVALID_HANDLE_VALUE) {
1123         const char *err = errorString();
1124         d_msg(__FILE__, __LINE__, 99,
1125               "Cannot open file for utime(%s,...):%s\n", tmpbuf, err);
1126         LocalFree((void *)err);
1127         return -1;
1128     }
1129
1130     int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
1131
1132     CloseHandle(h);
1133
1134     return rval;
1135 }
1136
1137 #if USE_WIN32_COMPAT_IO
1138
1139 int
1140 open(const char *file, int flags, int mode)
1141 {
1142     return _open(file, flags|_O_BINARY, mode);
1143
1144 }
1145
1146 int
1147 close(int fd)
1148 {
1149     return _close(fd);
1150 }
1151
1152 #ifndef HAVE_WXCONSOLE
1153 ssize_t
1154 read(int fd, void *buf, size_t len)
1155 {
1156     return _read(fd, buf, len);
1157 }
1158
1159 ssize_t
1160 write(int fd, const void *buf, size_t len)
1161 {
1162     return _write(fd, buf, len);
1163 }
1164 #endif
1165
1166 off_t
1167 lseek(int fd, off_t offset, int whence)
1168 {
1169     return _lseeki64(fd, offset, whence);
1170 }
1171
1172 int
1173 dup2(int fd1, int fd2)
1174 {
1175     return _dup2(fd1, fd2);
1176 }
1177 #else
1178 int
1179 open(const char *file, int flags, int mode)
1180 {
1181     DWORD access = 0;
1182     DWORD shareMode = 0;
1183     DWORD create = 0;
1184     DWORD msflags = 0;
1185     HANDLE foo;
1186     const char *remap = file;
1187
1188     if (flags & O_WRONLY) access = GENERIC_WRITE;
1189     else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
1190     else access = GENERIC_READ;
1191
1192     if (flags & O_CREAT) create = CREATE_NEW;
1193     else create = OPEN_EXISTING;
1194
1195     if (flags & O_TRUNC) create = TRUNCATE_EXISTING;
1196
1197     if (!(flags & O_EXCL))
1198         shareMode = FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE;
1199
1200     if (flags & O_APPEND)
1201     {
1202         printf("open...APPEND not implemented yet.");
1203         exit(-1);
1204     }
1205
1206     foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
1207     if (INVALID_HANDLE_VALUE == foo)
1208         return(int) -1;
1209
1210     return (int)foo;
1211
1212 }
1213
1214
1215 int
1216 close(int fd)
1217 {
1218     if (!CloseHandle((HANDLE)fd))
1219         return -1;
1220
1221     return 0;
1222 }
1223
1224 ssize_t
1225 write(int fd, const void *data, size_t len)
1226 {
1227     BOOL status;
1228     DWORD bwrite;
1229     status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
1230     if (status) return bwrite;
1231     return -1;
1232 }
1233
1234
1235 ssize_t
1236 read(int fd, void *data, size_t len)
1237 {
1238     BOOL status;
1239     DWORD bread;
1240
1241     status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
1242     if (status) return bread;
1243     return -1;
1244 }
1245
1246 off_t
1247 lseek(int fd, off_t offset, int whence)
1248 {
1249     DWORD method = 0;
1250     switch (whence) {
1251     case SEEK_SET :
1252         method = FILE_BEGIN;
1253         break;
1254     case SEEK_CUR:
1255         method = FILE_CURRENT;
1256         break;
1257     case SEEK_END:
1258         method = FILE_END;
1259         break;
1260     default:
1261         return -1;
1262     }
1263
1264     return SetFilePointer((HANDLE)fd, (DWORD)offset, NULL, method);
1265 }
1266
1267 int
1268 dup2(int, int)
1269 {
1270     return -1;
1271 }
1272
1273
1274 #endif
1275
1276 #endif //HAVE_MINGW
1277
1278 #ifdef HAVE_MINGW
1279 /* syslog function, added by Nicolas Boichat */
1280 void closelog() {}
1281 #endif //HAVE_MINGW