]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/compat.cpp
ebl Apply Riccardo's patch that fix some win32 compilation errors
[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       h = p_FindFirstFileW((LPCWSTR)pwszBuf, &info_w);
655       free_pool_memory(pwszBuf);
656
657       pdwFileAttributes = &info_w.dwFileAttributes;
658       pdwReserved0      = &info_w.dwReserved0;
659       pnFileSizeHigh    = &info_w.nFileSizeHigh;
660       pnFileSizeLow     = &info_w.nFileSizeLow;
661       pftLastAccessTime = &info_w.ftLastAccessTime;
662       pftLastWriteTime  = &info_w.ftLastWriteTime;
663       pftCreationTime   = &info_w.ftCreationTime;
664
665    // use ASCII
666    } else if (p_FindFirstFileA) {
667       h = p_FindFirstFileA(file, &info_a);
668
669       pdwFileAttributes = &info_a.dwFileAttributes;
670       pdwReserved0      = &info_a.dwReserved0;
671       pnFileSizeHigh    = &info_a.nFileSizeHigh;
672       pnFileSizeLow     = &info_a.nFileSizeLow;
673       pftLastAccessTime = &info_a.ftLastAccessTime;
674       pftLastWriteTime  = &info_a.ftLastWriteTime;
675       pftCreationTime   = &info_a.ftCreationTime;
676    }
677
678    if (h == INVALID_HANDLE_VALUE) {
679       const char *err = errorString();
680       Dmsg2(99, "FindFirstFile(%s):%s\n", file, err);
681       LocalFree((void *)err);
682       errno = b_errno_win32;
683       return -1;
684    } else {
685       FindClose(h);
686    }
687
688    sb->st_mode = 0777;               /* start with everything */
689    if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
690        sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
691    if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
692        sb->st_mode &= ~S_IRWXO; /* remove everything for other */
693    if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
694        sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
695    sb->st_mode |= S_IFDIR;
696
697    /* 
698     * Store reparse/mount point info in st_rdev.  Note a
699     *  Win32 reparse point (junction point) is like a link
700     *  though it can have many properties (directory link,
701     *  soft link, hard link, HSM, ...
702     *  A mount point is a reparse point where another volume
703     *  is mounted, so it is like a Unix mount point (change of
704     *  filesystem).
705     */
706    if (*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
707       if (*pdwReserved0 & IO_REPARSE_TAG_MOUNT_POINT) {
708          sb->st_rdev = WIN32_MOUNT_POINT;           /* mount point */
709       } else {
710          sb->st_rdev = WIN32_REPARSE_POINT;         /* reparse point */
711       }
712    }  
713    Dmsg2(100, "st_rdev=%d file=%s\n", sb->st_rdev, file);
714    sb->st_size = *pnFileSizeHigh;
715    sb->st_size <<= 32;
716    sb->st_size |= *pnFileSizeLow;
717    sb->st_blksize = 4096;
718    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
719
720    sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
721    sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
722    sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
723
724    return 0;
725 }
726
727 int
728 fstat(int fd, struct stat *sb)
729 {
730    BY_HANDLE_FILE_INFORMATION info;
731
732    if (!GetFileInformationByHandle((HANDLE)fd, &info)) {
733        const char *err = errorString();
734        Dmsg1(99, "GetfileInformationByHandle: %s\n", err);
735        LocalFree((void *)err);
736        errno = b_errno_win32;
737        return -1;
738    }
739
740    sb->st_dev = info.dwVolumeSerialNumber;
741    sb->st_ino = info.nFileIndexHigh;
742    sb->st_ino <<= 32;
743    sb->st_ino |= info.nFileIndexLow;
744    sb->st_nlink = (short)info.nNumberOfLinks;
745    if (sb->st_nlink > 1) {
746       Dmsg1(99,  "st_nlink=%d\n", sb->st_nlink);
747    }
748
749    sb->st_mode = 0777;               /* start with everything */
750    if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
751        sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
752    if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
753        sb->st_mode &= ~S_IRWXO; /* remove everything for other */
754    if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
755        sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
756    sb->st_mode |= S_IFREG;
757
758    /* Use st_rdev to store reparse attribute */
759    if  (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
760       sb->st_rdev = WIN32_REPARSE_POINT;
761    }
762    Dmsg3(100, "st_rdev=%d sizino=%d ino=%lld\n", sb->st_rdev, sizeof(sb->st_ino),
763       (long long)sb->st_ino);
764
765    sb->st_size = info.nFileSizeHigh;
766    sb->st_size <<= 32;
767    sb->st_size |= info.nFileSizeLow;
768    sb->st_blksize = 4096;
769    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
770    sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
771    sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
772    sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
773
774    return 0;
775 }
776
777 static int
778 stat2(const char *file, struct stat *sb)
779 {
780    HANDLE h;
781    int rval = 0;
782    char tmpbuf[5000];
783    conv_unix_to_win32_path(file, tmpbuf, 5000);
784
785    DWORD attr = (DWORD)-1;
786
787    if (p_GetFileAttributesW) {
788       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
789       make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
790
791       attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
792       free_pool_memory(pwszBuf);
793    } else if (p_GetFileAttributesA) {
794       attr = p_GetFileAttributesA(tmpbuf);
795    }
796
797    if (attr == (DWORD)-1) {
798       const char *err = errorString();
799       Dmsg2(99, "GetFileAttributes(%s): %s\n", tmpbuf, err);
800       LocalFree((void *)err);
801       errno = b_errno_win32;
802       return -1;
803    }
804
805    h = CreateFileA(tmpbuf, GENERIC_READ,
806                   FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
807
808    if (h == INVALID_HANDLE_VALUE) {
809       const char *err = errorString();
810       Dmsg2(99, "Cannot open file for stat (%s):%s\n", tmpbuf, err);
811       LocalFree((void *)err);
812       errno = b_errno_win32;
813       return -1;
814    }
815
816    rval = fstat((int)h, sb);
817    CloseHandle(h);
818
819    if (attr & FILE_ATTRIBUTE_DIRECTORY &&
820         file[1] == ':' && file[2] != 0) {
821       statDir(file, sb);
822    }
823
824    return rval;
825 }
826
827 int
828 stat(const char *file, struct stat *sb)
829 {
830    WIN32_FILE_ATTRIBUTE_DATA data;
831    errno = 0;
832
833    memset(sb, 0, sizeof(*sb));
834
835    if (p_GetFileAttributesExW) {
836       /* dynamically allocate enough space for UCS2 filename */
837       POOLMEM *pwszBuf = get_pool_memory(PM_FNAME);
838       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
839
840       BOOL b = p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, &data);
841       free_pool_memory(pwszBuf);
842
843       if (!b) {
844          return stat2(file, sb);
845       }
846
847    } else if (p_GetFileAttributesExA) {
848       if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
849          return stat2(file, sb);
850        }
851    } else {
852       return stat2(file, sb);
853    }
854
855    sb->st_mode = 0777;               /* start with everything */
856    if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
857       sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
858    }
859    if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
860       sb->st_mode &= ~S_IRWXO; /* remove everything for other */
861    }
862    if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
863       sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
864    }
865    if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
866       sb->st_mode |= S_IFDIR;
867    } else {
868       sb->st_mode |= S_IFREG;
869    }
870
871    /* Use st_rdev to store reparse attribute */
872    sb->st_rdev = (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0; 
873
874    sb->st_nlink = 1;
875    sb->st_size = data.nFileSizeHigh;
876    sb->st_size <<= 32;
877    sb->st_size |= data.nFileSizeLow;
878    sb->st_blksize = 4096;
879    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
880    sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
881    sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
882    sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
883
884    /*
885     * If we are not at the root, then to distinguish a reparse 
886     *  point from a mount point, we must call FindFirstFile() to
887     *  get the WIN32_FIND_DATA, which has the bit that indicates
888     *  that this directory is a mount point -- aren't Win32 APIs
889     *  wonderful? (sarcasm).  The code exists in the statDir
890     *  subroutine.
891     */
892    if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && 
893         file[1] == ':' && file[2] != 0) {
894       statDir(file, sb);
895    }
896    Dmsg3(100, "sizino=%d ino=%lld file=%s\n", sizeof(sb->st_ino),
897                        (long long)sb->st_ino, file);
898    return 0;
899 }
900
901 /*
902  * We write our own ftruncate because the one in the
903  *  Microsoft library mrcrt.dll does not truncate
904  *  files greater than 2GB.
905  *  KES - May 2007
906  */
907 int win32_ftruncate(int fd, int64_t length) 
908 {
909    /* Set point we want to truncate file */
910    __int64 pos = _lseeki64(fd, (__int64)length, SEEK_SET);
911
912    if (pos != (__int64)length) {
913       errno = EACCES;         /* truncation failed, get out */
914       return -1;
915    }
916
917    /* Truncate file */
918    if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0) {
919       errno = b_errno_win32;
920       return -1;
921    }
922    errno = 0;
923    return 0;
924 }
925
926 int fcntl(int fd, int cmd, long arg)
927 {
928    int rval = 0;
929
930    switch (cmd) {
931    case F_GETFL:
932       rval = O_NONBLOCK;
933       break;
934
935    case F_SETFL:
936       rval = 0;
937       break;
938
939    default:
940       errno = EINVAL;
941       rval = -1;
942       break;
943    }
944
945    return rval;
946 }
947
948 int
949 lstat(const char *file, struct stat *sb)
950 {
951    return stat(file, sb);
952 }
953
954 void
955 sleep(int sec)
956 {
957    Sleep(sec * 1000);
958 }
959
960 int
961 geteuid(void)
962 {
963    return 0;
964 }
965
966 int
967 execvp(const char *, char *[]) {
968    errno = ENOSYS;
969    return -1;
970 }
971
972
973 int
974 fork(void)
975 {
976    errno = ENOSYS;
977    return -1;
978 }
979
980 int
981 pipe(int[])
982 {
983    errno = ENOSYS;
984    return -1;
985 }
986
987 int
988 waitpid(int, int*, int)
989 {
990    errno = ENOSYS;
991    return -1;
992 }
993
994 int
995 readlink(const char *, char *, int)
996 {
997    errno = ENOSYS;
998    return -1;
999 }
1000
1001
1002 #ifndef HAVE_MINGW
1003 int
1004 strcasecmp(const char *s1, const char *s2)
1005 {
1006    register int ch1, ch2;
1007
1008    if (s1==s2)
1009       return 0;       /* strings are equal if same object. */
1010    else if (!s1)
1011       return -1;
1012    else if (!s2)
1013       return 1;
1014    do {
1015       ch1 = *s1;
1016       ch2 = *s2;
1017       s1++;
1018       s2++;
1019    } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
1020
1021    return(ch1 - ch2);
1022 }
1023 #endif //HAVE_MINGW
1024
1025 int
1026 strncasecmp(const char *s1, const char *s2, int len)
1027 {
1028    register int ch1 = 0, ch2 = 0;
1029
1030    if (s1==s2)
1031       return 0;       /* strings are equal if same object. */
1032    else if (!s1)
1033       return -1;
1034    else if (!s2)
1035       return 1;
1036
1037    while (len--) {
1038       ch1 = *s1;
1039       ch2 = *s2;
1040       s1++;
1041       s2++;
1042       if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
1043    }
1044
1045    return (ch1 - ch2);
1046 }
1047
1048 int
1049 gettimeofday(struct timeval *tv, struct timezone *)
1050 {
1051     SYSTEMTIME now;
1052     FILETIME tmp;
1053
1054     GetSystemTime(&now);
1055
1056     if (tv == NULL) {
1057        errno = EINVAL;
1058        return -1;
1059     }
1060     if (!SystemTimeToFileTime(&now, &tmp)) {
1061        errno = b_errno_win32;
1062        return -1;
1063     }
1064
1065     int64_t _100nsec = tmp.dwHighDateTime;
1066     _100nsec <<= 32;
1067     _100nsec |= tmp.dwLowDateTime;
1068     _100nsec -= WIN32_FILETIME_ADJUST;
1069
1070     tv->tv_sec = (long)(_100nsec / 10000000);
1071     tv->tv_usec = (long)((_100nsec % 10000000)/10);
1072     return 0;
1073
1074 }
1075
1076 /* For apcupsd this is in src/lib/wincompat.c */
1077 extern "C" void syslog(int type, const char *fmt, ...) 
1078 {
1079 /*#ifndef HAVE_CONSOLE
1080     MessageBox(NULL, msg, "Bacula", MB_OK);
1081 #endif*/
1082 }
1083
1084 void
1085 closelog()
1086 {
1087 }
1088
1089 struct passwd *
1090 getpwuid(uid_t)
1091 {
1092     return NULL;
1093 }
1094
1095 struct group *
1096 getgrgid(uid_t)
1097 {
1098     return NULL;
1099 }
1100
1101 // implement opendir/readdir/closedir on top of window's API
1102
1103 typedef struct _dir
1104 {
1105     WIN32_FIND_DATAA data_a;    // window's file info (ansii version)
1106     WIN32_FIND_DATAW data_w;    // window's file info (wchar version)
1107     const char *spec;           // the directory we're traversing
1108     HANDLE      dirh;           // the search handle
1109     BOOL        valid_a;        // the info in data_a field is valid
1110     BOOL        valid_w;        // the info in data_w field is valid
1111     UINT32      offset;         // pseudo offset for d_off
1112 } _dir;
1113
1114 DIR *
1115 opendir(const char *path)
1116 {
1117     /* enough space for VSS !*/
1118     int max_len = strlen(path) + MAX_PATH;
1119     _dir *rval = NULL;
1120     if (path == NULL) {
1121        errno = ENOENT;
1122        return NULL;
1123     }
1124
1125     Dmsg1(100, "Opendir path=%s\n", path);
1126     rval = (_dir *)malloc(sizeof(_dir));
1127     memset (rval, 0, sizeof (_dir));
1128     if (rval == NULL) return NULL;
1129     char *tspec = (char *)malloc(max_len);
1130     if (tspec == NULL) return NULL;
1131
1132     conv_unix_to_win32_path(path, tspec, max_len);
1133     Dmsg1(100, "win32 path=%s\n", tspec);
1134
1135     // add backslash only if there is none yet (think of c:\)
1136     if (tspec[strlen(tspec)-1] != '\\')
1137       bstrncat(tspec, "\\*", max_len);
1138     else
1139       bstrncat(tspec, "*", max_len);
1140
1141     rval->spec = tspec;
1142
1143     // convert to wchar_t
1144     if (p_FindFirstFileW) {
1145       POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
1146       make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec);
1147
1148       rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
1149
1150       free_pool_memory(pwcBuf);
1151
1152       if (rval->dirh != INVALID_HANDLE_VALUE)
1153         rval->valid_w = 1;
1154     } else if (p_FindFirstFileA) {
1155       rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
1156
1157       if (rval->dirh != INVALID_HANDLE_VALUE)
1158         rval->valid_a = 1;
1159     } else goto err;
1160
1161
1162     Dmsg3(99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
1163           path, rval->spec, rval->dirh);
1164
1165     rval->offset = 0;
1166     if (rval->dirh == INVALID_HANDLE_VALUE)
1167         goto err;
1168
1169     if (rval->valid_w) {
1170       Dmsg1(99, "\tFirstFile=%s\n", rval->data_w.cFileName);
1171     }
1172
1173     if (rval->valid_a) {
1174       Dmsg1(99, "\tFirstFile=%s\n", rval->data_a.cFileName);
1175     }
1176
1177     return (DIR *)rval;
1178
1179 err:
1180     free((void *)rval->spec);
1181     free(rval);
1182     errno = b_errno_win32;
1183     return NULL;
1184 }
1185
1186 int
1187 closedir(DIR *dirp)
1188 {
1189     _dir *dp = (_dir *)dirp;
1190     FindClose(dp->dirh);
1191     free((void *)dp->spec);
1192     free((void *)dp);
1193     return 0;
1194 }
1195
1196 /*
1197   typedef struct _WIN32_FIND_DATA {
1198     DWORD dwFileAttributes;
1199     FILETIME ftCreationTime;
1200     FILETIME ftLastAccessTime;
1201     FILETIME ftLastWriteTime;
1202     DWORD nFileSizeHigh;
1203     DWORD nFileSizeLow;
1204     DWORD dwReserved0;
1205     DWORD dwReserved1;
1206     TCHAR cFileName[MAX_PATH];
1207     TCHAR cAlternateFileName[14];
1208 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1209 */
1210
1211 static int
1212 copyin(struct dirent &dp, const char *fname)
1213 {
1214     dp.d_ino = 0;
1215     dp.d_reclen = 0;
1216     char *cp = dp.d_name;
1217     while (*fname) {
1218         *cp++ = *fname++;
1219         dp.d_reclen++;
1220     }
1221         *cp = 0;
1222     return dp.d_reclen;
1223 }
1224
1225 int
1226 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1227 {
1228     _dir *dp = (_dir *)dirp;
1229     if (dp->valid_w || dp->valid_a) {
1230       entry->d_off = dp->offset;
1231
1232       // copy unicode
1233       if (dp->valid_w) {
1234          char szBuf[MAX_PATH_UTF8+1];
1235          wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1236          dp->offset += copyin(*entry, szBuf);
1237       } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1238          dp->offset += copyin(*entry, dp->data_a.cFileName);
1239       }
1240
1241       *result = entry;              /* return entry address */
1242       Dmsg4(99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1243             dirp, entry->d_name, entry->d_reclen, entry->d_off);
1244     } else {
1245 //      Dmsg0(99, "readdir_r !valid\n");
1246         errno = b_errno_win32;
1247         return -1;
1248     }
1249
1250     // get next file, try unicode first
1251     if (p_FindNextFileW)
1252        dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1253     else if (p_FindNextFileA)
1254        dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1255     else {
1256        dp->valid_a = FALSE;
1257        dp->valid_w = FALSE;
1258     }
1259
1260     return 0;
1261 }
1262
1263 /*
1264  * Dotted IP address to network address
1265  *
1266  * Returns 1 if  OK
1267  *         0 on error
1268  */
1269 int
1270 inet_aton(const char *a, struct in_addr *inp)
1271 {
1272    const char *cp = a;
1273    uint32_t acc = 0, tmp = 0;
1274    int dotc = 0;
1275
1276    if (!isdigit(*cp)) {         /* first char must be digit */
1277       return 0;                 /* error */
1278    }
1279    do {
1280       if (isdigit(*cp)) {
1281          tmp = (tmp * 10) + (*cp -'0');
1282       } else if (*cp == '.' || *cp == 0) {
1283          if (tmp > 255) {
1284             return 0;           /* error */
1285          }
1286          acc = (acc << 8) + tmp;
1287          dotc++;
1288          tmp = 0;
1289       } else {
1290          return 0;              /* error */
1291       }
1292    } while (*cp++ != 0);
1293    if (dotc != 4) {              /* want 3 .'s plus EOS */
1294       return 0;                  /* error */
1295    }
1296    inp->s_addr = htonl(acc);     /* store addr in network format */
1297    return 1;
1298 }
1299
1300 int
1301 nanosleep(const struct timespec *req, struct timespec *rem)
1302 {
1303     if (rem)
1304         rem->tv_sec = rem->tv_nsec = 0;
1305     Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1306     return 0;
1307 }
1308
1309 void
1310 init_signals(void terminate(int sig))
1311 {
1312
1313 }
1314
1315 void
1316 init_stack_dump(void)
1317 {
1318
1319 }
1320
1321
1322 long
1323 pathconf(const char *path, int name)
1324 {
1325     switch(name) {
1326     case _PC_PATH_MAX :
1327         if (strncmp(path, "\\\\?\\", 4) == 0)
1328             return 32767;
1329     case _PC_NAME_MAX :
1330         return 255;
1331     }
1332     errno = ENOSYS;
1333     return -1;
1334 }
1335
1336 int
1337 WSA_Init(void)
1338 {
1339     WORD wVersionRequested = MAKEWORD( 1, 1);
1340     WSADATA wsaData;
1341
1342     int err = WSAStartup(wVersionRequested, &wsaData);
1343
1344
1345     if (err != 0) {
1346         printf("Can not start Windows Sockets\n");
1347         errno = ENOSYS;
1348         return -1;
1349     }
1350
1351     return 0;
1352 }
1353
1354 int win32_chmod(const char *path, mode_t mode)
1355 {
1356    DWORD attr = (DWORD)-1;
1357
1358    if (p_GetFileAttributesW) {
1359       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1360       make_win32_path_UTF8_2_wchar(&pwszBuf, path);
1361
1362       attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
1363       if (attr != INVALID_FILE_ATTRIBUTES) {
1364          /* Use Bacula mappings define in stat() above */
1365          if (mode & (S_IRUSR|S_IRGRP|S_IROTH)) {
1366             attr |= FILE_ATTRIBUTE_READONLY;
1367          } else {
1368             attr &= ~FILE_ATTRIBUTE_READONLY;
1369          }
1370          if (mode & S_ISVTX) {
1371             attr |= FILE_ATTRIBUTE_HIDDEN;
1372          } else {
1373             attr &= ~FILE_ATTRIBUTE_HIDDEN;
1374          }
1375          if (mode & S_IRWXO) { 
1376             attr |= FILE_ATTRIBUTE_SYSTEM;
1377          } else {
1378             attr &= ~FILE_ATTRIBUTE_SYSTEM;
1379          }
1380          attr = p_SetFileAttributesW((LPCWSTR)pwszBuf, attr);
1381       }
1382       free_pool_memory(pwszBuf);
1383    } else if (p_GetFileAttributesA) {
1384          if (mode & (S_IRUSR|S_IRGRP|S_IROTH)) {
1385             attr |= FILE_ATTRIBUTE_READONLY;
1386          } else {
1387             attr &= ~FILE_ATTRIBUTE_READONLY;
1388          }
1389          if (mode & S_ISVTX) {
1390             attr |= FILE_ATTRIBUTE_HIDDEN;
1391          } else {
1392             attr &= ~FILE_ATTRIBUTE_HIDDEN;
1393          }
1394          if (mode & S_IRWXO) { 
1395             attr |= FILE_ATTRIBUTE_SYSTEM;
1396          } else {
1397             attr &= ~FILE_ATTRIBUTE_SYSTEM;
1398          }
1399       attr = p_GetFileAttributesA(path);
1400       if (attr != INVALID_FILE_ATTRIBUTES) {
1401          attr = p_SetFileAttributesA(path, attr);
1402       }
1403    }
1404
1405    if (attr == (DWORD)-1) {
1406       const char *err = errorString();
1407       Dmsg2(99, "Get/SetFileAttributes(%s): %s\n", path, err);
1408       LocalFree((void *)err);
1409       errno = b_errno_win32;
1410       return -1;
1411    }
1412    return 0;
1413 }
1414
1415
1416 int
1417 win32_chdir(const char *dir)
1418 {
1419    if (p_SetCurrentDirectoryW) {
1420       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1421       make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1422
1423       BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1424       
1425       free_pool_memory(pwszBuf);
1426
1427       if (!b) {
1428          errno = b_errno_win32;
1429          return -1;
1430       }
1431    } else if (p_SetCurrentDirectoryA) {
1432       if (0 == p_SetCurrentDirectoryA(dir)) {
1433          errno = b_errno_win32;
1434          return -1;
1435       }
1436    } else {
1437       return -1;
1438    }
1439
1440    return 0;
1441 }
1442
1443 int
1444 win32_mkdir(const char *dir)
1445 {
1446    if (p_wmkdir){
1447       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1448       make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1449
1450       int n = p_wmkdir((LPCWSTR)pwszBuf);
1451       free_pool_memory(pwszBuf);
1452       return n;
1453    }
1454
1455    return _mkdir(dir);
1456 }
1457
1458
1459 char *
1460 win32_getcwd(char *buf, int maxlen)
1461 {
1462    int n=0;
1463
1464    if (p_GetCurrentDirectoryW) {
1465       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1466       pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1467
1468       n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1469       if (n!=0)
1470          n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1471       free_pool_memory(pwszBuf);
1472
1473    } else if (p_GetCurrentDirectoryA)
1474       n = p_GetCurrentDirectoryA(maxlen, buf);
1475
1476    if (n == 0 || n > maxlen) return NULL;
1477
1478    if (n+1 > maxlen) return NULL;
1479    if (n != 3) {
1480        buf[n] = '\\';
1481        buf[n+1] = 0;
1482    }
1483    return buf;
1484 }
1485
1486 int
1487 win32_fputs(const char *string, FILE *stream)
1488 {
1489    /* we use WriteConsoleA / WriteConsoleA
1490       so we can be sure that unicode support works on win32.
1491       with fallback if something fails
1492    */
1493
1494    HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1495    if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1496        p_MultiByteToWideChar && (stream == stdout)) {
1497
1498       POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1499
1500       DWORD dwCharsWritten;
1501       DWORD dwChars;
1502
1503       dwChars = UTF8_2_wchar(&pwszBuf, string);
1504
1505       /* try WriteConsoleW */
1506       if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1507          free_pool_memory(pwszBuf);
1508          return dwCharsWritten;
1509       }
1510
1511       /* convert to local codepage and try WriteConsoleA */
1512       POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1513       pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1514
1515       dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR)pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1516       free_pool_memory(pwszBuf);
1517
1518       if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1519          free_pool_memory(pszBuf);
1520          return dwCharsWritten;
1521       }
1522       free_pool_memory(pszBuf);
1523    }
1524    /* Fall back */
1525    return fputs(string, stream);
1526 }
1527
1528 char*
1529 win32_cgets (char* buffer, int len)
1530 {
1531    /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1532       from the win32 console and fallback if seomething fails */
1533
1534    HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1535    if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1536       DWORD dwRead;
1537       wchar_t wszBuf[1024];
1538       char  szBuf[1024];
1539
1540       /* nt and unicode conversion */
1541       if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1542
1543          /* null terminate at end */
1544          if (wszBuf[dwRead-1] == L'\n') {
1545             wszBuf[dwRead-1] = L'\0';
1546             dwRead --;
1547          }
1548
1549          if (wszBuf[dwRead-1] == L'\r') {
1550             wszBuf[dwRead-1] = L'\0';
1551             dwRead --;
1552          }
1553
1554          wchar_2_UTF8(buffer, wszBuf, len);
1555          return buffer;
1556       }
1557
1558       /* win 9x and unicode conversion */
1559       if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1560
1561          /* null terminate at end */
1562          if (szBuf[dwRead-1] == L'\n') {
1563             szBuf[dwRead-1] = L'\0';
1564             dwRead --;
1565          }
1566
1567          if (szBuf[dwRead-1] == L'\r') {
1568             szBuf[dwRead-1] = L'\0';
1569             dwRead --;
1570          }
1571
1572          /* convert from ansii to wchar_t */
1573          p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1574          /* convert from wchar_t to UTF-8 */
1575          if (wchar_2_UTF8(buffer, wszBuf, len))
1576             return buffer;
1577       }
1578    }
1579
1580    /* fallback */
1581    if (fgets(buffer, len, stdin))
1582       return buffer;
1583    else
1584       return NULL;
1585 }
1586
1587 int
1588 win32_unlink(const char *filename)
1589 {
1590    int nRetCode;
1591    if (p_wunlink) {
1592       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1593       make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1594
1595       nRetCode = _wunlink((LPCWSTR) pwszBuf);
1596
1597       /*
1598        * special case if file is readonly,
1599        * we retry but unset attribute before
1600        */
1601       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1602          DWORD dwAttr =  p_GetFileAttributesW((LPCWSTR)pwszBuf);
1603          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1604             if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1605                nRetCode = _wunlink((LPCWSTR) pwszBuf);
1606                /* reset to original if it didn't help */
1607                if (nRetCode == -1)
1608                   p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1609             }
1610          }
1611       }
1612       free_pool_memory(pwszBuf);
1613    } else {
1614       nRetCode = _unlink(filename);
1615
1616       /* special case if file is readonly,
1617       we retry but unset attribute before */
1618       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1619          DWORD dwAttr =  p_GetFileAttributesA(filename);
1620          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1621             if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1622                nRetCode = _unlink(filename);
1623                /* reset to original if it didn't help */
1624                if (nRetCode == -1)
1625                   p_SetFileAttributesA(filename, dwAttr);
1626             }
1627          }
1628       }
1629    }
1630    return nRetCode;
1631 }
1632
1633
1634 #include "mswinver.h"
1635
1636 char WIN_VERSION_LONG[64];
1637 char WIN_VERSION[32];
1638 char WIN_RAWVERSION[32];
1639
1640 class winver {
1641 public:
1642     winver(void);
1643 };
1644
1645 static winver INIT;                     // cause constructor to be called before main()
1646
1647
1648 winver::winver(void)
1649 {
1650     const char *version = "";
1651     const char *platform = "";
1652     OSVERSIONINFO osvinfo;
1653     osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1654
1655     // Get the current OS version
1656     if (!GetVersionEx(&osvinfo)) {
1657         version = "Unknown";
1658         platform = "Unknown";
1659     }
1660         const int ver = _mkversion(osvinfo.dwPlatformId,
1661                                    osvinfo.dwMajorVersion,
1662                                    osvinfo.dwMinorVersion);
1663         snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1664         switch (ver)
1665         {
1666         case MS_WINDOWS_95: (version =  "Windows 95"); break;
1667         case MS_WINDOWS_98: (version =  "Windows 98"); break;
1668         case MS_WINDOWS_ME: (version =  "Windows ME"); break;
1669         case MS_WINDOWS_NT4:(version =  "Windows NT 4.0"); platform = "NT"; break;
1670         case MS_WINDOWS_2K: (version =  "Windows 2000");platform = "NT"; break;
1671         case MS_WINDOWS_XP: (version =  "Windows XP");platform = "NT"; break;
1672         case MS_WINDOWS_S2003: (version =  "Windows Server 2003");platform = "NT"; break;
1673         default: version = WIN_RAWVERSION; break;
1674         }
1675
1676     bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1677     snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1678              platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1679
1680 #if 0
1681     HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1682     CloseHandle(h);
1683 #endif
1684 #if 0
1685     BPIPE *b = open_bpipe("ls -l", 10, "r");
1686     char buf[1024];
1687     while (!feof(b->rfd)) {
1688         fgets(buf, sizeof(buf), b->rfd);
1689     }
1690     close_bpipe(b);
1691 #endif
1692 }
1693
1694 BOOL CreateChildProcess(VOID);
1695 VOID WriteToPipe(VOID);
1696 VOID ReadFromPipe(VOID);
1697 VOID ErrorExit(LPCSTR);
1698 VOID ErrMsg(LPTSTR, BOOL);
1699
1700 /**
1701  * Check for a quoted path,  if an absolute path name is given and it contains
1702  * spaces it will need to be quoted.  i.e.  "c:/Program Files/foo/bar.exe"
1703  * CreateProcess() says the best way to ensure proper results with executables
1704  * with spaces in path or filename is to quote the string.
1705  */
1706 const char *
1707 getArgv0(const char *cmdline)
1708 {
1709
1710     int inquote = 0;
1711     const char *cp;
1712     for (cp = cmdline; *cp; cp++)
1713     {
1714         if (*cp == '"') {
1715             inquote = !inquote;
1716         }
1717         if (!inquote && isspace(*cp))
1718             break;
1719     }
1720
1721
1722     int len = cp - cmdline;
1723     char *rval = (char *)malloc(len+1);
1724
1725     cp = cmdline;
1726     char *rp = rval;
1727
1728     while (len--)
1729         *rp++ = *cp++;
1730
1731     *rp = 0;
1732     return rval;
1733 }
1734
1735 /*
1736  * Extracts the executable or script name from the first string in 
1737  * cmdline.
1738  *
1739  * If the name contains blanks then it must be quoted with double quotes,
1740  * otherwise quotes are optional.  If the name contains blanks then it 
1741  * will be converted to a short name.
1742  *
1743  * The optional quotes will be removed.  The result is copied to a malloc'ed
1744  * buffer and returned through the pexe argument.  The pargs parameter is set
1745  * to the address of the character in cmdline located after the name.
1746  *
1747  * The malloc'ed buffer returned in *pexe must be freed by the caller.
1748  */
1749 bool
1750 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1751 {
1752    const char *pExeStart = NULL;    /* Start of executable name in cmdline */
1753    const char *pExeEnd = NULL;      /* Character after executable name (separator) */
1754
1755    const char *pBasename = NULL;    /* Character after last path separator */
1756    const char *pExtension = NULL;   /* Period at start of extension */
1757
1758    const char *current = cmdline;
1759
1760    bool bQuoted = false;
1761
1762    /* Skip initial whitespace */
1763
1764    while (*current == ' ' || *current == '\t')
1765    {
1766       current++;
1767    }
1768
1769    /* Calculate start of name and determine if quoted */
1770
1771    if (*current == '"') {
1772       pExeStart = ++current;
1773       bQuoted = true;
1774    } else {
1775       pExeStart = current;
1776       bQuoted = false;
1777    }
1778
1779    *pargs = NULL;
1780    *pexe = NULL;
1781
1782    /* 
1783     * Scan command line looking for path separators (/ and \\) and the 
1784     * terminator, either a quote or a blank.  The location of the 
1785     * extension is also noted.
1786     */
1787
1788    for ( ; *current != '\0'; current++)
1789    {
1790       if (*current == '.') {
1791          pExtension = current;
1792       } else if (IsPathSeparator(*current) && current[1] != '\0') {
1793          pBasename = &current[1];
1794          pExtension = NULL;
1795       }
1796
1797       /* Check for terminator, either quote or blank */
1798       if (bQuoted) {
1799          if (*current != '"') {
1800             continue;
1801          }
1802       } else {
1803          if (*current != ' ') {
1804             continue;
1805          }
1806       }
1807
1808       /*
1809        * Hit terminator, remember end of name (address of terminator) and 
1810        * start of arguments 
1811        */
1812       pExeEnd = current;
1813
1814       if (bQuoted && *current == '"') {
1815          *pargs = &current[1];
1816       } else {
1817          *pargs = current;
1818       }
1819
1820       break;
1821    }
1822
1823    if (pBasename == NULL) {
1824       pBasename = pExeStart;
1825    }
1826
1827    if (pExeEnd == NULL) {
1828       pExeEnd = current;
1829    }
1830
1831    if (*pargs == NULL)
1832    {
1833       *pargs = current;
1834    }
1835
1836    bool bHasPathSeparators = pExeStart != pBasename;
1837
1838    /* We have pointers to all the useful parts of the name */
1839
1840    /* Default extensions in the order cmd.exe uses to search */
1841
1842    static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
1843    DWORD dwBasePathLength = pExeEnd - pExeStart;
1844
1845    DWORD dwAltNameLength = 0;
1846    char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1847    char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1848
1849    pPathname[MAX_PATHLENGTH] = '\0';
1850    pAltPathname[MAX_PATHLENGTH] = '\0';
1851
1852    memcpy(pPathname, pExeStart, dwBasePathLength);
1853    pPathname[dwBasePathLength] = '\0';
1854
1855    if (pExtension == NULL) {
1856       /* Try appending extensions */
1857       for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
1858
1859          if (!bHasPathSeparators) {
1860             /* There are no path separators, search in the standard locations */
1861             dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
1862             if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1863                memcpy(pPathname, pAltPathname, dwAltNameLength);
1864                pPathname[dwAltNameLength] = '\0';
1865                break;
1866             }
1867          } else {
1868             bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
1869             if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) {
1870                break;
1871             }
1872             pPathname[dwBasePathLength] = '\0';
1873          }
1874       }
1875    } else if (!bHasPathSeparators) {
1876       /* There are no path separators, search in the standard locations */
1877       dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
1878       if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) {
1879          memcpy(pPathname, pAltPathname, dwAltNameLength);
1880          pPathname[dwAltNameLength] = '\0';
1881       }
1882    }
1883
1884    if (strchr(pPathname, ' ') != NULL) {
1885       dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH);
1886
1887       if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1888          *pexe = (char *)malloc(dwAltNameLength + 1);
1889          if (*pexe == NULL) {
1890             return false;
1891          }
1892          memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
1893       }
1894    }
1895
1896    if (*pexe == NULL) {
1897       DWORD dwPathnameLength = strlen(pPathname);
1898       *pexe = (char *)malloc(dwPathnameLength + 1);
1899       if (*pexe == NULL) {
1900          return false;
1901       }
1902       memcpy(*pexe, pPathname, dwPathnameLength + 1);
1903    }
1904
1905    return true;
1906 }
1907
1908 /**
1909  * Create the process with WCHAR API
1910  */
1911 static BOOL
1912 CreateChildProcessW(const char *comspec, const char *cmdLine,
1913                     PROCESS_INFORMATION *hProcInfo,
1914                     HANDLE in, HANDLE out, HANDLE err)
1915 {
1916    STARTUPINFOW siStartInfo;
1917    BOOL bFuncRetn = FALSE;
1918
1919    // Set up members of the STARTUPINFO structure.
1920    ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
1921    siStartInfo.cb = sizeof(siStartInfo);
1922    // setup new process to use supplied handles for stdin,stdout,stderr
1923
1924    siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1925    siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
1926
1927    siStartInfo.hStdInput = in;
1928    siStartInfo.hStdOutput = out;
1929    siStartInfo.hStdError = err;
1930    
1931    // Convert argument to WCHAR
1932    POOLMEM *cmdLine_wchar = get_pool_memory(PM_FNAME);
1933    POOLMEM *comspec_wchar = get_pool_memory(PM_FNAME);
1934
1935    UTF8_2_wchar(&cmdLine_wchar, cmdLine);
1936    UTF8_2_wchar(&comspec_wchar, comspec);
1937
1938    // Create the child process.
1939    Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec_wchar, cmdLine_wchar);
1940
1941    // try to execute program
1942    bFuncRetn = p_CreateProcessW((WCHAR*)comspec_wchar,
1943                                 (WCHAR*)cmdLine_wchar,// command line
1944                                 NULL,      // process security attributes
1945                                 NULL,      // primary thread security attributes
1946                                 TRUE,      // handles are inherited
1947                                 0,         // creation flags
1948                                 NULL,      // use parent's environment
1949                                 NULL,      // use parent's current directory
1950                                 &siStartInfo,  // STARTUPINFO pointer
1951                                 hProcInfo);   // receives PROCESS_INFORMATION
1952    free_pool_memory(cmdLine_wchar);
1953    free_pool_memory(comspec_wchar);
1954
1955    return bFuncRetn;
1956 }
1957
1958
1959 /**
1960  * Create the process with ANSI API
1961  */
1962 static BOOL
1963 CreateChildProcessA(const char *comspec, char *cmdLine,
1964                     PROCESS_INFORMATION *hProcInfo,
1965                     HANDLE in, HANDLE out, HANDLE err)
1966 {
1967    STARTUPINFOA siStartInfo;
1968    BOOL bFuncRetn = FALSE;
1969
1970    // Set up members of the STARTUPINFO structure.
1971    ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
1972    siStartInfo.cb = sizeof(siStartInfo);
1973    // setup new process to use supplied handles for stdin,stdout,stderr
1974    siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1975    siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
1976
1977    siStartInfo.hStdInput = in;
1978    siStartInfo.hStdOutput = out;
1979    siStartInfo.hStdError = err;
1980
1981    // Create the child process.
1982    Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
1983
1984    // try to execute program
1985    bFuncRetn = p_CreateProcessA(comspec,
1986                                 cmdLine,  // command line
1987                                 NULL,     // process security attributes
1988                                 NULL,     // primary thread security attributes
1989                                 TRUE,     // handles are inherited
1990                                 0,        // creation flags
1991                                 NULL,     // use parent's environment
1992                                 NULL,     // use parent's current directory
1993                                 &siStartInfo,// STARTUPINFO pointer
1994                                 hProcInfo);// receives PROCESS_INFORMATION
1995    return bFuncRetn;
1996 }
1997
1998 /**
1999  * OK, so it would seem CreateProcess only handles true executables:
2000  * .com or .exe files.  So grab $COMSPEC value and pass command line to it.
2001  */
2002 HANDLE
2003 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
2004 {
2005    static const char *comspec = NULL;
2006    PROCESS_INFORMATION piProcInfo;
2007    BOOL bFuncRetn = FALSE;
2008
2009    if (!p_CreateProcessA || !p_CreateProcessW)
2010       return INVALID_HANDLE_VALUE;
2011
2012    if (comspec == NULL) 
2013       comspec = getenv("COMSPEC");
2014    if (comspec == NULL) // should never happen
2015       return INVALID_HANDLE_VALUE;
2016
2017    // Set up members of the PROCESS_INFORMATION structure.
2018    ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
2019
2020    // if supplied handles are not used the send a copy of our STD_HANDLE
2021    // as appropriate
2022    if (in == INVALID_HANDLE_VALUE)
2023       in = GetStdHandle(STD_INPUT_HANDLE);
2024
2025    if (out == INVALID_HANDLE_VALUE)
2026       out = GetStdHandle(STD_OUTPUT_HANDLE);
2027
2028    if (err == INVALID_HANDLE_VALUE)
2029       err = GetStdHandle(STD_ERROR_HANDLE);
2030
2031    char *exeFile;
2032    const char *argStart;
2033
2034    if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
2035       return INVALID_HANDLE_VALUE;
2036    }
2037
2038    POOL_MEM cmdLine(PM_FNAME);
2039    Mmsg(cmdLine, "%s /c %s%s", comspec, exeFile, argStart);
2040
2041    free(exeFile);
2042
2043    // New function disabled
2044    if (p_CreateProcessW && p_MultiByteToWideChar) {
2045       bFuncRetn = CreateChildProcessW(comspec, cmdLine.c_str(), &piProcInfo,
2046                                       in, out, err);
2047    } else {
2048       bFuncRetn = CreateChildProcessA(comspec, cmdLine.c_str(), &piProcInfo,
2049                                       in, out, err);
2050    }
2051
2052    if (bFuncRetn == 0) {
2053       ErrorExit("CreateProcess failed\n");
2054       const char *err = errorString();
2055       Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n",comspec,cmdLine.c_str(),err);
2056       LocalFree((void *)err);
2057       return INVALID_HANDLE_VALUE;
2058    }
2059    // we don't need a handle on the process primary thread so we close
2060    // this now.
2061    CloseHandle(piProcInfo.hThread);
2062    return piProcInfo.hProcess;
2063 }
2064
2065 void
2066 ErrorExit (LPCSTR lpszMessage)
2067 {
2068     Dmsg1(0, "%s", lpszMessage);
2069 }
2070
2071
2072 /*
2073 typedef struct s_bpipe {
2074    pid_t worker_pid;
2075    time_t worker_stime;
2076    int wait;
2077    btimer_t *timer_id;
2078    FILE *rfd;
2079    FILE *wfd;
2080 } BPIPE;
2081 */
2082
2083 static void
2084 CloseIfValid(HANDLE handle)
2085 {
2086     if (handle != INVALID_HANDLE_VALUE)
2087         CloseHandle(handle);
2088 }
2089
2090 BPIPE *
2091 open_bpipe(char *prog, int wait, const char *mode)
2092 {
2093     HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
2094         hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
2095         hInputFile;
2096
2097     SECURITY_ATTRIBUTES saAttr;
2098
2099     BOOL fSuccess;
2100
2101     hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
2102         hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
2103         hInputFile = INVALID_HANDLE_VALUE;
2104
2105     BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
2106     memset((void *)bpipe, 0, sizeof(BPIPE));
2107
2108     int mode_read = (mode[0] == 'r');
2109     int mode_write = (mode[0] == 'w' || mode[1] == 'w');
2110
2111
2112     // Set the bInheritHandle flag so pipe handles are inherited.
2113
2114     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
2115     saAttr.bInheritHandle = TRUE;
2116     saAttr.lpSecurityDescriptor = NULL;
2117
2118     if (mode_read) {
2119
2120         // Create a pipe for the child process's STDOUT.
2121         if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
2122             ErrorExit("Stdout pipe creation failed\n");
2123             goto cleanup;
2124         }
2125         // Create noninheritable read handle and close the inheritable read
2126         // handle.
2127
2128         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
2129                                    GetCurrentProcess(), &hChildStdoutRdDup , 0,
2130                                    FALSE,
2131                                    DUPLICATE_SAME_ACCESS);
2132         if ( !fSuccess ) {
2133             ErrorExit("DuplicateHandle failed");
2134             goto cleanup;
2135         }
2136
2137         CloseHandle(hChildStdoutRd);
2138         hChildStdoutRd = INVALID_HANDLE_VALUE;
2139     }
2140
2141     if (mode_write) {
2142
2143         // Create a pipe for the child process's STDIN.
2144
2145         if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
2146             ErrorExit("Stdin pipe creation failed\n");
2147             goto cleanup;
2148         }
2149
2150         // Duplicate the write handle to the pipe so it is not inherited.
2151         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
2152                                    GetCurrentProcess(), &hChildStdinWrDup,
2153                                    0,
2154                                    FALSE,                  // not inherited
2155                                    DUPLICATE_SAME_ACCESS);
2156         if (!fSuccess) {
2157             ErrorExit("DuplicateHandle failed");
2158             goto cleanup;
2159         }
2160
2161         CloseHandle(hChildStdinWr);
2162         hChildStdinWr = INVALID_HANDLE_VALUE;
2163     }
2164     // spawn program with redirected handles as appropriate
2165     bpipe->worker_pid = (pid_t)
2166         CreateChildProcess(prog,             // commandline
2167                            hChildStdinRd,    // stdin HANDLE
2168                            hChildStdoutWr,   // stdout HANDLE
2169                            hChildStdoutWr);  // stderr HANDLE
2170
2171     if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
2172         goto cleanup;
2173
2174     bpipe->wait = wait;
2175     bpipe->worker_stime = time(NULL);
2176
2177     if (mode_read) {
2178         CloseHandle(hChildStdoutWr); // close our write side so when
2179                                      // process terminates we can
2180                                      // detect eof.
2181         // ugly but convert WIN32 HANDLE to FILE*
2182         int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY | O_BINARY);
2183         if (rfd >= 0) {
2184            bpipe->rfd = _fdopen(rfd, "rb");
2185         }
2186     }
2187     if (mode_write) {
2188         CloseHandle(hChildStdinRd); // close our read side so as not
2189                                     // to interfre with child's copy
2190         // ugly but convert WIN32 HANDLE to FILE*
2191         int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY | O_BINARY);
2192         if (wfd >= 0) {
2193            bpipe->wfd = _fdopen(wfd, "wb");
2194         }
2195     }
2196
2197     if (wait > 0) {
2198         bpipe->timer_id = start_child_timer(NULL, bpipe->worker_pid, wait);
2199     }
2200
2201     return bpipe;
2202
2203 cleanup:
2204
2205     CloseIfValid(hChildStdoutRd);
2206     CloseIfValid(hChildStdoutRdDup);
2207     CloseIfValid(hChildStdinWr);
2208     CloseIfValid(hChildStdinWrDup);
2209
2210     free((void *) bpipe);
2211     errno = b_errno_win32;            /* do GetLastError() for error code */
2212     return NULL;
2213 }
2214
2215
2216 int
2217 kill(int pid, int signal)
2218 {
2219    int rval = 0;
2220    if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
2221       rval = -1;
2222       errno = b_errno_win32;
2223    }
2224    CloseHandle((HANDLE)pid);
2225    return rval;
2226 }
2227
2228
2229 int
2230 close_bpipe(BPIPE *bpipe)
2231 {
2232    int rval = 0;
2233    int32_t remaining_wait = bpipe->wait;
2234
2235    /* Close pipes */
2236    if (bpipe->rfd) {
2237       fclose(bpipe->rfd);
2238       bpipe->rfd = NULL;
2239    }
2240    if (bpipe->wfd) {
2241       fclose(bpipe->wfd);
2242       bpipe->wfd = NULL;
2243    }
2244
2245    if (remaining_wait == 0) {         /* wait indefinitely */
2246       remaining_wait = INT32_MAX;
2247    }
2248    for ( ;; ) {
2249       DWORD exitCode;
2250       if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
2251          const char *err = errorString();
2252          rval = b_errno_win32;
2253          Dmsg1(0, "GetExitCode error %s\n", err);
2254          LocalFree((void *)err);
2255          break;
2256       }
2257       if (exitCode == STILL_ACTIVE) {
2258          if (remaining_wait <= 0) {
2259             rval = ETIME;             /* timed out */
2260             break;
2261          }
2262          bmicrosleep(1, 0);           /* wait one second */
2263          remaining_wait--;
2264       } else if (exitCode != 0) {
2265          /* Truncate exit code as it doesn't seem to be correct */
2266          rval = (exitCode & 0xFF) | b_errno_exit;
2267          break;
2268       } else {
2269          break;                       /* Shouldn't get here */
2270       }
2271    }
2272
2273    if (bpipe->timer_id) {
2274        stop_child_timer(bpipe->timer_id);
2275    }
2276    if (bpipe->rfd) fclose(bpipe->rfd);
2277    if (bpipe->wfd) fclose(bpipe->wfd);
2278    free((void *)bpipe);
2279    return rval;
2280 }
2281
2282 int
2283 close_wpipe(BPIPE *bpipe)
2284 {
2285     int result = 1;
2286
2287     if (bpipe->wfd) {
2288         fflush(bpipe->wfd);
2289         if (fclose(bpipe->wfd) != 0) {
2290             result = 0;
2291         }
2292         bpipe->wfd = NULL;
2293     }
2294     return result;
2295 }
2296
2297 int
2298 utime(const char *fname, struct utimbuf *times)
2299 {
2300     FILETIME acc, mod;
2301     char tmpbuf[5000];
2302
2303     conv_unix_to_win32_path(fname, tmpbuf, 5000);
2304
2305     cvt_utime_to_ftime(times->actime, acc);
2306     cvt_utime_to_ftime(times->modtime, mod);
2307
2308     HANDLE h = INVALID_HANDLE_VALUE;
2309
2310     if (p_CreateFileW) {
2311        POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2312        make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
2313
2314        h = p_CreateFileW((LPCWSTR)pwszBuf,
2315                         FILE_WRITE_ATTRIBUTES,
2316                         FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2317                         NULL,
2318                         OPEN_EXISTING,
2319                         FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2320                         NULL);
2321
2322        free_pool_memory(pwszBuf);
2323     } else if (p_CreateFileA) {
2324        h = p_CreateFileA(tmpbuf,
2325                         FILE_WRITE_ATTRIBUTES,
2326                         FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2327                         NULL,
2328                         OPEN_EXISTING,
2329                         FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2330                         NULL);
2331     }
2332
2333     if (h == INVALID_HANDLE_VALUE) {
2334        const char *err = errorString();
2335        Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2336        LocalFree((void *)err);
2337        errno = b_errno_win32;
2338        return -1;
2339     }
2340
2341     int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2342     CloseHandle(h);
2343     if (rval == -1) {
2344        errno = b_errno_win32;
2345     }
2346     return rval;
2347 }
2348
2349 #if 0
2350 int
2351 file_open(const char *file, int flags, int mode)
2352 {
2353    DWORD access = 0;
2354    DWORD shareMode = 0;
2355    DWORD create = 0;
2356    DWORD msflags = 0;
2357    HANDLE foo = INVALID_HANDLE_VALUE;
2358    const char *remap = file;
2359
2360    if (flags & O_WRONLY) access = GENERIC_WRITE;
2361    else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2362    else access = GENERIC_READ;
2363
2364    if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2365       create = CREATE_NEW;
2366    else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2367       create = CREATE_ALWAYS;
2368    else if (flags & O_CREAT)
2369       create = OPEN_ALWAYS;
2370    else if (flags & O_TRUNC)
2371       create = TRUNCATE_EXISTING;
2372    else 
2373       create = OPEN_EXISTING;
2374
2375    shareMode = 0;
2376
2377    if (flags & O_APPEND) {
2378       printf("open...APPEND not implemented yet.");
2379       exit(-1);
2380    }
2381
2382    if (p_CreateFileW) {
2383       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2384       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
2385
2386       foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
2387       free_pool_memory(pwszBuf);
2388    } else if (p_CreateFileA)
2389       foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
2390
2391    if (INVALID_HANDLE_VALUE == foo) {
2392       errno = b_errno_win32;
2393       return (int)-1;
2394    }
2395    return (int)foo;
2396
2397 }
2398
2399
2400 int
2401 file_close(int fd)
2402 {
2403     if (!CloseHandle((HANDLE)fd)) {
2404         errno = b_errno_win32;
2405         return -1;
2406     }
2407
2408     return 0;
2409 }
2410
2411 ssize_t
2412 file_write(int fd, const void *data, ssize_t len)
2413 {
2414     BOOL status;
2415     DWORD bwrite;
2416     status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2417     if (status) return bwrite;
2418     errno = b_errno_win32;
2419     return -1;
2420 }
2421
2422
2423 ssize_t
2424 file_read(int fd, void *data, ssize_t len)
2425 {
2426     BOOL status;
2427     DWORD bread;
2428
2429     status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2430     if (status) return bread;
2431     errno = b_errno_win32;
2432     return -1;
2433 }
2434
2435 boffset_t
2436 file_seek(int fd, boffset_t offset, int whence)
2437 {
2438     DWORD method = 0;
2439     DWORD val;
2440     LONG  offset_low = (LONG)offset;
2441     LONG  offset_high = (LONG)(offset >> 32);
2442
2443     switch (whence) {
2444     case SEEK_SET :
2445         method = FILE_BEGIN;
2446         break;
2447     case SEEK_CUR:
2448         method = FILE_CURRENT;
2449         break;
2450     case SEEK_END:
2451         method = FILE_END;
2452         break;
2453     default:
2454         errno = EINVAL;
2455         return -1;
2456     }
2457
2458
2459     if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
2460        errno = b_errno_win32;
2461        return -1;
2462     }
2463     /* ***FIXME*** I doubt this works right */
2464     return val;
2465 }
2466
2467 int
2468 file_dup2(int, int)
2469 {
2470     errno = ENOSYS;
2471     return -1;
2472 }
2473 #endif
2474
2475 /* 
2476  * Emulation of mmap and unmmap for tokyo dbm
2477  */
2478 void *mmap(void *start, size_t length, int prot, int flags,
2479            int fd, off_t offset)
2480 {
2481    DWORD fm_access = 0;
2482    DWORD mv_access = 0;
2483    HANDLE h;
2484    HANDLE mv;
2485
2486    if (length == 0) {
2487       return MAP_FAILED;
2488    }
2489    if (!fd) {
2490       return MAP_FAILED;
2491    }
2492
2493    if (flags & PROT_WRITE) {
2494       fm_access |= PAGE_READWRITE;
2495    } else if (flags & PROT_READ) {
2496       fm_access |= PAGE_READONLY;
2497    }
2498    
2499    if (flags & PROT_READ) {
2500       mv_access |= FILE_MAP_READ;
2501    }
2502    if (flags & PROT_WRITE) {
2503       mv_access |= FILE_MAP_WRITE;
2504    }
2505
2506    h = CreateFileMapping((HANDLE)_get_osfhandle (fd), 
2507                          NULL /* security */, 
2508                          fm_access, 
2509                          0 /* MaximumSizeHigh */, 
2510                          0 /* MaximumSizeLow */, 
2511                          NULL /* name of the file mapping object */);
2512
2513    if (!h || h == INVALID_HANDLE_VALUE) {
2514       return MAP_FAILED;
2515    }
2516
2517    mv = MapViewOfFile(h, mv_access, 
2518                       0 /* offset hi */, 
2519                       0 /* offset lo */,
2520                       length);
2521    CloseHandle(h);
2522
2523    if (!mv || mv == INVALID_HANDLE_VALUE) {
2524       return MAP_FAILED;
2525    }
2526
2527    return (void *) mv;
2528 }
2529
2530 int munmap(void *start, size_t length)
2531 {
2532    if (!start) {
2533       return -1;
2534    }
2535    UnmapViewOfFile(start);
2536    return 0;
2537 }
2538
2539 #ifdef HAVE_MINGW
2540 /* syslog function, added by Nicolas Boichat */
2541 void openlog(const char *ident, int option, int facility) {}  
2542 #endif //HAVE_MINGW