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