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