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