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