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