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