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