]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/compat.cpp
Cleanup win32 compat code
[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     char *tspec = NULL;
1165     _dir *rval = NULL;
1166     if (path == NULL) {
1167        errno = ENOENT;
1168        return NULL;
1169     }
1170
1171     Dmsg1(100, "Opendir path=%s\n", path);
1172     rval = (_dir *)malloc(sizeof(_dir));
1173     if (!rval) {
1174        goto err;
1175     }
1176     memset (rval, 0, sizeof (_dir));
1177
1178     tspec = (char *)malloc(max_len);
1179     if (!tspec) { 
1180        goto err;
1181     }
1182
1183     conv_unix_to_win32_path(path, tspec, max_len);
1184     Dmsg1(100, "win32 path=%s\n", tspec);
1185
1186     // add backslash only if there is none yet (think of c:\)
1187     if (tspec[strlen(tspec)-1] != '\\')
1188       bstrncat(tspec, "\\*", max_len);
1189     else
1190       bstrncat(tspec, "*", max_len);
1191
1192     rval->spec = tspec;
1193
1194     // convert to wchar_t
1195     if (p_FindFirstFileW) {
1196       POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
1197       make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec);
1198
1199       rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
1200
1201       free_pool_memory(pwcBuf);
1202
1203       if (rval->dirh != INVALID_HANDLE_VALUE)
1204         rval->valid_w = 1;
1205     } else if (p_FindFirstFileA) {
1206       rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
1207
1208       if (rval->dirh != INVALID_HANDLE_VALUE)
1209         rval->valid_a = 1;
1210     } else goto err;
1211
1212
1213     Dmsg3(99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
1214           path, rval->spec, rval->dirh);
1215
1216     rval->offset = 0;
1217     if (rval->dirh == INVALID_HANDLE_VALUE)
1218         goto err;
1219
1220     if (rval->valid_w) {
1221       Dmsg1(99, "\tFirstFile=%s\n", rval->data_w.cFileName);
1222     }
1223
1224     if (rval->valid_a) {
1225       Dmsg1(99, "\tFirstFile=%s\n", rval->data_a.cFileName);
1226     }
1227
1228     return (DIR *)rval;
1229
1230 err:
1231     if (rval) {
1232        free(rval);
1233     }
1234     if (tspec) {
1235        free(tspec);
1236     }
1237     errno = b_errno_win32;
1238     return NULL;
1239 }
1240
1241 int
1242 closedir(DIR *dirp)
1243 {
1244     _dir *dp = (_dir *)dirp;
1245     FindClose(dp->dirh);
1246     free((void *)dp->spec);
1247     free((void *)dp);
1248     return 0;
1249 }
1250
1251 /*
1252   typedef struct _WIN32_FIND_DATA {
1253     DWORD dwFileAttributes;
1254     FILETIME ftCreationTime;
1255     FILETIME ftLastAccessTime;
1256     FILETIME ftLastWriteTime;
1257     DWORD nFileSizeHigh;
1258     DWORD nFileSizeLow;
1259     DWORD dwReserved0;
1260     DWORD dwReserved1;
1261     TCHAR cFileName[MAX_PATH];
1262     TCHAR cAlternateFileName[14];
1263 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1264 */
1265
1266 static int
1267 copyin(struct dirent &dp, const char *fname)
1268 {
1269     dp.d_ino = 0;
1270     dp.d_reclen = 0;
1271     char *cp = dp.d_name;
1272     while (*fname) {
1273         *cp++ = *fname++;
1274         dp.d_reclen++;
1275     }
1276         *cp = 0;
1277     return dp.d_reclen;
1278 }
1279
1280 int
1281 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1282 {
1283     _dir *dp = (_dir *)dirp;
1284     if (dp->valid_w || dp->valid_a) {
1285       entry->d_off = dp->offset;
1286
1287       // copy unicode
1288       if (dp->valid_w) {
1289          char szBuf[MAX_PATH_UTF8+1];
1290          wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1291          dp->offset += copyin(*entry, szBuf);
1292       } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1293          dp->offset += copyin(*entry, dp->data_a.cFileName);
1294       }
1295
1296       *result = entry;              /* return entry address */
1297       Dmsg4(99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1298             dirp, entry->d_name, entry->d_reclen, entry->d_off);
1299     } else {
1300 //      Dmsg0(99, "readdir_r !valid\n");
1301         errno = b_errno_win32;
1302         return -1;
1303     }
1304
1305     // get next file, try unicode first
1306     if (p_FindNextFileW)
1307        dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1308     else if (p_FindNextFileA)
1309        dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1310     else {
1311        dp->valid_a = FALSE;
1312        dp->valid_w = FALSE;
1313     }
1314
1315     return 0;
1316 }
1317
1318 /*
1319  * Dotted IP address to network address
1320  *
1321  * Returns 1 if  OK
1322  *         0 on error
1323  */
1324 int
1325 inet_aton(const char *a, struct in_addr *inp)
1326 {
1327    const char *cp = a;
1328    uint32_t acc = 0, tmp = 0;
1329    int dotc = 0;
1330
1331    if (!isdigit(*cp)) {         /* first char must be digit */
1332       return 0;                 /* error */
1333    }
1334    do {
1335       if (isdigit(*cp)) {
1336          tmp = (tmp * 10) + (*cp -'0');
1337       } else if (*cp == '.' || *cp == 0) {
1338          if (tmp > 255) {
1339             return 0;           /* error */
1340          }
1341          acc = (acc << 8) + tmp;
1342          dotc++;
1343          tmp = 0;
1344       } else {
1345          return 0;              /* error */
1346       }
1347    } while (*cp++ != 0);
1348    if (dotc != 4) {              /* want 3 .'s plus EOS */
1349       return 0;                  /* error */
1350    }
1351    inp->s_addr = htonl(acc);     /* store addr in network format */
1352    return 1;
1353 }
1354
1355 int
1356 nanosleep(const struct timespec *req, struct timespec *rem)
1357 {
1358     if (rem)
1359         rem->tv_sec = rem->tv_nsec = 0;
1360     Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1361     return 0;
1362 }
1363
1364 void
1365 init_signals(void terminate(int sig))
1366 {
1367
1368 }
1369
1370 void
1371 init_stack_dump(void)
1372 {
1373
1374 }
1375
1376
1377 long
1378 pathconf(const char *path, int name)
1379 {
1380     switch(name) {
1381     case _PC_PATH_MAX :
1382         if (strncmp(path, "\\\\?\\", 4) == 0)
1383             return 32767;
1384     case _PC_NAME_MAX :
1385         return 255;
1386     }
1387     errno = ENOSYS;
1388     return -1;
1389 }
1390
1391 int
1392 WSA_Init(void)
1393 {
1394     WORD wVersionRequested = MAKEWORD( 1, 1);
1395     WSADATA wsaData;
1396
1397     int err = WSAStartup(wVersionRequested, &wsaData);
1398
1399
1400     if (err != 0) {
1401         printf("Can not start Windows Sockets\n");
1402         errno = ENOSYS;
1403         return -1;
1404     }
1405
1406     return 0;
1407 }
1408
1409 static DWORD fill_attribute(DWORD attr, mode_t mode)
1410 {
1411    Dmsg1(200, "  before attr=%lld\n", (uint64_t) attr);
1412    /* Use Bacula mappings define in stat() above */
1413    if (mode & (S_IRUSR|S_IRGRP|S_IROTH)) { // If file is readable
1414       attr &= ~FILE_ATTRIBUTE_READONLY;    // then this is not READONLY
1415    } else {
1416       attr |= FILE_ATTRIBUTE_READONLY;
1417    }
1418    if (mode & S_ISVTX) {                   // The sticky bit <=> HIDDEN 
1419       attr |= FILE_ATTRIBUTE_HIDDEN;
1420    } else {
1421       attr &= ~FILE_ATTRIBUTE_HIDDEN;
1422    }
1423    if (mode & S_IRWXO) {              // Other can read/write/execute ?
1424       attr &= ~FILE_ATTRIBUTE_SYSTEM; // => Not system
1425    } else {
1426       attr |= FILE_ATTRIBUTE_SYSTEM;
1427    }
1428    Dmsg1(200, "  after attr=%lld\n", (uint64_t)attr);
1429    return attr;
1430 }
1431
1432 int win32_chmod(const char *path, mode_t mode)
1433 {
1434    bool ret=false;
1435    DWORD attr;
1436
1437    Dmsg2(100, "win32_chmod(path=%s mode=%lld)\n", path, (uint64_t)mode);
1438    if (p_GetFileAttributesW) {
1439       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1440       make_win32_path_UTF8_2_wchar(&pwszBuf, path);
1441
1442       attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
1443       if (attr != INVALID_FILE_ATTRIBUTES) {
1444          /* Use Bacula mappings define in stat() above */
1445          attr = fill_attribute(attr, mode);
1446          ret = p_SetFileAttributesW((LPCWSTR)pwszBuf, attr);
1447       }
1448       free_pool_memory(pwszBuf);
1449       Dmsg0(100, "Leave win32_chmod. AttributesW\n");
1450    } else if (p_GetFileAttributesA) {
1451       attr = p_GetFileAttributesA(path);
1452       if (attr != INVALID_FILE_ATTRIBUTES) {
1453          attr = fill_attribute(attr, mode);
1454          ret = p_SetFileAttributesA(path, attr);
1455       }
1456       Dmsg0(100, "Leave win32_chmod did AttributesA\n");
1457    } else {
1458       Dmsg0(100, "Leave win32_chmod did nothing\n");
1459    }
1460     
1461    if (!ret) {
1462       const char *err = errorString();
1463       Dmsg2(99, "Get/SetFileAttributes(%s): %s\n", path, err);
1464       LocalFree((void *)err);
1465       errno = b_errno_win32;
1466       return -1;
1467    }
1468    return 0;
1469 }
1470
1471
1472 int
1473 win32_chdir(const char *dir)
1474 {
1475    if (p_SetCurrentDirectoryW) {
1476       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1477       make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1478
1479       BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1480       
1481       free_pool_memory(pwszBuf);
1482
1483       if (!b) {
1484          errno = b_errno_win32;
1485          return -1;
1486       }
1487    } else if (p_SetCurrentDirectoryA) {
1488       if (0 == p_SetCurrentDirectoryA(dir)) {
1489          errno = b_errno_win32;
1490          return -1;
1491       }
1492    } else {
1493       return -1;
1494    }
1495
1496    return 0;
1497 }
1498
1499 int
1500 win32_mkdir(const char *dir)
1501 {
1502    Dmsg1(100, "enter win32_mkdir. dir=%s\n", dir);
1503    if (p_wmkdir){
1504       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1505       make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1506
1507       int n = p_wmkdir((LPCWSTR)pwszBuf);
1508       free_pool_memory(pwszBuf);
1509       Dmsg0(100, "Leave win32_mkdir did wmkdir\n");
1510       return n;
1511    }
1512
1513    Dmsg0(100, "Leave win32_mkdir did _mkdir\n");
1514    return _mkdir(dir);
1515 }
1516
1517
1518 char *
1519 win32_getcwd(char *buf, int maxlen)
1520 {
1521    int n=0;
1522
1523    if (p_GetCurrentDirectoryW) {
1524       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1525       pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1526
1527       n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1528       if (n!=0)
1529          n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1530       free_pool_memory(pwszBuf);
1531
1532    } else if (p_GetCurrentDirectoryA)
1533       n = p_GetCurrentDirectoryA(maxlen, buf);
1534
1535    if (n == 0 || n > maxlen) return NULL;
1536
1537    if (n+1 > maxlen) return NULL;
1538    if (n != 3) {
1539        buf[n] = '\\';
1540        buf[n+1] = 0;
1541    }
1542    return buf;
1543 }
1544
1545 int
1546 win32_fputs(const char *string, FILE *stream)
1547 {
1548    /* we use WriteConsoleA / WriteConsoleA
1549       so we can be sure that unicode support works on win32.
1550       with fallback if something fails
1551    */
1552
1553    HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1554    if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1555        p_MultiByteToWideChar && (stream == stdout)) {
1556
1557       POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1558
1559       DWORD dwCharsWritten;
1560       DWORD dwChars;
1561
1562       dwChars = UTF8_2_wchar(&pwszBuf, string);
1563
1564       /* try WriteConsoleW */
1565       if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1566          free_pool_memory(pwszBuf);
1567          return dwCharsWritten;
1568       }
1569
1570       /* convert to local codepage and try WriteConsoleA */
1571       POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1572       pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1573
1574       dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR)pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1575       free_pool_memory(pwszBuf);
1576
1577       if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1578          free_pool_memory(pszBuf);
1579          return dwCharsWritten;
1580       }
1581       free_pool_memory(pszBuf);
1582    }
1583    /* Fall back */
1584    return fputs(string, stream);
1585 }
1586
1587 char*
1588 win32_cgets (char* buffer, int len)
1589 {
1590    /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1591       from the win32 console and fallback if seomething fails */
1592
1593    HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1594    if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1595       DWORD dwRead;
1596       wchar_t wszBuf[1024];
1597       char  szBuf[1024];
1598
1599       /* nt and unicode conversion */
1600       if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1601
1602          /* null terminate at end */
1603          if (wszBuf[dwRead-1] == L'\n') {
1604             wszBuf[dwRead-1] = L'\0';
1605             dwRead --;
1606          }
1607
1608          if (wszBuf[dwRead-1] == L'\r') {
1609             wszBuf[dwRead-1] = L'\0';
1610             dwRead --;
1611          }
1612
1613          wchar_2_UTF8(buffer, wszBuf, len);
1614          return buffer;
1615       }
1616
1617       /* win 9x and unicode conversion */
1618       if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1619
1620          /* null terminate at end */
1621          if (szBuf[dwRead-1] == L'\n') {
1622             szBuf[dwRead-1] = L'\0';
1623             dwRead --;
1624          }
1625
1626          if (szBuf[dwRead-1] == L'\r') {
1627             szBuf[dwRead-1] = L'\0';
1628             dwRead --;
1629          }
1630
1631          /* convert from ansii to wchar_t */
1632          p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1633          /* convert from wchar_t to UTF-8 */
1634          if (wchar_2_UTF8(buffer, wszBuf, len))
1635             return buffer;
1636       }
1637    }
1638
1639    /* fallback */
1640    if (fgets(buffer, len, stdin))
1641       return buffer;
1642    else
1643       return NULL;
1644 }
1645
1646 int
1647 win32_unlink(const char *filename)
1648 {
1649    int nRetCode;
1650    if (p_wunlink) {
1651       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1652       make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1653
1654       nRetCode = _wunlink((LPCWSTR) pwszBuf);
1655
1656       /*
1657        * special case if file is readonly,
1658        * we retry but unset attribute before
1659        */
1660       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1661          DWORD dwAttr =  p_GetFileAttributesW((LPCWSTR)pwszBuf);
1662          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1663             if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1664                nRetCode = _wunlink((LPCWSTR) pwszBuf);
1665                /* reset to original if it didn't help */
1666                if (nRetCode == -1)
1667                   p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1668             }
1669          }
1670       }
1671       free_pool_memory(pwszBuf);
1672    } else {
1673       nRetCode = _unlink(filename);
1674
1675       /* special case if file is readonly,
1676       we retry but unset attribute before */
1677       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1678          DWORD dwAttr =  p_GetFileAttributesA(filename);
1679          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1680             if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1681                nRetCode = _unlink(filename);
1682                /* reset to original if it didn't help */
1683                if (nRetCode == -1)
1684                   p_SetFileAttributesA(filename, dwAttr);
1685             }
1686          }
1687       }
1688    }
1689    return nRetCode;
1690 }
1691
1692
1693 #include "mswinver.h"
1694
1695 char WIN_VERSION_LONG[64];
1696 char WIN_VERSION[32];
1697 char WIN_RAWVERSION[32];
1698
1699 class winver {
1700 public:
1701     winver(void);
1702 };
1703
1704 static winver INIT;                     // cause constructor to be called before main()
1705
1706
1707 winver::winver(void)
1708 {
1709     const char *version = "";
1710     const char *platform = "";
1711     OSVERSIONINFO osvinfo;
1712     osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1713
1714     // Get the current OS version
1715     if (!GetVersionEx(&osvinfo)) {
1716         version = "Unknown";
1717         platform = "Unknown";
1718     }
1719         const int ver = _mkversion(osvinfo.dwPlatformId,
1720                                    osvinfo.dwMajorVersion,
1721                                    osvinfo.dwMinorVersion);
1722         snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1723         switch (ver)
1724         {
1725         case MS_WINDOWS_95: (version =  "Windows 95"); break;
1726         case MS_WINDOWS_98: (version =  "Windows 98"); break;
1727         case MS_WINDOWS_ME: (version =  "Windows ME"); break;
1728         case MS_WINDOWS_NT4:(version =  "Windows NT 4.0"); platform = "NT"; break;
1729         case MS_WINDOWS_2K: (version =  "Windows 2000");platform = "NT"; break;
1730         case MS_WINDOWS_XP: (version =  "Windows XP");platform = "NT"; break;
1731         case MS_WINDOWS_S2003: (version =  "Windows Server 2003");platform = "NT"; break;
1732         default: version = WIN_RAWVERSION; break;
1733         }
1734
1735     bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1736     snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1737              platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1738
1739 #if 0
1740     HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1741     CloseHandle(h);
1742 #endif
1743 #if 0
1744     BPIPE *b = open_bpipe("ls -l", 10, "r");
1745     char buf[1024];
1746     while (!feof(b->rfd)) {
1747         fgets(buf, sizeof(buf), b->rfd);
1748     }
1749     close_bpipe(b);
1750 #endif
1751 }
1752
1753 BOOL CreateChildProcess(VOID);
1754 VOID WriteToPipe(VOID);
1755 VOID ReadFromPipe(VOID);
1756 VOID ErrorExit(LPCSTR);
1757 VOID ErrMsg(LPTSTR, BOOL);
1758
1759 /**
1760  * Check for a quoted path,  if an absolute path name is given and it contains
1761  * spaces it will need to be quoted.  i.e.  "c:/Program Files/foo/bar.exe"
1762  * CreateProcess() says the best way to ensure proper results with executables
1763  * with spaces in path or filename is to quote the string.
1764  */
1765 const char *
1766 getArgv0(const char *cmdline)
1767 {
1768
1769     int inquote = 0;
1770     const char *cp;
1771     for (cp = cmdline; *cp; cp++)
1772     {
1773         if (*cp == '"') {
1774             inquote = !inquote;
1775         }
1776         if (!inquote && isspace(*cp))
1777             break;
1778     }
1779
1780
1781     int len = cp - cmdline;
1782     char *rval = (char *)malloc(len+1);
1783
1784     cp = cmdline;
1785     char *rp = rval;
1786
1787     while (len--)
1788         *rp++ = *cp++;
1789
1790     *rp = 0;
1791     return rval;
1792 }
1793
1794 /*
1795  * Extracts the executable or script name from the first string in 
1796  * cmdline.
1797  *
1798  * If the name contains blanks then it must be quoted with double quotes,
1799  * otherwise quotes are optional.  If the name contains blanks then it 
1800  * will be converted to a short name.
1801  *
1802  * The optional quotes will be removed.  The result is copied to a malloc'ed
1803  * buffer and returned through the pexe argument.  The pargs parameter is set
1804  * to the address of the character in cmdline located after the name.
1805  *
1806  * The malloc'ed buffer returned in *pexe must be freed by the caller.
1807  */
1808 bool
1809 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1810 {
1811    const char *pExeStart = NULL;    /* Start of executable name in cmdline */
1812    const char *pExeEnd = NULL;      /* Character after executable name (separator) */
1813
1814    const char *pBasename = NULL;    /* Character after last path separator */
1815    const char *pExtension = NULL;   /* Period at start of extension */
1816
1817    const char *current = cmdline;
1818
1819    bool bQuoted = false;
1820
1821    /* Skip initial whitespace */
1822
1823    while (*current == ' ' || *current == '\t')
1824    {
1825       current++;
1826    }
1827
1828    /* Calculate start of name and determine if quoted */
1829
1830    if (*current == '"') {
1831       pExeStart = ++current;
1832       bQuoted = true;
1833    } else {
1834       pExeStart = current;
1835       bQuoted = false;
1836    }
1837
1838    *pargs = NULL;
1839    *pexe = NULL;
1840
1841    /* 
1842     * Scan command line looking for path separators (/ and \\) and the 
1843     * terminator, either a quote or a blank.  The location of the 
1844     * extension is also noted.
1845     */
1846
1847    for ( ; *current != '\0'; current++)
1848    {
1849       if (*current == '.') {
1850          pExtension = current;
1851       } else if (IsPathSeparator(*current) && current[1] != '\0') {
1852          pBasename = &current[1];
1853          pExtension = NULL;
1854       }
1855
1856       /* Check for terminator, either quote or blank */
1857       if (bQuoted) {
1858          if (*current != '"') {
1859             continue;
1860          }
1861       } else {
1862          if (*current != ' ') {
1863             continue;
1864          }
1865       }
1866
1867       /*
1868        * Hit terminator, remember end of name (address of terminator) and 
1869        * start of arguments 
1870        */
1871       pExeEnd = current;
1872
1873       if (bQuoted && *current == '"') {
1874          *pargs = &current[1];
1875       } else {
1876          *pargs = current;
1877       }
1878
1879       break;
1880    }
1881
1882    if (pBasename == NULL) {
1883       pBasename = pExeStart;
1884    }
1885
1886    if (pExeEnd == NULL) {
1887       pExeEnd = current;
1888    }
1889
1890    if (*pargs == NULL)
1891    {
1892       *pargs = current;
1893    }
1894
1895    bool bHasPathSeparators = pExeStart != pBasename;
1896
1897    /* We have pointers to all the useful parts of the name */
1898
1899    /* Default extensions in the order cmd.exe uses to search */
1900
1901    static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
1902    DWORD dwBasePathLength = pExeEnd - pExeStart;
1903
1904    DWORD dwAltNameLength = 0;
1905    char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1906    char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1907
1908    pPathname[MAX_PATHLENGTH] = '\0';
1909    pAltPathname[MAX_PATHLENGTH] = '\0';
1910
1911    memcpy(pPathname, pExeStart, dwBasePathLength);
1912    pPathname[dwBasePathLength] = '\0';
1913
1914    if (pExtension == NULL) {
1915       /* Try appending extensions */
1916       for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
1917
1918          if (!bHasPathSeparators) {
1919             /* There are no path separators, search in the standard locations */
1920             dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
1921             if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1922                memcpy(pPathname, pAltPathname, dwAltNameLength);
1923                pPathname[dwAltNameLength] = '\0';
1924                break;
1925             }
1926          } else {
1927             bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
1928             if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) {
1929                break;
1930             }
1931             pPathname[dwBasePathLength] = '\0';
1932          }
1933       }
1934    } else if (!bHasPathSeparators) {
1935       /* There are no path separators, search in the standard locations */
1936       dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
1937       if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) {
1938          memcpy(pPathname, pAltPathname, dwAltNameLength);
1939          pPathname[dwAltNameLength] = '\0';
1940       }
1941    }
1942
1943    if (strchr(pPathname, ' ') != NULL) {
1944       dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH);
1945
1946       if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1947          *pexe = (char *)malloc(dwAltNameLength + 1);
1948          if (*pexe == NULL) {
1949             return false;
1950          }
1951          memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
1952       }
1953    }
1954
1955    if (*pexe == NULL) {
1956       DWORD dwPathnameLength = strlen(pPathname);
1957       *pexe = (char *)malloc(dwPathnameLength + 1);
1958       if (*pexe == NULL) {
1959          return false;
1960       }
1961       memcpy(*pexe, pPathname, dwPathnameLength + 1);
1962    }
1963
1964    return true;
1965 }
1966
1967 /**
1968  * Create the process with WCHAR API
1969  */
1970 static BOOL
1971 CreateChildProcessW(const char *comspec, const char *cmdLine,
1972                     PROCESS_INFORMATION *hProcInfo,
1973                     HANDLE in, HANDLE out, HANDLE err)
1974 {
1975    STARTUPINFOW siStartInfo;
1976    BOOL bFuncRetn = FALSE;
1977
1978    // Set up members of the STARTUPINFO structure.
1979    ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
1980    siStartInfo.cb = sizeof(siStartInfo);
1981    // setup new process to use supplied handles for stdin,stdout,stderr
1982
1983    siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1984    siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
1985
1986    siStartInfo.hStdInput = in;
1987    siStartInfo.hStdOutput = out;
1988    siStartInfo.hStdError = err;
1989    
1990    // Convert argument to WCHAR
1991    POOLMEM *cmdLine_wchar = get_pool_memory(PM_FNAME);
1992    POOLMEM *comspec_wchar = get_pool_memory(PM_FNAME);
1993
1994    UTF8_2_wchar(&cmdLine_wchar, cmdLine);
1995    UTF8_2_wchar(&comspec_wchar, comspec);
1996
1997    // Create the child process.
1998    Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec_wchar, cmdLine_wchar);
1999
2000    // try to execute program
2001    bFuncRetn = p_CreateProcessW((WCHAR*)comspec_wchar,
2002                                 (WCHAR*)cmdLine_wchar,// command line
2003                                 NULL,      // process security attributes
2004                                 NULL,      // primary thread security attributes
2005                                 TRUE,      // handles are inherited
2006                                 0,         // creation flags
2007                                 NULL,      // use parent's environment
2008                                 NULL,      // use parent's current directory
2009                                 &siStartInfo,  // STARTUPINFO pointer
2010                                 hProcInfo);   // receives PROCESS_INFORMATION
2011    free_pool_memory(cmdLine_wchar);
2012    free_pool_memory(comspec_wchar);
2013
2014    return bFuncRetn;
2015 }
2016
2017
2018 /**
2019  * Create the process with ANSI API
2020  */
2021 static BOOL
2022 CreateChildProcessA(const char *comspec, char *cmdLine,
2023                     PROCESS_INFORMATION *hProcInfo,
2024                     HANDLE in, HANDLE out, HANDLE err)
2025 {
2026    STARTUPINFOA siStartInfo;
2027    BOOL bFuncRetn = FALSE;
2028
2029    // Set up members of the STARTUPINFO structure.
2030    ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
2031    siStartInfo.cb = sizeof(siStartInfo);
2032    // setup new process to use supplied handles for stdin,stdout,stderr
2033    siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
2034    siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
2035
2036    siStartInfo.hStdInput = in;
2037    siStartInfo.hStdOutput = out;
2038    siStartInfo.hStdError = err;
2039
2040    // Create the child process.
2041    Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
2042
2043    // try to execute program
2044    bFuncRetn = p_CreateProcessA(comspec,
2045                                 cmdLine,  // command line
2046                                 NULL,     // process security attributes
2047                                 NULL,     // primary thread security attributes
2048                                 TRUE,     // handles are inherited
2049                                 0,        // creation flags
2050                                 NULL,     // use parent's environment
2051                                 NULL,     // use parent's current directory
2052                                 &siStartInfo,// STARTUPINFO pointer
2053                                 hProcInfo);// receives PROCESS_INFORMATION
2054    return bFuncRetn;
2055 }
2056
2057 /**
2058  * OK, so it would seem CreateProcess only handles true executables:
2059  * .com or .exe files.  So grab $COMSPEC value and pass command line to it.
2060  */
2061 HANDLE
2062 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
2063 {
2064    static const char *comspec = NULL;
2065    PROCESS_INFORMATION piProcInfo;
2066    BOOL bFuncRetn = FALSE;
2067
2068    if (!p_CreateProcessA || !p_CreateProcessW)
2069       return INVALID_HANDLE_VALUE;
2070
2071    if (comspec == NULL) 
2072       comspec = getenv("COMSPEC");
2073    if (comspec == NULL) // should never happen
2074       return INVALID_HANDLE_VALUE;
2075
2076    // Set up members of the PROCESS_INFORMATION structure.
2077    ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
2078
2079    // if supplied handles are not used the send a copy of our STD_HANDLE
2080    // as appropriate
2081    if (in == INVALID_HANDLE_VALUE)
2082       in = GetStdHandle(STD_INPUT_HANDLE);
2083
2084    if (out == INVALID_HANDLE_VALUE)
2085       out = GetStdHandle(STD_OUTPUT_HANDLE);
2086
2087    if (err == INVALID_HANDLE_VALUE)
2088       err = GetStdHandle(STD_ERROR_HANDLE);
2089
2090    char *exeFile;
2091    const char *argStart;
2092
2093    if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
2094       return INVALID_HANDLE_VALUE;
2095    }
2096
2097    POOL_MEM cmdLine(PM_FNAME);
2098    Mmsg(cmdLine, "%s /c %s%s", comspec, exeFile, argStart);
2099
2100    free(exeFile);
2101
2102    // New function disabled
2103    if (p_CreateProcessW && p_MultiByteToWideChar) {
2104       bFuncRetn = CreateChildProcessW(comspec, cmdLine.c_str(), &piProcInfo,
2105                                       in, out, err);
2106    } else {
2107       bFuncRetn = CreateChildProcessA(comspec, cmdLine.c_str(), &piProcInfo,
2108                                       in, out, err);
2109    }
2110
2111    if (bFuncRetn == 0) {
2112       ErrorExit("CreateProcess failed\n");
2113       const char *err = errorString();
2114       Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n",comspec,cmdLine.c_str(),err);
2115       LocalFree((void *)err);
2116       return INVALID_HANDLE_VALUE;
2117    }
2118    // we don't need a handle on the process primary thread so we close
2119    // this now.
2120    CloseHandle(piProcInfo.hThread);
2121    return piProcInfo.hProcess;
2122 }
2123
2124 void
2125 ErrorExit (LPCSTR lpszMessage)
2126 {
2127     Dmsg1(0, "%s", lpszMessage);
2128 }
2129
2130
2131 /*
2132 typedef struct s_bpipe {
2133    pid_t worker_pid;
2134    time_t worker_stime;
2135    int wait;
2136    btimer_t *timer_id;
2137    FILE *rfd;
2138    FILE *wfd;
2139 } BPIPE;
2140 */
2141
2142 static void
2143 CloseIfValid(HANDLE handle)
2144 {
2145     if (handle != INVALID_HANDLE_VALUE)
2146         CloseHandle(handle);
2147 }
2148
2149 BPIPE *
2150 open_bpipe(char *prog, int wait, const char *mode)
2151 {
2152     HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
2153         hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
2154         hInputFile;
2155
2156     SECURITY_ATTRIBUTES saAttr;
2157
2158     BOOL fSuccess;
2159
2160     hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
2161         hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
2162         hInputFile = INVALID_HANDLE_VALUE;
2163
2164     BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
2165     memset((void *)bpipe, 0, sizeof(BPIPE));
2166
2167     int mode_read = (mode[0] == 'r');
2168     int mode_write = (mode[0] == 'w' || mode[1] == 'w');
2169
2170
2171     // Set the bInheritHandle flag so pipe handles are inherited.
2172
2173     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
2174     saAttr.bInheritHandle = TRUE;
2175     saAttr.lpSecurityDescriptor = NULL;
2176
2177     if (mode_read) {
2178
2179         // Create a pipe for the child process's STDOUT.
2180         if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
2181             ErrorExit("Stdout pipe creation failed\n");
2182             goto cleanup;
2183         }
2184         // Create noninheritable read handle and close the inheritable read
2185         // handle.
2186
2187         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
2188                                    GetCurrentProcess(), &hChildStdoutRdDup , 0,
2189                                    FALSE,
2190                                    DUPLICATE_SAME_ACCESS);
2191         if ( !fSuccess ) {
2192             ErrorExit("DuplicateHandle failed");
2193             goto cleanup;
2194         }
2195
2196         CloseHandle(hChildStdoutRd);
2197         hChildStdoutRd = INVALID_HANDLE_VALUE;
2198     }
2199
2200     if (mode_write) {
2201
2202         // Create a pipe for the child process's STDIN.
2203
2204         if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
2205             ErrorExit("Stdin pipe creation failed\n");
2206             goto cleanup;
2207         }
2208
2209         // Duplicate the write handle to the pipe so it is not inherited.
2210         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
2211                                    GetCurrentProcess(), &hChildStdinWrDup,
2212                                    0,
2213                                    FALSE,                  // not inherited
2214                                    DUPLICATE_SAME_ACCESS);
2215         if (!fSuccess) {
2216             ErrorExit("DuplicateHandle failed");
2217             goto cleanup;
2218         }
2219
2220         CloseHandle(hChildStdinWr);
2221         hChildStdinWr = INVALID_HANDLE_VALUE;
2222     }
2223     // spawn program with redirected handles as appropriate
2224     bpipe->worker_pid = (pid_t)
2225         CreateChildProcess(prog,             // commandline
2226                            hChildStdinRd,    // stdin HANDLE
2227                            hChildStdoutWr,   // stdout HANDLE
2228                            hChildStdoutWr);  // stderr HANDLE
2229
2230     if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
2231         goto cleanup;
2232
2233     bpipe->wait = wait;
2234     bpipe->worker_stime = time(NULL);
2235
2236     if (mode_read) {
2237         CloseHandle(hChildStdoutWr); // close our write side so when
2238                                      // process terminates we can
2239                                      // detect eof.
2240         // ugly but convert WIN32 HANDLE to FILE*
2241         int rfd = _open_osfhandle((intptr_t)hChildStdoutRdDup, O_RDONLY | O_BINARY);
2242         if (rfd >= 0) {
2243            bpipe->rfd = _fdopen(rfd, "rb");
2244         }
2245     }
2246     if (mode_write) {
2247         CloseHandle(hChildStdinRd); // close our read side so as not
2248                                     // to interfre with child's copy
2249         // ugly but convert WIN32 HANDLE to FILE*
2250         int wfd = _open_osfhandle((intptr_t)hChildStdinWrDup, O_WRONLY | O_BINARY);
2251         if (wfd >= 0) {
2252            bpipe->wfd = _fdopen(wfd, "wb");
2253         }
2254     }
2255
2256     if (wait > 0) {
2257         bpipe->timer_id = start_child_timer(NULL, bpipe->worker_pid, wait);
2258     }
2259
2260     return bpipe;
2261
2262 cleanup:
2263
2264     CloseIfValid(hChildStdoutRd);
2265     CloseIfValid(hChildStdoutRdDup);
2266     CloseIfValid(hChildStdinWr);
2267     CloseIfValid(hChildStdinWrDup);
2268
2269     free((void *) bpipe);
2270     errno = b_errno_win32;            /* do GetLastError() for error code */
2271     return NULL;
2272 }
2273
2274
2275 int
2276 kill(int pid, int signal)
2277 {
2278    int rval = 0;
2279    if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
2280       rval = -1;
2281       errno = b_errno_win32;
2282    }
2283    CloseHandle((HANDLE)pid);
2284    return rval;
2285 }
2286
2287
2288 int
2289 close_bpipe(BPIPE *bpipe)
2290 {
2291    int rval = 0;
2292    int32_t remaining_wait = bpipe->wait;
2293
2294    /* Close pipes */
2295    if (bpipe->rfd) {
2296       fclose(bpipe->rfd);
2297       bpipe->rfd = NULL;
2298    }
2299    if (bpipe->wfd) {
2300       fclose(bpipe->wfd);
2301       bpipe->wfd = NULL;
2302    }
2303
2304    if (remaining_wait == 0) {         /* wait indefinitely */
2305       remaining_wait = INT32_MAX;
2306    }
2307    for ( ;; ) {
2308       DWORD exitCode;
2309       if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
2310          const char *err = errorString();
2311          rval = b_errno_win32;
2312          Dmsg1(0, "GetExitCode error %s\n", err);
2313          LocalFree((void *)err);
2314          break;
2315       }
2316       if (exitCode == STILL_ACTIVE) {
2317          if (remaining_wait <= 0) {
2318             rval = ETIME;             /* timed out */
2319             break;
2320          }
2321          bmicrosleep(1, 0);           /* wait one second */
2322          remaining_wait--;
2323       } else if (exitCode != 0) {
2324          /* Truncate exit code as it doesn't seem to be correct */
2325          rval = (exitCode & 0xFF) | b_errno_exit;
2326          break;
2327       } else {
2328          break;                       /* Shouldn't get here */
2329       }
2330    }
2331
2332    if (bpipe->timer_id) {
2333        stop_child_timer(bpipe->timer_id);
2334    }
2335    if (bpipe->rfd) fclose(bpipe->rfd);
2336    if (bpipe->wfd) fclose(bpipe->wfd);
2337    free((void *)bpipe);
2338    return rval;
2339 }
2340
2341 int
2342 close_wpipe(BPIPE *bpipe)
2343 {
2344     int result = 1;
2345
2346     if (bpipe->wfd) {
2347         fflush(bpipe->wfd);
2348         if (fclose(bpipe->wfd) != 0) {
2349             result = 0;
2350         }
2351         bpipe->wfd = NULL;
2352     }
2353     return result;
2354 }
2355
2356 #ifndef MINGW64
2357 int
2358 utime(const char *fname, struct utimbuf *times)
2359 {
2360     FILETIME acc, mod;
2361     char tmpbuf[5000];
2362
2363     conv_unix_to_win32_path(fname, tmpbuf, 5000);
2364
2365     cvt_utime_to_ftime(times->actime, acc);
2366     cvt_utime_to_ftime(times->modtime, mod);
2367
2368     HANDLE h = INVALID_HANDLE_VALUE;
2369
2370     if (p_CreateFileW) {
2371        POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2372        make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
2373
2374        h = p_CreateFileW((LPCWSTR)pwszBuf,
2375                         FILE_WRITE_ATTRIBUTES,
2376                         FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2377                         NULL,
2378                         OPEN_EXISTING,
2379                         FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2380                         NULL);
2381
2382        free_pool_memory(pwszBuf);
2383     } else if (p_CreateFileA) {
2384        h = p_CreateFileA(tmpbuf,
2385                         FILE_WRITE_ATTRIBUTES,
2386                         FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2387                         NULL,
2388                         OPEN_EXISTING,
2389                         FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2390                         NULL);
2391     }
2392
2393     if (h == INVALID_HANDLE_VALUE) {
2394        const char *err = errorString();
2395        Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2396        LocalFree((void *)err);
2397        errno = b_errno_win32;
2398        return -1;
2399     }
2400
2401     int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2402     CloseHandle(h);
2403     if (rval == -1) {
2404        errno = b_errno_win32;
2405     }
2406     return rval;
2407 }
2408 #endif
2409
2410 #if 0
2411 int
2412 file_open(const char *file, int flags, int mode)
2413 {
2414    DWORD access = 0;
2415    DWORD shareMode = 0;
2416    DWORD create = 0;
2417    DWORD msflags = 0;
2418    HANDLE foo = INVALID_HANDLE_VALUE;
2419    const char *remap = file;
2420
2421    if (flags & O_WRONLY) access = GENERIC_WRITE;
2422    else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2423    else access = GENERIC_READ;
2424
2425    if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2426       create = CREATE_NEW;
2427    else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2428       create = CREATE_ALWAYS;
2429    else if (flags & O_CREAT)
2430       create = OPEN_ALWAYS;
2431    else if (flags & O_TRUNC)
2432       create = TRUNCATE_EXISTING;
2433    else 
2434       create = OPEN_EXISTING;
2435
2436    shareMode = 0;
2437
2438    if (flags & O_APPEND) {
2439       printf("open...APPEND not implemented yet.");
2440       exit(-1);
2441    }
2442
2443    if (p_CreateFileW) {
2444       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2445       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
2446
2447       foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
2448       free_pool_memory(pwszBuf);
2449    } else if (p_CreateFileA)
2450       foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
2451
2452    if (INVALID_HANDLE_VALUE == foo) {
2453       errno = b_errno_win32;
2454       return (int)-1;
2455    }
2456    return (int)foo;
2457
2458 }
2459
2460
2461 int
2462 file_close(int fd)
2463 {
2464     if (!CloseHandle((HANDLE)fd)) {
2465         errno = b_errno_win32;
2466         return -1;
2467     }
2468
2469     return 0;
2470 }
2471
2472 ssize_t
2473 file_write(int fd, const void *data, ssize_t len)
2474 {
2475     BOOL status;
2476     DWORD bwrite;
2477     status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2478     if (status) return bwrite;
2479     errno = b_errno_win32;
2480     return -1;
2481 }
2482
2483
2484 ssize_t
2485 file_read(int fd, void *data, ssize_t len)
2486 {
2487     BOOL status;
2488     DWORD bread;
2489
2490     status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2491     if (status) return bread;
2492     errno = b_errno_win32;
2493     return -1;
2494 }
2495
2496 boffset_t
2497 file_seek(int fd, boffset_t offset, int whence)
2498 {
2499     DWORD method = 0;
2500     DWORD val;
2501     LONG  offset_low = (LONG)offset;
2502     LONG  offset_high = (LONG)(offset >> 32);
2503
2504     switch (whence) {
2505     case SEEK_SET :
2506         method = FILE_BEGIN;
2507         break;
2508     case SEEK_CUR:
2509         method = FILE_CURRENT;
2510         break;
2511     case SEEK_END:
2512         method = FILE_END;
2513         break;
2514     default:
2515         errno = EINVAL;
2516         return -1;
2517     }
2518
2519
2520     if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
2521        errno = b_errno_win32;
2522        return -1;
2523     }
2524     /* ***FIXME*** I doubt this works right */
2525     return val;
2526 }
2527
2528 int
2529 file_dup2(int, int)
2530 {
2531     errno = ENOSYS;
2532     return -1;
2533 }
2534 #endif
2535
2536 #ifdef xxx
2537 /* 
2538  * Emulation of mmap and unmmap for tokyo dbm
2539  */
2540 void *mmap(void *start, size_t length, int prot, int flags,
2541            int fd, off_t offset)
2542 {
2543    DWORD fm_access = 0;
2544    DWORD mv_access = 0;
2545    HANDLE h;
2546    HANDLE mv;
2547
2548    if (length == 0) {
2549       return MAP_FAILED;
2550    }
2551    if (!fd) {
2552       return MAP_FAILED;
2553    }
2554
2555    if (flags & PROT_WRITE) {
2556       fm_access |= PAGE_READWRITE;
2557    } else if (flags & PROT_READ) {
2558       fm_access |= PAGE_READONLY;
2559    }
2560    
2561    if (flags & PROT_READ) {
2562       mv_access |= FILE_MAP_READ;
2563    }
2564    if (flags & PROT_WRITE) {
2565       mv_access |= FILE_MAP_WRITE;
2566    }
2567
2568    h = CreateFileMapping((HANDLE)_get_osfhandle (fd), 
2569                          NULL /* security */, 
2570                          fm_access, 
2571                          0 /* MaximumSizeHigh */, 
2572                          0 /* MaximumSizeLow */, 
2573                          NULL /* name of the file mapping object */);
2574
2575    if (!h || h == INVALID_HANDLE_VALUE) {
2576       return MAP_FAILED;
2577    }
2578
2579    mv = MapViewOfFile(h, mv_access, 
2580                       0 /* offset hi */, 
2581                       0 /* offset lo */,
2582                       length);
2583    CloseHandle(h);
2584
2585    if (!mv || mv == INVALID_HANDLE_VALUE) {
2586       return MAP_FAILED;
2587    }
2588
2589    return (void *) mv;
2590 }
2591
2592 int munmap(void *start, size_t length)
2593 {
2594    if (!start) {
2595       return -1;
2596    }
2597    UnmapViewOfFile(start);
2598    return 0;
2599 }
2600 #endif
2601
2602 #ifdef HAVE_MINGW
2603 /* syslog function, added by Nicolas Boichat */
2604 void openlog(const char *ident, int option, int facility) {}  
2605 #endif //HAVE_MINGW
2606
2607 /* Log an error message */
2608 void LogErrorMsg(const char *message)
2609 {
2610    HANDLE eventHandler;
2611    const char *strings[2];
2612
2613    /* Use the OS event logging to log the error */
2614    eventHandler = RegisterEventSource(NULL, "Bacula");
2615
2616    strings[0] = _("\n\nBacula ERROR: ");
2617    strings[1] = message;
2618
2619    if (eventHandler) {
2620       ReportEvent(eventHandler, EVENTLOG_ERROR_TYPE,
2621               0,                      /* category */
2622               0,                      /* ID */
2623               NULL,                   /* SID */
2624               2,                      /* Number of strings */
2625               0,                      /* raw data size */
2626               (const char **)strings, /* error strings */
2627               NULL);                  /* raw data */
2628       DeregisterEventSource(eventHandler);
2629    }
2630 }