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