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