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