]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/compat.cpp
9b0f3f046570b0ef9099f514b58cf02c29d1ff5b
[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-2005 Kern Sibbald
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
12 //  version 2 as amended with additional clauses defined in the
13 //  file LICENSE in the main source directory.
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 
18 //  the file LICENSE for additional details.
19 //
20 // Author          : Christopher S. Hull
21 // Created On      : Sat Jan 31 15:55:00 2004
22 // $Id$
23
24 #include "bacula.h"
25 #define b_errno_win32 (1<<29)
26
27 #include "vss.h"
28
29 #include "../../lib/winapi.h"
30
31
32 /* to allow the usage of the original version in this file here */
33 #undef fputs
34
35
36 #define USE_WIN32_COMPAT_IO 1
37
38 extern void d_msg(const char *file, int line, int level, const char *fmt,...);
39 extern DWORD   g_platform_id;
40 extern int enable_vss;  
41
42 // from MicroSoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970
43 #ifdef HAVE_MINGW
44 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000UL //Not sure it works
45 #else
46 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
47 #endif
48
49 #define WIN32_FILETIME_SCALE  10000000             // 100ns/second
50
51 void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize)
52 {
53     const char *fname = name;
54     char *tname = win32_name;
55     while (*name) {
56         /* Check for Unix separator and convert to Win32 */
57         if (name[0] == '/' && name[1] == '/') {  /* double slash? */
58            name++;                               /* yes, skip first one */
59         }
60         if (*name == '/') {
61             *win32_name++ = '\\';     /* convert char */
62         /* If Win32 separated that is "quoted", remove quote */
63         } else if (*name == '\\' && name[1] == '\\') {
64             *win32_name++ = '\\';
65             name++;                   /* skip first \ */
66         } else {
67             *win32_name++ = *name;    /* copy character */
68         }
69         name++;
70     }
71     /* Strip any trailing slash, if we stored something */
72     if (*fname != 0 && win32_name[-1] == '\\') {
73         win32_name[-1] = 0;
74     } else {
75         *win32_name = 0;
76     }
77
78 #ifdef WIN32_VSS
79     /* here we convert to VSS specific file name which
80        can get longer because VSS will make something like
81        \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
82        from c:\bacula\uninstall.exe
83     */ 
84     if (g_pVSSClient && enable_vss && g_pVSSClient->IsInitialized()) {
85        POOLMEM *pszBuf = get_pool_memory (PM_FNAME);
86        pszBuf = check_pool_memory_size(pszBuf, dwSize);
87        bstrncpy(pszBuf, tname, strlen(tname)+1);
88        g_pVSSClient->GetShadowPath(pszBuf, tname, dwSize);
89        free_pool_memory(pszBuf);
90     }
91 #endif
92 }
93
94 int 
95 wchar_2_UTF8(char *pszUTF, const WCHAR *pszUCS, int cchChar)
96 {
97    /* the return value is the number of bytes written to the buffer. 
98       The number includes the byte for the null terminator. */
99
100    if (p_WideCharToMultiByte) {
101          int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
102          ASSERT (nRet > 0);
103          return nRet;
104       }
105    else
106       return NULL;
107 }
108
109 int 
110 UTF8_2_wchar(POOLMEM **ppszUCS, const char *pszUTF)
111 {
112    /* the return value is the number of wide characters written to the buffer. */
113    /* convert null terminated string from utf-8 to ucs2, enlarge buffer if necessary */
114
115    if (p_MultiByteToWideChar) {
116       /* strlen of UTF8 +1 is enough */ 
117       DWORD cchSize = (strlen(pszUTF)+1);
118       *ppszUCS = check_pool_memory_size(*ppszUCS, cchSize*sizeof (WCHAR));
119       
120       int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
121       ASSERT (nRet > 0);
122       return nRet;
123    }
124    else
125       return NULL;
126 }
127
128
129 void
130 wchar_win32_path(const char *name, WCHAR *win32_name)
131 {
132     const char *fname = name;
133     while (*name) {
134         /* Check for Unix separator and convert to Win32 */
135         if (*name == '/') {
136             *win32_name++ = '\\';     /* convert char */
137         /* If Win32 separated that is "quoted", remove quote */
138         } else if (*name == '\\' && name[1] == '\\') {
139             *win32_name++ = '\\';
140             name++;                   /* skip first \ */
141         } else {
142             *win32_name++ = *name;    /* copy character */
143         }
144         name++;
145     }
146     /* Strip any trailing slash, if we stored something */
147     if (*fname != 0 && win32_name[-1] == '\\') {
148         win32_name[-1] = 0;
149     } else {
150         *win32_name = 0;
151     }
152 }
153
154 int umask(int)
155 {
156    return 0;
157 }
158
159 int chmod(const char *, mode_t)
160 {
161    return 0;
162 }
163
164 int chown(const char *k, uid_t, gid_t)
165 {
166    return 0;
167 }
168
169 int lchown(const char *k, uid_t, gid_t)
170 {
171    return 0;
172 }
173
174 #ifdef needed
175 bool fstype(const char *fname, char *fs, int fslen)
176 {
177    return true;                       /* accept anything */
178 }
179 #endif
180
181
182 long int
183 random(void)
184 {
185     return rand();
186 }
187
188 void
189 srandom(unsigned int seed)
190 {
191    srand(seed);
192 }
193 // /////////////////////////////////////////////////////////////////
194 // convert from Windows concept of time to Unix concept of time
195 // /////////////////////////////////////////////////////////////////
196 void
197 cvt_utime_to_ftime(const time_t  &time, FILETIME &wintime)
198 {
199     uint64_t mstime = time;
200     mstime *= WIN32_FILETIME_SCALE;
201     mstime += WIN32_FILETIME_ADJUST;
202
203     #ifdef HAVE_MINGW
204     wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL);
205     #else
206     wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
207     #endif
208     wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
209 }
210
211 time_t
212 cvt_ftime_to_utime(const FILETIME &time)
213 {
214     uint64_t mstime = time.dwHighDateTime;
215     mstime <<= 32;
216     mstime |= time.dwLowDateTime;
217
218     mstime -= WIN32_FILETIME_ADJUST;
219     mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
220
221     return (time_t) (mstime & 0xffffffff);
222 }
223
224 static const char *
225 errorString(void)
226 {
227    LPVOID lpMsgBuf;
228
229    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
230                  FORMAT_MESSAGE_FROM_SYSTEM |
231                  FORMAT_MESSAGE_IGNORE_INSERTS,
232                  NULL,
233                  GetLastError(),
234                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
235                  (LPTSTR) &lpMsgBuf,
236                  0,
237                  NULL);
238
239    return (const char *) lpMsgBuf;
240 }
241
242 #ifndef HAVE_MINGW
243
244 static int
245 statDir(const char *file, struct stat *sb)
246 {
247    WIN32_FIND_DATAW info_w;       // window's file info
248    WIN32_FIND_DATAA info_a;       // window's file info
249
250    // cache some common vars to make code more transparent
251    DWORD* pdwFileAttributes;
252    DWORD* pnFileSizeHigh;
253    DWORD* pnFileSizeLow;
254    FILETIME* pftLastAccessTime;
255    FILETIME* pftLastWriteTime;
256    FILETIME* pftCreationTime;
257
258    if (file[1] == ':' && file[2] == 0) {
259         d_msg(__FILE__, __LINE__, 99, "faking ROOT attrs(%s).\n", file);
260         sb->st_mode = S_IFDIR;
261         sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
262         time(&sb->st_ctime);
263         time(&sb->st_mtime);
264         time(&sb->st_atime);
265         return 0;
266     }
267
268    HANDLE h = INVALID_HANDLE_VALUE;
269
270    // use unicode or ascii
271    if (p_FindFirstFileW) {
272       POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);         
273       UTF8_2_wchar(&pwszBuf, file);
274       
275       h = p_FindFirstFileW((LPCWSTR) pwszBuf, &info_w);
276       free_pool_memory(pwszBuf);
277
278       pdwFileAttributes = &info_w.dwFileAttributes;
279       pnFileSizeHigh    = &info_w.nFileSizeHigh;
280       pnFileSizeLow     = &info_w.nFileSizeLow;
281       pftLastAccessTime = &info_w.ftLastAccessTime;
282       pftLastWriteTime  = &info_w.ftLastWriteTime;
283       pftCreationTime   = &info_w.ftCreationTime;
284    }
285    else if (p_FindFirstFileA) {
286       h = p_FindFirstFileA(file, &info_a);
287
288       pdwFileAttributes = &info_a.dwFileAttributes;
289       pnFileSizeHigh    = &info_a.nFileSizeHigh;
290       pnFileSizeLow     = &info_a.nFileSizeLow;
291       pftLastAccessTime = &info_a.ftLastAccessTime;
292       pftLastWriteTime  = &info_a.ftLastWriteTime;
293       pftCreationTime   = &info_a.ftCreationTime;
294    }
295
296     if (h == INVALID_HANDLE_VALUE) {
297         const char *err = errorString();
298         d_msg(__FILE__, __LINE__, 99, "FindFirstFile(%s):%s\n", file, err);
299         LocalFree((void *)err);
300         errno = b_errno_win32;
301         return -1;
302     }
303
304     sb->st_mode = 0777;               /* start with everything */
305     if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
306         sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
307     if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
308         sb->st_mode &= ~S_IRWXO; /* remove everything for other */
309     if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
310         sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
311     sb->st_mode |= S_IFDIR;
312
313     sb->st_size = *pnFileSizeHigh;
314     sb->st_size <<= 32;
315     sb->st_size |= *pnFileSizeLow;
316     sb->st_blksize = 4096;
317     sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
318
319     sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
320     sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
321     sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
322     FindClose(h);
323
324     return 0;
325 }
326
327 static int
328 stat2(const char *file, struct stat *sb)
329 {
330     BY_HANDLE_FILE_INFORMATION info;
331     HANDLE h;
332     int rval = 0;
333     char tmpbuf[1024];
334     conv_unix_to_win32_path(file, tmpbuf, 1024);
335
336     DWORD attr = -1;
337
338     if (p_GetFileAttributesW) {
339       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
340       UTF8_2_wchar(&pwszBuf, tmpbuf);
341       
342       attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
343       free_pool_memory(pwszBuf);
344     } else if (p_GetFileAttributesA) {
345        attr = p_GetFileAttributesA(tmpbuf);
346     }
347
348     if (attr == -1) {
349         const char *err = errorString();
350         d_msg(__FILE__, __LINE__, 99,
351               "GetFileAttrubtes(%s): %s\n", tmpbuf, err);
352         LocalFree((void *)err);
353         errno = b_errno_win32;
354         return -1;
355     }
356
357     if (attr & FILE_ATTRIBUTE_DIRECTORY)
358         return statDir(tmpbuf, sb);
359
360     h = CreateFileA(tmpbuf, GENERIC_READ,
361                    FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
362
363     if (h == INVALID_HANDLE_VALUE) {
364         const char *err = errorString();
365         d_msg(__FILE__, __LINE__, 99,
366               "Cannot open file for stat (%s):%s\n", tmpbuf, err);
367         LocalFree((void *)err);
368         rval = -1;
369         errno = b_errno_win32;
370         goto error;
371     }
372
373     if (!GetFileInformationByHandle(h, &info)) {
374         const char *err = errorString();
375         d_msg(__FILE__, __LINE__, 99,
376               "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
377         LocalFree((void *)err);
378         rval = -1;
379         errno = b_errno_win32;
380         goto error;
381     }
382
383     sb->st_dev = info.dwVolumeSerialNumber;
384     sb->st_ino = info.nFileIndexHigh;
385     sb->st_ino <<= 32;
386     sb->st_ino |= info.nFileIndexLow;
387     sb->st_nlink = (short)info.nNumberOfLinks;
388     if (sb->st_nlink > 1) {
389        d_msg(__FILE__, __LINE__, 99,  "st_nlink=%d\n", sb->st_nlink);
390     }
391
392     sb->st_mode = 0777;               /* start with everything */
393     if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
394         sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
395     if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
396         sb->st_mode &= ~S_IRWXO; /* remove everything for other */
397     if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
398         sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
399     sb->st_mode |= S_IFREG;
400
401     sb->st_size = info.nFileSizeHigh;
402     sb->st_size <<= 32;
403     sb->st_size |= info.nFileSizeLow;
404     sb->st_blksize = 4096;
405     sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
406     sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
407     sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
408     sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
409
410 error:
411     CloseHandle(h);
412     return rval;
413 }
414
415 int
416 stat(const char *file, struct stat *sb)
417 {
418    WIN32_FILE_ATTRIBUTE_DATA data;
419    errno = 0;
420
421
422    memset(sb, 0, sizeof(*sb));
423
424    if (g_platform_id == VER_PLATFORM_WIN32_WINDOWS) {
425       return stat2(file, sb);
426    }
427
428    // otherwise we're on NT
429 #if 0
430    WCHAR buf[32767];
431    buf[0] = '\\';
432    buf[1] = '\\';
433    buf[2] = '?';
434    buf[3] = '\\';
435
436    wchar_win32_path(file, buf+4);
437
438    if (!GetFileAttributesExW((WCHAR *)buf, GetFileExInfoStandard, &data)) {
439       return stat2(file, sb);
440    }
441 #else
442
443    if (p_GetFileAttributesExW) {
444       /* dynamically allocate enough space for UCS2 filename */
445       POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);          
446       UTF8_2_wchar(&pwszBuf, file);
447
448       BOOL b = p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, &data);
449       free_pool_memory(pwszBuf);
450                         
451       if (!b) {
452          return stat2(file, sb);
453       }
454    } else if (p_GetFileAttributesExA) {
455       if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
456          return stat2(file, sb);
457        }
458    } else {
459       return stat2(file, sb);
460    }
461
462 #endif
463
464    sb->st_mode = 0777;               /* start with everything */
465    if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
466       sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
467    }
468    if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
469       sb->st_mode &= ~S_IRWXO; /* remove everything for other */
470    }
471    if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
472       sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
473    }
474    if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
475       sb->st_mode |= S_IFDIR;
476    } else {
477       sb->st_mode |= S_IFREG;
478    }
479
480    sb->st_nlink = 1;
481    sb->st_size = data.nFileSizeHigh;
482    sb->st_size <<= 32;
483    sb->st_size |= data.nFileSizeLow;
484    sb->st_blksize = 4096;
485    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
486    sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
487    sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
488    sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
489    return 0;
490 }
491
492 #endif //HAVE_MINGW
493
494 int
495 lstat(const char *file, struct stat *sb)
496 {
497    return stat(file, sb);
498 }
499
500 void
501 sleep(int sec)
502 {
503    Sleep(sec * 1000);
504 }
505
506 int
507 geteuid(void)
508 {
509    return 0;
510 }
511
512 int
513 execvp(const char *, char *[]) {
514    errno = ENOSYS;
515    return -1;
516 }
517
518
519 int
520 fork(void)
521 {
522    errno = ENOSYS;
523    return -1;
524 }
525
526 int
527 pipe(int[])
528 {
529    errno = ENOSYS;
530    return -1;
531 }
532
533 int
534 waitpid(int, int*, int)
535 {
536    errno = ENOSYS;
537    return -1;
538 }
539
540 int
541 readlink(const char *, char *, int)
542 {
543    errno = ENOSYS;
544    return -1;
545 }
546
547
548 #ifndef HAVE_MINGW
549 int
550 strcasecmp(const char *s1, const char *s2)
551 {
552    register int ch1, ch2;
553
554    if (s1==s2)
555       return 0;       /* strings are equal if same object. */
556    else if (!s1)
557       return -1;
558    else if (!s2)
559       return 1;
560    do {
561       ch1 = *s1;
562       ch2 = *s2;
563       s1++;
564       s2++;
565    } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
566
567    return(ch1 - ch2);
568 }
569 #endif //HAVE_MINGW
570
571 int
572 strncasecmp(const char *s1, const char *s2, int len)
573 {
574     register int ch1, ch2;
575
576     if (s1==s2)
577         return 0;       /* strings are equal if same object. */
578     else if (!s1)
579         return -1;
580     else if (!s2)
581         return 1;
582     while (len--) {
583         ch1 = *s1;
584         ch2 = *s2;
585         s1++;
586         s2++;
587         if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
588     } 
589
590     return (ch1 - ch2);
591 }
592
593 int
594 gettimeofday(struct timeval *tv, struct timezone *)
595 {
596     SYSTEMTIME now;
597     FILETIME tmp;
598     GetSystemTime(&now);
599
600     if (tv == NULL) {
601        errno = EINVAL;
602        return -1;
603     }
604     if (!SystemTimeToFileTime(&now, &tmp)) {
605        errno = b_errno_win32;
606        return -1;
607     }
608
609     int64_t _100nsec = tmp.dwHighDateTime;
610     _100nsec <<= 32;
611     _100nsec |= tmp.dwLowDateTime;
612     _100nsec -= WIN32_FILETIME_ADJUST;
613
614     tv->tv_sec =(long) (_100nsec / 10000000);
615     tv->tv_usec = (long) ((_100nsec % 10000000)/10);
616     return 0;
617
618 }
619
620 int
621 syslog(int type, const char *fmt, const char *msg)
622 {
623 /*#ifndef HAVE_CONSOLE
624     MessageBox(NULL, msg, "Bacula", MB_OK);
625 #endif*/
626     return 0;
627 }
628
629 struct passwd *
630 getpwuid(uid_t)
631 {
632     return NULL;
633 }
634
635 struct group *
636 getgrgid(uid_t)
637 {
638     return NULL;
639 }
640
641 // implement opendir/readdir/closedir on top of window's API
642
643 typedef struct _dir
644 {
645     WIN32_FIND_DATAA data_a;    // window's file info (ansii version)
646     WIN32_FIND_DATAW data_w;    // window's file info (wchar version)
647     const char *spec;           // the directory we're traversing
648     HANDLE      dirh;           // the search handle
649     BOOL        valid_a;        // the info in data_a field is valid
650     BOOL        valid_w;        // the info in data_w field is valid
651     UINT32      offset;         // pseudo offset for d_off
652 } _dir;
653
654 DIR *
655 opendir(const char *path)
656 {
657     /* enough space for VSS !*/
658     int max_len = strlen(path) + MAX_PATH;
659     _dir *rval = NULL;
660     if (path == NULL) {
661        errno = ENOENT;
662        return NULL;
663     }
664
665     rval = (_dir *)malloc(sizeof(_dir));
666     memset (rval, 0, sizeof (_dir));
667     if (rval == NULL) return NULL;
668     char *tspec = (char *)malloc(max_len);
669     if (tspec == NULL) return NULL;
670
671     if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS) {
672 #ifdef WIN32_VSS
673        /* will append \\?\ at front itself */
674        conv_unix_to_win32_path(path, tspec, max_len-4);
675 #else
676        /* allow path to be 32767 bytes */
677        tspec[0] = '\\';
678        tspec[1] = '\\';
679        tspec[2] = '?';
680        tspec[3] = '\\';
681        tspec[4] = 0;
682        conv_unix_to_win32_path(path, tspec+4, max_len-4);
683 #endif
684     } else {
685        conv_unix_to_win32_path(path, tspec, max_len);
686     }
687
688     bstrncat(tspec, "\\*", max_len);
689     rval->spec = tspec;
690
691     // convert to WCHAR
692     if (p_FindFirstFileW) {
693       POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
694       UTF8_2_wchar(&pwcBuf,rval->spec);
695       rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);   
696
697       free_pool_memory(pwcBuf);
698
699       if (rval->dirh != INVALID_HANDLE_VALUE)
700         rval->valid_w = 1;
701     } else if (p_FindFirstFileA) {
702       rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
703       
704       if (rval->dirh != INVALID_HANDLE_VALUE)
705         rval->valid_a = 1;
706     } else goto err;
707
708
709     d_msg(__FILE__, __LINE__,
710           99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
711           path, rval->spec, rval->dirh);
712
713     rval->offset = 0;
714     if (rval->dirh == INVALID_HANDLE_VALUE)
715         goto err;
716
717     if (rval->valid_w)
718       d_msg(__FILE__, __LINE__,
719             99, "\tFirstFile=%s\n", rval->data_w.cFileName);
720
721     if (rval->valid_a)
722       d_msg(__FILE__, __LINE__,
723             99, "\tFirstFile=%s\n", rval->data_a.cFileName);
724
725     return (DIR *)rval;
726
727 err:
728     free((void *)rval->spec);
729     free(rval);
730     errno = b_errno_win32;
731     return NULL;
732 }
733
734 int
735 closedir(DIR *dirp)
736 {
737     _dir *dp = (_dir *)dirp;
738     FindClose(dp->dirh);
739     free((void *)dp->spec);
740     free((void *)dp);
741     return 0;
742 }
743
744 /*
745   typedef struct _WIN32_FIND_DATA {
746     DWORD dwFileAttributes;
747     FILETIME ftCreationTime;
748     FILETIME ftLastAccessTime;
749     FILETIME ftLastWriteTime;
750     DWORD nFileSizeHigh;
751     DWORD nFileSizeLow;
752     DWORD dwReserved0;
753     DWORD dwReserved1;
754     TCHAR cFileName[MAX_PATH];
755     TCHAR cAlternateFileName[14];
756 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
757 */
758
759 static int
760 copyin(struct dirent &dp, const char *fname)
761 {
762     dp.d_ino = 0;
763     dp.d_reclen = 0;
764     char *cp = dp.d_name;
765     while (*fname) {
766         *cp++ = *fname++;
767         dp.d_reclen++;
768     }
769         *cp = 0;
770     return dp.d_reclen;
771 }
772
773 int
774 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
775 {
776     _dir *dp = (_dir *)dirp;
777     if (dp->valid_w || dp->valid_a) {
778       entry->d_off = dp->offset;
779                 
780       // copy unicode
781       if (dp->valid_w) {
782          char szBuf[MAX_PATH_UTF8];
783          wchar_2_UTF8(szBuf,dp->data_w.cFileName);
784          dp->offset += copyin(*entry, szBuf);
785       } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
786          dp->offset += copyin(*entry, dp->data_a.cFileName);
787       }
788                 
789       *result = entry;              /* return entry address */
790       d_msg(__FILE__, __LINE__,
791             99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
792             dirp, entry->d_name, entry->d_reclen, entry->d_off);
793     } else {
794 //      d_msg(__FILE__, __LINE__, 99, "readdir_r !valid\n");
795         errno = b_errno_win32;
796         return -1;
797     }
798
799     // get next file, try unicode first
800     if (p_FindNextFileW) 
801        dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
802     else if (p_FindNextFileA)
803        dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
804     else {
805        dp->valid_a = FALSE;
806        dp->valid_w = FALSE;
807     }
808
809     return 0;
810 }
811
812 /*
813  * Dotted IP address to network address
814  *
815  * Returns 1 if  OK
816  *         0 on error
817  */
818 int
819 inet_aton(const char *a, struct in_addr *inp)
820 {
821    const char *cp = a;
822    uint32_t acc = 0, tmp = 0;
823    int dotc = 0;
824
825    if (!isdigit(*cp)) {         /* first char must be digit */
826       return 0;                 /* error */
827    }
828    do {
829       if (isdigit(*cp)) {
830          tmp = (tmp * 10) + (*cp -'0');
831       } else if (*cp == '.' || *cp == 0) {
832          if (tmp > 255) {
833             return 0;           /* error */
834          }
835          acc = (acc << 8) + tmp;
836          dotc++;
837          tmp = 0;
838       } else {
839          return 0;              /* error */
840       }
841    } while (*cp++ != 0);
842    if (dotc != 4) {              /* want 3 .'s plus EOS */
843       return 0;                  /* error */
844    }
845    inp->s_addr = htonl(acc);     /* store addr in network format */
846    return 1;
847 }
848
849 int
850 nanosleep(const struct timespec *req, struct timespec *rem)
851 {
852     if (rem)
853         rem->tv_sec = rem->tv_nsec = 0;
854     Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
855     return 0;
856 }
857
858 void
859 init_signals(void terminate(int sig))
860 {
861
862 }
863
864 void
865 init_stack_dump(void)
866 {
867
868 }
869
870
871 long
872 pathconf(const char *path, int name)
873 {
874     switch(name) {
875     case _PC_PATH_MAX :
876         if (strncmp(path, "\\\\?\\", 4) == 0)
877             return 32767;
878     case _PC_NAME_MAX :
879         return 255;
880     }
881     errno = ENOSYS;                                                         
882     return -1;
883 }
884
885 int
886 WSA_Init(void)
887 {
888     WORD wVersionRequested = MAKEWORD( 1, 1);
889     WSADATA wsaData;
890
891     int err = WSAStartup(wVersionRequested, &wsaData);
892
893
894     if (err != 0) {
895         printf("Can not start Windows Sockets\n");
896         errno = ENOSYS;
897         return -1;
898     }
899
900     return 0;
901 }
902
903
904 int
905 win32_chdir(const char *dir)
906 {
907    if (p_SetCurrentDirectoryW) {
908       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
909       UTF8_2_wchar(&pwszBuf, dir);
910
911       BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
912       free_pool_memory(pwszBuf);
913
914       if (!b) {
915          errno = b_errno_win32;
916          return -1;
917       }
918    }
919    else if (p_SetCurrentDirectoryA) {
920       if (0 == p_SetCurrentDirectoryA(dir)) {
921          errno = b_errno_win32;
922          return -1;
923       }
924    }
925    else return -1;
926    
927    return 0;
928 }
929
930 int
931 win32_mkdir(const char *dir)
932 {
933    if (p_wmkdir){
934       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
935       UTF8_2_wchar(&pwszBuf, dir);
936
937       int n=p_wmkdir((LPCWSTR)pwszBuf);
938       free_pool_memory(pwszBuf);      
939       return n;
940    }
941
942    return _mkdir(dir);        
943 }
944
945
946 char *
947 win32_getcwd(char *buf, int maxlen)
948 {
949    int n=0;
950
951    if (p_GetCurrentDirectoryW) {
952       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
953       pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(WCHAR));
954
955       n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
956       n = wchar_2_UTF8 (buf, (WCHAR*)pwszBuf, maxlen)-1;
957       free_pool_memory(pwszBuf);
958
959    } else if (p_GetCurrentDirectoryA)
960       n = p_GetCurrentDirectoryA(maxlen, buf);
961
962    if (n == 0 || n > maxlen) return NULL;
963
964    if (n+1 > maxlen) return NULL;
965    if (n != 3) {
966        buf[n] = '\\';
967        buf[n+1] = 0;
968    }
969    return buf;
970 }
971
972 int 
973 win32_fputs(const char *string, FILE *stream)
974 {
975    /* we use WriteConsoleA / WriteConsoleA
976       so we can be sure that unicode support works on win32.
977       with fallback if something fails
978    */   
979
980    HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
981    if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && 
982        p_MultiByteToWideChar && (stream == stdout)) {
983       
984       POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
985       
986       DWORD dwCharsWritten;
987       DWORD dwChars;
988          
989       dwChars = UTF8_2_wchar(&pwszBuf, string);
990
991       /* try WriteConsoleW */
992       if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
993          free_pool_memory(pwszBuf);
994          return dwCharsWritten;   
995       }
996       
997       /* convert to local codepage and try WriteConsoleA */      
998       POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);         
999       pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1000
1001       dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR) pwszBuf,-1,pszBuf,dwChars,NULL,NULL);      
1002       free_pool_memory(pwszBuf);
1003
1004       if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1005          free_pool_memory(pszBuf);
1006          return dwCharsWritten;   
1007       }
1008    }
1009
1010    return fputs(string, stream);
1011 }
1012
1013 char*
1014 win32_cgets (char* buffer, int len)
1015 {
1016    /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1017       from the win32 console and fallback if seomething fails */
1018
1019    HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1020    if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {            
1021       DWORD dwRead;
1022       WCHAR wszBuf[1024];
1023       char  szBuf[1024];    
1024
1025       /* nt and unicode conversion */
1026       if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1027
1028          /* null terminate at end */                
1029          if (wszBuf[dwRead-1] == L'\n') {
1030             wszBuf[dwRead-1] = L'\0';
1031             dwRead --;
1032          }
1033
1034          if (wszBuf[dwRead-1] == L'\r') {
1035             wszBuf[dwRead-1] = L'\0';
1036             dwRead --;
1037          }
1038          
1039          wchar_2_UTF8(buffer, wszBuf, len);
1040          return buffer;
1041       }    
1042       
1043       /* win 9x and unicode conversion */
1044       if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1045
1046          /* null terminate at end */                
1047          if (szBuf[dwRead-1] == L'\n') {
1048             szBuf[dwRead-1] = L'\0';
1049             dwRead --;
1050          }
1051
1052          if (szBuf[dwRead-1] == L'\r') {
1053             szBuf[dwRead-1] = L'\0';
1054             dwRead --;
1055          }
1056
1057          /* convert from ansii to WCHAR */
1058          p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1059          /* convert from WCHAR to UTF-8 */
1060          if (wchar_2_UTF8(buffer, wszBuf, len))
1061             return buffer;         
1062       }
1063    }
1064
1065    /* fallback */
1066    if (fgets(buffer, len, stdin)) 
1067       return buffer;   
1068    else
1069       return NULL;
1070 }
1071
1072 int
1073 win32_unlink(const char *filename)
1074 {
1075    int nRetCode;
1076    if (p_wunlink) {
1077       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);      
1078       UTF8_2_wchar(&pwszBuf, filename);
1079       nRetCode = _wunlink((LPCWSTR) pwszBuf);
1080  
1081       /* special case if file is readonly, 
1082       we retry but unset attribute before */
1083       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1084          DWORD dwAttr =  p_GetFileAttributesW((LPCWSTR)pwszBuf);
1085          if (dwAttr != INVALID_FILE_ATTRIBUTES) {            
1086             if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1087                nRetCode = _wunlink((LPCWSTR) pwszBuf);
1088                /* reset to original if it didn't help */
1089                if (nRetCode == -1)
1090                   p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1091             }
1092          }
1093       }
1094       free_pool_memory(pwszBuf);
1095    } else {
1096       nRetCode = _unlink(filename);
1097
1098       /* special case if file is readonly, 
1099       we retry but unset attribute before */
1100       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1101          DWORD dwAttr =  p_GetFileAttributesA(filename);
1102          if (dwAttr != INVALID_FILE_ATTRIBUTES) {            
1103             if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1104                nRetCode = _unlink(filename);
1105                /* reset to original if it didn't help */
1106                if (nRetCode == -1)
1107                   p_SetFileAttributesA(filename, dwAttr);
1108             }
1109          }
1110       }
1111    }   
1112    return nRetCode;
1113 }
1114
1115
1116 #include "mswinver.h"
1117
1118 char WIN_VERSION_LONG[64];
1119 char WIN_VERSION[32];
1120
1121 class winver {
1122 public:
1123     winver(void);
1124 };
1125
1126 static winver INIT;                     // cause constructor to be called before main()
1127
1128 #include "bacula.h"
1129 #include "jcr.h"
1130
1131 winver::winver(void)
1132 {
1133     const char *version = "";
1134     const char *platform = "";
1135     OSVERSIONINFO osvinfo;
1136     osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1137
1138     // Get the current OS version
1139     if (!GetVersionEx(&osvinfo)) {
1140         version = "Unknown";
1141         platform = "Unknown";
1142     }
1143     else
1144         switch (_mkversion(osvinfo.dwPlatformId, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion))
1145         {
1146         case MS_WINDOWS_95: (version =  "Windows 95"); break;
1147         case MS_WINDOWS_98: (version =  "Windows 98"); break;
1148         case MS_WINDOWS_ME: (version =  "Windows ME"); break;
1149         case MS_WINDOWS_NT4:(version =  "Windows NT 4.0"); platform = "NT"; break;
1150         case MS_WINDOWS_2K: (version =  "Windows 2000");platform = "NT"; break;
1151         case MS_WINDOWS_XP: (version =  "Windows XP");platform = "NT"; break;
1152         case MS_WINDOWS_S2003: (version =  "Windows Server 2003");platform = "NT"; break;
1153         default: version = "Windows ??"; break;
1154         }
1155
1156     bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1157     snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %d.%d.%d",
1158              platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1159
1160 #if 0
1161     HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1162     CloseHandle(h);
1163 #endif
1164 #if 0
1165     BPIPE *b = open_bpipe("ls -l", 10, "r");
1166     char buf[1024];
1167     while (!feof(b->rfd)) {
1168         fgets(buf, sizeof(buf), b->rfd);
1169     }
1170     close_bpipe(b);
1171 #endif
1172 }
1173
1174 BOOL CreateChildProcess(VOID);
1175 VOID WriteToPipe(VOID);
1176 VOID ReadFromPipe(VOID);
1177 VOID ErrorExit(LPCSTR);
1178 VOID ErrMsg(LPTSTR, BOOL);
1179
1180 /**
1181  * Check for a quoted path,  if an absolute path name is given and it contains
1182  * spaces it will need to be quoted.  i.e.  "c:/Program Files/foo/bar.exe"
1183  * CreateProcess() says the best way to ensure proper results with executables
1184  * with spaces in path or filename is to quote the string.
1185  */
1186 const char *
1187 getArgv0(const char *cmdline)
1188 {
1189
1190     int inquote = 0;
1191     for (const char *cp = cmdline; *cp; cp++)
1192     {
1193         if (*cp == '"') {
1194             inquote = !inquote;
1195         }
1196         if (!inquote && isspace(*cp))
1197             break;
1198     }
1199
1200         
1201     int len = cp - cmdline;
1202     char *rval = (char *)malloc(len+1);
1203
1204     cp = cmdline;
1205     char *rp = rval;
1206     
1207     while (len--)
1208         *rp++ = *cp++;
1209
1210     *rp = 0;
1211     return rval;
1212 }
1213
1214
1215 /**
1216  * OK, so it would seem CreateProcess only handles true executables:
1217  *  .com or .exe files.
1218  * So test to see whether we're getting a .bat file and if so grab
1219  * $COMSPEC value and pass batch file to it.
1220  */
1221 HANDLE
1222 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1223 {
1224     PROCESS_INFORMATION piProcInfo;
1225     STARTUPINFOA siStartInfo;
1226     BOOL bFuncRetn = FALSE;
1227
1228     // Set up members of the PROCESS_INFORMATION structure.
1229
1230     ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1231
1232     // Set up members of the STARTUPINFO structure.
1233
1234     ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1235     siStartInfo.cb = sizeof(STARTUPINFO);
1236     // setup new process to use supplied handles for stdin,stdout,stderr
1237     // if supplied handles are not used the send a copy of our STD_HANDLE
1238     // as appropriate
1239     siStartInfo.dwFlags = STARTF_USESTDHANDLES;
1240
1241     if (in != INVALID_HANDLE_VALUE)
1242         siStartInfo.hStdInput = in;
1243     else
1244         siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1245
1246     if (out != INVALID_HANDLE_VALUE)
1247         siStartInfo.hStdOutput = out;
1248     else
1249         siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1250     if (err != INVALID_HANDLE_VALUE)
1251         siStartInfo.hStdError = err;
1252     else
1253         siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1254     // Create the child process.
1255
1256     char exeFile[256];
1257
1258     const char *comspec = getenv("COMSPEC");
1259     
1260     if (comspec == NULL) // should never happen
1261         return INVALID_HANDLE_VALUE;
1262
1263     char *cmdLine = (char *)alloca(strlen(cmdline) + strlen(comspec) + 16);
1264     
1265     strcpy(exeFile, comspec);
1266     strcpy(cmdLine, comspec);
1267     strcat(cmdLine, " /c ");
1268     strcat(cmdLine, cmdline);
1269
1270     // try to execute program
1271     bFuncRetn = CreateProcessA(exeFile,
1272                               cmdLine, // command line
1273                               NULL, // process security attributes
1274                               NULL, // primary thread security attributes
1275                               TRUE, // handles are inherited
1276                               0, // creation flags
1277                               NULL, // use parent's environment
1278                               NULL, // use parent's current directory
1279                               &siStartInfo, // STARTUPINFO pointer
1280                               &piProcInfo); // receives PROCESS_INFORMATION
1281
1282     if (bFuncRetn == 0) {
1283         ErrorExit("CreateProcess failed\n");
1284         const char *err = errorString();
1285         d_msg(__FILE__, __LINE__, 99,
1286               "CreateProcess(%s, %s, ...)=%s\n", exeFile, cmdLine, err);
1287         LocalFree((void *)err);
1288         return INVALID_HANDLE_VALUE;
1289     }
1290     // we don't need a handle on the process primary thread so we close
1291     // this now.
1292     CloseHandle(piProcInfo.hThread);
1293
1294     return piProcInfo.hProcess;
1295 }
1296
1297
1298 void
1299 ErrorExit (LPCSTR lpszMessage)
1300 {
1301     d_msg(__FILE__, __LINE__, 0, "%s", lpszMessage);
1302 }
1303
1304
1305 /*
1306 typedef struct s_bpipe {
1307    pid_t worker_pid;
1308    time_t worker_stime;
1309    int wait;
1310    btimer_t *timer_id;
1311    FILE *rfd;
1312    FILE *wfd;
1313 } BPIPE;
1314 */
1315
1316 static void
1317 CloseIfValid(HANDLE handle)
1318 {
1319     if (handle != INVALID_HANDLE_VALUE)
1320         CloseHandle(handle);
1321 }
1322
1323 #ifndef HAVE_MINGW
1324 BPIPE *
1325 open_bpipe(char *prog, int wait, const char *mode)
1326 {
1327     HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1328         hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1329         hInputFile;
1330
1331     SECURITY_ATTRIBUTES saAttr;
1332
1333     BOOL fSuccess;
1334
1335     hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1336         hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1337         hInputFile = INVALID_HANDLE_VALUE;
1338
1339     BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1340     memset((void *)bpipe, 0, sizeof(BPIPE));
1341
1342     int mode_read = (mode[0] == 'r');
1343     int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1344
1345
1346     // Set the bInheritHandle flag so pipe handles are inherited.
1347
1348     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1349     saAttr.bInheritHandle = TRUE;
1350     saAttr.lpSecurityDescriptor = NULL;
1351
1352     if (mode_read) {
1353
1354         // Create a pipe for the child process's STDOUT.
1355         if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1356             ErrorExit("Stdout pipe creation failed\n");
1357             goto cleanup;
1358         }
1359         // Create noninheritable read handle and close the inheritable read
1360         // handle.
1361
1362         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1363                                    GetCurrentProcess(), &hChildStdoutRdDup , 0,
1364                                    FALSE,
1365                                    DUPLICATE_SAME_ACCESS);
1366         if ( !fSuccess ) {
1367             ErrorExit("DuplicateHandle failed");
1368             goto cleanup;
1369         }
1370
1371         CloseHandle(hChildStdoutRd);
1372         hChildStdoutRd = INVALID_HANDLE_VALUE;
1373     }
1374
1375     if (mode_write) {
1376
1377         // Create a pipe for the child process's STDIN.
1378
1379         if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1380             ErrorExit("Stdin pipe creation failed\n");
1381             goto cleanup;
1382         }
1383
1384         // Duplicate the write handle to the pipe so it is not inherited.
1385         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
1386                                    GetCurrentProcess(), &hChildStdinWrDup,
1387                                    0,
1388                                    FALSE,                  // not inherited
1389                                    DUPLICATE_SAME_ACCESS);
1390         if (!fSuccess) {
1391             ErrorExit("DuplicateHandle failed");
1392             goto cleanup;
1393         }
1394
1395         CloseHandle(hChildStdinWr);
1396         hChildStdinWr = INVALID_HANDLE_VALUE;
1397     }
1398     // spawn program with redirected handles as appropriate
1399     bpipe->worker_pid = (pid_t)
1400         CreateChildProcess(prog,             // commandline
1401                            hChildStdinRd,    // stdin HANDLE
1402                            hChildStdoutWr,   // stdout HANDLE
1403                            hChildStdoutWr);  // stderr HANDLE
1404
1405     if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1406         goto cleanup;
1407
1408     bpipe->wait = wait;
1409     bpipe->worker_stime = time(NULL);
1410
1411     if (mode_read) {
1412         CloseHandle(hChildStdoutWr); // close our write side so when
1413                                      // process terminates we can
1414                                      // detect eof.
1415         // ugly but convert WIN32 HANDLE to FILE*
1416         int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY);
1417         if (rfd >= 0) {
1418            bpipe->rfd = _fdopen(rfd, "r");
1419         }
1420     }
1421     if (mode_write) {
1422         CloseHandle(hChildStdinRd); // close our read side so as not
1423                                     // to interfre with child's copy
1424         // ugly but convert WIN32 HANDLE to FILE*
1425         int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY);
1426         if (wfd >= 0) {
1427            bpipe->wfd = _fdopen(wfd, "w");
1428         }
1429     }
1430
1431     if (wait > 0) {
1432         bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
1433     }
1434
1435     return bpipe;
1436
1437 cleanup:
1438
1439     CloseIfValid(hChildStdoutRd);
1440     CloseIfValid(hChildStdoutRdDup);
1441     CloseIfValid(hChildStdinWr);
1442     CloseIfValid(hChildStdinWrDup);
1443
1444     free((void *) bpipe);
1445     errno = b_errno_win32;            /* do GetLastError() for error code */
1446     return NULL;
1447 }
1448
1449 #endif //HAVE_MINGW
1450
1451 int
1452 kill(int pid, int signal)
1453 {
1454    int rval = 0;
1455    if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
1456       rval = -1;
1457       errno = b_errno_win32;
1458    }
1459    CloseHandle((HANDLE)pid);
1460    return rval;
1461 }
1462
1463 #ifndef HAVE_MINGW
1464
1465 int
1466 close_bpipe(BPIPE *bpipe)
1467 {
1468    int rval = 0;
1469    int32_t remaining_wait = bpipe->wait;
1470
1471    if (remaining_wait == 0) {         /* wait indefinitely */
1472       remaining_wait = INT32_MAX;
1473    }
1474    for ( ;; ) {
1475       DWORD exitCode;
1476       if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
1477          const char *err = errorString();
1478          rval = b_errno_win32;
1479          d_msg(__FILE__, __LINE__, 0,
1480                "GetExitCode error %s\n", err);
1481          LocalFree((void *)err);
1482          break;
1483       }
1484       if (exitCode == STILL_ACTIVE) {
1485          if (remaining_wait <= 0) {
1486             rval = ETIME;             /* timed out */
1487             break;
1488          }
1489          bmicrosleep(1, 0);           /* wait one second */
1490          remaining_wait--;
1491       } else if (exitCode != 0) {
1492          /* Truncate exit code as it doesn't seem to be correct */
1493          rval = (exitCode & 0xFF) | b_errno_exit;
1494          break;
1495       } else {
1496          break;                       /* Shouldn't get here */
1497       }
1498    }
1499
1500    if (bpipe->timer_id) {
1501        stop_child_timer(bpipe->timer_id);
1502    }
1503    if (bpipe->rfd) fclose(bpipe->rfd);
1504    if (bpipe->wfd) fclose(bpipe->wfd);
1505    free((void *)bpipe);
1506    return rval;
1507 }
1508
1509 int
1510 close_wpipe(BPIPE *bpipe)
1511 {
1512     int stat = 1;
1513
1514     if (bpipe->wfd) {
1515         fflush(bpipe->wfd);
1516         if (fclose(bpipe->wfd) != 0) {
1517             stat = 0;
1518         }
1519         bpipe->wfd = NULL;
1520     }
1521     return stat;
1522 }
1523
1524 #include "findlib/find.h"
1525
1526 int
1527 utime(const char *fname, struct utimbuf *times)
1528 {
1529     FILETIME acc, mod;
1530     char tmpbuf[1024];
1531
1532     conv_unix_to_win32_path(fname, tmpbuf, 1024);
1533
1534     cvt_utime_to_ftime(times->actime, acc);
1535     cvt_utime_to_ftime(times->modtime, mod);
1536
1537     HANDLE h = INVALID_HANDLE_VALUE;
1538
1539     if (p_CreateFileW) {
1540       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1541       UTF8_2_wchar(&pwszBuf, tmpbuf);
1542
1543       h = p_CreateFileW((LPCWSTR) pwszBuf,
1544                         FILE_WRITE_ATTRIBUTES,
1545                         FILE_SHARE_WRITE,
1546                         NULL,
1547                         OPEN_EXISTING,
1548                         0,
1549                         NULL);
1550      
1551       free_pool_memory(pwszBuf);
1552     } else if (p_CreateFileA) {
1553       h = p_CreateFileA(tmpbuf,
1554                         FILE_WRITE_ATTRIBUTES,
1555                         FILE_SHARE_WRITE,
1556                         NULL,
1557                         OPEN_EXISTING,
1558                         0,
1559                         NULL);
1560     }
1561
1562     if (h == INVALID_HANDLE_VALUE) {
1563         const char *err = errorString();
1564         d_msg(__FILE__, __LINE__, 99,
1565               "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
1566         LocalFree((void *)err);
1567         errno = b_errno_win32;
1568         return -1;
1569     }
1570
1571     int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
1572     CloseHandle(h);
1573     if (rval == -1) {
1574        errno = b_errno_win32;
1575     }
1576     return rval;
1577 }
1578
1579 #if USE_WIN32_COMPAT_IO
1580
1581 int
1582 open(const char *file, int flags, int mode)
1583 {
1584    if (p_wopen) {
1585       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);      
1586       UTF8_2_wchar(&pwszBuf, file);
1587
1588       int nRet = p_wopen((LPCWSTR) pwszBuf, flags|_O_BINARY, mode);
1589       free_pool_memory(pwszBuf);
1590
1591       return nRet;
1592    }
1593
1594    return _open(file, flags|_O_BINARY, mode);
1595 }
1596
1597 /*
1598  * Note, this works only for a file. If you want
1599  *   to close a socket, use closesocket(). 
1600  *   Bacula has been modified in src/lib/bnet.c
1601  *   to use closesocket().
1602  */
1603 int
1604 close(int fd)
1605 {
1606     return _close(fd);
1607 }
1608
1609 #ifndef HAVE_WXCONSOLE
1610 ssize_t
1611 read(int fd, void *buf, ssize_t len)
1612 {
1613     return _read(fd, buf, (size_t)len);
1614 }
1615
1616 ssize_t
1617 write(int fd, const void *buf, ssize_t len)
1618 {
1619     return _write(fd, buf, (size_t)len);
1620 }
1621 #endif
1622
1623
1624 off_t
1625 lseek(int fd, off_t offset, int whence)
1626 {
1627     return _lseeki64(fd, offset, whence);
1628 }
1629
1630 int
1631 dup2(int fd1, int fd2)
1632 {
1633     return _dup2(fd1, fd2);
1634 }
1635 #else
1636 int
1637 open(const char *file, int flags, int mode)
1638 {
1639     DWORD access = 0;
1640     DWORD shareMode = 0;
1641     DWORD create = 0;
1642     DWORD msflags = 0;
1643     HANDLE foo = INVALID_HANDLE_VALUE;
1644     const char *remap = file;
1645
1646     if (flags & O_WRONLY) access = GENERIC_WRITE;
1647     else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
1648     else access = GENERIC_READ;
1649
1650     if (flags & O_CREAT) create = CREATE_NEW;
1651     else create = OPEN_EXISTING;
1652
1653     if (flags & O_TRUNC) create = TRUNCATE_EXISTING;
1654
1655     if (!(flags & O_EXCL))
1656         shareMode = FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE;
1657
1658     if (flags & O_APPEND) {
1659         printf("open...APPEND not implemented yet.");
1660         exit(-1);
1661     }
1662
1663     if (p_CreateFileW) {
1664        POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);       
1665        UTF8_2_wchar(pwszBuf, file);
1666
1667        foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
1668        free_pool_memory(pwszBuf);
1669     }
1670     else if (p_CreateFileA)
1671        foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
1672
1673     if (INVALID_HANDLE_VALUE == foo) {
1674         errno = b_errno_win32;
1675         return(int) -1;
1676     }
1677     return (int)foo;
1678
1679 }
1680
1681
1682 int
1683 close(int fd)
1684 {
1685     if (!CloseHandle((HANDLE)fd)) {
1686         errno = b_errno_win32;
1687         return -1;
1688     }
1689
1690     return 0;
1691 }
1692
1693 ssize_t
1694 write(int fd, const void *data, ssize_t len)
1695 {
1696     BOOL status;
1697     DWORD bwrite;
1698     status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
1699     if (status) return bwrite;
1700     errno = b_errno_win32;
1701     return -1;
1702 }
1703
1704
1705 ssize_t
1706 read(int fd, void *data, ssize_t len)
1707 {
1708     BOOL status;
1709     DWORD bread;
1710
1711     status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
1712     if (status) return bread;
1713     errno = b_errno_win32;
1714     return -1;
1715 }
1716
1717 off_t
1718 lseek(int fd, off_t offset, int whence)
1719 {
1720     DWORD method = 0;
1721     DWORD val;
1722     switch (whence) {
1723     case SEEK_SET :
1724         method = FILE_BEGIN;
1725         break;
1726     case SEEK_CUR:
1727         method = FILE_CURRENT;
1728         break;
1729     case SEEK_END:
1730         method = FILE_END;
1731         break;
1732     default:
1733         errno = EINVAL;
1734         return -1;
1735     }
1736
1737     if ((val=SetFilePointer((HANDLE)fd, (DWORD)offset, NULL, method)) == INVALID_SET_FILE_POINTER) {
1738        errno = b_errno_win32;
1739        return -1;
1740     }
1741     /* ***FIXME*** I doubt this works right */
1742     return val;
1743 }
1744
1745 int
1746 dup2(int, int)
1747 {
1748     errno = ENOSYS;
1749     return -1;
1750 }
1751
1752
1753 #endif
1754
1755 #endif //HAVE_MINGW
1756
1757 #ifdef HAVE_MINGW
1758 /* syslog function, added by Nicolas Boichat */
1759 void closelog() {}
1760 #endif //HAVE_MINGW