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