]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/compat.cpp
moved fdplugins directory to under bin in the winbacula installer
[bacula/bacula] / bacula / src / win32 / compat / compat.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2004-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 //                              -*- Mode: C++ -*-
29 // compat.cpp -- compatibilty layer to make bacula-fd run
30 //               natively under windows
31 //
32 // Copyright transferred from Raider Solutions, Inc to
33 //   Kern Sibbald and John Walker by express permission.
34 //
35 // Author          : Christopher S. Hull
36 // Created On      : Sat Jan 31 15:55:00 2004
37 // $Id$
38
39
40 #include "bacula.h"
41 #include "compat.h"
42 #include "jcr.h"
43
44 #define b_errno_win32 (1<<29)
45
46 #define MAX_PATHLENGTH  1024
47
48 /* UTF-8 to UCS2 path conversion is expensive,
49    so we cache the conversion. During backup the
50    conversion is called 3 times (lstat, attribs, open),
51    by using the cache this is reduced to 1 time */
52
53 static POOLMEM *g_pWin32ConvUTF8Cache = get_pool_memory(PM_FNAME);
54 static POOLMEM *g_pWin32ConvUCS2Cache = get_pool_memory(PM_FNAME);
55 static DWORD g_dwWin32ConvUTF8strlen = 0;
56 static pthread_mutex_t Win32Convmutex = PTHREAD_MUTEX_INITIALIZER;
57
58 static t_pVSSPathConvert   g_pVSSPathConvert;
59 static t_pVSSPathConvertW  g_pVSSPathConvertW;
60
61 /* Forward referenced functions */
62 static const char *errorString(void);
63
64
65 void SetVSSPathConvert(t_pVSSPathConvert pPathConvert, t_pVSSPathConvertW pPathConvertW)
66 {
67    g_pVSSPathConvert = pPathConvert;
68    g_pVSSPathConvertW = pPathConvertW;
69 }
70
71 void Win32ConvCleanupCache()
72 {
73    if (g_pWin32ConvUTF8Cache) {
74       free_pool_memory(g_pWin32ConvUTF8Cache);
75       g_pWin32ConvUTF8Cache = NULL;
76    }
77
78    if (g_pWin32ConvUCS2Cache) {
79       free_pool_memory(g_pWin32ConvUCS2Cache);   
80       g_pWin32ConvUCS2Cache = NULL;
81    }
82
83    g_dwWin32ConvUTF8strlen = 0;
84 }
85
86
87 /* to allow the usage of the original version in this file here */
88 #undef fputs
89
90
91 //#define USE_WIN32_COMPAT_IO 1
92 #define USE_WIN32_32KPATHCONVERSION 1
93
94 extern DWORD   g_platform_id;
95 extern DWORD   g_MinorVersion;
96
97 // from MicroSoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970
98 #ifdef HAVE_MINGW
99 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL 
100 #else
101 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
102 #endif
103
104 #define WIN32_FILETIME_SCALE  10000000             // 100ns/second
105
106 void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize)
107 {
108     const char *fname = name;
109     char *tname = win32_name;
110
111     Dmsg0(100, "Enter convert_unix_to_win32_path\n");
112
113     if (IsPathSeparator(name[0]) &&
114         IsPathSeparator(name[1]) &&
115         name[2] == '.' &&
116         IsPathSeparator(name[3])) {
117
118         *win32_name++ = '\\';
119         *win32_name++ = '\\';
120         *win32_name++ = '.';
121         *win32_name++ = '\\';
122
123         name += 4;
124     } else if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS &&
125                g_pVSSPathConvert == NULL) {
126         /* allow path to be 32767 bytes */
127         *win32_name++ = '\\';
128         *win32_name++ = '\\';
129         *win32_name++ = '?';
130         *win32_name++ = '\\';
131     }
132
133     while (*name) {
134         /* Check for Unix separator and convert to Win32 */
135         if (name[0] == '/' && name[1] == '/') {  /* double slash? */
136            name++;                               /* yes, skip first one */
137         }
138         if (*name == '/') {
139             *win32_name++ = '\\';     /* convert char */
140         /* If Win32 separator that is "quoted", remove quote */
141         } else if (*name == '\\' && name[1] == '\\') {
142             *win32_name++ = '\\';
143             name++;                   /* skip first \ */
144         } else {
145             *win32_name++ = *name;    /* copy character */
146         }
147         name++;
148     }
149     /* Strip any trailing slash, if we stored something */
150     /* but leave "c:\" with backslash (root directory case */
151     if (*fname != 0 && win32_name[-1] == '\\' && strlen (fname) != 3) {
152         win32_name[-1] = 0;
153     } else {
154         *win32_name = 0;
155     }
156
157     /* here we convert to VSS specific file name which
158        can get longer because VSS will make something like
159        \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
160        from c:\bacula\uninstall.exe
161     */
162     Dmsg1(100, "path=%s\n", tname);
163     if (g_pVSSPathConvert != NULL) {
164        POOLMEM *pszBuf = get_pool_memory (PM_FNAME);
165        pszBuf = check_pool_memory_size(pszBuf, dwSize);
166        bstrncpy(pszBuf, tname, strlen(tname)+1);
167        g_pVSSPathConvert(pszBuf, tname, dwSize);
168        free_pool_memory(pszBuf);
169     }
170
171     Dmsg1(100, "Leave cvt_u_to_win32_path path=%s\n", tname);
172 }
173
174 /* Conversion of a Unix filename to a Win32 filename */
175 void unix_name_to_win32(POOLMEM **win32_name, char *name)
176 {
177    /* One extra byte should suffice, but we double it */
178    /* add MAX_PATH bytes for VSS shadow copy name */
179    DWORD dwSize = 2*strlen(name)+MAX_PATH;
180    *win32_name = check_pool_memory_size(*win32_name, dwSize);
181    conv_unix_to_win32_path(name, *win32_name, dwSize);
182 }
183
184 POOLMEM* 
185 make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/)
186 {
187    /* created 02/27/2006 Thorsten Engel
188     * 
189     * This function expects an UCS-encoded standard wchar_t in pszUCSPath and
190     * will complete the input path to an absolue path of the form \\?\c:\path\file
191     * 
192     * With this trick, it is possible to have 32K characters long paths.
193     *
194     * Optionally one can use pBIsRawPath to determine id pszUCSPath contains a path
195     * to a raw windows partition.  
196     */
197
198    Dmsg0(100, "Enter wchar_win32_path\n");
199    if (pBIsRawPath) {
200       *pBIsRawPath = FALSE;              /* Initialize, set later */
201    }
202
203    if (!p_GetCurrentDirectoryW) {
204       Dmsg0(100, "Leave wchar_win32_path no change \n");
205       return pszUCSPath;
206    }
207    
208    wchar_t *name = (wchar_t *)pszUCSPath;
209
210    /* if it has already the desired form, exit without changes */
211    if (wcslen(name) > 3 && wcsncmp(name, L"\\\\?\\", 4) == 0) {
212       Dmsg0(100, "Leave wchar_win32_path no change \n");
213       return pszUCSPath;
214    }
215
216    wchar_t *pwszBuf = (wchar_t *)get_pool_memory(PM_FNAME);
217    wchar_t *pwszCurDirBuf = (wchar_t *)get_pool_memory(PM_FNAME);
218    DWORD dwCurDirPathSize = 0;
219
220    /* get buffer with enough size (name+max 6. wchars+1 null terminator */
221    DWORD dwBufCharsNeeded = (wcslen(name)+7);
222    pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
223       
224    /* add \\?\ to support 32K long filepaths 
225       it is important to make absolute paths, so we add drive and
226       current path if necessary */
227
228    BOOL bAddDrive = TRUE;
229    BOOL bAddCurrentPath = TRUE;
230    BOOL bAddPrefix = TRUE;
231
232    /* does path begin with drive? if yes, it is absolute */
233    if (iswalpha(name[0]) && name[1] == ':' && IsPathSeparator(name[2])) {
234       bAddDrive = FALSE;
235       bAddCurrentPath = FALSE;
236    }
237
238    /* is path absolute? */
239    if (IsPathSeparator(name[0]))
240       bAddCurrentPath = FALSE; 
241
242    /* is path relative to itself?, if yes, skip ./ */
243    if (name[0] == '.' && IsPathSeparator(name[1])) {
244       name += 2;
245    }
246
247    /* is path of form '//./'? */
248    if (IsPathSeparator(name[0]) && 
249        IsPathSeparator(name[1]) && 
250        name[2] == '.' && 
251        IsPathSeparator(name[3])) {
252       bAddDrive = FALSE;
253       bAddCurrentPath = FALSE;
254       bAddPrefix = FALSE;
255       if (pBIsRawPath) {
256          *pBIsRawPath = TRUE;
257       }
258    }
259
260    int nParseOffset = 0;
261    
262    /* add 4 bytes header */
263    if (bAddPrefix) {
264       nParseOffset = 4;
265       wcscpy(pwszBuf, L"\\\\?\\");
266    }
267
268    /* get current path if needed */
269    if (bAddDrive || bAddCurrentPath) {
270       dwCurDirPathSize = p_GetCurrentDirectoryW(0, NULL);
271       if (dwCurDirPathSize > 0) {
272          /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */         
273          pwszCurDirBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszCurDirBuf, (dwCurDirPathSize+1)*sizeof(wchar_t));
274          p_GetCurrentDirectoryW(dwCurDirPathSize, pwszCurDirBuf);
275       } else {
276          /* we have no info for doing so */
277          bAddDrive = FALSE;
278          bAddCurrentPath = FALSE;
279       }
280    }
281       
282
283    /* add drive if needed */
284    if (bAddDrive && !bAddCurrentPath) {
285       wchar_t szDrive[3];
286
287       if (IsPathSeparator(pwszCurDirBuf[0]) && 
288           IsPathSeparator(pwszCurDirBuf[1]) && 
289           pwszCurDirBuf[2] == '?' && 
290           IsPathSeparator(pwszCurDirBuf[3])) {
291          /* copy drive character */
292          szDrive[0] = pwszCurDirBuf[4];
293       } else {
294          /* copy drive character */
295          szDrive[0] = pwszCurDirBuf[0];
296       }
297
298       szDrive[1] = ':';
299       szDrive[2] = 0;
300
301       wcscat(pwszBuf, szDrive);
302       nParseOffset +=2;
303    }
304
305    /* add path if needed */
306    if (bAddCurrentPath) {
307       /* the 1 add. character is for the eventually added backslash */
308       dwBufCharsNeeded += dwCurDirPathSize+1; 
309       pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
310       /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
311       
312       if (IsPathSeparator(pwszCurDirBuf[0]) && 
313           IsPathSeparator(pwszCurDirBuf[1]) && 
314           pwszCurDirBuf[2] == '?' && 
315           IsPathSeparator(pwszCurDirBuf[3])) {
316          /* copy complete string */
317          wcscpy(pwszBuf, pwszCurDirBuf);
318       } else {
319          /* append path  */
320          wcscat(pwszBuf, pwszCurDirBuf);
321       }
322
323       nParseOffset = wcslen((LPCWSTR) pwszBuf);
324
325       /* check if path ends with backslash, if not, add one */
326       if (!IsPathSeparator(pwszBuf[nParseOffset-1])) {
327          wcscat(pwszBuf, L"\\");
328          nParseOffset++;
329       }
330    }
331
332    wchar_t *win32_name = &pwszBuf[nParseOffset];
333    wchar_t *name_start = name;
334
335    while (*name) {
336       /* Check for Unix separator and convert to Win32, eliminating 
337        * duplicate separators.
338        */
339       if (IsPathSeparator(*name)) {
340          *win32_name++ = '\\';     /* convert char */
341
342          /* Eliminate consecutive slashes, but not at the start so that 
343           * \\.\ still works.
344           */
345          if (name_start != name && IsPathSeparator(name[1])) {
346             name++;
347          }
348       } else {
349          *win32_name++ = *name;    /* copy character */
350       }
351       name++;
352    }
353
354    /* null terminate string */
355    *win32_name = 0;
356
357    /* here we convert to VSS specific file name which
358     * can get longer because VSS will make something like
359     * \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
360     * from c:\bacula\uninstall.exe
361    */ 
362    if (g_pVSSPathConvertW != NULL) {
363       /* is output buffer large enough? */
364       pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, 
365                                                   (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
366       /* create temp. buffer */
367       wchar_t *pszBuf = (wchar_t *)get_pool_memory(PM_FNAME);
368       pszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pszBuf, 
369                                                  (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
370       if (bAddPrefix)
371          nParseOffset = 4;
372       else
373          nParseOffset = 0; 
374       wcsncpy(pszBuf, &pwszBuf[nParseOffset], wcslen(pwszBuf)+1-nParseOffset);
375       g_pVSSPathConvertW(pszBuf, pwszBuf, dwBufCharsNeeded+MAX_PATH);
376       free_pool_memory((POOLMEM *)pszBuf);
377    }   
378
379    free_pool_memory(pszUCSPath);
380    free_pool_memory((POOLMEM *)pwszCurDirBuf);
381
382    Dmsg1(100, "Leave wchar_win32_path=%s\n", pwszBuf);
383    return (POOLMEM *)pwszBuf;
384 }
385
386 int
387 wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
388 {
389    /* the return value is the number of bytes written to the buffer.
390       The number includes the byte for the null terminator. */
391
392    if (p_WideCharToMultiByte) {
393          int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
394          ASSERT (nRet > 0);
395          return nRet;
396       }
397    else
398       return 0;
399 }
400
401 int
402 UTF8_2_wchar(POOLMEM **ppszUCS, const char *pszUTF)
403 {
404    /* the return value is the number of wide characters written to the buffer. */
405    /* convert null terminated string from utf-8 to ucs2, enlarge buffer if necessary */
406
407    if (p_MultiByteToWideChar) {
408       /* strlen of UTF8 +1 is enough */
409       DWORD cchSize = (strlen(pszUTF)+1);
410       *ppszUCS = check_pool_memory_size(*ppszUCS, cchSize*sizeof (wchar_t));
411
412       int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
413       ASSERT (nRet > 0);
414       return nRet;
415    }
416    else
417       return 0;
418 }
419
420
421 void
422 wchar_win32_path(const char *name, wchar_t *win32_name)
423 {
424     const char *fname = name;
425     while (*name) {
426         /* Check for Unix separator and convert to Win32 */
427         if (*name == '/') {
428             *win32_name++ = '\\';     /* convert char */
429         /* If Win32 separated that is "quoted", remove quote */
430         } else if (*name == '\\' && name[1] == '\\') {
431             *win32_name++ = '\\';
432             name++;                   /* skip first \ */
433         } else {
434             *win32_name++ = *name;    /* copy character */
435         }
436         name++;
437     }
438     /* Strip any trailing slash, if we stored something */
439     if (*fname != 0 && win32_name[-1] == '\\') {
440         win32_name[-1] = 0;
441     } else {
442         *win32_name = 0;
443     }
444 }
445
446 int 
447 make_win32_path_UTF8_2_wchar(POOLMEM **pszUCS, const char *pszUTF, BOOL* pBIsRawPath /*= NULL*/)
448 {
449    P(Win32Convmutex);
450    /* if we find the utf8 string in cache, we use the cached ucs2 version.
451       we compare the stringlength first (quick check) and then compare the content.            
452    */
453    if (g_dwWin32ConvUTF8strlen == strlen(pszUTF)) {
454       if (bstrcmp(pszUTF, g_pWin32ConvUTF8Cache)) {
455          int32_t nBufSize = sizeof_pool_memory(g_pWin32ConvUCS2Cache);
456          *pszUCS = check_pool_memory_size(*pszUCS, nBufSize);      
457          wcscpy((LPWSTR) *pszUCS, (LPWSTR) g_pWin32ConvUCS2Cache);
458          V(Win32Convmutex);
459          return nBufSize / sizeof (WCHAR);
460       }
461    }
462
463    /* helper to convert from utf-8 to UCS-2 and to complete a path for 32K path syntax */
464    int nRet = UTF8_2_wchar(pszUCS, pszUTF);
465
466 #ifdef USE_WIN32_32KPATHCONVERSION
467    /* add \\?\ to support 32K long filepaths */
468    *pszUCS = make_wchar_win32_path(*pszUCS, pBIsRawPath);
469 #else
470    if (pBIsRawPath)
471       *pBIsRawPath = FALSE;
472 #endif
473
474    /* populate cache */      
475    g_pWin32ConvUCS2Cache = check_pool_memory_size(g_pWin32ConvUCS2Cache, sizeof_pool_memory(*pszUCS));
476    wcscpy((LPWSTR) g_pWin32ConvUCS2Cache, (LPWSTR) *pszUCS);
477    
478    g_dwWin32ConvUTF8strlen = strlen(pszUTF);
479    g_pWin32ConvUTF8Cache = check_pool_memory_size(g_pWin32ConvUTF8Cache, g_dwWin32ConvUTF8strlen+1);
480    bstrncpy(g_pWin32ConvUTF8Cache, pszUTF, g_dwWin32ConvUTF8strlen+1);
481    V(Win32Convmutex);
482
483    return nRet;
484 }
485
486 #if !defined(_MSC_VER) || (_MSC_VER < 1400) // VC8+
487 int umask(int)
488 {
489    return 0;
490 }
491 #endif
492
493 #ifndef LOAD_WITH_ALTERED_SEARCH_PATH
494 #define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008
495 #endif
496
497 void *dlopen(const char *file, int mode)
498 {
499    void *handle;
500
501    handle = LoadLibraryEx(file, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
502    return handle;
503 }
504
505 void *dlsym(void *handle, const char *name)
506 {
507    void *symaddr;
508    symaddr = (void *)GetProcAddress((HMODULE)handle, name);
509    return symaddr;
510 }
511
512 int dlclose(void *handle) 
513 {
514    if (handle && !FreeLibrary((HMODULE)handle)) {
515       errno = b_errno_win32;
516       return 1;        /* failed */
517    }
518    return 0;           /* OK */
519 }
520
521 char *dlerror(void) 
522 {
523    static char buf[200];
524    const char *err = errorString();
525    bstrncpy(buf, (char *)err, sizeof(buf));
526    LocalFree((void *)err);
527    return buf;
528 }
529
530 int fcntl(int fd, int cmd)
531 {
532    return 0;
533 }
534
535 int chmod(const char *, mode_t)
536 {
537    return 0;
538 }
539
540 int chown(const char *k, uid_t, gid_t)
541 {
542    return 0;
543 }
544
545 int lchown(const char *k, uid_t, gid_t)
546 {
547    return 0;
548 }
549
550 long int
551 random(void)
552 {
553     return rand();
554 }
555
556 void
557 srandom(unsigned int seed)
558 {
559    srand(seed);
560 }
561 // /////////////////////////////////////////////////////////////////
562 // convert from Windows concept of time to Unix concept of time
563 // /////////////////////////////////////////////////////////////////
564 void
565 cvt_utime_to_ftime(const time_t  &time, FILETIME &wintime)
566 {
567    uint64_t mstime = time;
568    mstime *= WIN32_FILETIME_SCALE;
569    mstime += WIN32_FILETIME_ADJUST;
570
571 #if defined(_MSC_VER)
572    wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
573 #else
574    wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL);
575 #endif
576    wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
577 }
578
579 time_t
580 cvt_ftime_to_utime(const FILETIME &time)
581 {
582     uint64_t mstime = time.dwHighDateTime;
583     mstime <<= 32;
584     mstime |= time.dwLowDateTime;
585
586     mstime -= WIN32_FILETIME_ADJUST;
587     mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
588
589     return (time_t) (mstime & 0xffffffff);
590 }
591
592 static const char *errorString(void)
593 {
594    LPVOID lpMsgBuf;
595
596    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
597                  FORMAT_MESSAGE_FROM_SYSTEM |
598                  FORMAT_MESSAGE_IGNORE_INSERTS,
599                  NULL,
600                  GetLastError(),
601                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
602                  (LPTSTR) &lpMsgBuf,
603                  0,
604                  NULL);
605
606    /* Strip any \r or \n */
607    char *rval = (char *) lpMsgBuf;
608    char *cp = strchr(rval, '\r');
609    if (cp != NULL) {
610       *cp = 0;
611    } else {
612       cp = strchr(rval, '\n');
613       if (cp != NULL)
614          *cp = 0;
615    }
616    return rval;
617 }
618
619
620 static int
621 statDir(const char *file, struct stat *sb)
622 {
623    WIN32_FIND_DATAW info_w;       // window's file info
624    WIN32_FIND_DATAA info_a;       // window's file info
625
626    // cache some common vars to make code more transparent
627    DWORD *pdwFileAttributes;
628    DWORD *pnFileSizeHigh;
629    DWORD *pnFileSizeLow;
630    DWORD *pdwReserved0;
631    FILETIME *pftLastAccessTime;
632    FILETIME *pftLastWriteTime;
633    FILETIME *pftCreationTime;
634
635    /* 
636     * Oh, cool, another exception: Microsoft doesn't let us do 
637     *  FindFile operations on a Drive, so simply fake root attibutes.
638     */
639    if (file[1] == ':' && file[2] == 0) {
640       time_t now = time(NULL);
641       Dmsg1(99, "faking ROOT attrs(%s).\n", file);
642       sb->st_mode = S_IFDIR;
643       sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
644       sb->st_ctime = now;
645       sb->st_mtime = now;
646       sb->st_atime = now;
647       sb->st_rdev = 0;
648       return 0;
649     }
650
651    HANDLE h = INVALID_HANDLE_VALUE;
652
653    // use unicode
654    if (p_FindFirstFileW) {
655       POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
656       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
657
658       h = p_FindFirstFileW((LPCWSTR)pwszBuf, &info_w);
659       free_pool_memory(pwszBuf);
660
661       pdwFileAttributes = &info_w.dwFileAttributes;
662       pdwReserved0      = &info_w.dwReserved0;
663       pnFileSizeHigh    = &info_w.nFileSizeHigh;
664       pnFileSizeLow     = &info_w.nFileSizeLow;
665       pftLastAccessTime = &info_w.ftLastAccessTime;
666       pftLastWriteTime  = &info_w.ftLastWriteTime;
667       pftCreationTime   = &info_w.ftCreationTime;
668
669    // use ASCII
670    } else if (p_FindFirstFileA) {
671       h = p_FindFirstFileA(file, &info_a);
672
673       pdwFileAttributes = &info_a.dwFileAttributes;
674       pdwReserved0      = &info_a.dwReserved0;
675       pnFileSizeHigh    = &info_a.nFileSizeHigh;
676       pnFileSizeLow     = &info_a.nFileSizeLow;
677       pftLastAccessTime = &info_a.ftLastAccessTime;
678       pftLastWriteTime  = &info_a.ftLastWriteTime;
679       pftCreationTime   = &info_a.ftCreationTime;
680    }
681
682    if (h == INVALID_HANDLE_VALUE) {
683       const char *err = errorString();
684       Dmsg2(99, "FindFirstFile(%s):%s\n", file, err);
685       LocalFree((void *)err);
686       errno = b_errno_win32;
687       return -1;
688    } else {
689       FindClose(h);
690    }
691
692    sb->st_mode = 0777;               /* start with everything */
693    if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
694        sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
695    if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
696        sb->st_mode &= ~S_IRWXO; /* remove everything for other */
697    if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
698        sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
699    sb->st_mode |= S_IFDIR;
700
701    /* 
702     * Store reparse/mount point info in st_rdev.  Note a
703     *  Win32 reparse point (junction point) is like a link
704     *  though it can have many properties (directory link,
705     *  soft link, hard link, HSM, ...
706     *  A mount point is a reparse point where another volume
707     *  is mounted, so it is like a Unix mount point (change of
708     *  filesystem).
709     */
710    if (*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
711       if (*pdwReserved0 & IO_REPARSE_TAG_MOUNT_POINT) {
712          sb->st_rdev = WIN32_MOUNT_POINT;           /* mount point */
713       } else {
714          sb->st_rdev = WIN32_REPARSE_POINT;         /* reparse point */
715       }
716    }  
717    Dmsg2(100, "st_rdev=%d file=%s\n", sb->st_rdev, file);
718    sb->st_size = *pnFileSizeHigh;
719    sb->st_size <<= 32;
720    sb->st_size |= *pnFileSizeLow;
721    sb->st_blksize = 4096;
722    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
723
724    sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
725    sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
726    sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
727
728    return 0;
729 }
730
731 int
732 fstat(int fd, struct stat *sb)
733 {
734    BY_HANDLE_FILE_INFORMATION info;
735
736    if (!GetFileInformationByHandle((HANDLE)fd, &info)) {
737        const char *err = errorString();
738        Dmsg1(99, "GetfileInformationByHandle: %s\n", err);
739        LocalFree((void *)err);
740        errno = b_errno_win32;
741        return -1;
742    }
743
744    sb->st_dev = info.dwVolumeSerialNumber;
745    sb->st_ino = info.nFileIndexHigh;
746    sb->st_ino <<= 32;
747    sb->st_ino |= info.nFileIndexLow;
748    sb->st_nlink = (short)info.nNumberOfLinks;
749    if (sb->st_nlink > 1) {
750       Dmsg1(99,  "st_nlink=%d\n", sb->st_nlink);
751    }
752
753    sb->st_mode = 0777;               /* start with everything */
754    if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
755        sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
756    if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
757        sb->st_mode &= ~S_IRWXO; /* remove everything for other */
758    if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
759        sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
760    sb->st_mode |= S_IFREG;
761
762    /* Use st_rdev to store reparse attribute */
763    if  (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
764       sb->st_rdev = WIN32_REPARSE_POINT;
765    }
766    Dmsg3(100, "st_rdev=%d sizino=%d ino=%lld\n", sb->st_rdev, sizeof(sb->st_ino),
767       (long long)sb->st_ino);
768
769    sb->st_size = info.nFileSizeHigh;
770    sb->st_size <<= 32;
771    sb->st_size |= info.nFileSizeLow;
772    sb->st_blksize = 4096;
773    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
774    sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
775    sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
776    sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
777
778    return 0;
779 }
780
781 static int
782 stat2(const char *file, struct stat *sb)
783 {
784    HANDLE h;
785    int rval = 0;
786    char tmpbuf[5000];
787    conv_unix_to_win32_path(file, tmpbuf, 5000);
788
789    DWORD attr = (DWORD)-1;
790
791    if (p_GetFileAttributesW) {
792       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
793       make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
794
795       attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
796       free_pool_memory(pwszBuf);
797    } else if (p_GetFileAttributesA) {
798       attr = p_GetFileAttributesA(tmpbuf);
799    }
800
801    if (attr == (DWORD)-1) {
802       const char *err = errorString();
803       Dmsg2(99, "GetFileAttributes(%s): %s\n", tmpbuf, err);
804       LocalFree((void *)err);
805       errno = b_errno_win32;
806       return -1;
807    }
808
809    h = CreateFileA(tmpbuf, GENERIC_READ,
810                   FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
811
812    if (h == INVALID_HANDLE_VALUE) {
813       const char *err = errorString();
814       Dmsg2(99, "Cannot open file for stat (%s):%s\n", tmpbuf, err);
815       LocalFree((void *)err);
816       errno = b_errno_win32;
817       return -1;
818    }
819
820    rval = fstat((int)h, sb);
821    CloseHandle(h);
822
823    if (attr & FILE_ATTRIBUTE_DIRECTORY &&
824         file[1] == ':' && file[2] != 0) {
825       statDir(file, sb);
826    }
827
828    return rval;
829 }
830
831 int
832 stat(const char *file, struct stat *sb)
833 {
834    WIN32_FILE_ATTRIBUTE_DATA data;
835    errno = 0;
836
837    memset(sb, 0, sizeof(*sb));
838
839    if (p_GetFileAttributesExW) {
840       /* dynamically allocate enough space for UCS2 filename */
841       POOLMEM *pwszBuf = get_pool_memory(PM_FNAME);
842       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
843
844       BOOL b = p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, &data);
845       free_pool_memory(pwszBuf);
846
847       if (!b) {
848          return stat2(file, sb);
849       }
850
851    } else if (p_GetFileAttributesExA) {
852       if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
853          return stat2(file, sb);
854        }
855    } else {
856       return stat2(file, sb);
857    }
858
859    sb->st_mode = 0777;               /* start with everything */
860    if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
861       sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
862    }
863    if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
864       sb->st_mode &= ~S_IRWXO; /* remove everything for other */
865    }
866    if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
867       sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
868    }
869    if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
870       sb->st_mode |= S_IFDIR;
871    } else {
872       sb->st_mode |= S_IFREG;
873    }
874
875    /* Use st_rdev to store reparse attribute */
876    sb->st_rdev = (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0; 
877
878    sb->st_nlink = 1;
879    sb->st_size = data.nFileSizeHigh;
880    sb->st_size <<= 32;
881    sb->st_size |= data.nFileSizeLow;
882    sb->st_blksize = 4096;
883    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
884    sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
885    sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
886    sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
887
888    /*
889     * If we are not at the root, then to distinguish a reparse 
890     *  point from a mount point, we must call FindFirstFile() to
891     *  get the WIN32_FIND_DATA, which has the bit that indicates
892     *  that this directory is a mount point -- aren't Win32 APIs
893     *  wonderful? (sarcasm).  The code exists in the statDir
894     *  subroutine.
895     */
896    if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && 
897         file[1] == ':' && file[2] != 0) {
898       statDir(file, sb);
899    }
900    Dmsg3(100, "sizino=%d ino=%lld file=%s\n", sizeof(sb->st_ino),
901                        (long long)sb->st_ino, file);
902    return 0;
903 }
904
905 /*
906  * We write our own ftruncate because the one in the
907  *  Microsoft library mrcrt.dll does not truncate
908  *  files greater than 2GB.
909  *  KES - May 2007
910  */
911 int win32_ftruncate(int fd, int64_t length) 
912 {
913    /* Set point we want to truncate file */
914    __int64 pos = _lseeki64(fd, (__int64)length, SEEK_SET);
915
916    if (pos != (__int64)length) {
917       errno = EACCES;         /* truncation failed, get out */
918       return -1;
919    }
920
921    /* Truncate file */
922    if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0) {
923       errno = b_errno_win32;
924       return -1;
925    }
926    errno = 0;
927    return 0;
928 }
929
930 int fcntl(int fd, int cmd, long arg)
931 {
932    int rval = 0;
933
934    switch (cmd) {
935    case F_GETFL:
936       rval = O_NONBLOCK;
937       break;
938
939    case F_SETFL:
940       rval = 0;
941       break;
942
943    default:
944       errno = EINVAL;
945       rval = -1;
946       break;
947    }
948
949    return rval;
950 }
951
952 int
953 lstat(const char *file, struct stat *sb)
954 {
955    return stat(file, sb);
956 }
957
958 void
959 sleep(int sec)
960 {
961    Sleep(sec * 1000);
962 }
963
964 int
965 geteuid(void)
966 {
967    return 0;
968 }
969
970 int
971 execvp(const char *, char *[]) {
972    errno = ENOSYS;
973    return -1;
974 }
975
976
977 int
978 fork(void)
979 {
980    errno = ENOSYS;
981    return -1;
982 }
983
984 int
985 pipe(int[])
986 {
987    errno = ENOSYS;
988    return -1;
989 }
990
991 int
992 waitpid(int, int*, int)
993 {
994    errno = ENOSYS;
995    return -1;
996 }
997
998 int
999 readlink(const char *, char *, int)
1000 {
1001    errno = ENOSYS;
1002    return -1;
1003 }
1004
1005
1006 #ifndef HAVE_MINGW
1007 int
1008 strcasecmp(const char *s1, const char *s2)
1009 {
1010    register int ch1, ch2;
1011
1012    if (s1==s2)
1013       return 0;       /* strings are equal if same object. */
1014    else if (!s1)
1015       return -1;
1016    else if (!s2)
1017       return 1;
1018    do {
1019       ch1 = *s1;
1020       ch2 = *s2;
1021       s1++;
1022       s2++;
1023    } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
1024
1025    return(ch1 - ch2);
1026 }
1027 #endif //HAVE_MINGW
1028
1029 int
1030 strncasecmp(const char *s1, const char *s2, int len)
1031 {
1032    register int ch1 = 0, ch2 = 0;
1033
1034    if (s1==s2)
1035       return 0;       /* strings are equal if same object. */
1036    else if (!s1)
1037       return -1;
1038    else if (!s2)
1039       return 1;
1040
1041    while (len--) {
1042       ch1 = *s1;
1043       ch2 = *s2;
1044       s1++;
1045       s2++;
1046       if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
1047    }
1048
1049    return (ch1 - ch2);
1050 }
1051
1052 int
1053 gettimeofday(struct timeval *tv, struct timezone *)
1054 {
1055     SYSTEMTIME now;
1056     FILETIME tmp;
1057
1058     GetSystemTime(&now);
1059
1060     if (tv == NULL) {
1061        errno = EINVAL;
1062        return -1;
1063     }
1064     if (!SystemTimeToFileTime(&now, &tmp)) {
1065        errno = b_errno_win32;
1066        return -1;
1067     }
1068
1069     int64_t _100nsec = tmp.dwHighDateTime;
1070     _100nsec <<= 32;
1071     _100nsec |= tmp.dwLowDateTime;
1072     _100nsec -= WIN32_FILETIME_ADJUST;
1073
1074     tv->tv_sec = (long)(_100nsec / 10000000);
1075     tv->tv_usec = (long)((_100nsec % 10000000)/10);
1076     return 0;
1077
1078 }
1079
1080 /* For apcupsd this is in src/lib/wincompat.c */
1081 extern "C" void syslog(int type, const char *fmt, ...) 
1082 {
1083 /*#ifndef HAVE_CONSOLE
1084     MessageBox(NULL, msg, "Bacula", MB_OK);
1085 #endif*/
1086 }
1087
1088 void
1089 closelog()
1090 {
1091 }
1092
1093 struct passwd *
1094 getpwuid(uid_t)
1095 {
1096     return NULL;
1097 }
1098
1099 struct group *
1100 getgrgid(uid_t)
1101 {
1102     return NULL;
1103 }
1104
1105 // implement opendir/readdir/closedir on top of window's API
1106
1107 typedef struct _dir
1108 {
1109     WIN32_FIND_DATAA data_a;    // window's file info (ansii version)
1110     WIN32_FIND_DATAW data_w;    // window's file info (wchar version)
1111     const char *spec;           // the directory we're traversing
1112     HANDLE      dirh;           // the search handle
1113     BOOL        valid_a;        // the info in data_a field is valid
1114     BOOL        valid_w;        // the info in data_w field is valid
1115     UINT32      offset;         // pseudo offset for d_off
1116 } _dir;
1117
1118 DIR *
1119 opendir(const char *path)
1120 {
1121     /* enough space for VSS !*/
1122     int max_len = strlen(path) + MAX_PATH;
1123     _dir *rval = NULL;
1124     if (path == NULL) {
1125        errno = ENOENT;
1126        return NULL;
1127     }
1128
1129     Dmsg1(100, "Opendir path=%s\n", path);
1130     rval = (_dir *)malloc(sizeof(_dir));
1131     memset (rval, 0, sizeof (_dir));
1132     if (rval == NULL) return NULL;
1133     char *tspec = (char *)malloc(max_len);
1134     if (tspec == NULL) return NULL;
1135
1136     conv_unix_to_win32_path(path, tspec, max_len);
1137     Dmsg1(100, "win32 path=%s\n", tspec);
1138
1139     // add backslash only if there is none yet (think of c:\)
1140     if (tspec[strlen(tspec)-1] != '\\')
1141       bstrncat(tspec, "\\*", max_len);
1142     else
1143       bstrncat(tspec, "*", max_len);
1144
1145     rval->spec = tspec;
1146
1147     // convert to wchar_t
1148     if (p_FindFirstFileW) {
1149       POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
1150       make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec);
1151
1152       rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
1153
1154       free_pool_memory(pwcBuf);
1155
1156       if (rval->dirh != INVALID_HANDLE_VALUE)
1157         rval->valid_w = 1;
1158     } else if (p_FindFirstFileA) {
1159       rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
1160
1161       if (rval->dirh != INVALID_HANDLE_VALUE)
1162         rval->valid_a = 1;
1163     } else goto err;
1164
1165
1166     Dmsg3(99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
1167           path, rval->spec, rval->dirh);
1168
1169     rval->offset = 0;
1170     if (rval->dirh == INVALID_HANDLE_VALUE)
1171         goto err;
1172
1173     if (rval->valid_w) {
1174       Dmsg1(99, "\tFirstFile=%s\n", rval->data_w.cFileName);
1175     }
1176
1177     if (rval->valid_a) {
1178       Dmsg1(99, "\tFirstFile=%s\n", rval->data_a.cFileName);
1179     }
1180
1181     return (DIR *)rval;
1182
1183 err:
1184     free((void *)rval->spec);
1185     free(rval);
1186     errno = b_errno_win32;
1187     return NULL;
1188 }
1189
1190 int
1191 closedir(DIR *dirp)
1192 {
1193     _dir *dp = (_dir *)dirp;
1194     FindClose(dp->dirh);
1195     free((void *)dp->spec);
1196     free((void *)dp);
1197     return 0;
1198 }
1199
1200 /*
1201   typedef struct _WIN32_FIND_DATA {
1202     DWORD dwFileAttributes;
1203     FILETIME ftCreationTime;
1204     FILETIME ftLastAccessTime;
1205     FILETIME ftLastWriteTime;
1206     DWORD nFileSizeHigh;
1207     DWORD nFileSizeLow;
1208     DWORD dwReserved0;
1209     DWORD dwReserved1;
1210     TCHAR cFileName[MAX_PATH];
1211     TCHAR cAlternateFileName[14];
1212 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1213 */
1214
1215 static int
1216 copyin(struct dirent &dp, const char *fname)
1217 {
1218     dp.d_ino = 0;
1219     dp.d_reclen = 0;
1220     char *cp = dp.d_name;
1221     while (*fname) {
1222         *cp++ = *fname++;
1223         dp.d_reclen++;
1224     }
1225         *cp = 0;
1226     return dp.d_reclen;
1227 }
1228
1229 int
1230 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1231 {
1232     _dir *dp = (_dir *)dirp;
1233     if (dp->valid_w || dp->valid_a) {
1234       entry->d_off = dp->offset;
1235
1236       // copy unicode
1237       if (dp->valid_w) {
1238          char szBuf[MAX_PATH_UTF8+1];
1239          wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1240          dp->offset += copyin(*entry, szBuf);
1241       } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1242          dp->offset += copyin(*entry, dp->data_a.cFileName);
1243       }
1244
1245       *result = entry;              /* return entry address */
1246       Dmsg4(99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1247             dirp, entry->d_name, entry->d_reclen, entry->d_off);
1248     } else {
1249 //      Dmsg0(99, "readdir_r !valid\n");
1250         errno = b_errno_win32;
1251         return -1;
1252     }
1253
1254     // get next file, try unicode first
1255     if (p_FindNextFileW)
1256        dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1257     else if (p_FindNextFileA)
1258        dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1259     else {
1260        dp->valid_a = FALSE;
1261        dp->valid_w = FALSE;
1262     }
1263
1264     return 0;
1265 }
1266
1267 /*
1268  * Dotted IP address to network address
1269  *
1270  * Returns 1 if  OK
1271  *         0 on error
1272  */
1273 int
1274 inet_aton(const char *a, struct in_addr *inp)
1275 {
1276    const char *cp = a;
1277    uint32_t acc = 0, tmp = 0;
1278    int dotc = 0;
1279
1280    if (!isdigit(*cp)) {         /* first char must be digit */
1281       return 0;                 /* error */
1282    }
1283    do {
1284       if (isdigit(*cp)) {
1285          tmp = (tmp * 10) + (*cp -'0');
1286       } else if (*cp == '.' || *cp == 0) {
1287          if (tmp > 255) {
1288             return 0;           /* error */
1289          }
1290          acc = (acc << 8) + tmp;
1291          dotc++;
1292          tmp = 0;
1293       } else {
1294          return 0;              /* error */
1295       }
1296    } while (*cp++ != 0);
1297    if (dotc != 4) {              /* want 3 .'s plus EOS */
1298       return 0;                  /* error */
1299    }
1300    inp->s_addr = htonl(acc);     /* store addr in network format */
1301    return 1;
1302 }
1303
1304 int
1305 nanosleep(const struct timespec *req, struct timespec *rem)
1306 {
1307     if (rem)
1308         rem->tv_sec = rem->tv_nsec = 0;
1309     Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1310     return 0;
1311 }
1312
1313 void
1314 init_signals(void terminate(int sig))
1315 {
1316
1317 }
1318
1319 void
1320 init_stack_dump(void)
1321 {
1322
1323 }
1324
1325
1326 long
1327 pathconf(const char *path, int name)
1328 {
1329     switch(name) {
1330     case _PC_PATH_MAX :
1331         if (strncmp(path, "\\\\?\\", 4) == 0)
1332             return 32767;
1333     case _PC_NAME_MAX :
1334         return 255;
1335     }
1336     errno = ENOSYS;
1337     return -1;
1338 }
1339
1340 int
1341 WSA_Init(void)
1342 {
1343     WORD wVersionRequested = MAKEWORD( 1, 1);
1344     WSADATA wsaData;
1345
1346     int err = WSAStartup(wVersionRequested, &wsaData);
1347
1348
1349     if (err != 0) {
1350         printf("Can not start Windows Sockets\n");
1351         errno = ENOSYS;
1352         return -1;
1353     }
1354
1355     return 0;
1356 }
1357
1358
1359 int
1360 win32_chdir(const char *dir)
1361 {
1362    if (p_SetCurrentDirectoryW) {
1363       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1364       make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1365
1366       BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1367       
1368       free_pool_memory(pwszBuf);
1369
1370       if (!b) {
1371          errno = b_errno_win32;
1372          return -1;
1373       }
1374    }
1375    else if (p_SetCurrentDirectoryA) {
1376       if (0 == p_SetCurrentDirectoryA(dir)) {
1377          errno = b_errno_win32;
1378          return -1;
1379       }
1380    }
1381    else return -1;
1382
1383    return 0;
1384 }
1385
1386 int
1387 win32_mkdir(const char *dir)
1388 {
1389    if (p_wmkdir){
1390       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1391       make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1392
1393       int n = p_wmkdir((LPCWSTR)pwszBuf);
1394       free_pool_memory(pwszBuf);
1395       return n;
1396    }
1397
1398    return _mkdir(dir);
1399 }
1400
1401
1402 char *
1403 win32_getcwd(char *buf, int maxlen)
1404 {
1405    int n=0;
1406
1407    if (p_GetCurrentDirectoryW) {
1408       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1409       pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1410
1411       n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1412       if (n!=0)
1413          n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1414       free_pool_memory(pwszBuf);
1415
1416    } else if (p_GetCurrentDirectoryA)
1417       n = p_GetCurrentDirectoryA(maxlen, buf);
1418
1419    if (n == 0 || n > maxlen) return NULL;
1420
1421    if (n+1 > maxlen) return NULL;
1422    if (n != 3) {
1423        buf[n] = '\\';
1424        buf[n+1] = 0;
1425    }
1426    return buf;
1427 }
1428
1429 int
1430 win32_fputs(const char *string, FILE *stream)
1431 {
1432    /* we use WriteConsoleA / WriteConsoleA
1433       so we can be sure that unicode support works on win32.
1434       with fallback if something fails
1435    */
1436
1437    HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1438    if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1439        p_MultiByteToWideChar && (stream == stdout)) {
1440
1441       POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1442
1443       DWORD dwCharsWritten;
1444       DWORD dwChars;
1445
1446       dwChars = UTF8_2_wchar(&pwszBuf, string);
1447
1448       /* try WriteConsoleW */
1449       if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1450          free_pool_memory(pwszBuf);
1451          return dwCharsWritten;
1452       }
1453
1454       /* convert to local codepage and try WriteConsoleA */
1455       POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1456       pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1457
1458       dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR)pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1459       free_pool_memory(pwszBuf);
1460
1461       if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1462          free_pool_memory(pszBuf);
1463          return dwCharsWritten;
1464       }
1465       free_pool_memory(pszBuf);
1466    }
1467    /* Fall back */
1468    return fputs(string, stream);
1469 }
1470
1471 char*
1472 win32_cgets (char* buffer, int len)
1473 {
1474    /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1475       from the win32 console and fallback if seomething fails */
1476
1477    HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1478    if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1479       DWORD dwRead;
1480       wchar_t wszBuf[1024];
1481       char  szBuf[1024];
1482
1483       /* nt and unicode conversion */
1484       if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1485
1486          /* null terminate at end */
1487          if (wszBuf[dwRead-1] == L'\n') {
1488             wszBuf[dwRead-1] = L'\0';
1489             dwRead --;
1490          }
1491
1492          if (wszBuf[dwRead-1] == L'\r') {
1493             wszBuf[dwRead-1] = L'\0';
1494             dwRead --;
1495          }
1496
1497          wchar_2_UTF8(buffer, wszBuf, len);
1498          return buffer;
1499       }
1500
1501       /* win 9x and unicode conversion */
1502       if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1503
1504          /* null terminate at end */
1505          if (szBuf[dwRead-1] == L'\n') {
1506             szBuf[dwRead-1] = L'\0';
1507             dwRead --;
1508          }
1509
1510          if (szBuf[dwRead-1] == L'\r') {
1511             szBuf[dwRead-1] = L'\0';
1512             dwRead --;
1513          }
1514
1515          /* convert from ansii to wchar_t */
1516          p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1517          /* convert from wchar_t to UTF-8 */
1518          if (wchar_2_UTF8(buffer, wszBuf, len))
1519             return buffer;
1520       }
1521    }
1522
1523    /* fallback */
1524    if (fgets(buffer, len, stdin))
1525       return buffer;
1526    else
1527       return NULL;
1528 }
1529
1530 int
1531 win32_unlink(const char *filename)
1532 {
1533    int nRetCode;
1534    if (p_wunlink) {
1535       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1536       make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1537
1538       nRetCode = _wunlink((LPCWSTR) pwszBuf);
1539
1540       /* special case if file is readonly,
1541       we retry but unset attribute before */
1542       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1543          DWORD dwAttr =  p_GetFileAttributesW((LPCWSTR)pwszBuf);
1544          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1545             if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1546                nRetCode = _wunlink((LPCWSTR) pwszBuf);
1547                /* reset to original if it didn't help */
1548                if (nRetCode == -1)
1549                   p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1550             }
1551          }
1552       }
1553       free_pool_memory(pwszBuf);
1554    } else {
1555       nRetCode = _unlink(filename);
1556
1557       /* special case if file is readonly,
1558       we retry but unset attribute before */
1559       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1560          DWORD dwAttr =  p_GetFileAttributesA(filename);
1561          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1562             if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1563                nRetCode = _unlink(filename);
1564                /* reset to original if it didn't help */
1565                if (nRetCode == -1)
1566                   p_SetFileAttributesA(filename, dwAttr);
1567             }
1568          }
1569       }
1570    }
1571    return nRetCode;
1572 }
1573
1574
1575 #include "mswinver.h"
1576
1577 char WIN_VERSION_LONG[64];
1578 char WIN_VERSION[32];
1579 char WIN_RAWVERSION[32];
1580
1581 class winver {
1582 public:
1583     winver(void);
1584 };
1585
1586 static winver INIT;                     // cause constructor to be called before main()
1587
1588
1589 winver::winver(void)
1590 {
1591     const char *version = "";
1592     const char *platform = "";
1593     OSVERSIONINFO osvinfo;
1594     osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1595
1596     // Get the current OS version
1597     if (!GetVersionEx(&osvinfo)) {
1598         version = "Unknown";
1599         platform = "Unknown";
1600     }
1601         const int ver = _mkversion(osvinfo.dwPlatformId,
1602                                    osvinfo.dwMajorVersion,
1603                                    osvinfo.dwMinorVersion);
1604         snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1605         switch (ver)
1606         {
1607         case MS_WINDOWS_95: (version =  "Windows 95"); break;
1608         case MS_WINDOWS_98: (version =  "Windows 98"); break;
1609         case MS_WINDOWS_ME: (version =  "Windows ME"); break;
1610         case MS_WINDOWS_NT4:(version =  "Windows NT 4.0"); platform = "NT"; break;
1611         case MS_WINDOWS_2K: (version =  "Windows 2000");platform = "NT"; break;
1612         case MS_WINDOWS_XP: (version =  "Windows XP");platform = "NT"; break;
1613         case MS_WINDOWS_S2003: (version =  "Windows Server 2003");platform = "NT"; break;
1614         default: version = WIN_RAWVERSION; break;
1615         }
1616
1617     bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1618     snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1619              platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1620
1621 #if 0
1622     HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1623     CloseHandle(h);
1624 #endif
1625 #if 0
1626     BPIPE *b = open_bpipe("ls -l", 10, "r");
1627     char buf[1024];
1628     while (!feof(b->rfd)) {
1629         fgets(buf, sizeof(buf), b->rfd);
1630     }
1631     close_bpipe(b);
1632 #endif
1633 }
1634
1635 BOOL CreateChildProcess(VOID);
1636 VOID WriteToPipe(VOID);
1637 VOID ReadFromPipe(VOID);
1638 VOID ErrorExit(LPCSTR);
1639 VOID ErrMsg(LPTSTR, BOOL);
1640
1641 /**
1642  * Check for a quoted path,  if an absolute path name is given and it contains
1643  * spaces it will need to be quoted.  i.e.  "c:/Program Files/foo/bar.exe"
1644  * CreateProcess() says the best way to ensure proper results with executables
1645  * with spaces in path or filename is to quote the string.
1646  */
1647 const char *
1648 getArgv0(const char *cmdline)
1649 {
1650
1651     int inquote = 0;
1652     const char *cp;
1653     for (cp = cmdline; *cp; cp++)
1654     {
1655         if (*cp == '"') {
1656             inquote = !inquote;
1657         }
1658         if (!inquote && isspace(*cp))
1659             break;
1660     }
1661
1662
1663     int len = cp - cmdline;
1664     char *rval = (char *)malloc(len+1);
1665
1666     cp = cmdline;
1667     char *rp = rval;
1668
1669     while (len--)
1670         *rp++ = *cp++;
1671
1672     *rp = 0;
1673     return rval;
1674 }
1675
1676 /*
1677  * Extracts the executable or script name from the first string in 
1678  * cmdline.
1679  *
1680  * If the name contains blanks then it must be quoted with double quotes,
1681  * otherwise quotes are optional.  If the name contains blanks then it 
1682  * will be converted to a short name.
1683  *
1684  * The optional quotes will be removed.  The result is copied to a malloc'ed
1685  * buffer and returned through the pexe argument.  The pargs parameter is set
1686  * to the address of the character in cmdline located after the name.
1687  *
1688  * The malloc'ed buffer returned in *pexe must be freed by the caller.
1689  */
1690 bool
1691 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1692 {
1693    const char *pExeStart = NULL;    /* Start of executable name in cmdline */
1694    const char *pExeEnd = NULL;      /* Character after executable name (separator) */
1695
1696    const char *pBasename = NULL;    /* Character after last path separator */
1697    const char *pExtension = NULL;   /* Period at start of extension */
1698
1699    const char *current = cmdline;
1700
1701    bool bQuoted = false;
1702
1703    /* Skip initial whitespace */
1704
1705    while (*current == ' ' || *current == '\t')
1706    {
1707       current++;
1708    }
1709
1710    /* Calculate start of name and determine if quoted */
1711
1712    if (*current == '"') {
1713       pExeStart = ++current;
1714       bQuoted = true;
1715    } else {
1716       pExeStart = current;
1717       bQuoted = false;
1718    }
1719
1720    *pargs = NULL;
1721    *pexe = NULL;
1722
1723    /* 
1724     * Scan command line looking for path separators (/ and \\) and the 
1725     * terminator, either a quote or a blank.  The location of the 
1726     * extension is also noted.
1727     */
1728
1729    for ( ; *current != '\0'; current++)
1730    {
1731       if (*current == '.') {
1732          pExtension = current;
1733       } else if (IsPathSeparator(*current) && current[1] != '\0') {
1734          pBasename = &current[1];
1735          pExtension = NULL;
1736       }
1737
1738       /* Check for terminator, either quote or blank */
1739       if (bQuoted) {
1740          if (*current != '"') {
1741             continue;
1742          }
1743       } else {
1744          if (*current != ' ') {
1745             continue;
1746          }
1747       }
1748
1749       /*
1750        * Hit terminator, remember end of name (address of terminator) and 
1751        * start of arguments 
1752        */
1753       pExeEnd = current;
1754
1755       if (bQuoted && *current == '"') {
1756          *pargs = &current[1];
1757       } else {
1758          *pargs = current;
1759       }
1760
1761       break;
1762    }
1763
1764    if (pBasename == NULL) {
1765       pBasename = pExeStart;
1766    }
1767
1768    if (pExeEnd == NULL) {
1769       pExeEnd = current;
1770    }
1771
1772    if (*pargs == NULL)
1773    {
1774       *pargs = current;
1775    }
1776
1777    bool bHasPathSeparators = pExeStart != pBasename;
1778
1779    /* We have pointers to all the useful parts of the name */
1780
1781    /* Default extensions in the order cmd.exe uses to search */
1782
1783    static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
1784    DWORD dwBasePathLength = pExeEnd - pExeStart;
1785
1786    DWORD dwAltNameLength = 0;
1787    char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1788    char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1789
1790    pPathname[MAX_PATHLENGTH] = '\0';
1791    pAltPathname[MAX_PATHLENGTH] = '\0';
1792
1793    memcpy(pPathname, pExeStart, dwBasePathLength);
1794    pPathname[dwBasePathLength] = '\0';
1795
1796    if (pExtension == NULL) {
1797       /* Try appending extensions */
1798       for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
1799
1800          if (!bHasPathSeparators) {
1801             /* There are no path separators, search in the standard locations */
1802             dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
1803             if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1804                memcpy(pPathname, pAltPathname, dwAltNameLength);
1805                pPathname[dwAltNameLength] = '\0';
1806                break;
1807             }
1808          } else {
1809             bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
1810             if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) {
1811                break;
1812             }
1813             pPathname[dwBasePathLength] = '\0';
1814          }
1815       }
1816    } else if (!bHasPathSeparators) {
1817       /* There are no path separators, search in the standard locations */
1818       dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
1819       if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) {
1820          memcpy(pPathname, pAltPathname, dwAltNameLength);
1821          pPathname[dwAltNameLength] = '\0';
1822       }
1823    }
1824
1825    if (strchr(pPathname, ' ') != NULL) {
1826       dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH);
1827
1828       if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1829          *pexe = (char *)malloc(dwAltNameLength + 1);
1830          if (*pexe == NULL) {
1831             return false;
1832          }
1833          memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
1834       }
1835    }
1836
1837    if (*pexe == NULL) {
1838       DWORD dwPathnameLength = strlen(pPathname);
1839       *pexe = (char *)malloc(dwPathnameLength + 1);
1840       if (*pexe == NULL) {
1841          return false;
1842       }
1843       memcpy(*pexe, pPathname, dwPathnameLength + 1);
1844    }
1845
1846    return true;
1847 }
1848
1849 /**
1850  * Create the process with WCHAR API
1851  */
1852 static BOOL
1853 CreateChildProcessW(const char *comspec, const char *cmdLine,
1854                     PROCESS_INFORMATION *hProcInfo,
1855                     HANDLE in, HANDLE out, HANDLE err)
1856 {
1857    STARTUPINFOW siStartInfo;
1858    BOOL bFuncRetn = FALSE;
1859
1860    // Set up members of the STARTUPINFO structure.
1861    ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
1862    siStartInfo.cb = sizeof(siStartInfo);
1863    // setup new process to use supplied handles for stdin,stdout,stderr
1864
1865    siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1866    siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
1867
1868    siStartInfo.hStdInput = in;
1869    siStartInfo.hStdOutput = out;
1870    siStartInfo.hStdError = err;
1871    
1872    // Convert argument to WCHAR
1873    POOLMEM *cmdLine_wchar = get_pool_memory(PM_FNAME);
1874    POOLMEM *comspec_wchar = get_pool_memory(PM_FNAME);
1875
1876    UTF8_2_wchar(&cmdLine_wchar, cmdLine);
1877    UTF8_2_wchar(&comspec_wchar, comspec);
1878
1879    // Create the child process.
1880    Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec_wchar, cmdLine_wchar);
1881
1882    // try to execute program
1883    bFuncRetn = p_CreateProcessW((WCHAR*)comspec_wchar,
1884                                 (WCHAR*)cmdLine_wchar,// command line
1885                                 NULL,      // process security attributes
1886                                 NULL,      // primary thread security attributes
1887                                 TRUE,      // handles are inherited
1888                                 0,         // creation flags
1889                                 NULL,      // use parent's environment
1890                                 NULL,      // use parent's current directory
1891                                 &siStartInfo,  // STARTUPINFO pointer
1892                                 hProcInfo);   // receives PROCESS_INFORMATION
1893    free_pool_memory(cmdLine_wchar);
1894    free_pool_memory(comspec_wchar);
1895
1896    return bFuncRetn;
1897 }
1898
1899
1900 /**
1901  * Create the process with ANSI API
1902  */
1903 static BOOL
1904 CreateChildProcessA(const char *comspec, char *cmdLine,
1905                     PROCESS_INFORMATION *hProcInfo,
1906                     HANDLE in, HANDLE out, HANDLE err)
1907 {
1908    STARTUPINFOA siStartInfo;
1909    BOOL bFuncRetn = FALSE;
1910
1911    // Set up members of the STARTUPINFO structure.
1912    ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
1913    siStartInfo.cb = sizeof(siStartInfo);
1914    // setup new process to use supplied handles for stdin,stdout,stderr
1915    siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1916    siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
1917
1918    siStartInfo.hStdInput = in;
1919    siStartInfo.hStdOutput = out;
1920    siStartInfo.hStdError = err;
1921
1922    // Create the child process.
1923    Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
1924
1925    // try to execute program
1926    bFuncRetn = p_CreateProcessA(comspec,
1927                                 cmdLine,  // command line
1928                                 NULL,     // process security attributes
1929                                 NULL,     // primary thread security attributes
1930                                 TRUE,     // handles are inherited
1931                                 0,        // creation flags
1932                                 NULL,     // use parent's environment
1933                                 NULL,     // use parent's current directory
1934                                 &siStartInfo,// STARTUPINFO pointer
1935                                 hProcInfo);// receives PROCESS_INFORMATION
1936    return bFuncRetn;
1937 }
1938
1939 /**
1940  * OK, so it would seem CreateProcess only handles true executables:
1941  * .com or .exe files.  So grab $COMSPEC value and pass command line to it.
1942  */
1943 HANDLE
1944 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1945 {
1946    static const char *comspec = NULL;
1947    PROCESS_INFORMATION piProcInfo;
1948    BOOL bFuncRetn = FALSE;
1949
1950    if (!p_CreateProcessA || !p_CreateProcessW)
1951       return INVALID_HANDLE_VALUE;
1952
1953    if (comspec == NULL) 
1954       comspec = getenv("COMSPEC");
1955    if (comspec == NULL) // should never happen
1956       return INVALID_HANDLE_VALUE;
1957
1958    // Set up members of the PROCESS_INFORMATION structure.
1959    ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1960
1961    // if supplied handles are not used the send a copy of our STD_HANDLE
1962    // as appropriate
1963    if (in == INVALID_HANDLE_VALUE)
1964       in = GetStdHandle(STD_INPUT_HANDLE);
1965
1966    if (out == INVALID_HANDLE_VALUE)
1967       out = GetStdHandle(STD_OUTPUT_HANDLE);
1968
1969    if (err == INVALID_HANDLE_VALUE)
1970       err = GetStdHandle(STD_ERROR_HANDLE);
1971
1972    char *exeFile;
1973    const char *argStart;
1974
1975    if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
1976       return INVALID_HANDLE_VALUE;
1977    }
1978
1979    POOL_MEM cmdLine(PM_FNAME);
1980    Mmsg(cmdLine, "%s /c %s%s", comspec, exeFile, argStart);
1981
1982    free(exeFile);
1983
1984    // New function disabled
1985    if (p_CreateProcessW && p_MultiByteToWideChar) {
1986       bFuncRetn = CreateChildProcessW(comspec, cmdLine.c_str(), &piProcInfo,
1987                                       in, out, err);
1988    } else {
1989       bFuncRetn = CreateChildProcessA(comspec, cmdLine.c_str(), &piProcInfo,
1990                                       in, out, err);
1991    }
1992
1993    if (bFuncRetn == 0) {
1994       ErrorExit("CreateProcess failed\n");
1995       const char *err = errorString();
1996       Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n",comspec,cmdLine.c_str(),err);
1997       LocalFree((void *)err);
1998       return INVALID_HANDLE_VALUE;
1999    }
2000    // we don't need a handle on the process primary thread so we close
2001    // this now.
2002    CloseHandle(piProcInfo.hThread);
2003    return piProcInfo.hProcess;
2004 }
2005
2006 void
2007 ErrorExit (LPCSTR lpszMessage)
2008 {
2009     Dmsg1(0, "%s", lpszMessage);
2010 }
2011
2012
2013 /*
2014 typedef struct s_bpipe {
2015    pid_t worker_pid;
2016    time_t worker_stime;
2017    int wait;
2018    btimer_t *timer_id;
2019    FILE *rfd;
2020    FILE *wfd;
2021 } BPIPE;
2022 */
2023
2024 static void
2025 CloseIfValid(HANDLE handle)
2026 {
2027     if (handle != INVALID_HANDLE_VALUE)
2028         CloseHandle(handle);
2029 }
2030
2031 BPIPE *
2032 open_bpipe(char *prog, int wait, const char *mode)
2033 {
2034     HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
2035         hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
2036         hInputFile;
2037
2038     SECURITY_ATTRIBUTES saAttr;
2039
2040     BOOL fSuccess;
2041
2042     hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
2043         hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
2044         hInputFile = INVALID_HANDLE_VALUE;
2045
2046     BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
2047     memset((void *)bpipe, 0, sizeof(BPIPE));
2048
2049     int mode_read = (mode[0] == 'r');
2050     int mode_write = (mode[0] == 'w' || mode[1] == 'w');
2051
2052
2053     // Set the bInheritHandle flag so pipe handles are inherited.
2054
2055     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
2056     saAttr.bInheritHandle = TRUE;
2057     saAttr.lpSecurityDescriptor = NULL;
2058
2059     if (mode_read) {
2060
2061         // Create a pipe for the child process's STDOUT.
2062         if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
2063             ErrorExit("Stdout pipe creation failed\n");
2064             goto cleanup;
2065         }
2066         // Create noninheritable read handle and close the inheritable read
2067         // handle.
2068
2069         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
2070                                    GetCurrentProcess(), &hChildStdoutRdDup , 0,
2071                                    FALSE,
2072                                    DUPLICATE_SAME_ACCESS);
2073         if ( !fSuccess ) {
2074             ErrorExit("DuplicateHandle failed");
2075             goto cleanup;
2076         }
2077
2078         CloseHandle(hChildStdoutRd);
2079         hChildStdoutRd = INVALID_HANDLE_VALUE;
2080     }
2081
2082     if (mode_write) {
2083
2084         // Create a pipe for the child process's STDIN.
2085
2086         if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
2087             ErrorExit("Stdin pipe creation failed\n");
2088             goto cleanup;
2089         }
2090
2091         // Duplicate the write handle to the pipe so it is not inherited.
2092         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
2093                                    GetCurrentProcess(), &hChildStdinWrDup,
2094                                    0,
2095                                    FALSE,                  // not inherited
2096                                    DUPLICATE_SAME_ACCESS);
2097         if (!fSuccess) {
2098             ErrorExit("DuplicateHandle failed");
2099             goto cleanup;
2100         }
2101
2102         CloseHandle(hChildStdinWr);
2103         hChildStdinWr = INVALID_HANDLE_VALUE;
2104     }
2105     // spawn program with redirected handles as appropriate
2106     bpipe->worker_pid = (pid_t)
2107         CreateChildProcess(prog,             // commandline
2108                            hChildStdinRd,    // stdin HANDLE
2109                            hChildStdoutWr,   // stdout HANDLE
2110                            hChildStdoutWr);  // stderr HANDLE
2111
2112     if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
2113         goto cleanup;
2114
2115     bpipe->wait = wait;
2116     bpipe->worker_stime = time(NULL);
2117
2118     if (mode_read) {
2119         CloseHandle(hChildStdoutWr); // close our write side so when
2120                                      // process terminates we can
2121                                      // detect eof.
2122         // ugly but convert WIN32 HANDLE to FILE*
2123         int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY | O_BINARY);
2124         if (rfd >= 0) {
2125            bpipe->rfd = _fdopen(rfd, "rb");
2126         }
2127     }
2128     if (mode_write) {
2129         CloseHandle(hChildStdinRd); // close our read side so as not
2130                                     // to interfre with child's copy
2131         // ugly but convert WIN32 HANDLE to FILE*
2132         int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY | O_BINARY);
2133         if (wfd >= 0) {
2134            bpipe->wfd = _fdopen(wfd, "wb");
2135         }
2136     }
2137
2138     if (wait > 0) {
2139         bpipe->timer_id = start_child_timer(NULL, bpipe->worker_pid, wait);
2140     }
2141
2142     return bpipe;
2143
2144 cleanup:
2145
2146     CloseIfValid(hChildStdoutRd);
2147     CloseIfValid(hChildStdoutRdDup);
2148     CloseIfValid(hChildStdinWr);
2149     CloseIfValid(hChildStdinWrDup);
2150
2151     free((void *) bpipe);
2152     errno = b_errno_win32;            /* do GetLastError() for error code */
2153     return NULL;
2154 }
2155
2156
2157 int
2158 kill(int pid, int signal)
2159 {
2160    int rval = 0;
2161    if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
2162       rval = -1;
2163       errno = b_errno_win32;
2164    }
2165    CloseHandle((HANDLE)pid);
2166    return rval;
2167 }
2168
2169
2170 int
2171 close_bpipe(BPIPE *bpipe)
2172 {
2173    int rval = 0;
2174    int32_t remaining_wait = bpipe->wait;
2175
2176    /* Close pipes */
2177    if (bpipe->rfd) {
2178       fclose(bpipe->rfd);
2179       bpipe->rfd = NULL;
2180    }
2181    if (bpipe->wfd) {
2182       fclose(bpipe->wfd);
2183       bpipe->wfd = NULL;
2184    }
2185
2186    if (remaining_wait == 0) {         /* wait indefinitely */
2187       remaining_wait = INT32_MAX;
2188    }
2189    for ( ;; ) {
2190       DWORD exitCode;
2191       if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
2192          const char *err = errorString();
2193          rval = b_errno_win32;
2194          Dmsg1(0, "GetExitCode error %s\n", err);
2195          LocalFree((void *)err);
2196          break;
2197       }
2198       if (exitCode == STILL_ACTIVE) {
2199          if (remaining_wait <= 0) {
2200             rval = ETIME;             /* timed out */
2201             break;
2202          }
2203          bmicrosleep(1, 0);           /* wait one second */
2204          remaining_wait--;
2205       } else if (exitCode != 0) {
2206          /* Truncate exit code as it doesn't seem to be correct */
2207          rval = (exitCode & 0xFF) | b_errno_exit;
2208          break;
2209       } else {
2210          break;                       /* Shouldn't get here */
2211       }
2212    }
2213
2214    if (bpipe->timer_id) {
2215        stop_child_timer(bpipe->timer_id);
2216    }
2217    if (bpipe->rfd) fclose(bpipe->rfd);
2218    if (bpipe->wfd) fclose(bpipe->wfd);
2219    free((void *)bpipe);
2220    return rval;
2221 }
2222
2223 int
2224 close_wpipe(BPIPE *bpipe)
2225 {
2226     int result = 1;
2227
2228     if (bpipe->wfd) {
2229         fflush(bpipe->wfd);
2230         if (fclose(bpipe->wfd) != 0) {
2231             result = 0;
2232         }
2233         bpipe->wfd = NULL;
2234     }
2235     return result;
2236 }
2237
2238 #include "findlib/find.h"
2239
2240 int
2241 utime(const char *fname, struct utimbuf *times)
2242 {
2243     FILETIME acc, mod;
2244     char tmpbuf[5000];
2245
2246     conv_unix_to_win32_path(fname, tmpbuf, 5000);
2247
2248     cvt_utime_to_ftime(times->actime, acc);
2249     cvt_utime_to_ftime(times->modtime, mod);
2250
2251     HANDLE h = INVALID_HANDLE_VALUE;
2252
2253     if (p_CreateFileW) {
2254        POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2255        make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
2256
2257        h = p_CreateFileW((LPCWSTR)pwszBuf,
2258                         FILE_WRITE_ATTRIBUTES,
2259                         FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2260                         NULL,
2261                         OPEN_EXISTING,
2262                         FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2263                         NULL);
2264
2265        free_pool_memory(pwszBuf);
2266     } else if (p_CreateFileA) {
2267        h = p_CreateFileA(tmpbuf,
2268                         FILE_WRITE_ATTRIBUTES,
2269                         FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2270                         NULL,
2271                         OPEN_EXISTING,
2272                         FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2273                         NULL);
2274     }
2275
2276     if (h == INVALID_HANDLE_VALUE) {
2277        const char *err = errorString();
2278        Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2279        LocalFree((void *)err);
2280        errno = b_errno_win32;
2281        return -1;
2282     }
2283
2284     int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2285     CloseHandle(h);
2286     if (rval == -1) {
2287        errno = b_errno_win32;
2288     }
2289     return rval;
2290 }
2291
2292 #if 0
2293 int
2294 file_open(const char *file, int flags, int mode)
2295 {
2296    DWORD access = 0;
2297    DWORD shareMode = 0;
2298    DWORD create = 0;
2299    DWORD msflags = 0;
2300    HANDLE foo = INVALID_HANDLE_VALUE;
2301    const char *remap = file;
2302
2303    if (flags & O_WRONLY) access = GENERIC_WRITE;
2304    else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2305    else access = GENERIC_READ;
2306
2307    if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2308       create = CREATE_NEW;
2309    else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2310       create = CREATE_ALWAYS;
2311    else if (flags & O_CREAT)
2312       create = OPEN_ALWAYS;
2313    else if (flags & O_TRUNC)
2314       create = TRUNCATE_EXISTING;
2315    else 
2316       create = OPEN_EXISTING;
2317
2318    shareMode = 0;
2319
2320    if (flags & O_APPEND) {
2321       printf("open...APPEND not implemented yet.");
2322       exit(-1);
2323    }
2324
2325    if (p_CreateFileW) {
2326       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2327       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
2328
2329       foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
2330       free_pool_memory(pwszBuf);
2331    } else if (p_CreateFileA)
2332       foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
2333
2334    if (INVALID_HANDLE_VALUE == foo) {
2335       errno = b_errno_win32;
2336       return (int)-1;
2337    }
2338    return (int)foo;
2339
2340 }
2341
2342
2343 int
2344 file_close(int fd)
2345 {
2346     if (!CloseHandle((HANDLE)fd)) {
2347         errno = b_errno_win32;
2348         return -1;
2349     }
2350
2351     return 0;
2352 }
2353
2354 ssize_t
2355 file_write(int fd, const void *data, ssize_t len)
2356 {
2357     BOOL status;
2358     DWORD bwrite;
2359     status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2360     if (status) return bwrite;
2361     errno = b_errno_win32;
2362     return -1;
2363 }
2364
2365
2366 ssize_t
2367 file_read(int fd, void *data, ssize_t len)
2368 {
2369     BOOL status;
2370     DWORD bread;
2371
2372     status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2373     if (status) return bread;
2374     errno = b_errno_win32;
2375     return -1;
2376 }
2377
2378 boffset_t
2379 file_seek(int fd, boffset_t offset, int whence)
2380 {
2381     DWORD method = 0;
2382     DWORD val;
2383     LONG  offset_low = (LONG)offset;
2384     LONG  offset_high = (LONG)(offset >> 32);
2385
2386     switch (whence) {
2387     case SEEK_SET :
2388         method = FILE_BEGIN;
2389         break;
2390     case SEEK_CUR:
2391         method = FILE_CURRENT;
2392         break;
2393     case SEEK_END:
2394         method = FILE_END;
2395         break;
2396     default:
2397         errno = EINVAL;
2398         return -1;
2399     }
2400
2401
2402     if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
2403        errno = b_errno_win32;
2404        return -1;
2405     }
2406     /* ***FIXME*** I doubt this works right */
2407     return val;
2408 }
2409
2410 int
2411 file_dup2(int, int)
2412 {
2413     errno = ENOSYS;
2414     return -1;
2415 }
2416 #endif
2417
2418 /* 
2419  * Emulation of mmap and unmmap for tokyo dbm
2420  */
2421 void *mmap(void *start, size_t length, int prot, int flags,
2422            int fd, off_t offset)
2423 {
2424    DWORD fm_access = 0;
2425    DWORD mv_access = 0;
2426    HANDLE h;
2427    HANDLE mv;
2428
2429    if (length == 0) {
2430       return MAP_FAILED;
2431    }
2432    if (!fd) {
2433       return MAP_FAILED;
2434    }
2435
2436    if (flags & PROT_WRITE) {
2437       fm_access |= PAGE_READWRITE;
2438    } else if (flags & PROT_READ) {
2439       fm_access |= PAGE_READONLY;
2440    }
2441    
2442    if (flags & PROT_READ) {
2443       mv_access |= FILE_MAP_READ;
2444    }
2445    if (flags & PROT_WRITE) {
2446       mv_access |= FILE_MAP_WRITE;
2447    }
2448
2449    h = CreateFileMapping((HANDLE)_get_osfhandle (fd), 
2450                          NULL /* security */, 
2451                          fm_access, 
2452                          0 /* MaximumSizeHigh */, 
2453                          0 /* MaximumSizeLow */, 
2454                          NULL /* name of the file mapping object */);
2455
2456    if (!h || h == INVALID_HANDLE_VALUE) {
2457       return MAP_FAILED;
2458    }
2459
2460    mv = MapViewOfFile(h, mv_access, 
2461                       0 /* offset hi */, 
2462                       0 /* offset lo */,
2463                       length);
2464    CloseHandle(h);
2465
2466    if (!mv || mv == INVALID_HANDLE_VALUE) {
2467       return MAP_FAILED;
2468    }
2469
2470    return (void *) mv;
2471 }
2472
2473 int munmap(void *start, size_t length)
2474 {
2475    if (!start) {
2476       return -1;
2477    }
2478    UnmapViewOfFile(start);
2479    return 0;
2480 }
2481
2482 #ifdef HAVE_MINGW
2483 /* syslog function, added by Nicolas Boichat */
2484 void openlog(const char *ident, int option, int facility) {}  
2485 #endif //HAVE_MINGW