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