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