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