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