]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/compat.cpp
80a77f578d8152f78a349974c01b3064d599c5dd
[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 MicroSoft SDK (KES) is the 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     while (len--)
450     {
451         ch1 = *s1;
452         ch2 = *s2;
453         s1++;
454         s2++;
455         if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
456     } 
457
458     return(ch1 - ch2);
459 }
460
461 int
462 gettimeofday(struct timeval *tv, struct timezone *)
463 {
464     SYSTEMTIME now;
465     FILETIME tmp;
466     GetSystemTime(&now);
467
468     if (tv == NULL) return -1;
469     if (!SystemTimeToFileTime(&now, &tmp)) return -1;
470
471     int64_t _100nsec = tmp.dwHighDateTime;
472     _100nsec <<= 32;
473     _100nsec |= tmp.dwLowDateTime;
474     _100nsec -= WIN32_FILETIME_ADJUST;
475
476     tv->tv_sec =(long) (_100nsec / 10000000);
477     tv->tv_usec = (long) ((_100nsec % 10000000)/10);
478     return 0;
479
480 }
481
482 int
483 syslog(int type, const char *fmt, const char *msg)
484 {
485 /*#ifndef HAVE_CONSOLE
486     MessageBox(NULL, msg, "Bacula", MB_OK);
487 #endif*/
488     return 0;
489 }
490
491 struct passwd *
492 getpwuid(uid_t)
493 {
494     return NULL;
495 }
496
497 struct group *
498 getgrgid(uid_t)
499 {
500     return NULL;
501 }
502
503 // implement opendir/readdir/closedir on top of window's API
504 typedef struct _dir
505 {
506     WIN32_FIND_DATA data;       // window's file info
507     const char *spec;           // the directory we're traversing
508     HANDLE      dirh;           // the search handle
509     BOOL        valid;          // the info in data field is valid
510     UINT32      offset;         // pseudo offset for d_off
511 } _dir;
512
513 DIR *
514 opendir(const char *path)
515 {
516     int max_len = strlen(path) + 16;
517     _dir *rval = NULL;
518     if (path == NULL) return NULL;
519
520     rval = (_dir *)malloc(sizeof(_dir));
521     if (rval == NULL) return NULL;
522     char *tspec = (char *)malloc(max_len);
523     if (tspec == NULL) goto err1;
524
525     if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS) {
526         // allow path to be 32767 bytes
527         tspec[0] = '\\';
528         tspec[1] = '\\';
529         tspec[2] = '?';
530         tspec[3] = '\\';
531         tspec[4] = 0;
532         cygwin_conv_to_win32_path(path, tspec+4);
533     } else {
534         cygwin_conv_to_win32_path(path, tspec);
535     }
536
537     strncat(tspec, "\\*", max_len);
538     rval->spec = tspec;
539
540     rval->dirh = FindFirstFile(rval->spec, &rval->data);
541     d_msg(__FILE__, __LINE__,
542           99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
543           path, rval->spec, rval->dirh);
544
545     rval->offset = 0;
546     if (rval->dirh == INVALID_HANDLE_VALUE)
547         goto err;
548     rval->valid = 1;
549     d_msg(__FILE__, __LINE__,
550           99, "\tFirstFile=%s\n", rval->data.cFileName);
551     return (DIR *)rval;
552 err:
553     free((void *)rval->spec);
554 err1:
555     free(rval);
556     return NULL;
557 }
558
559 int
560 closedir(DIR *dirp)
561 {
562     _dir *dp = (_dir *)dirp;
563     FindClose(dp->dirh);
564     free((void *)dp->spec);
565     free((void *)dp);
566     return 0;
567 }
568
569 /*
570   typedef struct _WIN32_FIND_DATA {
571     DWORD dwFileAttributes;
572     FILETIME ftCreationTime;
573     FILETIME ftLastAccessTime;
574     FILETIME ftLastWriteTime;
575     DWORD nFileSizeHigh;
576     DWORD nFileSizeLow;
577     DWORD dwReserved0;
578     DWORD dwReserved1;
579     TCHAR cFileName[MAX_PATH];
580     TCHAR cAlternateFileName[14];
581 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
582 */
583
584 static int
585 copyin(struct dirent &dp, const char *fname)
586 {
587     dp.d_ino = 0;
588     dp.d_reclen = 0;
589     char *cp = dp.d_name;
590     while (*fname) {
591         *cp++ = *fname++;
592         dp.d_reclen++;
593     }
594         *cp = 0;
595     return dp.d_reclen;
596 }
597
598 int
599 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
600 {
601
602     _dir *dp = (_dir *)dirp;
603     if (dp->valid) {
604         entry->d_off = dp->offset;
605         dp->offset += copyin(*entry, dp->data.cFileName);
606         *result = entry;              /* return entry address */
607         d_msg(__FILE__, __LINE__,
608               99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
609               dirp, entry->d_name, entry->d_reclen, entry->d_off);
610     } else {
611 //      d_msg(__FILE__, __LINE__, 99, "readdir_r !valid\n");
612         return -1;
613     }
614     dp->valid = FindNextFile(dp->dirh, &dp->data);
615     return 0;
616 }
617
618 int
619 inet_aton(const char *a, struct in_addr *inp)
620 {
621
622     const char *cp = a;
623     uint32_t acc = 0, tmp = 0;
624     int dotc = 0;
625     if (!isdigit(*a)) return 0;
626     while (*cp) {
627         if (isdigit(*cp))
628             tmp = (tmp * 10) + (*cp -'0');
629         else if (*cp == '.') {
630             if (tmp > 255) return 0;
631             acc = (acc << 8) + tmp;
632             dotc++;
633         }
634         else return 0;
635     }
636
637     if (dotc != 3) return 0;
638     inp->s_addr = acc;
639     return 1;
640 }
641
642 int
643 nanosleep(const struct timespec *req, struct timespec *rem)
644 {
645     if (rem)
646         rem->tv_sec = rem->tv_nsec = 0;
647     Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
648     return 0;
649 }
650
651 void
652 init_signals(void terminate(int sig))
653 {
654
655 }
656
657 void
658 init_stack_dump(void)
659 {
660
661 }
662
663
664 long
665 pathconf(const char *path, int name)
666 {
667     switch(name) {
668     case _PC_PATH_MAX :
669         if (strncmp(path, "\\\\?\\", 4) == 0)
670             return 32767;
671     case _PC_NAME_MAX :
672         return 255;
673     }
674
675     return -1;
676 }
677
678 int
679 WSA_Init(void)
680 {
681     WORD wVersionRequested = MAKEWORD( 1, 1);
682     WSADATA wsaData;
683
684     int err = WSAStartup(wVersionRequested, &wsaData);
685
686
687     if (err != 0)
688     {
689         printf("Can not start Windows Sockets\n");
690         return -1;
691     }
692
693     return 0;
694 }
695
696
697 int
698 win32_chdir(const char *dir)
699 {
700     if (0 == SetCurrentDirectory(dir)) return -1;
701     return 0;
702 }
703
704 char *
705 win32_getcwd(char *buf, int maxlen)
706 {
707    int n =  GetCurrentDirectory(maxlen, buf);
708
709    if (n == 0 || n > maxlen) return NULL;
710
711    if (n+1 > maxlen) return NULL;
712    if (n != 3) {
713        buf[n] = '\\';
714        buf[n+1] = 0;
715    }
716
717    return buf;
718 }
719
720 #include "mswinver.h"
721
722 char WIN_VERSION_LONG[64];
723 char WIN_VERSION[32];
724
725 class winver {
726 public:
727     winver(void);
728 };
729
730 static winver INIT;                     // cause constructor to be called before main()
731
732 #include "bacula.h"
733 #include "jcr.h"
734
735 winver::winver(void)
736 {
737     const char *version = "";
738     const char *platform = "";
739     OSVERSIONINFO osvinfo;
740     osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
741
742     // Get the current OS version
743     if (!GetVersionEx(&osvinfo)) {
744         version = "Unknown";
745         platform = "Unknown";
746     }
747     else
748         switch (_mkversion(osvinfo.dwPlatformId, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion))
749         {
750         case MS_WINDOWS_95: (version =  "Windows 95"); break;
751         case MS_WINDOWS_98: (version =  "Windows 98"); break;
752         case MS_WINDOWS_ME: (version =  "Windows ME"); break;
753         case MS_WINDOWS_NT4:(version =  "Windows NT 4.0"); platform = "NT"; break;
754         case MS_WINDOWS_2K: (version =  "Windows 2000");platform = "NT"; break;
755         case MS_WINDOWS_XP: (version =  "Windows XP");platform = "NT"; break;
756         case MS_WINDOWS_S2003: (version =  "Windows Server 2003");platform = "NT"; break;
757         default: version = "Windows ??"; break;
758         }
759
760     bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
761     snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %d.%d.%d",
762              platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
763
764 #if 0
765     HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
766     CloseHandle(h);
767 #endif
768 #if 0
769     BPIPE *b = open_bpipe("ls -l", 10, "r");
770     char buf[1024];
771     while (!feof(b->rfd)) {
772         fgets(buf, sizeof(buf), b->rfd);
773     }
774     close_bpipe(b);
775 #endif
776 }
777
778 BOOL CreateChildProcess(VOID);
779 VOID WriteToPipe(VOID);
780 VOID ReadFromPipe(VOID);
781 VOID ErrorExit(LPTSTR);
782 VOID ErrMsg(LPTSTR, BOOL);
783
784 /**
785  * Check for a quoted path,  if an absolute path name is given and it contains
786  * spaces it will need to be quoted.  i.e.  "c:/Program Files/foo/bar.exe"
787  * CreateProcess() says the best way to ensure proper results with executables
788  * with spaces in path or filename is to quote the string.
789  */
790 const char *
791 getArgv0(const char *cmdline)
792 {
793
794     int inquote = 0;
795     for (const char *cp = cmdline; *cp; cp++)
796     {
797         if (*cp == '"') {
798             inquote = !inquote;
799         }
800         if (!inquote && isspace(*cp))
801             break;
802     }
803
804         
805     int len = cp - cmdline;
806     char *rval = (char *)malloc(len+1);
807
808     cp = cmdline;
809     char *rp = rval;
810     
811     while (len--)
812         *rp++ = *cp++;
813
814     *rp = 0;
815     return rval;
816 }
817
818
819 /**
820  * OK, so it would seem CreateProcess only handles true executables:
821  *  .com or .exe files.
822  * So test to see whether we're getting a .bat file and if so grab
823  * $COMSPEC value and pass batch file to it.
824  */
825 HANDLE
826 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
827 {
828     PROCESS_INFORMATION piProcInfo;
829     STARTUPINFO siStartInfo;
830     BOOL bFuncRetn = FALSE;
831
832     // Set up members of the PROCESS_INFORMATION structure.
833
834     ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
835
836     // Set up members of the STARTUPINFO structure.
837
838     ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
839     siStartInfo.cb = sizeof(STARTUPINFO);
840     // setup new process to use supplied handles for stdin,stdout,stderr
841     // if supplied handles are not used the send a copy of our STD_HANDLE
842     // as appropriate
843     siStartInfo.dwFlags = STARTF_USESTDHANDLES;
844
845     if (in != INVALID_HANDLE_VALUE)
846         siStartInfo.hStdInput = in;
847     else
848         siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
849
850     if (out != INVALID_HANDLE_VALUE)
851         siStartInfo.hStdOutput = out;
852     else
853         siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
854     if (err != INVALID_HANDLE_VALUE)
855         siStartInfo.hStdError = err;
856     else
857         siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
858     // Create the child process.
859
860     char exeFile[256];
861
862     const char *comspec = getenv("COMSPEC");
863     
864     if (comspec == NULL) // should never happen
865         return INVALID_HANDLE_VALUE;
866
867     char *cmdLine = (char *)alloca(strlen(cmdline) + strlen(comspec) + 16);
868     
869     strcpy(exeFile, comspec);
870     strcpy(cmdLine, comspec);
871     strcat(cmdLine, " /c ");
872     strcat(cmdLine, cmdline);
873
874     // try to execute program
875     bFuncRetn = CreateProcess(exeFile,
876                               cmdLine, // command line
877                               NULL, // process security attributes
878                               NULL, // primary thread security attributes
879                               TRUE, // handles are inherited
880                               0, // creation flags
881                               NULL, // use parent's environment
882                               NULL, // use parent's current directory
883                               &siStartInfo, // STARTUPINFO pointer
884                               &piProcInfo); // receives PROCESS_INFORMATION
885
886     if (bFuncRetn == 0) {
887         ErrorExit("CreateProcess failed\n");
888         const char *err = errorString();
889         d_msg(__FILE__, __LINE__, 99,
890               "CreateProcess(%s, %s, ...)=%s\n", exeFile, cmdLine, err);
891         LocalFree((void *)err);
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
927 #ifndef HAVE_MINGW
928 BPIPE *
929 open_bpipe(char *prog, int wait, const char *mode)
930 {
931     HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
932         hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
933         hInputFile;
934
935     SECURITY_ATTRIBUTES saAttr;
936
937     BOOL fSuccess;
938
939     hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
940         hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
941         hInputFile = INVALID_HANDLE_VALUE;
942
943     BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
944     memset((void *)bpipe, 0, sizeof(BPIPE));
945
946     int mode_read = (mode[0] == 'r');
947     int mode_write = (mode[0] == 'w' || mode[1] == 'w');
948
949
950     // Set the bInheritHandle flag so pipe handles are inherited.
951
952     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
953     saAttr.bInheritHandle = TRUE;
954     saAttr.lpSecurityDescriptor = NULL;
955
956     if (mode_read) {
957
958         // Create a pipe for the child process's STDOUT.
959         if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
960             ErrorExit("Stdout pipe creation failed\n");
961             goto cleanup;
962         }
963         // Create noninheritable read handle and close the inheritable read
964         // handle.
965
966         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
967                                    GetCurrentProcess(), &hChildStdoutRdDup , 0,
968                                    FALSE,
969                                    DUPLICATE_SAME_ACCESS);
970         if ( !fSuccess ) {
971             ErrorExit("DuplicateHandle failed");
972             goto cleanup;
973         }
974
975         CloseHandle(hChildStdoutRd);
976         hChildStdoutRd = INVALID_HANDLE_VALUE;
977     }
978
979     if (mode_write) {
980
981         // Create a pipe for the child process's STDIN.
982
983         if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
984             ErrorExit("Stdin pipe creation failed\n");
985             goto cleanup;
986         }
987
988         // Duplicate the write handle to the pipe so it is not inherited.
989         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
990                                    GetCurrentProcess(), &hChildStdinWrDup,
991                                    0,
992                                    FALSE,                  // not inherited
993                                    DUPLICATE_SAME_ACCESS);
994         if (!fSuccess) {
995             ErrorExit("DuplicateHandle failed");
996             goto cleanup;
997         }
998
999         CloseHandle(hChildStdinWr);
1000         hChildStdinWr = INVALID_HANDLE_VALUE;
1001     }
1002     // spawn program with redirected handles as appropriate
1003     bpipe->worker_pid = (pid_t)
1004         CreateChildProcess(prog,             // commandline
1005                            hChildStdinRd,    // stdin HANDLE
1006                            hChildStdoutWr,   // stdout HANDLE
1007                            hChildStdoutWr);  // stderr HANDLE
1008
1009     if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1010         goto cleanup;
1011
1012     bpipe->wait = wait;
1013     bpipe->worker_stime = time(NULL);
1014
1015     if (mode_read) {
1016         CloseHandle(hChildStdoutWr); // close our write side so when
1017                                      // process terminates we can
1018                                      // detect eof.
1019         // ugly but convert WIN32 HANDLE to FILE*
1020         int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY);
1021         if (rfd >= 0) {
1022            bpipe->rfd = _fdopen(rfd, "r");
1023         }
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         if (wfd >= 0) {
1031            bpipe->wfd = _fdopen(wfd, "w");
1032         }
1033     }
1034
1035     if (wait > 0) {
1036         bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
1037     }
1038
1039     return bpipe;
1040
1041 cleanup:
1042
1043     CloseIfValid(hChildStdoutRd);
1044     CloseIfValid(hChildStdoutRdDup);
1045     CloseIfValid(hChildStdinWr);
1046     CloseIfValid(hChildStdinWrDup);
1047
1048     free((void *) bpipe);
1049
1050     return NULL;
1051 }
1052
1053 #endif //HAVE_MINGW
1054
1055 int
1056 kill(int pid, int signal)
1057 {
1058     int rval = 0;
1059     if (!TerminateProcess((HANDLE)pid, (UINT) signal))
1060         rval = -1;
1061     CloseHandle((HANDLE)pid);
1062     return rval;
1063 }
1064
1065 #ifndef HAVE_MINGW
1066
1067 int
1068 close_bpipe(BPIPE *bpipe)
1069 {
1070     int rval = 0;
1071     if (bpipe->rfd) fclose(bpipe->rfd);
1072     if (bpipe->wfd) fclose(bpipe->wfd);
1073
1074     if (bpipe->wait) {
1075         int remaining_wait = bpipe->wait;
1076         do {
1077             DWORD exitCode;
1078             if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
1079                 const char *err = errorString();
1080                 rval = GetLastError();
1081                 d_msg(__FILE__, __LINE__, 0,
1082                       "GetExitCode error %s\n", err);
1083                 LocalFree((void *)err);
1084                 break;
1085             }
1086
1087             if (exitCode == STILL_ACTIVE) {
1088                 bmicrosleep(1, 0);             /* wait one second */
1089                 remaining_wait--;
1090             }
1091             else break;
1092         } while(remaining_wait);
1093     }
1094
1095     if (bpipe->timer_id) {
1096         stop_child_timer(bpipe->timer_id);
1097     }
1098     free((void *)bpipe);
1099     return rval;
1100 }
1101
1102 int
1103 close_wpipe(BPIPE *bpipe)
1104 {
1105     int stat = 1;
1106
1107     if (bpipe->wfd) {
1108         fflush(bpipe->wfd);
1109         if (fclose(bpipe->wfd) != 0) {
1110             stat = 0;
1111       }
1112         bpipe->wfd = NULL;
1113     }
1114     return stat;
1115 }
1116
1117 #include "findlib/find.h"
1118
1119 int
1120 utime(const char *fname, struct utimbuf *times)
1121 {
1122     FILETIME acc, mod;
1123     char tmpbuf[1024];
1124
1125     cygwin_conv_to_win32_path(fname, tmpbuf);
1126
1127     cvt_utime_to_ftime(times->actime, acc);
1128     cvt_utime_to_ftime(times->modtime, mod);
1129
1130     HANDLE h = CreateFile(tmpbuf,
1131                           FILE_WRITE_ATTRIBUTES,
1132                           FILE_SHARE_WRITE,
1133                           NULL,
1134                           OPEN_EXISTING,
1135                           0,
1136                           NULL);
1137
1138     if (h == INVALID_HANDLE_VALUE) {
1139         const char *err = errorString();
1140         d_msg(__FILE__, __LINE__, 99,
1141               "Cannot open file for utime(%s,...):%s\n", tmpbuf, err);
1142         LocalFree((void *)err);
1143         return -1;
1144     }
1145
1146     int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
1147
1148     CloseHandle(h);
1149
1150     return rval;
1151 }
1152
1153 #if USE_WIN32_COMPAT_IO
1154
1155 int
1156 open(const char *file, int flags, int mode)
1157 {
1158     return _open(file, flags|_O_BINARY, mode);
1159
1160 }
1161
1162 int
1163 close(int fd)
1164 {
1165     int rval = _close(fd);
1166     if (rval == -1)
1167         rval = closesocket(fd);
1168     return rval;
1169 }
1170
1171 #ifndef HAVE_WXCONSOLE
1172 ssize_t
1173 read(int fd, void *buf, size_t len)
1174 {
1175     return _read(fd, buf, len);
1176 }
1177
1178 ssize_t
1179 write(int fd, const void *buf, size_t len)
1180 {
1181     return _write(fd, buf, len);
1182 }
1183 #endif
1184
1185 off_t
1186 lseek(int fd, off_t offset, int whence)
1187 {
1188     return (off_t)_lseeki64(fd, offset, whence);
1189 }
1190
1191 int
1192 dup2(int fd1, int fd2)
1193 {
1194     return _dup2(fd1, fd2);
1195 }
1196 #else
1197 int
1198 open(const char *file, int flags, int mode)
1199 {
1200     DWORD access = 0;
1201     DWORD shareMode = 0;
1202     DWORD create = 0;
1203     DWORD msflags = 0;
1204     HANDLE foo;
1205     const char *remap = file;
1206
1207     if (flags & O_WRONLY) access = GENERIC_WRITE;
1208     else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
1209     else access = GENERIC_READ;
1210
1211     if (flags & O_CREAT) create = CREATE_NEW;
1212     else create = OPEN_EXISTING;
1213
1214     if (flags & O_TRUNC) create = TRUNCATE_EXISTING;
1215
1216     if (!(flags & O_EXCL))
1217         shareMode = FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE;
1218
1219     if (flags & O_APPEND)
1220     {
1221         printf("open...APPEND not implemented yet.");
1222         exit(-1);
1223     }
1224
1225     foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
1226     if (INVALID_HANDLE_VALUE == foo)
1227         return(int) -1;
1228
1229     return (int)foo;
1230
1231 }
1232
1233
1234 int
1235 close(int fd)
1236 {
1237     if (!CloseHandle((HANDLE)fd))
1238         return -1;
1239
1240     return 0;
1241 }
1242
1243 ssize_t
1244 write(int fd, const void *data, size_t len)
1245 {
1246     BOOL status;
1247     DWORD bwrite;
1248     status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
1249     if (status) return bwrite;
1250     return -1;
1251 }
1252
1253
1254 ssize_t
1255 read(int fd, void *data, size_t len)
1256 {
1257     BOOL status;
1258     DWORD bread;
1259
1260     status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
1261     if (status) return bread;
1262     return -1;
1263 }
1264
1265 off_t
1266 lseek(int fd, off_t offset, int whence)
1267 {
1268     DWORD method = 0;
1269     switch (whence) {
1270     case SEEK_SET :
1271         method = FILE_BEGIN;
1272         break;
1273     case SEEK_CUR:
1274         method = FILE_CURRENT;
1275         break;
1276     case SEEK_END:
1277         method = FILE_END;
1278         break;
1279     default:
1280         return -1;
1281     }
1282
1283     return SetFilePointer((HANDLE)fd, (DWORD)offset, NULL, method);
1284 }
1285
1286 int
1287 dup2(int, int)
1288 {
1289     return -1;
1290 }
1291
1292
1293 #endif
1294
1295 #endif //HAVE_MINGW
1296
1297 #ifdef HAVE_MINGW
1298 /* syslog function, added by Nicolas Boichat */
1299 void closelog() {}
1300 #endif //HAVE_MINGW