]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/compat.cpp
0dc526753a710c53f5c7ca7065c20bebcb167303
[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 NULL;
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 NULL;
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    return (const char *) lpMsgBuf;
443 }
444
445 #ifndef HAVE_MINGW
446
447 static int
448 statDir(const char *file, struct stat *sb)
449 {
450    WIN32_FIND_DATAW info_w;       // window's file info
451    WIN32_FIND_DATAA info_a;       // window's file info
452
453    // cache some common vars to make code more transparent
454    DWORD* pdwFileAttributes;
455    DWORD* pnFileSizeHigh;
456    DWORD* pnFileSizeLow;
457    FILETIME* pftLastAccessTime;
458    FILETIME* pftLastWriteTime;
459    FILETIME* pftCreationTime;
460
461    if (file[1] == ':' && file[2] == 0) {
462         d_msg(__FILE__, __LINE__, 99, "faking ROOT attrs(%s).\n", file);
463         sb->st_mode = S_IFDIR;
464         sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
465         time(&sb->st_ctime);
466         time(&sb->st_mtime);
467         time(&sb->st_atime);
468         return 0;
469     }
470
471    HANDLE h = INVALID_HANDLE_VALUE;
472
473    // use unicode or ascii
474    if (p_FindFirstFileW) {
475       POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
476       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
477
478       h = p_FindFirstFileW((LPCWSTR) pwszBuf, &info_w);
479       free_pool_memory(pwszBuf);
480
481       pdwFileAttributes = &info_w.dwFileAttributes;
482       pnFileSizeHigh    = &info_w.nFileSizeHigh;
483       pnFileSizeLow     = &info_w.nFileSizeLow;
484       pftLastAccessTime = &info_w.ftLastAccessTime;
485       pftLastWriteTime  = &info_w.ftLastWriteTime;
486       pftCreationTime   = &info_w.ftCreationTime;
487    }
488    else if (p_FindFirstFileA) {
489       h = p_FindFirstFileA(file, &info_a);
490
491       pdwFileAttributes = &info_a.dwFileAttributes;
492       pnFileSizeHigh    = &info_a.nFileSizeHigh;
493       pnFileSizeLow     = &info_a.nFileSizeLow;
494       pftLastAccessTime = &info_a.ftLastAccessTime;
495       pftLastWriteTime  = &info_a.ftLastWriteTime;
496       pftCreationTime   = &info_a.ftCreationTime;
497    }
498
499     if (h == INVALID_HANDLE_VALUE) {
500         const char *err = errorString();
501         d_msg(__FILE__, __LINE__, 99, "FindFirstFile(%s):%s\n", file, err);
502         LocalFree((void *)err);
503         errno = b_errno_win32;
504         return -1;
505     }
506
507     sb->st_mode = 0777;               /* start with everything */
508     if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
509         sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
510     if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
511         sb->st_mode &= ~S_IRWXO; /* remove everything for other */
512     if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
513         sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
514     sb->st_mode |= S_IFDIR;
515
516     sb->st_size = *pnFileSizeHigh;
517     sb->st_size <<= 32;
518     sb->st_size |= *pnFileSizeLow;
519     sb->st_blksize = 4096;
520     sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
521
522     sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
523     sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
524     sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
525     FindClose(h);
526
527     return 0;
528 }
529
530 static int
531 stat2(const char *file, struct stat *sb)
532 {
533     BY_HANDLE_FILE_INFORMATION info;
534     HANDLE h;
535     int rval = 0;
536     char tmpbuf[1024];
537     conv_unix_to_win32_path(file, tmpbuf, 1024);
538
539     DWORD attr = -1;
540
541     if (p_GetFileAttributesW) {
542       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
543       make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
544
545       attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
546       free_pool_memory(pwszBuf);
547     } else if (p_GetFileAttributesA) {
548        attr = p_GetFileAttributesA(tmpbuf);
549     }
550
551     if (attr == -1) {
552         const char *err = errorString();
553         d_msg(__FILE__, __LINE__, 99,
554               "GetFileAttributes(%s): %s\n", tmpbuf, err);
555         LocalFree((void *)err);
556         errno = b_errno_win32;
557         return -1;
558     }
559
560     if (attr & FILE_ATTRIBUTE_DIRECTORY)
561         return statDir(tmpbuf, sb);
562
563     h = CreateFileA(tmpbuf, GENERIC_READ,
564                    FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
565
566     if (h == INVALID_HANDLE_VALUE) {
567         const char *err = errorString();
568         d_msg(__FILE__, __LINE__, 99,
569               "Cannot open file for stat (%s):%s\n", tmpbuf, err);
570         LocalFree((void *)err);
571         rval = -1;
572         errno = b_errno_win32;
573         goto error;
574     }
575
576     if (!GetFileInformationByHandle(h, &info)) {
577         const char *err = errorString();
578         d_msg(__FILE__, __LINE__, 99,
579               "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
580         LocalFree((void *)err);
581         rval = -1;
582         errno = b_errno_win32;
583         goto error;
584     }
585
586     sb->st_dev = info.dwVolumeSerialNumber;
587     sb->st_ino = info.nFileIndexHigh;
588     sb->st_ino <<= 32;
589     sb->st_ino |= info.nFileIndexLow;
590     sb->st_nlink = (short)info.nNumberOfLinks;
591     if (sb->st_nlink > 1) {
592        d_msg(__FILE__, __LINE__, 99,  "st_nlink=%d\n", sb->st_nlink);
593     }
594
595     sb->st_mode = 0777;               /* start with everything */
596     if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
597         sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
598     if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
599         sb->st_mode &= ~S_IRWXO; /* remove everything for other */
600     if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
601         sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
602     sb->st_mode |= S_IFREG;
603
604     sb->st_size = info.nFileSizeHigh;
605     sb->st_size <<= 32;
606     sb->st_size |= info.nFileSizeLow;
607     sb->st_blksize = 4096;
608     sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
609     sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
610     sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
611     sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
612
613 error:
614     CloseHandle(h);
615     return rval;
616 }
617
618 int
619 stat(const char *file, struct stat *sb)
620 {
621    WIN32_FILE_ATTRIBUTE_DATA data;
622    errno = 0;
623
624
625    memset(sb, 0, sizeof(*sb));
626
627    /* why not allow win 95 to use p_GetFileAttributesExA ? 
628     * this function allows _some_ open files to be stat'ed 
629     * if (g_platform_id == VER_PLATFORM_WIN32_WINDOWS) {
630     *    return stat2(file, sb);
631     * }
632     */
633
634    if (p_GetFileAttributesExW) {
635       /* dynamically allocate enough space for UCS2 filename */
636       POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
637       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
638
639       BOOL b = p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, &data);
640       free_pool_memory(pwszBuf);
641
642       if (!b) {
643          return stat2(file, sb);
644       }
645    } else if (p_GetFileAttributesExA) {
646       if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
647          return stat2(file, sb);
648        }
649    } else {
650       return stat2(file, sb);
651    }
652
653    sb->st_mode = 0777;               /* start with everything */
654    if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
655       sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
656    }
657    if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
658       sb->st_mode &= ~S_IRWXO; /* remove everything for other */
659    }
660    if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
661       sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
662    }
663    if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
664       sb->st_mode |= S_IFDIR;
665    } else {
666       sb->st_mode |= S_IFREG;
667    }
668
669    sb->st_nlink = 1;
670    sb->st_size = data.nFileSizeHigh;
671    sb->st_size <<= 32;
672    sb->st_size |= data.nFileSizeLow;
673    sb->st_blksize = 4096;
674    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
675    sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
676    sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
677    sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
678    return 0;
679 }
680
681 #endif //HAVE_MINGW
682
683 int
684 lstat(const char *file, struct stat *sb)
685 {
686    return stat(file, sb);
687 }
688
689 void
690 sleep(int sec)
691 {
692    Sleep(sec * 1000);
693 }
694
695 int
696 geteuid(void)
697 {
698    return 0;
699 }
700
701 int
702 execvp(const char *, char *[]) {
703    errno = ENOSYS;
704    return -1;
705 }
706
707
708 int
709 fork(void)
710 {
711    errno = ENOSYS;
712    return -1;
713 }
714
715 int
716 pipe(int[])
717 {
718    errno = ENOSYS;
719    return -1;
720 }
721
722 int
723 waitpid(int, int*, int)
724 {
725    errno = ENOSYS;
726    return -1;
727 }
728
729 int
730 readlink(const char *, char *, int)
731 {
732    errno = ENOSYS;
733    return -1;
734 }
735
736
737 #ifndef HAVE_MINGW
738 int
739 strcasecmp(const char *s1, const char *s2)
740 {
741    register int ch1, ch2;
742
743    if (s1==s2)
744       return 0;       /* strings are equal if same object. */
745    else if (!s1)
746       return -1;
747    else if (!s2)
748       return 1;
749    do {
750       ch1 = *s1;
751       ch2 = *s2;
752       s1++;
753       s2++;
754    } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
755
756    return(ch1 - ch2);
757 }
758 #endif //HAVE_MINGW
759
760 int
761 strncasecmp(const char *s1, const char *s2, int len)
762 {
763     register int ch1, ch2;
764
765     if (s1==s2)
766         return 0;       /* strings are equal if same object. */
767     else if (!s1)
768         return -1;
769     else if (!s2)
770         return 1;
771     while (len--) {
772         ch1 = *s1;
773         ch2 = *s2;
774         s1++;
775         s2++;
776         if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
777     }
778
779     return (ch1 - ch2);
780 }
781
782 int
783 gettimeofday(struct timeval *tv, struct timezone *)
784 {
785     SYSTEMTIME now;
786     FILETIME tmp;
787     GetSystemTime(&now);
788
789     if (tv == NULL) {
790        errno = EINVAL;
791        return -1;
792     }
793     if (!SystemTimeToFileTime(&now, &tmp)) {
794        errno = b_errno_win32;
795        return -1;
796     }
797
798     int64_t _100nsec = tmp.dwHighDateTime;
799     _100nsec <<= 32;
800     _100nsec |= tmp.dwLowDateTime;
801     _100nsec -= WIN32_FILETIME_ADJUST;
802
803     tv->tv_sec =(long) (_100nsec / 10000000);
804     tv->tv_usec = (long) ((_100nsec % 10000000)/10);
805     return 0;
806
807 }
808
809 int
810 syslog(int type, const char *fmt, const char *msg)
811 {
812 /*#ifndef HAVE_CONSOLE
813     MessageBox(NULL, msg, "Bacula", MB_OK);
814 #endif*/
815     return 0;
816 }
817
818 struct passwd *
819 getpwuid(uid_t)
820 {
821     return NULL;
822 }
823
824 struct group *
825 getgrgid(uid_t)
826 {
827     return NULL;
828 }
829
830 // implement opendir/readdir/closedir on top of window's API
831
832 typedef struct _dir
833 {
834     WIN32_FIND_DATAA data_a;    // window's file info (ansii version)
835     WIN32_FIND_DATAW data_w;    // window's file info (wchar version)
836     const char *spec;           // the directory we're traversing
837     HANDLE      dirh;           // the search handle
838     BOOL        valid_a;        // the info in data_a field is valid
839     BOOL        valid_w;        // the info in data_w field is valid
840     UINT32      offset;         // pseudo offset for d_off
841 } _dir;
842
843 DIR *
844 opendir(const char *path)
845 {
846     /* enough space for VSS !*/
847     int max_len = strlen(path) + MAX_PATH;
848     _dir *rval = NULL;
849     if (path == NULL) {
850        errno = ENOENT;
851        return NULL;
852     }
853
854     rval = (_dir *)malloc(sizeof(_dir));
855     memset (rval, 0, sizeof (_dir));
856     if (rval == NULL) return NULL;
857     char *tspec = (char *)malloc(max_len);
858     if (tspec == NULL) return NULL;
859
860     if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS) {
861 #ifdef WIN32_VSS
862        /* will append \\?\ at front itself */
863        conv_unix_to_win32_path(path, tspec, max_len-4);
864 #else
865        /* allow path to be 32767 bytes */
866        tspec[0] = '\\';
867        tspec[1] = '\\';
868        tspec[2] = '?';
869        tspec[3] = '\\';
870        tspec[4] = 0;
871        conv_unix_to_win32_path(path, tspec+4, max_len-4);
872 #endif
873     } else {
874        conv_unix_to_win32_path(path, tspec, max_len);
875     }
876
877     // add backslash only if there is none yet (think of c:\)
878     if (tspec[strlen(tspec)-1] != '\\')
879       bstrncat(tspec, "\\*", max_len);
880     else
881       bstrncat(tspec, "*", max_len);
882
883     rval->spec = tspec;
884
885     // convert to WCHAR
886     if (p_FindFirstFileW) {
887       POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
888       make_win32_path_UTF8_2_wchar(&pwcBuf,rval->spec);
889
890       rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
891
892       free_pool_memory(pwcBuf);
893
894       if (rval->dirh != INVALID_HANDLE_VALUE)
895         rval->valid_w = 1;
896     } else if (p_FindFirstFileA) {
897       rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
898
899       if (rval->dirh != INVALID_HANDLE_VALUE)
900         rval->valid_a = 1;
901     } else goto err;
902
903
904     d_msg(__FILE__, __LINE__,
905           99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
906           path, rval->spec, rval->dirh);
907
908     rval->offset = 0;
909     if (rval->dirh == INVALID_HANDLE_VALUE)
910         goto err;
911
912     if (rval->valid_w)
913       d_msg(__FILE__, __LINE__,
914             99, "\tFirstFile=%s\n", rval->data_w.cFileName);
915
916     if (rval->valid_a)
917       d_msg(__FILE__, __LINE__,
918             99, "\tFirstFile=%s\n", rval->data_a.cFileName);
919
920     return (DIR *)rval;
921
922 err:
923     free((void *)rval->spec);
924     free(rval);
925     errno = b_errno_win32;
926     return NULL;
927 }
928
929 int
930 closedir(DIR *dirp)
931 {
932     _dir *dp = (_dir *)dirp;
933     FindClose(dp->dirh);
934     free((void *)dp->spec);
935     free((void *)dp);
936     return 0;
937 }
938
939 /*
940   typedef struct _WIN32_FIND_DATA {
941     DWORD dwFileAttributes;
942     FILETIME ftCreationTime;
943     FILETIME ftLastAccessTime;
944     FILETIME ftLastWriteTime;
945     DWORD nFileSizeHigh;
946     DWORD nFileSizeLow;
947     DWORD dwReserved0;
948     DWORD dwReserved1;
949     TCHAR cFileName[MAX_PATH];
950     TCHAR cAlternateFileName[14];
951 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
952 */
953
954 static int
955 copyin(struct dirent &dp, const char *fname)
956 {
957     dp.d_ino = 0;
958     dp.d_reclen = 0;
959     char *cp = dp.d_name;
960     while (*fname) {
961         *cp++ = *fname++;
962         dp.d_reclen++;
963     }
964         *cp = 0;
965     return dp.d_reclen;
966 }
967
968 int
969 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
970 {
971     _dir *dp = (_dir *)dirp;
972     if (dp->valid_w || dp->valid_a) {
973       entry->d_off = dp->offset;
974
975       // copy unicode
976       if (dp->valid_w) {
977          char szBuf[MAX_PATH_UTF8+1];
978          wchar_2_UTF8(szBuf,dp->data_w.cFileName);
979          dp->offset += copyin(*entry, szBuf);
980       } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
981          dp->offset += copyin(*entry, dp->data_a.cFileName);
982       }
983
984       *result = entry;              /* return entry address */
985       d_msg(__FILE__, __LINE__,
986             99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
987             dirp, entry->d_name, entry->d_reclen, entry->d_off);
988     } else {
989 //      d_msg(__FILE__, __LINE__, 99, "readdir_r !valid\n");
990         errno = b_errno_win32;
991         return -1;
992     }
993
994     // get next file, try unicode first
995     if (p_FindNextFileW)
996        dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
997     else if (p_FindNextFileA)
998        dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
999     else {
1000        dp->valid_a = FALSE;
1001        dp->valid_w = FALSE;
1002     }
1003
1004     return 0;
1005 }
1006
1007 /*
1008  * Dotted IP address to network address
1009  *
1010  * Returns 1 if  OK
1011  *         0 on error
1012  */
1013 int
1014 inet_aton(const char *a, struct in_addr *inp)
1015 {
1016    const char *cp = a;
1017    uint32_t acc = 0, tmp = 0;
1018    int dotc = 0;
1019
1020    if (!isdigit(*cp)) {         /* first char must be digit */
1021       return 0;                 /* error */
1022    }
1023    do {
1024       if (isdigit(*cp)) {
1025          tmp = (tmp * 10) + (*cp -'0');
1026       } else if (*cp == '.' || *cp == 0) {
1027          if (tmp > 255) {
1028             return 0;           /* error */
1029          }
1030          acc = (acc << 8) + tmp;
1031          dotc++;
1032          tmp = 0;
1033       } else {
1034          return 0;              /* error */
1035       }
1036    } while (*cp++ != 0);
1037    if (dotc != 4) {              /* want 3 .'s plus EOS */
1038       return 0;                  /* error */
1039    }
1040    inp->s_addr = htonl(acc);     /* store addr in network format */
1041    return 1;
1042 }
1043
1044 int
1045 nanosleep(const struct timespec *req, struct timespec *rem)
1046 {
1047     if (rem)
1048         rem->tv_sec = rem->tv_nsec = 0;
1049     Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1050     return 0;
1051 }
1052
1053 void
1054 init_signals(void terminate(int sig))
1055 {
1056
1057 }
1058
1059 void
1060 init_stack_dump(void)
1061 {
1062
1063 }
1064
1065
1066 long
1067 pathconf(const char *path, int name)
1068 {
1069     switch(name) {
1070     case _PC_PATH_MAX :
1071         if (strncmp(path, "\\\\?\\", 4) == 0)
1072             return 32767;
1073     case _PC_NAME_MAX :
1074         return 255;
1075     }
1076     errno = ENOSYS;
1077     return -1;
1078 }
1079
1080 int
1081 WSA_Init(void)
1082 {
1083     WORD wVersionRequested = MAKEWORD( 1, 1);
1084     WSADATA wsaData;
1085
1086     int err = WSAStartup(wVersionRequested, &wsaData);
1087
1088
1089     if (err != 0) {
1090         printf("Can not start Windows Sockets\n");
1091         errno = ENOSYS;
1092         return -1;
1093     }
1094
1095     return 0;
1096 }
1097
1098
1099 int
1100 win32_chdir(const char *dir)
1101 {
1102    if (p_SetCurrentDirectoryW) {
1103       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1104       make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1105
1106       BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1107       
1108       free_pool_memory(pwszBuf);
1109
1110       if (!b) {
1111          errno = b_errno_win32;
1112          return -1;
1113       }
1114    }
1115    else if (p_SetCurrentDirectoryA) {
1116       if (0 == p_SetCurrentDirectoryA(dir)) {
1117          errno = b_errno_win32;
1118          return -1;
1119       }
1120    }
1121    else return -1;
1122
1123    return 0;
1124 }
1125
1126 int
1127 win32_mkdir(const char *dir)
1128 {
1129    if (p_wmkdir){
1130       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1131       make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1132
1133       int n = p_wmkdir((LPCWSTR)pwszBuf);
1134       free_pool_memory(pwszBuf);
1135       return n;
1136    }
1137
1138    return _mkdir(dir);
1139 }
1140
1141
1142 char *
1143 win32_getcwd(char *buf, int maxlen)
1144 {
1145    int n=0;
1146
1147    if (p_GetCurrentDirectoryW) {
1148       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1149       pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(WCHAR));
1150
1151       n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1152       if (n!=0)
1153          n = wchar_2_UTF8 (buf, (WCHAR*)pwszBuf, maxlen)-1;
1154       free_pool_memory(pwszBuf);
1155
1156    } else if (p_GetCurrentDirectoryA)
1157       n = p_GetCurrentDirectoryA(maxlen, buf);
1158
1159    if (n == 0 || n > maxlen) return NULL;
1160
1161    if (n+1 > maxlen) return NULL;
1162    if (n != 3) {
1163        buf[n] = '\\';
1164        buf[n+1] = 0;
1165    }
1166    return buf;
1167 }
1168
1169 int
1170 win32_fputs(const char *string, FILE *stream)
1171 {
1172    /* we use WriteConsoleA / WriteConsoleA
1173       so we can be sure that unicode support works on win32.
1174       with fallback if something fails
1175    */
1176
1177    HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1178    if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1179        p_MultiByteToWideChar && (stream == stdout)) {
1180
1181       POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1182
1183       DWORD dwCharsWritten;
1184       DWORD dwChars;
1185
1186       dwChars = UTF8_2_wchar(&pwszBuf, string);
1187
1188       /* try WriteConsoleW */
1189       if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1190          free_pool_memory(pwszBuf);
1191          return dwCharsWritten;
1192       }
1193
1194       /* convert to local codepage and try WriteConsoleA */
1195       POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1196       pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1197
1198       dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR) pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1199       free_pool_memory(pwszBuf);
1200
1201       if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1202          free_pool_memory(pszBuf);
1203          return dwCharsWritten;
1204       }
1205    }
1206
1207    return fputs(string, stream);
1208 }
1209
1210 char*
1211 win32_cgets (char* buffer, int len)
1212 {
1213    /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1214       from the win32 console and fallback if seomething fails */
1215
1216    HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1217    if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1218       DWORD dwRead;
1219       WCHAR wszBuf[1024];
1220       char  szBuf[1024];
1221
1222       /* nt and unicode conversion */
1223       if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1224
1225          /* null terminate at end */
1226          if (wszBuf[dwRead-1] == L'\n') {
1227             wszBuf[dwRead-1] = L'\0';
1228             dwRead --;
1229          }
1230
1231          if (wszBuf[dwRead-1] == L'\r') {
1232             wszBuf[dwRead-1] = L'\0';
1233             dwRead --;
1234          }
1235
1236          wchar_2_UTF8(buffer, wszBuf, len);
1237          return buffer;
1238       }
1239
1240       /* win 9x and unicode conversion */
1241       if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1242
1243          /* null terminate at end */
1244          if (szBuf[dwRead-1] == L'\n') {
1245             szBuf[dwRead-1] = L'\0';
1246             dwRead --;
1247          }
1248
1249          if (szBuf[dwRead-1] == L'\r') {
1250             szBuf[dwRead-1] = L'\0';
1251             dwRead --;
1252          }
1253
1254          /* convert from ansii to WCHAR */
1255          p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1256          /* convert from WCHAR to UTF-8 */
1257          if (wchar_2_UTF8(buffer, wszBuf, len))
1258             return buffer;
1259       }
1260    }
1261
1262    /* fallback */
1263    if (fgets(buffer, len, stdin))
1264       return buffer;
1265    else
1266       return NULL;
1267 }
1268
1269 int
1270 win32_unlink(const char *filename)
1271 {
1272    int nRetCode;
1273    if (p_wunlink) {
1274       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1275       make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1276
1277       nRetCode = _wunlink((LPCWSTR) pwszBuf);
1278
1279       /* special case if file is readonly,
1280       we retry but unset attribute before */
1281       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1282          DWORD dwAttr =  p_GetFileAttributesW((LPCWSTR)pwszBuf);
1283          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1284             if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1285                nRetCode = _wunlink((LPCWSTR) pwszBuf);
1286                /* reset to original if it didn't help */
1287                if (nRetCode == -1)
1288                   p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1289             }
1290          }
1291       }
1292       free_pool_memory(pwszBuf);
1293    } else {
1294       nRetCode = _unlink(filename);
1295
1296       /* special case if file is readonly,
1297       we retry but unset attribute before */
1298       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1299          DWORD dwAttr =  p_GetFileAttributesA(filename);
1300          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1301             if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1302                nRetCode = _unlink(filename);
1303                /* reset to original if it didn't help */
1304                if (nRetCode == -1)
1305                   p_SetFileAttributesA(filename, dwAttr);
1306             }
1307          }
1308       }
1309    }
1310    return nRetCode;
1311 }
1312
1313
1314 #include "mswinver.h"
1315
1316 char WIN_VERSION_LONG[64];
1317 char WIN_VERSION[32];
1318
1319 class winver {
1320 public:
1321     winver(void);
1322 };
1323
1324 static winver INIT;                     // cause constructor to be called before main()
1325
1326 #include "bacula.h"
1327 #include "jcr.h"
1328
1329 winver::winver(void)
1330 {
1331     const char *version = "";
1332     const char *platform = "";
1333     OSVERSIONINFO osvinfo;
1334     osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1335
1336     // Get the current OS version
1337     if (!GetVersionEx(&osvinfo)) {
1338         version = "Unknown";
1339         platform = "Unknown";
1340     }
1341     else
1342         switch (_mkversion(osvinfo.dwPlatformId, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion))
1343         {
1344         case MS_WINDOWS_95: (version =  "Windows 95"); break;
1345         case MS_WINDOWS_98: (version =  "Windows 98"); break;
1346         case MS_WINDOWS_ME: (version =  "Windows ME"); break;
1347         case MS_WINDOWS_NT4:(version =  "Windows NT 4.0"); platform = "NT"; break;
1348         case MS_WINDOWS_2K: (version =  "Windows 2000");platform = "NT"; break;
1349         case MS_WINDOWS_XP: (version =  "Windows XP");platform = "NT"; break;
1350         case MS_WINDOWS_S2003: (version =  "Windows Server 2003");platform = "NT"; break;
1351         default: version = "Windows ??"; break;
1352         }
1353
1354     bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1355     snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %d.%d.%d",
1356              platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1357
1358 #if 0
1359     HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1360     CloseHandle(h);
1361 #endif
1362 #if 0
1363     BPIPE *b = open_bpipe("ls -l", 10, "r");
1364     char buf[1024];
1365     while (!feof(b->rfd)) {
1366         fgets(buf, sizeof(buf), b->rfd);
1367     }
1368     close_bpipe(b);
1369 #endif
1370 }
1371
1372 BOOL CreateChildProcess(VOID);
1373 VOID WriteToPipe(VOID);
1374 VOID ReadFromPipe(VOID);
1375 VOID ErrorExit(LPCSTR);
1376 VOID ErrMsg(LPTSTR, BOOL);
1377
1378 /**
1379  * Check for a quoted path,  if an absolute path name is given and it contains
1380  * spaces it will need to be quoted.  i.e.  "c:/Program Files/foo/bar.exe"
1381  * CreateProcess() says the best way to ensure proper results with executables
1382  * with spaces in path or filename is to quote the string.
1383  */
1384 const char *
1385 getArgv0(const char *cmdline)
1386 {
1387
1388     int inquote = 0;
1389     const char *cp;
1390     for (cp = cmdline; *cp; cp++)
1391     {
1392         if (*cp == '"') {
1393             inquote = !inquote;
1394         }
1395         if (!inquote && isspace(*cp))
1396             break;
1397     }
1398
1399
1400     int len = cp - cmdline;
1401     char *rval = (char *)malloc(len+1);
1402
1403     cp = cmdline;
1404     char *rp = rval;
1405
1406     while (len--)
1407         *rp++ = *cp++;
1408
1409     *rp = 0;
1410     return rval;
1411 }
1412
1413
1414 /**
1415  * OK, so it would seem CreateProcess only handles true executables:
1416  *  .com or .exe files.
1417  * So test to see whether we're getting a .bat file and if so grab
1418  * $COMSPEC value and pass batch file to it.
1419  */
1420 HANDLE
1421 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1422 {
1423     PROCESS_INFORMATION piProcInfo;
1424     STARTUPINFOA siStartInfo;
1425     BOOL bFuncRetn = FALSE;
1426
1427     // Set up members of the PROCESS_INFORMATION structure.
1428
1429     ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1430
1431     // Set up members of the STARTUPINFO structure.
1432
1433     ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1434     siStartInfo.cb = sizeof(STARTUPINFO);
1435     // setup new process to use supplied handles for stdin,stdout,stderr
1436     // if supplied handles are not used the send a copy of our STD_HANDLE
1437     // as appropriate
1438     siStartInfo.dwFlags = STARTF_USESTDHANDLES;
1439
1440     if (in != INVALID_HANDLE_VALUE)
1441         siStartInfo.hStdInput = in;
1442     else
1443         siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1444
1445     if (out != INVALID_HANDLE_VALUE)
1446         siStartInfo.hStdOutput = out;
1447     else
1448         siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1449     if (err != INVALID_HANDLE_VALUE)
1450         siStartInfo.hStdError = err;
1451     else
1452         siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1453     // Create the child process.
1454
1455     char exeFile[256];
1456
1457     const char *comspec = getenv("COMSPEC");
1458
1459     if (comspec == NULL) // should never happen
1460         return INVALID_HANDLE_VALUE;
1461
1462     char *cmdLine = (char *)alloca(strlen(cmdline) + strlen(comspec) + 16);
1463
1464     strcpy(exeFile, comspec);
1465     strcpy(cmdLine, comspec);
1466     strcat(cmdLine, " /c ");
1467     strcat(cmdLine, cmdline);
1468
1469     // try to execute program
1470     bFuncRetn = CreateProcessA(exeFile,
1471                               cmdLine, // command line
1472                               NULL, // process security attributes
1473                               NULL, // primary thread security attributes
1474                               TRUE, // handles are inherited
1475                               0, // creation flags
1476                               NULL, // use parent's environment
1477                               NULL, // use parent's current directory
1478                               &siStartInfo, // STARTUPINFO pointer
1479                               &piProcInfo); // receives PROCESS_INFORMATION
1480
1481     if (bFuncRetn == 0) {
1482         ErrorExit("CreateProcess failed\n");
1483         const char *err = errorString();
1484         d_msg(__FILE__, __LINE__, 99,
1485               "CreateProcess(%s, %s, ...)=%s\n", exeFile, cmdLine, err);
1486         LocalFree((void *)err);
1487         return INVALID_HANDLE_VALUE;
1488     }
1489     // we don't need a handle on the process primary thread so we close
1490     // this now.
1491     CloseHandle(piProcInfo.hThread);
1492
1493     return piProcInfo.hProcess;
1494 }
1495
1496
1497 void
1498 ErrorExit (LPCSTR lpszMessage)
1499 {
1500     d_msg(__FILE__, __LINE__, 0, "%s", lpszMessage);
1501 }
1502
1503
1504 /*
1505 typedef struct s_bpipe {
1506    pid_t worker_pid;
1507    time_t worker_stime;
1508    int wait;
1509    btimer_t *timer_id;
1510    FILE *rfd;
1511    FILE *wfd;
1512 } BPIPE;
1513 */
1514
1515 static void
1516 CloseIfValid(HANDLE handle)
1517 {
1518     if (handle != INVALID_HANDLE_VALUE)
1519         CloseHandle(handle);
1520 }
1521
1522 #ifndef HAVE_MINGW
1523 BPIPE *
1524 open_bpipe(char *prog, int wait, const char *mode)
1525 {
1526     HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1527         hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1528         hInputFile;
1529
1530     SECURITY_ATTRIBUTES saAttr;
1531
1532     BOOL fSuccess;
1533
1534     hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1535         hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1536         hInputFile = INVALID_HANDLE_VALUE;
1537
1538     BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1539     memset((void *)bpipe, 0, sizeof(BPIPE));
1540
1541     int mode_read = (mode[0] == 'r');
1542     int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1543
1544
1545     // Set the bInheritHandle flag so pipe handles are inherited.
1546
1547     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1548     saAttr.bInheritHandle = TRUE;
1549     saAttr.lpSecurityDescriptor = NULL;
1550
1551     if (mode_read) {
1552
1553         // Create a pipe for the child process's STDOUT.
1554         if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1555             ErrorExit("Stdout pipe creation failed\n");
1556             goto cleanup;
1557         }
1558         // Create noninheritable read handle and close the inheritable read
1559         // handle.
1560
1561         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1562                                    GetCurrentProcess(), &hChildStdoutRdDup , 0,
1563                                    FALSE,
1564                                    DUPLICATE_SAME_ACCESS);
1565         if ( !fSuccess ) {
1566             ErrorExit("DuplicateHandle failed");
1567             goto cleanup;
1568         }
1569
1570         CloseHandle(hChildStdoutRd);
1571         hChildStdoutRd = INVALID_HANDLE_VALUE;
1572     }
1573
1574     if (mode_write) {
1575
1576         // Create a pipe for the child process's STDIN.
1577
1578         if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1579             ErrorExit("Stdin pipe creation failed\n");
1580             goto cleanup;
1581         }
1582
1583         // Duplicate the write handle to the pipe so it is not inherited.
1584         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
1585                                    GetCurrentProcess(), &hChildStdinWrDup,
1586                                    0,
1587                                    FALSE,                  // not inherited
1588                                    DUPLICATE_SAME_ACCESS);
1589         if (!fSuccess) {
1590             ErrorExit("DuplicateHandle failed");
1591             goto cleanup;
1592         }
1593
1594         CloseHandle(hChildStdinWr);
1595         hChildStdinWr = INVALID_HANDLE_VALUE;
1596     }
1597     // spawn program with redirected handles as appropriate
1598     bpipe->worker_pid = (pid_t)
1599         CreateChildProcess(prog,             // commandline
1600                            hChildStdinRd,    // stdin HANDLE
1601                            hChildStdoutWr,   // stdout HANDLE
1602                            hChildStdoutWr);  // stderr HANDLE
1603
1604     if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1605         goto cleanup;
1606
1607     bpipe->wait = wait;
1608     bpipe->worker_stime = time(NULL);
1609
1610     if (mode_read) {
1611         CloseHandle(hChildStdoutWr); // close our write side so when
1612                                      // process terminates we can
1613                                      // detect eof.
1614         // ugly but convert WIN32 HANDLE to FILE*
1615         int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY);
1616         if (rfd >= 0) {
1617            bpipe->rfd = _fdopen(rfd, "r");
1618         }
1619     }
1620     if (mode_write) {
1621         CloseHandle(hChildStdinRd); // close our read side so as not
1622                                     // to interfre with child's copy
1623         // ugly but convert WIN32 HANDLE to FILE*
1624         int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY);
1625         if (wfd >= 0) {
1626            bpipe->wfd = _fdopen(wfd, "w");
1627         }
1628     }
1629
1630     if (wait > 0) {
1631         bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
1632     }
1633
1634     return bpipe;
1635
1636 cleanup:
1637
1638     CloseIfValid(hChildStdoutRd);
1639     CloseIfValid(hChildStdoutRdDup);
1640     CloseIfValid(hChildStdinWr);
1641     CloseIfValid(hChildStdinWrDup);
1642
1643     free((void *) bpipe);
1644     errno = b_errno_win32;            /* do GetLastError() for error code */
1645     return NULL;
1646 }
1647
1648 #endif //HAVE_MINGW
1649
1650 int
1651 kill(int pid, int signal)
1652 {
1653    int rval = 0;
1654    if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
1655       rval = -1;
1656       errno = b_errno_win32;
1657    }
1658    CloseHandle((HANDLE)pid);
1659    return rval;
1660 }
1661
1662 #ifndef HAVE_MINGW
1663
1664 int
1665 close_bpipe(BPIPE *bpipe)
1666 {
1667    int rval = 0;
1668    int32_t remaining_wait = bpipe->wait;
1669
1670    if (remaining_wait == 0) {         /* wait indefinitely */
1671       remaining_wait = INT32_MAX;
1672    }
1673    for ( ;; ) {
1674       DWORD exitCode;
1675       if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
1676          const char *err = errorString();
1677          rval = b_errno_win32;
1678          d_msg(__FILE__, __LINE__, 0,
1679                "GetExitCode error %s\n", err);
1680          LocalFree((void *)err);
1681          break;
1682       }
1683       if (exitCode == STILL_ACTIVE) {
1684          if (remaining_wait <= 0) {
1685             rval = ETIME;             /* timed out */
1686             break;
1687          }
1688          bmicrosleep(1, 0);           /* wait one second */
1689          remaining_wait--;
1690       } else if (exitCode != 0) {
1691          /* Truncate exit code as it doesn't seem to be correct */
1692          rval = (exitCode & 0xFF) | b_errno_exit;
1693          break;
1694       } else {
1695          break;                       /* Shouldn't get here */
1696       }
1697    }
1698
1699    if (bpipe->timer_id) {
1700        stop_child_timer(bpipe->timer_id);
1701    }
1702    if (bpipe->rfd) fclose(bpipe->rfd);
1703    if (bpipe->wfd) fclose(bpipe->wfd);
1704    free((void *)bpipe);
1705    return rval;
1706 }
1707
1708 int
1709 close_wpipe(BPIPE *bpipe)
1710 {
1711     int stat = 1;
1712
1713     if (bpipe->wfd) {
1714         fflush(bpipe->wfd);
1715         if (fclose(bpipe->wfd) != 0) {
1716             stat = 0;
1717         }
1718         bpipe->wfd = NULL;
1719     }
1720     return stat;
1721 }
1722
1723 #include "findlib/find.h"
1724
1725 int
1726 utime(const char *fname, struct utimbuf *times)
1727 {
1728     FILETIME acc, mod;
1729     char tmpbuf[1024];
1730
1731     conv_unix_to_win32_path(fname, tmpbuf, 1024);
1732
1733     cvt_utime_to_ftime(times->actime, acc);
1734     cvt_utime_to_ftime(times->modtime, mod);
1735
1736     HANDLE h = INVALID_HANDLE_VALUE;
1737
1738     if (p_CreateFileW) {
1739       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1740       make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
1741
1742       h = p_CreateFileW((LPCWSTR) pwszBuf,
1743                         FILE_WRITE_ATTRIBUTES,
1744                         FILE_SHARE_WRITE,
1745                         NULL,
1746                         OPEN_EXISTING,
1747                         0,
1748                         NULL);
1749
1750       free_pool_memory(pwszBuf);
1751     } else if (p_CreateFileA) {
1752       h = p_CreateFileA(tmpbuf,
1753                         FILE_WRITE_ATTRIBUTES,
1754                         FILE_SHARE_WRITE,
1755                         NULL,
1756                         OPEN_EXISTING,
1757                         0,
1758                         NULL);
1759     }
1760
1761     if (h == INVALID_HANDLE_VALUE) {
1762         const char *err = errorString();
1763         d_msg(__FILE__, __LINE__, 99,
1764               "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
1765         LocalFree((void *)err);
1766         errno = b_errno_win32;
1767         return -1;
1768     }
1769
1770     int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
1771     CloseHandle(h);
1772     if (rval == -1) {
1773        errno = b_errno_win32;
1774     }
1775     return rval;
1776 }
1777
1778 #if USE_WIN32_COMPAT_IO
1779
1780 int
1781 open(const char *file, int flags, int mode)
1782 {
1783    if (p_wopen) {
1784       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1785       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
1786
1787       int nRet = p_wopen((LPCWSTR) pwszBuf, flags|_O_BINARY, mode);
1788       free_pool_memory(pwszBuf);
1789
1790       return nRet;
1791    }
1792
1793    return _open(file, flags|_O_BINARY, mode);
1794 }
1795
1796 /*
1797  * Note, this works only for a file. If you want
1798  *   to close a socket, use closesocket().
1799  *   Bacula has been modified in src/lib/bnet.c
1800  *   to use closesocket().
1801  */
1802 #ifndef HAVE_VC8
1803 int
1804 close(int fd)
1805 {
1806     return _close(fd);
1807 }
1808
1809 #ifndef HAVE_WXCONSOLE
1810 ssize_t
1811 read(int fd, void *buf, ssize_t len)
1812 {
1813     return _read(fd, buf, (size_t)len);
1814 }
1815
1816 ssize_t
1817 write(int fd, const void *buf, ssize_t len)
1818 {
1819     return _write(fd, buf, (size_t)len);
1820 }
1821 #endif
1822
1823
1824 off_t
1825 lseek(int fd, off_t offset, int whence)
1826 {
1827     return (off_t)_lseeki64(fd, offset, whence);
1828 }
1829
1830 int
1831 dup2(int fd1, int fd2)
1832 {
1833     return _dup2(fd1, fd2);
1834 }
1835 #endif
1836 #else
1837 int
1838 open(const char *file, int flags, int mode)
1839 {
1840     DWORD access = 0;
1841     DWORD shareMode = 0;
1842     DWORD create = 0;
1843     DWORD msflags = 0;
1844     HANDLE foo = INVALID_HANDLE_VALUE;
1845     const char *remap = file;
1846
1847     if (flags & O_WRONLY) access = GENERIC_WRITE;
1848     else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
1849     else access = GENERIC_READ;
1850
1851     if (flags & O_CREAT) create = CREATE_NEW;
1852     else create = OPEN_EXISTING;
1853
1854     if (flags & O_TRUNC) create = TRUNCATE_EXISTING;
1855
1856     if (!(flags & O_EXCL))
1857         shareMode = FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE;
1858
1859     if (flags & O_APPEND) {
1860         printf("open...APPEND not implemented yet.");
1861         exit(-1);
1862     }
1863
1864     if (p_CreateFileW) {
1865        POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1866        make_win32_path_UTF8_2_wchar(pwszBuf, file);
1867
1868        foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
1869        free_pool_memory(pwszBuf);
1870     }
1871     else if (p_CreateFileA)
1872        foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
1873
1874     if (INVALID_HANDLE_VALUE == foo) {
1875         errno = b_errno_win32;
1876         return(int) -1;
1877     }
1878     return (int)foo;
1879
1880 }
1881
1882
1883 int
1884 close(int fd)
1885 {
1886     if (!CloseHandle((HANDLE)fd)) {
1887         errno = b_errno_win32;
1888         return -1;
1889     }
1890
1891     return 0;
1892 }
1893
1894 ssize_t
1895 write(int fd, const void *data, ssize_t len)
1896 {
1897     BOOL status;
1898     DWORD bwrite;
1899     status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
1900     if (status) return bwrite;
1901     errno = b_errno_win32;
1902     return -1;
1903 }
1904
1905
1906 ssize_t
1907 read(int fd, void *data, ssize_t len)
1908 {
1909     BOOL status;
1910     DWORD bread;
1911
1912     status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
1913     if (status) return bread;
1914     errno = b_errno_win32;
1915     return -1;
1916 }
1917
1918 off_t
1919 lseek(int fd, off_t offset, int whence)
1920 {
1921     DWORD method = 0;
1922     DWORD val;
1923     switch (whence) {
1924     case SEEK_SET :
1925         method = FILE_BEGIN;
1926         break;
1927     case SEEK_CUR:
1928         method = FILE_CURRENT;
1929         break;
1930     case SEEK_END:
1931         method = FILE_END;
1932         break;
1933     default:
1934         errno = EINVAL;
1935         return -1;
1936     }
1937
1938     if ((val=SetFilePointer((HANDLE)fd, (DWORD)offset, NULL, method)) == INVALID_SET_FILE_POINTER) {
1939        errno = b_errno_win32;
1940        return -1;
1941     }
1942     /* ***FIXME*** I doubt this works right */
1943     return val;
1944 }
1945
1946 int
1947 dup2(int, int)
1948 {
1949     errno = ENOSYS;
1950     return -1;
1951 }
1952
1953
1954 #endif
1955
1956 #endif //HAVE_MINGW
1957
1958 #ifdef HAVE_MINGW
1959 /* syslog function, added by Nicolas Boichat */
1960 void closelog() {}
1961 #endif //HAVE_MINGW