]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/compat.cpp
152dc23b1a011eae72eb6533fbe8dd763b487c57
[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 John Walker.
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       return 0;
648     }
649
650    HANDLE h = INVALID_HANDLE_VALUE;
651
652    // use unicode
653    if (p_FindFirstFileW) {
654       POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
655       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
656
657       h = p_FindFirstFileW((LPCWSTR)pwszBuf, &info_w);
658       free_pool_memory(pwszBuf);
659
660       pdwFileAttributes = &info_w.dwFileAttributes;
661       pdwReserved0      = &info_w.dwReserved0;
662       pnFileSizeHigh    = &info_w.nFileSizeHigh;
663       pnFileSizeLow     = &info_w.nFileSizeLow;
664       pftLastAccessTime = &info_w.ftLastAccessTime;
665       pftLastWriteTime  = &info_w.ftLastWriteTime;
666       pftCreationTime   = &info_w.ftCreationTime;
667
668    // use ASCII
669    } else if (p_FindFirstFileA) {
670       h = p_FindFirstFileA(file, &info_a);
671
672       pdwFileAttributes = &info_a.dwFileAttributes;
673       pdwReserved0      = &info_a.dwReserved0;
674       pnFileSizeHigh    = &info_a.nFileSizeHigh;
675       pnFileSizeLow     = &info_a.nFileSizeLow;
676       pftLastAccessTime = &info_a.ftLastAccessTime;
677       pftLastWriteTime  = &info_a.ftLastWriteTime;
678       pftCreationTime   = &info_a.ftCreationTime;
679    }
680
681    if (h == INVALID_HANDLE_VALUE) {
682       const char *err = errorString();
683       Dmsg2(99, "FindFirstFile(%s):%s\n", file, err);
684       LocalFree((void *)err);
685       errno = b_errno_win32;
686       return -1;
687    }
688
689    sb->st_mode = 0777;               /* start with everything */
690    if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
691        sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
692    if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
693        sb->st_mode &= ~S_IRWXO; /* remove everything for other */
694    if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
695        sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
696    sb->st_mode |= S_IFDIR;
697
698    /* Use st_rdev to store reparse attribute */
699    sb->st_rdev = (*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0; 
700    if (sb->st_rdev == 1 && *pdwReserved0 & IO_REPARSE_TAG_MOUNT_POINT) {
701       sb->st_rdev = 2;                /* mount point */
702    }
703
704    sb->st_size = *pnFileSizeHigh;
705    sb->st_size <<= 32;
706    sb->st_size |= *pnFileSizeLow;
707    sb->st_blksize = 4096;
708    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
709
710    sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
711    sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
712    sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
713    FindClose(h);
714
715    return 0;
716 }
717
718 int
719 fstat(int fd, struct stat *sb)
720 {
721    BY_HANDLE_FILE_INFORMATION info;
722    char tmpbuf[1024];
723
724    if (!GetFileInformationByHandle((HANDLE)fd, &info)) {
725        const char *err = errorString();
726        Dmsg2(99, "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
727        LocalFree((void *)err);
728        errno = b_errno_win32;
729        return -1;
730    }
731
732    sb->st_dev = info.dwVolumeSerialNumber;
733    sb->st_ino = info.nFileIndexHigh;
734    sb->st_ino <<= 32;
735    sb->st_ino |= info.nFileIndexLow;
736    sb->st_nlink = (short)info.nNumberOfLinks;
737    if (sb->st_nlink > 1) {
738       Dmsg1(99,  "st_nlink=%d\n", sb->st_nlink);
739    }
740
741    sb->st_mode = 0777;               /* start with everything */
742    if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
743        sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
744    if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
745        sb->st_mode &= ~S_IRWXO; /* remove everything for other */
746    if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
747        sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
748    sb->st_mode |= S_IFREG;
749
750    /* Use st_rdev to store reparse attribute */
751    sb->st_rdev = (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0; 
752
753    sb->st_size = info.nFileSizeHigh;
754    sb->st_size <<= 32;
755    sb->st_size |= info.nFileSizeLow;
756    sb->st_blksize = 4096;
757    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
758    sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
759    sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
760    sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
761
762    return 0;
763 }
764
765 static int
766 stat2(const char *file, struct stat *sb)
767 {
768    HANDLE h;
769    int rval = 0;
770    char tmpbuf[1024];
771    conv_unix_to_win32_path(file, tmpbuf, 1024);
772
773    DWORD attr = (DWORD)-1;
774
775    if (p_GetFileAttributesW) {
776       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
777       make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
778
779       attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
780       free_pool_memory(pwszBuf);
781    } else if (p_GetFileAttributesA) {
782       attr = p_GetFileAttributesA(tmpbuf);
783    }
784
785    if (attr == (DWORD)-1) {
786       const char *err = errorString();
787       Dmsg2(99, "GetFileAttributes(%s): %s\n", tmpbuf, err);
788       LocalFree((void *)err);
789       errno = b_errno_win32;
790       return -1;
791    }
792
793    h = CreateFileA(tmpbuf, GENERIC_READ,
794                   FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
795
796    if (h == INVALID_HANDLE_VALUE) {
797       const char *err = errorString();
798       Dmsg2(99, "Cannot open file for stat (%s):%s\n", tmpbuf, err);
799       LocalFree((void *)err);
800       errno = b_errno_win32;
801       return -1;
802    }
803
804    rval = fstat((int)h, sb);
805    CloseHandle(h);
806
807    if (attr & FILE_ATTRIBUTE_DIRECTORY &&
808         file[1] == ':' && file[2] != 0) {
809       statDir(file, sb);
810    }
811
812    return rval;
813 }
814
815 int
816 stat(const char *file, struct stat *sb)
817 {
818    WIN32_FILE_ATTRIBUTE_DATA data;
819    errno = 0;
820
821
822    memset(sb, 0, sizeof(*sb));
823
824    if (p_GetFileAttributesExW) {
825       /* dynamically allocate enough space for UCS2 filename */
826       POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
827       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
828
829       BOOL b = p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, &data);
830       free_pool_memory(pwszBuf);
831
832       if (!b) {
833          return stat2(file, sb);
834       }
835    } else if (p_GetFileAttributesExA) {
836       if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
837          return stat2(file, sb);
838        }
839    } else {
840       return stat2(file, sb);
841    }
842
843    sb->st_mode = 0777;               /* start with everything */
844    if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
845       sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
846    }
847    if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
848       sb->st_mode &= ~S_IRWXO; /* remove everything for other */
849    }
850    if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
851       sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
852    }
853    if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
854       sb->st_mode |= S_IFDIR;
855    } else {
856       sb->st_mode |= S_IFREG;
857    }
858
859    /* Use st_rdev to store reparse attribute */
860    sb->st_rdev = (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0; 
861
862    sb->st_nlink = 1;
863    sb->st_size = data.nFileSizeHigh;
864    sb->st_size <<= 32;
865    sb->st_size |= data.nFileSizeLow;
866    sb->st_blksize = 4096;
867    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
868    sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
869    sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
870    sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
871
872    /*
873     * If we are not at the root, then to distinguish a reparse 
874     *  point from a mount point, we must call FindFirstFile() to
875     *  get the WIN32_FIND_DATA, which has the bit that indicates
876     *  that this directory is a mount point -- aren't Win32 APIs
877     *  wonderful? (sarcasm).  The code exists in the statDir
878     *  subroutine.
879     */
880    if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && 
881         file[1] == ':' && file[2] != 0) {
882       statDir(file, sb);
883    }
884    return 0;
885 }
886
887 /*
888  * We write our own ftruncate because the one in the
889  *  Microsoft library mrcrt.dll does not truncate
890  *  files greater than 2GB.
891  *  KES - May 2007
892  */
893 int win32_ftruncate(int fd, int64_t length) 
894 {
895    /* Set point we want to truncate file */
896    __int64 pos = _lseeki64(fd, (__int64)length, SEEK_SET);
897
898    if (pos != (__int64)length) {
899       errno = EACCES;         /* truncation failed, get out */
900       return -1;
901    }
902
903    /* Truncate file */
904    if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0) {
905       errno = b_errno_win32;
906       return -1;
907    }
908    errno = 0;
909    return 0;
910 }
911
912 int fcntl(int fd, int cmd, long arg)
913 {
914    int rval = 0;
915
916    switch (cmd) {
917    case F_GETFL:
918       rval = O_NONBLOCK;
919       break;
920
921    case F_SETFL:
922       rval = 0;
923       break;
924
925    default:
926       errno = EINVAL;
927       rval = -1;
928       break;
929    }
930
931    return rval;
932 }
933
934 int
935 lstat(const char *file, struct stat *sb)
936 {
937    return stat(file, sb);
938 }
939
940 void
941 sleep(int sec)
942 {
943    Sleep(sec * 1000);
944 }
945
946 int
947 geteuid(void)
948 {
949    return 0;
950 }
951
952 int
953 execvp(const char *, char *[]) {
954    errno = ENOSYS;
955    return -1;
956 }
957
958
959 int
960 fork(void)
961 {
962    errno = ENOSYS;
963    return -1;
964 }
965
966 int
967 pipe(int[])
968 {
969    errno = ENOSYS;
970    return -1;
971 }
972
973 int
974 waitpid(int, int*, int)
975 {
976    errno = ENOSYS;
977    return -1;
978 }
979
980 int
981 readlink(const char *, char *, int)
982 {
983    errno = ENOSYS;
984    return -1;
985 }
986
987
988 #ifndef HAVE_MINGW
989 int
990 strcasecmp(const char *s1, const char *s2)
991 {
992    register int ch1, ch2;
993
994    if (s1==s2)
995       return 0;       /* strings are equal if same object. */
996    else if (!s1)
997       return -1;
998    else if (!s2)
999       return 1;
1000    do {
1001       ch1 = *s1;
1002       ch2 = *s2;
1003       s1++;
1004       s2++;
1005    } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
1006
1007    return(ch1 - ch2);
1008 }
1009 #endif //HAVE_MINGW
1010
1011 int
1012 strncasecmp(const char *s1, const char *s2, int len)
1013 {
1014    register int ch1 = 0, ch2 = 0;
1015
1016    if (s1==s2)
1017       return 0;       /* strings are equal if same object. */
1018    else if (!s1)
1019       return -1;
1020    else if (!s2)
1021       return 1;
1022
1023    while (len--) {
1024       ch1 = *s1;
1025       ch2 = *s2;
1026       s1++;
1027       s2++;
1028       if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
1029    }
1030
1031    return (ch1 - ch2);
1032 }
1033
1034 int
1035 gettimeofday(struct timeval *tv, struct timezone *)
1036 {
1037     SYSTEMTIME now;
1038     FILETIME tmp;
1039
1040     GetSystemTime(&now);
1041
1042     if (tv == NULL) {
1043        errno = EINVAL;
1044        return -1;
1045     }
1046     if (!SystemTimeToFileTime(&now, &tmp)) {
1047        errno = b_errno_win32;
1048        return -1;
1049     }
1050
1051     int64_t _100nsec = tmp.dwHighDateTime;
1052     _100nsec <<= 32;
1053     _100nsec |= tmp.dwLowDateTime;
1054     _100nsec -= WIN32_FILETIME_ADJUST;
1055
1056     tv->tv_sec = (long)(_100nsec / 10000000);
1057     tv->tv_usec = (long)((_100nsec % 10000000)/10);
1058     return 0;
1059
1060 }
1061
1062 /* For apcupsd this is in src/lib/wincompat.c */
1063 extern "C" void syslog(int type, const char *fmt, ...) 
1064 {
1065 /*#ifndef HAVE_CONSOLE
1066     MessageBox(NULL, msg, "Bacula", MB_OK);
1067 #endif*/
1068 }
1069
1070 void
1071 closelog()
1072 {
1073 }
1074
1075 struct passwd *
1076 getpwuid(uid_t)
1077 {
1078     return NULL;
1079 }
1080
1081 struct group *
1082 getgrgid(uid_t)
1083 {
1084     return NULL;
1085 }
1086
1087 // implement opendir/readdir/closedir on top of window's API
1088
1089 typedef struct _dir
1090 {
1091     WIN32_FIND_DATAA data_a;    // window's file info (ansii version)
1092     WIN32_FIND_DATAW data_w;    // window's file info (wchar version)
1093     const char *spec;           // the directory we're traversing
1094     HANDLE      dirh;           // the search handle
1095     BOOL        valid_a;        // the info in data_a field is valid
1096     BOOL        valid_w;        // the info in data_w field is valid
1097     UINT32      offset;         // pseudo offset for d_off
1098 } _dir;
1099
1100 DIR *
1101 opendir(const char *path)
1102 {
1103     /* enough space for VSS !*/
1104     int max_len = strlen(path) + MAX_PATH;
1105     _dir *rval = NULL;
1106     if (path == NULL) {
1107        errno = ENOENT;
1108        return NULL;
1109     }
1110
1111     Dmsg1(100, "Opendir path=%s\n", path);
1112     rval = (_dir *)malloc(sizeof(_dir));
1113     memset (rval, 0, sizeof (_dir));
1114     if (rval == NULL) return NULL;
1115     char *tspec = (char *)malloc(max_len);
1116     if (tspec == NULL) return NULL;
1117
1118     conv_unix_to_win32_path(path, tspec, max_len);
1119     Dmsg1(100, "win32 path=%s\n", tspec);
1120
1121     // add backslash only if there is none yet (think of c:\)
1122     if (tspec[strlen(tspec)-1] != '\\')
1123       bstrncat(tspec, "\\*", max_len);
1124     else
1125       bstrncat(tspec, "*", max_len);
1126
1127     rval->spec = tspec;
1128
1129     // convert to wchar_t
1130     if (p_FindFirstFileW) {
1131       POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
1132       make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec);
1133
1134       rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
1135
1136       free_pool_memory(pwcBuf);
1137
1138       if (rval->dirh != INVALID_HANDLE_VALUE)
1139         rval->valid_w = 1;
1140     } else if (p_FindFirstFileA) {
1141       rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
1142
1143       if (rval->dirh != INVALID_HANDLE_VALUE)
1144         rval->valid_a = 1;
1145     } else goto err;
1146
1147
1148     Dmsg3(99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
1149           path, rval->spec, rval->dirh);
1150
1151     rval->offset = 0;
1152     if (rval->dirh == INVALID_HANDLE_VALUE)
1153         goto err;
1154
1155     if (rval->valid_w) {
1156       Dmsg1(99, "\tFirstFile=%s\n", rval->data_w.cFileName);
1157     }
1158
1159     if (rval->valid_a) {
1160       Dmsg1(99, "\tFirstFile=%s\n", rval->data_a.cFileName);
1161     }
1162
1163     return (DIR *)rval;
1164
1165 err:
1166     free((void *)rval->spec);
1167     free(rval);
1168     errno = b_errno_win32;
1169     return NULL;
1170 }
1171
1172 int
1173 closedir(DIR *dirp)
1174 {
1175     _dir *dp = (_dir *)dirp;
1176     FindClose(dp->dirh);
1177     free((void *)dp->spec);
1178     free((void *)dp);
1179     return 0;
1180 }
1181
1182 /*
1183   typedef struct _WIN32_FIND_DATA {
1184     DWORD dwFileAttributes;
1185     FILETIME ftCreationTime;
1186     FILETIME ftLastAccessTime;
1187     FILETIME ftLastWriteTime;
1188     DWORD nFileSizeHigh;
1189     DWORD nFileSizeLow;
1190     DWORD dwReserved0;
1191     DWORD dwReserved1;
1192     TCHAR cFileName[MAX_PATH];
1193     TCHAR cAlternateFileName[14];
1194 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1195 */
1196
1197 static int
1198 copyin(struct dirent &dp, const char *fname)
1199 {
1200     dp.d_ino = 0;
1201     dp.d_reclen = 0;
1202     char *cp = dp.d_name;
1203     while (*fname) {
1204         *cp++ = *fname++;
1205         dp.d_reclen++;
1206     }
1207         *cp = 0;
1208     return dp.d_reclen;
1209 }
1210
1211 int
1212 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1213 {
1214     _dir *dp = (_dir *)dirp;
1215     if (dp->valid_w || dp->valid_a) {
1216       entry->d_off = dp->offset;
1217
1218       // copy unicode
1219       if (dp->valid_w) {
1220          char szBuf[MAX_PATH_UTF8+1];
1221          wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1222          dp->offset += copyin(*entry, szBuf);
1223       } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1224          dp->offset += copyin(*entry, dp->data_a.cFileName);
1225       }
1226
1227       *result = entry;              /* return entry address */
1228       Dmsg4(99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1229             dirp, entry->d_name, entry->d_reclen, entry->d_off);
1230     } else {
1231 //      Dmsg0(99, "readdir_r !valid\n");
1232         errno = b_errno_win32;
1233         return -1;
1234     }
1235
1236     // get next file, try unicode first
1237     if (p_FindNextFileW)
1238        dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1239     else if (p_FindNextFileA)
1240        dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1241     else {
1242        dp->valid_a = FALSE;
1243        dp->valid_w = FALSE;
1244     }
1245
1246     return 0;
1247 }
1248
1249 /*
1250  * Dotted IP address to network address
1251  *
1252  * Returns 1 if  OK
1253  *         0 on error
1254  */
1255 int
1256 inet_aton(const char *a, struct in_addr *inp)
1257 {
1258    const char *cp = a;
1259    uint32_t acc = 0, tmp = 0;
1260    int dotc = 0;
1261
1262    if (!isdigit(*cp)) {         /* first char must be digit */
1263       return 0;                 /* error */
1264    }
1265    do {
1266       if (isdigit(*cp)) {
1267          tmp = (tmp * 10) + (*cp -'0');
1268       } else if (*cp == '.' || *cp == 0) {
1269          if (tmp > 255) {
1270             return 0;           /* error */
1271          }
1272          acc = (acc << 8) + tmp;
1273          dotc++;
1274          tmp = 0;
1275       } else {
1276          return 0;              /* error */
1277       }
1278    } while (*cp++ != 0);
1279    if (dotc != 4) {              /* want 3 .'s plus EOS */
1280       return 0;                  /* error */
1281    }
1282    inp->s_addr = htonl(acc);     /* store addr in network format */
1283    return 1;
1284 }
1285
1286 int
1287 nanosleep(const struct timespec *req, struct timespec *rem)
1288 {
1289     if (rem)
1290         rem->tv_sec = rem->tv_nsec = 0;
1291     Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1292     return 0;
1293 }
1294
1295 void
1296 init_signals(void terminate(int sig))
1297 {
1298
1299 }
1300
1301 void
1302 init_stack_dump(void)
1303 {
1304
1305 }
1306
1307
1308 long
1309 pathconf(const char *path, int name)
1310 {
1311     switch(name) {
1312     case _PC_PATH_MAX :
1313         if (strncmp(path, "\\\\?\\", 4) == 0)
1314             return 32767;
1315     case _PC_NAME_MAX :
1316         return 255;
1317     }
1318     errno = ENOSYS;
1319     return -1;
1320 }
1321
1322 int
1323 WSA_Init(void)
1324 {
1325     WORD wVersionRequested = MAKEWORD( 1, 1);
1326     WSADATA wsaData;
1327
1328     int err = WSAStartup(wVersionRequested, &wsaData);
1329
1330
1331     if (err != 0) {
1332         printf("Can not start Windows Sockets\n");
1333         errno = ENOSYS;
1334         return -1;
1335     }
1336
1337     return 0;
1338 }
1339
1340
1341 int
1342 win32_chdir(const char *dir)
1343 {
1344    if (p_SetCurrentDirectoryW) {
1345       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1346       make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1347
1348       BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1349       
1350       free_pool_memory(pwszBuf);
1351
1352       if (!b) {
1353          errno = b_errno_win32;
1354          return -1;
1355       }
1356    }
1357    else if (p_SetCurrentDirectoryA) {
1358       if (0 == p_SetCurrentDirectoryA(dir)) {
1359          errno = b_errno_win32;
1360          return -1;
1361       }
1362    }
1363    else return -1;
1364
1365    return 0;
1366 }
1367
1368 int
1369 win32_mkdir(const char *dir)
1370 {
1371    if (p_wmkdir){
1372       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1373       make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1374
1375       int n = p_wmkdir((LPCWSTR)pwszBuf);
1376       free_pool_memory(pwszBuf);
1377       return n;
1378    }
1379
1380    return _mkdir(dir);
1381 }
1382
1383
1384 char *
1385 win32_getcwd(char *buf, int maxlen)
1386 {
1387    int n=0;
1388
1389    if (p_GetCurrentDirectoryW) {
1390       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1391       pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1392
1393       n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1394       if (n!=0)
1395          n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1396       free_pool_memory(pwszBuf);
1397
1398    } else if (p_GetCurrentDirectoryA)
1399       n = p_GetCurrentDirectoryA(maxlen, buf);
1400
1401    if (n == 0 || n > maxlen) return NULL;
1402
1403    if (n+1 > maxlen) return NULL;
1404    if (n != 3) {
1405        buf[n] = '\\';
1406        buf[n+1] = 0;
1407    }
1408    return buf;
1409 }
1410
1411 int
1412 win32_fputs(const char *string, FILE *stream)
1413 {
1414    /* we use WriteConsoleA / WriteConsoleA
1415       so we can be sure that unicode support works on win32.
1416       with fallback if something fails
1417    */
1418
1419    HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1420    if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1421        p_MultiByteToWideChar && (stream == stdout)) {
1422
1423       POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1424
1425       DWORD dwCharsWritten;
1426       DWORD dwChars;
1427
1428       dwChars = UTF8_2_wchar(&pwszBuf, string);
1429
1430       /* try WriteConsoleW */
1431       if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1432          free_pool_memory(pwszBuf);
1433          return dwCharsWritten;
1434       }
1435
1436       /* convert to local codepage and try WriteConsoleA */
1437       POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1438       pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1439
1440       dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR)pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1441       free_pool_memory(pwszBuf);
1442
1443       if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1444          free_pool_memory(pszBuf);
1445          return dwCharsWritten;
1446       }
1447       free_pool_memory(pszBuf);
1448    }
1449    /* Fall back */
1450    return fputs(string, stream);
1451 }
1452
1453 char*
1454 win32_cgets (char* buffer, int len)
1455 {
1456    /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1457       from the win32 console and fallback if seomething fails */
1458
1459    HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1460    if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1461       DWORD dwRead;
1462       wchar_t wszBuf[1024];
1463       char  szBuf[1024];
1464
1465       /* nt and unicode conversion */
1466       if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1467
1468          /* null terminate at end */
1469          if (wszBuf[dwRead-1] == L'\n') {
1470             wszBuf[dwRead-1] = L'\0';
1471             dwRead --;
1472          }
1473
1474          if (wszBuf[dwRead-1] == L'\r') {
1475             wszBuf[dwRead-1] = L'\0';
1476             dwRead --;
1477          }
1478
1479          wchar_2_UTF8(buffer, wszBuf, len);
1480          return buffer;
1481       }
1482
1483       /* win 9x and unicode conversion */
1484       if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1485
1486          /* null terminate at end */
1487          if (szBuf[dwRead-1] == L'\n') {
1488             szBuf[dwRead-1] = L'\0';
1489             dwRead --;
1490          }
1491
1492          if (szBuf[dwRead-1] == L'\r') {
1493             szBuf[dwRead-1] = L'\0';
1494             dwRead --;
1495          }
1496
1497          /* convert from ansii to wchar_t */
1498          p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1499          /* convert from wchar_t to UTF-8 */
1500          if (wchar_2_UTF8(buffer, wszBuf, len))
1501             return buffer;
1502       }
1503    }
1504
1505    /* fallback */
1506    if (fgets(buffer, len, stdin))
1507       return buffer;
1508    else
1509       return NULL;
1510 }
1511
1512 int
1513 win32_unlink(const char *filename)
1514 {
1515    int nRetCode;
1516    if (p_wunlink) {
1517       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1518       make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1519
1520       nRetCode = _wunlink((LPCWSTR) pwszBuf);
1521
1522       /* special case if file is readonly,
1523       we retry but unset attribute before */
1524       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1525          DWORD dwAttr =  p_GetFileAttributesW((LPCWSTR)pwszBuf);
1526          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1527             if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1528                nRetCode = _wunlink((LPCWSTR) pwszBuf);
1529                /* reset to original if it didn't help */
1530                if (nRetCode == -1)
1531                   p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1532             }
1533          }
1534       }
1535       free_pool_memory(pwszBuf);
1536    } else {
1537       nRetCode = _unlink(filename);
1538
1539       /* special case if file is readonly,
1540       we retry but unset attribute before */
1541       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1542          DWORD dwAttr =  p_GetFileAttributesA(filename);
1543          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1544             if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1545                nRetCode = _unlink(filename);
1546                /* reset to original if it didn't help */
1547                if (nRetCode == -1)
1548                   p_SetFileAttributesA(filename, dwAttr);
1549             }
1550          }
1551       }
1552    }
1553    return nRetCode;
1554 }
1555
1556
1557 #include "mswinver.h"
1558
1559 char WIN_VERSION_LONG[64];
1560 char WIN_VERSION[32];
1561 char WIN_RAWVERSION[32];
1562
1563 class winver {
1564 public:
1565     winver(void);
1566 };
1567
1568 static winver INIT;                     // cause constructor to be called before main()
1569
1570
1571 winver::winver(void)
1572 {
1573     const char *version = "";
1574     const char *platform = "";
1575     OSVERSIONINFO osvinfo;
1576     osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1577
1578     // Get the current OS version
1579     if (!GetVersionEx(&osvinfo)) {
1580         version = "Unknown";
1581         platform = "Unknown";
1582     }
1583         const int ver = _mkversion(osvinfo.dwPlatformId,
1584                                    osvinfo.dwMajorVersion,
1585                                    osvinfo.dwMinorVersion);
1586         snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1587         switch (ver)
1588         {
1589         case MS_WINDOWS_95: (version =  "Windows 95"); break;
1590         case MS_WINDOWS_98: (version =  "Windows 98"); break;
1591         case MS_WINDOWS_ME: (version =  "Windows ME"); break;
1592         case MS_WINDOWS_NT4:(version =  "Windows NT 4.0"); platform = "NT"; break;
1593         case MS_WINDOWS_2K: (version =  "Windows 2000");platform = "NT"; break;
1594         case MS_WINDOWS_XP: (version =  "Windows XP");platform = "NT"; break;
1595         case MS_WINDOWS_S2003: (version =  "Windows Server 2003");platform = "NT"; break;
1596         default: version = WIN_RAWVERSION; break;
1597         }
1598
1599     bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1600     snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1601              platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1602
1603 #if 0
1604     HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1605     CloseHandle(h);
1606 #endif
1607 #if 0
1608     BPIPE *b = open_bpipe("ls -l", 10, "r");
1609     char buf[1024];
1610     while (!feof(b->rfd)) {
1611         fgets(buf, sizeof(buf), b->rfd);
1612     }
1613     close_bpipe(b);
1614 #endif
1615 }
1616
1617 BOOL CreateChildProcess(VOID);
1618 VOID WriteToPipe(VOID);
1619 VOID ReadFromPipe(VOID);
1620 VOID ErrorExit(LPCSTR);
1621 VOID ErrMsg(LPTSTR, BOOL);
1622
1623 /**
1624  * Check for a quoted path,  if an absolute path name is given and it contains
1625  * spaces it will need to be quoted.  i.e.  "c:/Program Files/foo/bar.exe"
1626  * CreateProcess() says the best way to ensure proper results with executables
1627  * with spaces in path or filename is to quote the string.
1628  */
1629 const char *
1630 getArgv0(const char *cmdline)
1631 {
1632
1633     int inquote = 0;
1634     const char *cp;
1635     for (cp = cmdline; *cp; cp++)
1636     {
1637         if (*cp == '"') {
1638             inquote = !inquote;
1639         }
1640         if (!inquote && isspace(*cp))
1641             break;
1642     }
1643
1644
1645     int len = cp - cmdline;
1646     char *rval = (char *)malloc(len+1);
1647
1648     cp = cmdline;
1649     char *rp = rval;
1650
1651     while (len--)
1652         *rp++ = *cp++;
1653
1654     *rp = 0;
1655     return rval;
1656 }
1657
1658 /*
1659  * Extracts the executable or script name from the first string in 
1660  * cmdline.
1661  *
1662  * If the name contains blanks then it must be quoted with double quotes,
1663  * otherwise quotes are optional.  If the name contains blanks then it 
1664  * will be converted to a short name.
1665  *
1666  * The optional quotes will be removed.  The result is copied to a malloc'ed
1667  * buffer and returned through the pexe argument.  The pargs parameter is set
1668  * to the address of the character in cmdline located after the name.
1669  *
1670  * The malloc'ed buffer returned in *pexe must be freed by the caller.
1671  */
1672 bool
1673 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1674 {
1675    const char *pExeStart = NULL;    /* Start of executable name in cmdline */
1676    const char *pExeEnd = NULL;      /* Character after executable name (separator) */
1677
1678    const char *pBasename = NULL;    /* Character after last path separator */
1679    const char *pExtension = NULL;   /* Period at start of extension */
1680
1681    const char *current = cmdline;
1682
1683    bool bQuoted = false;
1684
1685    /* Skip initial whitespace */
1686
1687    while (*current == ' ' || *current == '\t')
1688    {
1689       current++;
1690    }
1691
1692    /* Calculate start of name and determine if quoted */
1693
1694    if (*current == '"') {
1695       pExeStart = ++current;
1696       bQuoted = true;
1697    } else {
1698       pExeStart = current;
1699       bQuoted = false;
1700    }
1701
1702    *pargs = NULL;
1703    *pexe = NULL;
1704
1705    /* 
1706     * Scan command line looking for path separators (/ and \\) and the 
1707     * terminator, either a quote or a blank.  The location of the 
1708     * extension is also noted.
1709     */
1710
1711    for ( ; *current != '\0'; current++)
1712    {
1713       if (*current == '.') {
1714          pExtension = current;
1715       } else if (IsPathSeparator(*current) && current[1] != '\0') {
1716          pBasename = &current[1];
1717          pExtension = NULL;
1718       }
1719
1720       /* Check for terminator, either quote or blank */
1721       if (bQuoted) {
1722          if (*current != '"') {
1723             continue;
1724          }
1725       } else {
1726          if (*current != ' ') {
1727             continue;
1728          }
1729       }
1730
1731       /*
1732        * Hit terminator, remember end of name (address of terminator) and 
1733        * start of arguments 
1734        */
1735       pExeEnd = current;
1736
1737       if (bQuoted && *current == '"') {
1738          *pargs = &current[1];
1739       } else {
1740          *pargs = current;
1741       }
1742
1743       break;
1744    }
1745
1746    if (pBasename == NULL) {
1747       pBasename = pExeStart;
1748    }
1749
1750    if (pExeEnd == NULL) {
1751       pExeEnd = current;
1752    }
1753
1754    if (*pargs == NULL)
1755    {
1756       *pargs = current;
1757    }
1758
1759    bool bHasPathSeparators = pExeStart != pBasename;
1760
1761    /* We have pointers to all the useful parts of the name */
1762
1763    /* Default extensions in the order cmd.exe uses to search */
1764
1765    static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
1766    DWORD dwBasePathLength = pExeEnd - pExeStart;
1767
1768    DWORD dwAltNameLength = 0;
1769    char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1770    char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1771
1772    pPathname[MAX_PATHLENGTH] = '\0';
1773    pAltPathname[MAX_PATHLENGTH] = '\0';
1774
1775    memcpy(pPathname, pExeStart, dwBasePathLength);
1776    pPathname[dwBasePathLength] = '\0';
1777
1778    if (pExtension == NULL) {
1779       /* Try appending extensions */
1780       for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
1781
1782          if (!bHasPathSeparators) {
1783             /* There are no path separators, search in the standard locations */
1784             dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
1785             if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1786                memcpy(pPathname, pAltPathname, dwAltNameLength);
1787                pPathname[dwAltNameLength] = '\0';
1788                break;
1789             }
1790          } else {
1791             bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
1792             if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) {
1793                break;
1794             }
1795             pPathname[dwBasePathLength] = '\0';
1796          }
1797       }
1798    } else if (!bHasPathSeparators) {
1799       /* There are no path separators, search in the standard locations */
1800       dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
1801       if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) {
1802          memcpy(pPathname, pAltPathname, dwAltNameLength);
1803          pPathname[dwAltNameLength] = '\0';
1804       }
1805    }
1806
1807    if (strchr(pPathname, ' ') != NULL) {
1808       dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH);
1809
1810       if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1811          *pexe = (char *)malloc(dwAltNameLength + 1);
1812          if (*pexe == NULL) {
1813             return false;
1814          }
1815          memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
1816       }
1817    }
1818
1819    if (*pexe == NULL) {
1820       DWORD dwPathnameLength = strlen(pPathname);
1821       *pexe = (char *)malloc(dwPathnameLength + 1);
1822       if (*pexe == NULL) {
1823          return false;
1824       }
1825       memcpy(*pexe, pPathname, dwPathnameLength + 1);
1826    }
1827
1828    return true;
1829 }
1830
1831 /**
1832  * OK, so it would seem CreateProcess only handles true executables:
1833  * .com or .exe files.  So grab $COMSPEC value and pass command line to it.
1834  */
1835 HANDLE
1836 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1837 {
1838    static const char *comspec = NULL;
1839    PROCESS_INFORMATION piProcInfo;
1840    STARTUPINFOA siStartInfo;
1841    BOOL bFuncRetn = FALSE;
1842
1843    if (comspec == NULL) {
1844       comspec = getenv("COMSPEC");
1845    }
1846    if (comspec == NULL) // should never happen
1847       return INVALID_HANDLE_VALUE;
1848
1849    // Set up members of the PROCESS_INFORMATION structure.
1850    ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1851
1852    // Set up members of the STARTUPINFO structure.
1853
1854    ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1855    siStartInfo.cb = sizeof(STARTUPINFO);
1856    // setup new process to use supplied handles for stdin,stdout,stderr
1857    // if supplied handles are not used the send a copy of our STD_HANDLE
1858    // as appropriate
1859    siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1860    siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
1861
1862    if (in != INVALID_HANDLE_VALUE)
1863       siStartInfo.hStdInput = in;
1864    else
1865       siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1866
1867    if (out != INVALID_HANDLE_VALUE)
1868       siStartInfo.hStdOutput = out;
1869    else
1870       siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1871    if (err != INVALID_HANDLE_VALUE)
1872       siStartInfo.hStdError = err;
1873    else
1874       siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1875
1876    // Create the child process.
1877
1878    char *exeFile;
1879    const char *argStart;
1880
1881    if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
1882       return INVALID_HANDLE_VALUE;
1883    }
1884
1885    int cmdLen = strlen(comspec) + 4 + strlen(exeFile) + strlen(argStart) + 1;
1886
1887    char *cmdLine = (char *)alloca(cmdLen);
1888
1889    snprintf(cmdLine, cmdLen, "%s /c %s%s", comspec, exeFile, argStart);
1890
1891    free(exeFile);
1892
1893    Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
1894
1895    // try to execute program
1896    bFuncRetn = CreateProcessA(comspec,
1897                               cmdLine,       // command line
1898                               NULL,          // process security attributes
1899                               NULL,          // primary thread security attributes
1900                               TRUE,          // handles are inherited
1901                               0,             // creation flags
1902                               NULL,          // use parent's environment
1903                               NULL,          // use parent's current directory
1904                               &siStartInfo,  // STARTUPINFO pointer
1905                               &piProcInfo);  // receives PROCESS_INFORMATION
1906
1907    if (bFuncRetn == 0) {
1908       ErrorExit("CreateProcess failed\n");
1909       const char *err = errorString();
1910       Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n", comspec, cmdLine, err);
1911       LocalFree((void *)err);
1912       return INVALID_HANDLE_VALUE;
1913    }
1914    // we don't need a handle on the process primary thread so we close
1915    // this now.
1916    CloseHandle(piProcInfo.hThread);
1917
1918    return piProcInfo.hProcess;
1919 }
1920
1921
1922 void
1923 ErrorExit (LPCSTR lpszMessage)
1924 {
1925     Dmsg1(0, "%s", lpszMessage);
1926 }
1927
1928
1929 /*
1930 typedef struct s_bpipe {
1931    pid_t worker_pid;
1932    time_t worker_stime;
1933    int wait;
1934    btimer_t *timer_id;
1935    FILE *rfd;
1936    FILE *wfd;
1937 } BPIPE;
1938 */
1939
1940 static void
1941 CloseIfValid(HANDLE handle)
1942 {
1943     if (handle != INVALID_HANDLE_VALUE)
1944         CloseHandle(handle);
1945 }
1946
1947 BPIPE *
1948 open_bpipe(char *prog, int wait, const char *mode)
1949 {
1950     HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1951         hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1952         hInputFile;
1953
1954     SECURITY_ATTRIBUTES saAttr;
1955
1956     BOOL fSuccess;
1957
1958     hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1959         hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1960         hInputFile = INVALID_HANDLE_VALUE;
1961
1962     BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1963     memset((void *)bpipe, 0, sizeof(BPIPE));
1964
1965     int mode_read = (mode[0] == 'r');
1966     int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1967
1968
1969     // Set the bInheritHandle flag so pipe handles are inherited.
1970
1971     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1972     saAttr.bInheritHandle = TRUE;
1973     saAttr.lpSecurityDescriptor = NULL;
1974
1975     if (mode_read) {
1976
1977         // Create a pipe for the child process's STDOUT.
1978         if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1979             ErrorExit("Stdout pipe creation failed\n");
1980             goto cleanup;
1981         }
1982         // Create noninheritable read handle and close the inheritable read
1983         // handle.
1984
1985         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1986                                    GetCurrentProcess(), &hChildStdoutRdDup , 0,
1987                                    FALSE,
1988                                    DUPLICATE_SAME_ACCESS);
1989         if ( !fSuccess ) {
1990             ErrorExit("DuplicateHandle failed");
1991             goto cleanup;
1992         }
1993
1994         CloseHandle(hChildStdoutRd);
1995         hChildStdoutRd = INVALID_HANDLE_VALUE;
1996     }
1997
1998     if (mode_write) {
1999
2000         // Create a pipe for the child process's STDIN.
2001
2002         if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
2003             ErrorExit("Stdin pipe creation failed\n");
2004             goto cleanup;
2005         }
2006
2007         // Duplicate the write handle to the pipe so it is not inherited.
2008         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
2009                                    GetCurrentProcess(), &hChildStdinWrDup,
2010                                    0,
2011                                    FALSE,                  // not inherited
2012                                    DUPLICATE_SAME_ACCESS);
2013         if (!fSuccess) {
2014             ErrorExit("DuplicateHandle failed");
2015             goto cleanup;
2016         }
2017
2018         CloseHandle(hChildStdinWr);
2019         hChildStdinWr = INVALID_HANDLE_VALUE;
2020     }
2021     // spawn program with redirected handles as appropriate
2022     bpipe->worker_pid = (pid_t)
2023         CreateChildProcess(prog,             // commandline
2024                            hChildStdinRd,    // stdin HANDLE
2025                            hChildStdoutWr,   // stdout HANDLE
2026                            hChildStdoutWr);  // stderr HANDLE
2027
2028     if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
2029         goto cleanup;
2030
2031     bpipe->wait = wait;
2032     bpipe->worker_stime = time(NULL);
2033
2034     if (mode_read) {
2035         CloseHandle(hChildStdoutWr); // close our write side so when
2036                                      // process terminates we can
2037                                      // detect eof.
2038         // ugly but convert WIN32 HANDLE to FILE*
2039         int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY | O_BINARY);
2040         if (rfd >= 0) {
2041            bpipe->rfd = _fdopen(rfd, "rb");
2042         }
2043     }
2044     if (mode_write) {
2045         CloseHandle(hChildStdinRd); // close our read side so as not
2046                                     // to interfre with child's copy
2047         // ugly but convert WIN32 HANDLE to FILE*
2048         int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY | O_BINARY);
2049         if (wfd >= 0) {
2050            bpipe->wfd = _fdopen(wfd, "wb");
2051         }
2052     }
2053
2054     if (wait > 0) {
2055         bpipe->timer_id = start_child_timer(NULL, bpipe->worker_pid, wait);
2056     }
2057
2058     return bpipe;
2059
2060 cleanup:
2061
2062     CloseIfValid(hChildStdoutRd);
2063     CloseIfValid(hChildStdoutRdDup);
2064     CloseIfValid(hChildStdinWr);
2065     CloseIfValid(hChildStdinWrDup);
2066
2067     free((void *) bpipe);
2068     errno = b_errno_win32;            /* do GetLastError() for error code */
2069     return NULL;
2070 }
2071
2072
2073 int
2074 kill(int pid, int signal)
2075 {
2076    int rval = 0;
2077    if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
2078       rval = -1;
2079       errno = b_errno_win32;
2080    }
2081    CloseHandle((HANDLE)pid);
2082    return rval;
2083 }
2084
2085
2086 int
2087 close_bpipe(BPIPE *bpipe)
2088 {
2089    int rval = 0;
2090    int32_t remaining_wait = bpipe->wait;
2091
2092    /* Close pipes */
2093    if (bpipe->rfd) {
2094       fclose(bpipe->rfd);
2095       bpipe->rfd = NULL;
2096    }
2097    if (bpipe->wfd) {
2098       fclose(bpipe->wfd);
2099       bpipe->wfd = NULL;
2100    }
2101
2102    if (remaining_wait == 0) {         /* wait indefinitely */
2103       remaining_wait = INT32_MAX;
2104    }
2105    for ( ;; ) {
2106       DWORD exitCode;
2107       if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
2108          const char *err = errorString();
2109          rval = b_errno_win32;
2110          Dmsg1(0, "GetExitCode error %s\n", err);
2111          LocalFree((void *)err);
2112          break;
2113       }
2114       if (exitCode == STILL_ACTIVE) {
2115          if (remaining_wait <= 0) {
2116             rval = ETIME;             /* timed out */
2117             break;
2118          }
2119          bmicrosleep(1, 0);           /* wait one second */
2120          remaining_wait--;
2121       } else if (exitCode != 0) {
2122          /* Truncate exit code as it doesn't seem to be correct */
2123          rval = (exitCode & 0xFF) | b_errno_exit;
2124          break;
2125       } else {
2126          break;                       /* Shouldn't get here */
2127       }
2128    }
2129
2130    if (bpipe->timer_id) {
2131        stop_child_timer(bpipe->timer_id);
2132    }
2133    if (bpipe->rfd) fclose(bpipe->rfd);
2134    if (bpipe->wfd) fclose(bpipe->wfd);
2135    free((void *)bpipe);
2136    return rval;
2137 }
2138
2139 int
2140 close_wpipe(BPIPE *bpipe)
2141 {
2142     int result = 1;
2143
2144     if (bpipe->wfd) {
2145         fflush(bpipe->wfd);
2146         if (fclose(bpipe->wfd) != 0) {
2147             result = 0;
2148         }
2149         bpipe->wfd = NULL;
2150     }
2151     return result;
2152 }
2153
2154 #include "findlib/find.h"
2155
2156 int
2157 utime(const char *fname, struct utimbuf *times)
2158 {
2159     FILETIME acc, mod;
2160     char tmpbuf[5000];
2161
2162     conv_unix_to_win32_path(fname, tmpbuf, 5000);
2163
2164     cvt_utime_to_ftime(times->actime, acc);
2165     cvt_utime_to_ftime(times->modtime, mod);
2166
2167     HANDLE h = INVALID_HANDLE_VALUE;
2168
2169     if (p_CreateFileW) {
2170       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2171       make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
2172
2173       h = p_CreateFileW((LPCWSTR)pwszBuf,
2174                         FILE_WRITE_ATTRIBUTES,
2175                         FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2176                         NULL,
2177                         OPEN_EXISTING,
2178                         FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2179                         NULL);
2180
2181       free_pool_memory(pwszBuf);
2182     } else if (p_CreateFileA) {
2183       h = p_CreateFileA(tmpbuf,
2184                         FILE_WRITE_ATTRIBUTES,
2185                         FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2186                         NULL,
2187                         OPEN_EXISTING,
2188                         FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2189                         NULL);
2190     }
2191
2192     if (h == INVALID_HANDLE_VALUE) {
2193         const char *err = errorString();
2194         Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2195         LocalFree((void *)err);
2196         errno = b_errno_win32;
2197         return -1;
2198     }
2199
2200     int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2201     CloseHandle(h);
2202     if (rval == -1) {
2203        errno = b_errno_win32;
2204     }
2205     return rval;
2206 }
2207
2208 #if 0
2209 int
2210 file_open(const char *file, int flags, int mode)
2211 {
2212     DWORD access = 0;
2213     DWORD shareMode = 0;
2214     DWORD create = 0;
2215     DWORD msflags = 0;
2216     HANDLE foo = INVALID_HANDLE_VALUE;
2217     const char *remap = file;
2218
2219     if (flags & O_WRONLY) access = GENERIC_WRITE;
2220     else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2221     else access = GENERIC_READ;
2222
2223     if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2224        create = CREATE_NEW;
2225     else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2226        create = CREATE_ALWAYS;
2227     else if (flags & O_CREAT)
2228        create = OPEN_ALWAYS;
2229     else if (flags & O_TRUNC)
2230        create = TRUNCATE_EXISTING;
2231     else 
2232        create = OPEN_EXISTING;
2233
2234     shareMode = 0;
2235
2236     if (flags & O_APPEND) {
2237         printf("open...APPEND not implemented yet.");
2238         exit(-1);
2239     }
2240
2241     if (p_CreateFileW) {
2242        POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2243        make_win32_path_UTF8_2_wchar(&pwszBuf, file);
2244
2245        foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
2246        free_pool_memory(pwszBuf);
2247     } else if (p_CreateFileA)
2248        foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
2249
2250     if (INVALID_HANDLE_VALUE == foo) {
2251         errno = b_errno_win32;
2252         return(int) -1;
2253     }
2254     return (int)foo;
2255
2256 }
2257
2258
2259 int
2260 file_close(int fd)
2261 {
2262     if (!CloseHandle((HANDLE)fd)) {
2263         errno = b_errno_win32;
2264         return -1;
2265     }
2266
2267     return 0;
2268 }
2269
2270 ssize_t
2271 file_write(int fd, const void *data, ssize_t len)
2272 {
2273     BOOL status;
2274     DWORD bwrite;
2275     status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2276     if (status) return bwrite;
2277     errno = b_errno_win32;
2278     return -1;
2279 }
2280
2281
2282 ssize_t
2283 file_read(int fd, void *data, ssize_t len)
2284 {
2285     BOOL status;
2286     DWORD bread;
2287
2288     status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2289     if (status) return bread;
2290     errno = b_errno_win32;
2291     return -1;
2292 }
2293
2294 boffset_t
2295 file_seek(int fd, boffset_t offset, int whence)
2296 {
2297     DWORD method = 0;
2298     DWORD val;
2299     LONG  offset_low = (LONG)offset;
2300     LONG  offset_high = (LONG)(offset >> 32);
2301
2302     switch (whence) {
2303     case SEEK_SET :
2304         method = FILE_BEGIN;
2305         break;
2306     case SEEK_CUR:
2307         method = FILE_CURRENT;
2308         break;
2309     case SEEK_END:
2310         method = FILE_END;
2311         break;
2312     default:
2313         errno = EINVAL;
2314         return -1;
2315     }
2316
2317
2318     if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
2319        errno = b_errno_win32;
2320        return -1;
2321     }
2322     /* ***FIXME*** I doubt this works right */
2323     return val;
2324 }
2325
2326 int
2327 file_dup2(int, int)
2328 {
2329     errno = ENOSYS;
2330     return -1;
2331 }
2332 #endif
2333
2334 #ifdef HAVE_MINGW
2335 /* syslog function, added by Nicolas Boichat */
2336 void openlog(const char *ident, int option, int facility) {}  
2337 #endif //HAVE_MINGW