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