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