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