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