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