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