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