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