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