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