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