]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/compat/compat.cpp
Tweak put compat.cpp debug on variable
[bacula/bacula] / bacula / src / win32 / compat / compat.cpp
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2004-2010 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 //                              -*- Mode: C++ -*-
29 // compat.cpp -- compatibilty layer to make bacula-fd run
30 //               natively under windows
31 //
32 // Copyright transferred from Raider Solutions, Inc to
33 //   Kern Sibbald and John Walker by express permission.
34 //
35 // Author          : Christopher S. Hull
36 // Created On      : Sat Jan 31 15:55:00 2004
37
38
39 #include "bacula.h"
40 #include "compat.h"
41 #include "jcr.h"
42 #include "findlib/find.h"
43
44 static const int dbglvl = 500;
45
46 #define b_errno_win32 (1<<29)
47
48 #define MAX_PATHLENGTH  1024
49
50 /**
51    UTF-8 to UCS2 path conversion is expensive,
52    so we cache the conversion. During backup the
53    conversion is called 3 times (lstat, attribs, open),
54    by using the cache this is reduced to 1 time
55  */
56 static POOLMEM *g_pWin32ConvUTF8Cache = NULL;
57 static POOLMEM *g_pWin32ConvUCS2Cache = NULL;
58 static DWORD g_dwWin32ConvUTF8strlen = 0;
59 static pthread_mutex_t Win32Convmutex = PTHREAD_MUTEX_INITIALIZER;
60
61 static t_pVSSPathConvert   g_pVSSPathConvert;
62 static t_pVSSPathConvertW  g_pVSSPathConvertW;
63
64 /* Forward referenced functions */
65 static const char *errorString(void);
66
67
68 void SetVSSPathConvert(t_pVSSPathConvert pPathConvert, t_pVSSPathConvertW pPathConvertW)
69 {
70    g_pVSSPathConvert = pPathConvert;
71    g_pVSSPathConvertW = pPathConvertW;
72 }
73
74 static void Win32ConvInitCache()
75 {
76    if (g_pWin32ConvUTF8Cache) {
77       return;
78    }
79    g_pWin32ConvUTF8Cache = get_pool_memory(PM_FNAME);
80    g_pWin32ConvUCS2Cache = get_pool_memory(PM_FNAME);
81 }
82
83 void Win32ConvCleanupCache()
84 {
85    P(Win32Convmutex);
86    if (g_pWin32ConvUTF8Cache) {
87       free_pool_memory(g_pWin32ConvUTF8Cache);
88       g_pWin32ConvUTF8Cache = NULL;
89    }
90
91    if (g_pWin32ConvUCS2Cache) {
92       free_pool_memory(g_pWin32ConvUCS2Cache);   
93       g_pWin32ConvUCS2Cache = NULL;
94    }
95
96    g_dwWin32ConvUTF8strlen = 0;
97    V(Win32Convmutex);
98 }
99
100
101 /* to allow the usage of the original version in this file here */
102 #undef fputs
103
104
105 //#define USE_WIN32_COMPAT_IO 1
106 #define USE_WIN32_32KPATHCONVERSION 1
107
108 extern DWORD   g_platform_id;
109 extern DWORD   g_MinorVersion;
110
111 /* From Microsoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970 */
112 #ifdef HAVE_MINGW
113 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL 
114 #else
115 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
116 #endif
117
118 #define WIN32_FILETIME_SCALE  10000000             // 100ns/second
119
120 /**
121  * Convert from UTF-8 to VSS Windows path/file 
122  *  Used by compatibility layer for Unix system calls
123  */
124 static void conv_unix_to_vss_win32_path(const char *name, char *win32_name, DWORD dwSize)
125 {
126     const char *fname = name;
127     char *tname = win32_name;
128
129     Dmsg0(dbglvl, "Enter convert_unix_to_win32_path\n");
130
131     if (IsPathSeparator(name[0]) &&
132         IsPathSeparator(name[1]) &&
133         name[2] == '.' &&
134         IsPathSeparator(name[3])) {
135
136         *win32_name++ = '\\';
137         *win32_name++ = '\\';
138         *win32_name++ = '.';
139         *win32_name++ = '\\';
140
141         name += 4;
142     } else if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS &&
143                g_pVSSPathConvert == NULL) {
144         /* allow path to be 32767 bytes */
145         *win32_name++ = '\\';
146         *win32_name++ = '\\';
147         *win32_name++ = '?';
148         *win32_name++ = '\\';
149     }
150
151     while (*name) {
152         /** Check for Unix separator and convert to Win32 */
153         if (name[0] == '/' && name[1] == '/') {  /* double slash? */
154            name++;                               /* yes, skip first one */
155         }
156         if (*name == '/') {
157             *win32_name++ = '\\';     /* convert char */
158         /* If Win32 separator that is "quoted", remove quote */
159         } else if (*name == '\\' && name[1] == '\\') {
160             *win32_name++ = '\\';
161             name++;                   /* skip first \ */
162         } else {
163             *win32_name++ = *name;    /* copy character */
164         }
165         name++;
166     }
167     /** Strip any trailing slash, if we stored something
168      * but leave "c:\" with backslash (root directory case
169      */
170     if (*fname != 0 && win32_name[-1] == '\\' && strlen (fname) != 3) {
171         win32_name[-1] = 0;
172     } else {
173         *win32_name = 0;
174     }
175
176     /** here we convert to VSS specific file name which
177        can get longer because VSS will make something like
178        \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
179        from c:\bacula\uninstall.exe
180     */
181     Dmsg1(dbglvl, "path=%s\n", tname);
182     if (g_pVSSPathConvert != NULL) {
183        POOLMEM *pszBuf = get_pool_memory (PM_FNAME);
184        pszBuf = check_pool_memory_size(pszBuf, dwSize);
185        bstrncpy(pszBuf, tname, strlen(tname)+1);
186        g_pVSSPathConvert(pszBuf, tname, dwSize);
187        free_pool_memory(pszBuf);
188     }
189
190     Dmsg1(dbglvl, "Leave cvt_u_to_win32_path path=%s\n", tname);
191 }
192
193 /** Conversion of a Unix filename to a Win32 filename */
194 void unix_name_to_win32(POOLMEM **win32_name, char *name)
195 {
196    /* One extra byte should suffice, but we double it */
197    /* add MAX_PATH bytes for VSS shadow copy name */
198    DWORD dwSize = 2*strlen(name)+MAX_PATH;
199    *win32_name = check_pool_memory_size(*win32_name, dwSize);
200    conv_unix_to_vss_win32_path(name, *win32_name, dwSize);
201 }
202
203
204 /**
205  * This function expects an UCS-encoded standard wchar_t in pszUCSPath and
206  * will complete the input path to an absolue path of the form \\?\c:\path\file
207  * 
208  * With this trick, it is possible to have 32K characters long paths.
209  *
210  * Optionally one can use pBIsRawPath to determine id pszUCSPath contains a path
211  * to a raw windows partition.  
212  *
213  *        created 02/27/2006 Thorsten Engel
214  */
215 static POOLMEM* 
216 make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/)
217 {
218
219    Dmsg0(dbglvl, "Enter wchar_win32_path\n");
220    if (pBIsRawPath) {
221       *pBIsRawPath = FALSE;              /* Initialize, set later */
222    }
223
224    if (!p_GetCurrentDirectoryW) {
225       Dmsg0(dbglvl, "Leave wchar_win32_path no change \n");
226       return pszUCSPath;
227    }
228    
229    wchar_t *name = (wchar_t *)pszUCSPath;
230
231    /* if it has already the desired form, exit without changes */
232    if (wcslen(name) > 3 && wcsncmp(name, L"\\\\?\\", 4) == 0) {
233       Dmsg0(dbglvl, "Leave wchar_win32_path no change \n");
234       return pszUCSPath;
235    }
236
237    wchar_t *pwszBuf = (wchar_t *)get_pool_memory(PM_FNAME);
238    wchar_t *pwszCurDirBuf = (wchar_t *)get_pool_memory(PM_FNAME);
239    DWORD dwCurDirPathSize = 0;
240
241    /* get buffer with enough size (name+max 6. wchars+1 null terminator */
242    DWORD dwBufCharsNeeded = (wcslen(name)+7);
243    pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
244       
245    /* add \\?\ to support 32K long filepaths 
246       it is important to make absolute paths, so we add drive and
247       current path if necessary */
248
249    BOOL bAddDrive = TRUE;
250    BOOL bAddCurrentPath = TRUE;
251    BOOL bAddPrefix = TRUE;
252
253    /* does path begin with drive? if yes, it is absolute */
254    if (iswalpha(name[0]) && name[1] == ':' && IsPathSeparator(name[2])) {
255       bAddDrive = FALSE;
256       bAddCurrentPath = FALSE;
257    }
258
259    /* is path absolute? */
260    if (IsPathSeparator(name[0]))
261       bAddCurrentPath = FALSE; 
262
263    /* is path relative to itself?, if yes, skip ./ */
264    if (name[0] == '.' && IsPathSeparator(name[1])) {
265       name += 2;
266    }
267
268    /* is path of form '//./'? */
269    if (IsPathSeparator(name[0]) && 
270        IsPathSeparator(name[1]) && 
271        name[2] == '.' && 
272        IsPathSeparator(name[3])) {
273       bAddDrive = FALSE;
274       bAddCurrentPath = FALSE;
275       bAddPrefix = FALSE;
276       if (pBIsRawPath) {
277          *pBIsRawPath = TRUE;
278       }
279    }
280
281    int nParseOffset = 0;
282    
283    /* add 4 bytes header */
284    if (bAddPrefix) {
285       nParseOffset = 4;
286       wcscpy(pwszBuf, L"\\\\?\\");
287    }
288
289    /* get current path if needed */
290    if (bAddDrive || bAddCurrentPath) {
291       dwCurDirPathSize = p_GetCurrentDirectoryW(0, NULL);
292       if (dwCurDirPathSize > 0) {
293          /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */         
294          pwszCurDirBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszCurDirBuf, (dwCurDirPathSize+1)*sizeof(wchar_t));
295          p_GetCurrentDirectoryW(dwCurDirPathSize, pwszCurDirBuf);
296       } else {
297          /* we have no info for doing so */
298          bAddDrive = FALSE;
299          bAddCurrentPath = FALSE;
300       }
301    }
302       
303
304    /* add drive if needed */
305    if (bAddDrive && !bAddCurrentPath) {
306       wchar_t szDrive[3];
307
308       if (IsPathSeparator(pwszCurDirBuf[0]) && 
309           IsPathSeparator(pwszCurDirBuf[1]) && 
310           pwszCurDirBuf[2] == '?' && 
311           IsPathSeparator(pwszCurDirBuf[3])) {
312          /* copy drive character */
313          szDrive[0] = pwszCurDirBuf[4];
314       } else {
315          /* copy drive character */
316          szDrive[0] = pwszCurDirBuf[0];
317       }
318
319       szDrive[1] = ':';
320       szDrive[2] = 0;
321
322       wcscat(pwszBuf, szDrive);
323       nParseOffset +=2;
324    }
325
326    /* add path if needed */
327    if (bAddCurrentPath) {
328       /* the 1 add. character is for the eventually added backslash */
329       dwBufCharsNeeded += dwCurDirPathSize+1; 
330       pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
331       /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
332       
333       if (IsPathSeparator(pwszCurDirBuf[0]) && 
334           IsPathSeparator(pwszCurDirBuf[1]) && 
335           pwszCurDirBuf[2] == '?' && 
336           IsPathSeparator(pwszCurDirBuf[3])) {
337          /* copy complete string */
338          wcscpy(pwszBuf, pwszCurDirBuf);
339       } else {
340          /* append path  */
341          wcscat(pwszBuf, pwszCurDirBuf);
342       }
343
344       nParseOffset = wcslen((LPCWSTR) pwszBuf);
345
346       /* check if path ends with backslash, if not, add one */
347       if (!IsPathSeparator(pwszBuf[nParseOffset-1])) {
348          wcscat(pwszBuf, L"\\");
349          nParseOffset++;
350       }
351    }
352
353    wchar_t *win32_name = &pwszBuf[nParseOffset];
354    wchar_t *name_start = name;
355
356    while (*name) {
357       /* Check for Unix separator and convert to Win32, eliminating 
358        * duplicate separators.
359        */
360       if (IsPathSeparator(*name)) {
361          *win32_name++ = '\\';     /* convert char */
362
363          /* Eliminate consecutive slashes, but not at the start so that 
364           * \\.\ still works.
365           */
366          if (name_start != name && IsPathSeparator(name[1])) {
367             name++;
368          }
369       } else {
370          *win32_name++ = *name;    /* copy character */
371       }
372       name++;
373    }
374
375    /* null terminate string */
376    *win32_name = 0;
377
378    /* here we convert to VSS specific file name which
379     * can get longer because VSS will make something like
380     * \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
381     * from c:\bacula\uninstall.exe
382    */ 
383    if (g_pVSSPathConvertW != NULL) {
384       /* is output buffer large enough? */
385       pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, 
386                                                   (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
387       /* create temp. buffer */
388       wchar_t *pszBuf = (wchar_t *)get_pool_memory(PM_FNAME);
389       pszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pszBuf, 
390                                                  (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
391       if (bAddPrefix)
392          nParseOffset = 4;
393       else
394          nParseOffset = 0; 
395       wcsncpy(pszBuf, &pwszBuf[nParseOffset], wcslen(pwszBuf)+1-nParseOffset);
396       g_pVSSPathConvertW(pszBuf, pwszBuf, dwBufCharsNeeded+MAX_PATH);
397       free_pool_memory((POOLMEM *)pszBuf);
398    }   
399
400    free_pool_memory(pszUCSPath);
401    free_pool_memory((POOLMEM *)pwszCurDirBuf);
402
403    Dmsg1(dbglvl, "Leave wchar_win32_path=%s\n", pwszBuf);
404    return (POOLMEM *)pwszBuf;
405 }
406
407 int
408 wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
409 {
410    /**
411     * The return value is the number of bytes written to the buffer.
412     * The number includes the byte for the null terminator.
413     */
414
415    if (p_WideCharToMultiByte) {
416       int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
417       ASSERT (nRet > 0);
418       return nRet;
419    } else {
420       return 0;
421    }
422 }
423
424 int
425 UTF8_2_wchar(POOLMEM **ppszUCS, const char *pszUTF)
426 {
427    /* the return value is the number of wide characters written to the buffer. */
428    /* convert null terminated string from utf-8 to ucs2, enlarge buffer if necessary */
429
430    if (p_MultiByteToWideChar) {
431       /* strlen of UTF8 +1 is enough */
432       DWORD cchSize = (strlen(pszUTF)+1);
433       *ppszUCS = check_pool_memory_size(*ppszUCS, cchSize*sizeof (wchar_t));
434
435       int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
436       ASSERT (nRet > 0);
437       return nRet;
438    } else {
439       return 0;
440    }
441 }
442
443
444 void
445 wchar_win32_path(const char *name, wchar_t *win32_name)
446 {
447     const char *fname = name;
448     while (*name) {
449         /* Check for Unix separator and convert to Win32 */
450         if (*name == '/') {
451             *win32_name++ = '\\';     /* convert char */
452         /* If Win32 separated that is "quoted", remove quote */
453         } else if (*name == '\\' && name[1] == '\\') {
454             *win32_name++ = '\\';
455             name++;                   /* skip first \ */
456         } else {
457             *win32_name++ = *name;    /* copy character */
458         }
459         name++;
460     }
461     /* Strip any trailing slash, if we stored something */
462     if (*fname != 0 && win32_name[-1] == '\\') {
463         win32_name[-1] = 0;
464     } else {
465         *win32_name = 0;
466     }
467 }
468
469 int 
470 make_win32_path_UTF8_2_wchar(POOLMEM **pszUCS, const char *pszUTF, BOOL* pBIsRawPath /*= NULL*/)
471 {
472    P(Win32Convmutex);
473    /* if we find the utf8 string in cache, we use the cached ucs2 version.
474       we compare the stringlength first (quick check) and then compare the content.            
475    */
476    if (!g_pWin32ConvUTF8Cache) {
477       Win32ConvInitCache();
478    } else if (g_dwWin32ConvUTF8strlen == strlen(pszUTF)) {
479       if (bstrcmp(pszUTF, g_pWin32ConvUTF8Cache)) {
480          /* Return cached value */
481          int32_t nBufSize = sizeof_pool_memory(g_pWin32ConvUCS2Cache);
482          *pszUCS = check_pool_memory_size(*pszUCS, nBufSize);      
483          wcscpy((LPWSTR) *pszUCS, (LPWSTR)g_pWin32ConvUCS2Cache);
484          V(Win32Convmutex);
485          return nBufSize / sizeof (WCHAR);
486       }
487    }
488
489    /* helper to convert from utf-8 to UCS-2 and to complete a path for 32K path syntax */
490    int nRet = UTF8_2_wchar(pszUCS, pszUTF);
491
492 #ifdef USE_WIN32_32KPATHCONVERSION
493    /* add \\?\ to support 32K long filepaths */
494    *pszUCS = make_wchar_win32_path(*pszUCS, pBIsRawPath);
495 #else
496    if (pBIsRawPath)
497       *pBIsRawPath = FALSE;
498 #endif
499
500    /* populate cache */      
501    g_pWin32ConvUCS2Cache = check_pool_memory_size(g_pWin32ConvUCS2Cache, sizeof_pool_memory(*pszUCS));
502    wcscpy((LPWSTR) g_pWin32ConvUCS2Cache, (LPWSTR) *pszUCS);
503    
504    g_dwWin32ConvUTF8strlen = strlen(pszUTF);
505    g_pWin32ConvUTF8Cache = check_pool_memory_size(g_pWin32ConvUTF8Cache, g_dwWin32ConvUTF8strlen+2);
506    bstrncpy(g_pWin32ConvUTF8Cache, pszUTF, g_dwWin32ConvUTF8strlen+1);
507    V(Win32Convmutex);
508
509    return nRet;
510 }
511
512 #if !defined(_MSC_VER) || (_MSC_VER < 1400) // VC8+
513 int umask(int)
514 {
515    return 0;
516 }
517 #endif
518
519 #ifndef LOAD_WITH_ALTERED_SEARCH_PATH
520 #define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008
521 #endif
522
523 void *dlopen(const char *file, int mode)
524 {
525    void *handle;
526
527    handle = LoadLibraryEx(file, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
528    return handle;
529 }
530
531 void *dlsym(void *handle, const char *name)
532 {
533    void *symaddr;
534    symaddr = (void *)GetProcAddress((HMODULE)handle, name);
535    return symaddr;
536 }
537
538 int dlclose(void *handle) 
539 {
540    if (handle && !FreeLibrary((HMODULE)handle)) {
541       errno = b_errno_win32;
542       return 1;        /* failed */
543    }
544    return 0;           /* OK */
545 }
546
547 char *dlerror(void) 
548 {
549    static char buf[200];
550    const char *err = errorString();
551    bstrncpy(buf, (char *)err, sizeof(buf));
552    LocalFree((void *)err);
553    return buf;
554 }
555
556 int fcntl(int fd, int cmd)
557 {
558    return 0;
559 }
560
561 int chown(const char *k, uid_t, gid_t)
562 {
563    return 0;
564 }
565
566 int lchown(const char *k, uid_t, gid_t)
567 {
568    return 0;
569 }
570
571 long int
572 random(void)
573 {
574     return rand();
575 }
576
577 void
578 srandom(unsigned int seed)
579 {
580    srand(seed);
581 }
582 // /////////////////////////////////////////////////////////////////
583 // convert from Windows concept of time to Unix concept of time
584 // /////////////////////////////////////////////////////////////////
585 void
586 cvt_utime_to_ftime(const time_t  &time, FILETIME &wintime)
587 {
588    uint64_t mstime = time;
589    mstime *= WIN32_FILETIME_SCALE;
590    mstime += WIN32_FILETIME_ADJUST;
591
592 #if defined(_MSC_VER)
593    wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
594 #else
595    wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL);
596 #endif
597    wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
598 }
599
600 time_t
601 cvt_ftime_to_utime(const FILETIME &time)
602 {
603     uint64_t mstime = time.dwHighDateTime;
604     mstime <<= 32;
605     mstime |= time.dwLowDateTime;
606
607     mstime -= WIN32_FILETIME_ADJUST;
608     mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
609
610     return (time_t) (mstime & 0xffffffff);
611 }
612
613 static const char *errorString(void)
614 {
615    LPVOID lpMsgBuf;
616
617    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
618                  FORMAT_MESSAGE_FROM_SYSTEM |
619                  FORMAT_MESSAGE_IGNORE_INSERTS,
620                  NULL,
621                  GetLastError(),
622                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
623                  (LPTSTR) &lpMsgBuf,
624                  0,
625                  NULL);
626
627    /* Strip any \r or \n */
628    char *rval = (char *) lpMsgBuf;
629    char *cp = strchr(rval, '\r');
630    if (cp != NULL) {
631       *cp = 0;
632    } else {
633       cp = strchr(rval, '\n');
634       if (cp != NULL)
635          *cp = 0;
636    }
637    return rval;
638 }
639
640
641 static int
642 statDir(const char *file, struct stat *sb)
643 {
644    WIN32_FIND_DATAW info_w;       // window's file info
645    WIN32_FIND_DATAA info_a;       // window's file info
646
647    // cache some common vars to make code more transparent
648    DWORD *pdwFileAttributes;
649    DWORD *pnFileSizeHigh;
650    DWORD *pnFileSizeLow;
651    DWORD *pdwReserved0;
652    FILETIME *pftLastAccessTime;
653    FILETIME *pftLastWriteTime;
654    FILETIME *pftCreationTime;
655
656    /* 
657     * Oh, cool, another exception: Microsoft doesn't let us do 
658     *  FindFile operations on a Drive, so simply fake root attibutes.
659     */
660    if (file[1] == ':' && file[2] == 0) {
661       time_t now = time(NULL);
662       Dmsg1(dbglvl, "faking ROOT attrs(%s).\n", file);
663       sb->st_mode = S_IFDIR;
664       sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
665       sb->st_ctime = now;
666       sb->st_mtime = now;
667       sb->st_atime = now;
668       sb->st_rdev = 0;
669       return 0;
670     }
671
672    HANDLE h = INVALID_HANDLE_VALUE;
673
674    // use unicode
675    if (p_FindFirstFileW) {
676       POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
677       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
678
679       Dmsg1(dbglvl, "FindFirstFileW=%s\n", file);
680       h = p_FindFirstFileW((LPCWSTR)pwszBuf, &info_w);
681       free_pool_memory(pwszBuf);
682
683       pdwFileAttributes = &info_w.dwFileAttributes;
684       pdwReserved0      = &info_w.dwReserved0;
685       pnFileSizeHigh    = &info_w.nFileSizeHigh;
686       pnFileSizeLow     = &info_w.nFileSizeLow;
687       pftLastAccessTime = &info_w.ftLastAccessTime;
688       pftLastWriteTime  = &info_w.ftLastWriteTime;
689       pftCreationTime   = &info_w.ftCreationTime;
690
691    // use ASCII
692    } else if (p_FindFirstFileA) {
693       Dmsg1(dbglvl, "FindFirstFileA=%s\n", file);
694       h = p_FindFirstFileA(file, &info_a);
695
696       pdwFileAttributes = &info_a.dwFileAttributes;
697       pdwReserved0      = &info_a.dwReserved0;
698       pnFileSizeHigh    = &info_a.nFileSizeHigh;
699       pnFileSizeLow     = &info_a.nFileSizeLow;
700       pftLastAccessTime = &info_a.ftLastAccessTime;
701       pftLastWriteTime  = &info_a.ftLastWriteTime;
702       pftCreationTime   = &info_a.ftCreationTime;
703    } else {
704       Dmsg0(dbglvl, "No findFirstFile A or W found\n");
705    }
706
707    if (h == INVALID_HANDLE_VALUE) {
708       const char *err = errorString();
709       /*
710        * Note, in creating leading paths, it is normal that
711        * the file does not exist.
712        */
713       Dmsg2(2099, "FindFirstFile(%s):%s\n", file, err);
714       LocalFree((void *)err);
715       errno = b_errno_win32;
716       return -1;
717    } else {
718       FindClose(h);
719    }
720
721    sb->st_mode = 0777;               /* start with everything */
722    if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
723        sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
724    if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
725        sb->st_mode &= ~S_IRWXO; /* remove everything for other */
726    if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
727        sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
728    sb->st_mode |= S_IFDIR;
729
730    /* 
731     * Store reparse/mount point info in st_rdev.  Note a
732     *  Win32 reparse point (junction point) is like a link
733     *  though it can have many properties (directory link,
734     *  soft link, hard link, HSM, ...
735     *  A mount point is a reparse point where another volume
736     *  is mounted, so it is like a Unix mount point (change of
737     *  filesystem).
738     */
739    if (*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
740       if (*pdwReserved0 & IO_REPARSE_TAG_MOUNT_POINT) {
741          sb->st_rdev = WIN32_MOUNT_POINT;           /* mount point */
742       } else {
743          sb->st_rdev = WIN32_REPARSE_POINT;         /* reparse point */
744       }
745    }  
746    Dmsg2(dbglvl, "st_rdev=%d file=%s\n", sb->st_rdev, file);
747    sb->st_size = *pnFileSizeHigh;
748    sb->st_size <<= 32;
749    sb->st_size |= *pnFileSizeLow;
750    sb->st_blksize = 4096;
751    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
752
753    sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
754    sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
755    sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
756
757    return 0;
758 }
759
760 int
761 fstat(intptr_t fd, struct stat *sb)
762 {
763    BY_HANDLE_FILE_INFORMATION info;
764
765    if (!GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
766        const char *err = errorString();
767        Dmsg1(2099, "GetfileInformationByHandle: %s\n", err);
768        LocalFree((void *)err);
769        errno = b_errno_win32;
770        return -1;
771    }
772
773    sb->st_dev = info.dwVolumeSerialNumber;
774    sb->st_ino = info.nFileIndexHigh;
775    sb->st_ino <<= 32;
776    sb->st_ino |= info.nFileIndexLow;
777    sb->st_nlink = (short)info.nNumberOfLinks;
778    if (sb->st_nlink > 1) {
779       Dmsg1(dbglvl,  "st_nlink=%d\n", sb->st_nlink);
780    }
781
782    sb->st_mode = 0777;               /* start with everything */
783    if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
784        sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
785    if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
786        sb->st_mode &= ~S_IRWXO; /* remove everything for other */
787    if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
788        sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
789    sb->st_mode |= S_IFREG;
790
791    /* Use st_rdev to store reparse attribute */
792    if  (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
793       sb->st_rdev = WIN32_REPARSE_POINT;
794    }
795    Dmsg3(dbglvl, "st_rdev=%d sizino=%d ino=%lld\n", sb->st_rdev, sizeof(sb->st_ino),
796       (long long)sb->st_ino);
797
798    sb->st_size = info.nFileSizeHigh;
799    sb->st_size <<= 32;
800    sb->st_size |= info.nFileSizeLow;
801    sb->st_blksize = 4096;
802    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
803    sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
804    sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
805    sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
806
807    return 0;
808 }
809
810 static int
811 stat2(const char *file, struct stat *sb)
812 {
813    HANDLE h = INVALID_HANDLE_VALUE;
814    int rval = 0;
815    char tmpbuf[5000];
816    conv_unix_to_vss_win32_path(file, tmpbuf, 5000);
817
818    DWORD attr = (DWORD)-1;
819
820    if (p_GetFileAttributesW) {
821       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
822       make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
823
824       attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
825       if (p_CreateFileW) {
826          h = CreateFileW((LPCWSTR)pwszBuf, GENERIC_READ,
827                 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
828       }
829       free_pool_memory(pwszBuf);
830    } else if (p_GetFileAttributesA) {
831       attr = p_GetFileAttributesA(tmpbuf);
832       h = CreateFileA(tmpbuf, GENERIC_READ,
833                FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
834    }
835
836    if (attr == (DWORD)-1) {
837       const char *err = errorString();
838       Dmsg2(2099, "GetFileAttributes(%s): %s\n", tmpbuf, err);
839       LocalFree((void *)err);
840       if (h != INVALID_HANDLE_VALUE) {
841          CloseHandle(h);
842       }
843       errno = b_errno_win32;
844       return -1;
845    }
846
847    if (h == INVALID_HANDLE_VALUE) {
848       const char *err = errorString();
849       Dmsg2(2099, "Cannot open file for stat (%s):%s\n", tmpbuf, err);
850       LocalFree((void *)err);
851       errno = b_errno_win32;
852       return -1;
853    }
854
855    rval = fstat((intptr_t)h, sb);
856    CloseHandle(h);
857
858    if (attr & FILE_ATTRIBUTE_DIRECTORY &&
859         file[1] == ':' && file[2] != 0) {
860       rval = statDir(file, sb);
861    }
862    return rval;
863 }
864
865 int
866 stat(const char *file, struct stat *sb)
867 {
868    WIN32_FILE_ATTRIBUTE_DATA data;
869    errno = 0;
870
871    memset(sb, 0, sizeof(*sb));
872
873    if (p_GetFileAttributesExW) {
874       /* dynamically allocate enough space for UCS2 filename */
875       POOLMEM *pwszBuf = get_pool_memory(PM_FNAME);
876       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
877
878       BOOL b = p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, &data);
879       free_pool_memory(pwszBuf);
880
881       if (!b) {
882          return stat2(file, sb);
883       }
884
885    } else if (p_GetFileAttributesExA) {
886       if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
887          return stat2(file, sb);
888        }
889    } else {
890       return stat2(file, sb);
891    }
892
893    sb->st_mode = 0777;               /* start with everything */
894    if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
895       sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
896    }
897    if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
898       sb->st_mode &= ~S_IRWXO; /* remove everything for other */
899    }
900    if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
901       sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
902    }
903    if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
904       sb->st_mode |= S_IFDIR;
905    } else {
906       sb->st_mode |= S_IFREG;
907    }
908
909    /* Use st_rdev to store reparse attribute */
910    sb->st_rdev = (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0; 
911
912    sb->st_nlink = 1;
913    sb->st_size = data.nFileSizeHigh;
914    sb->st_size <<= 32;
915    sb->st_size |= data.nFileSizeLow;
916    sb->st_blksize = 4096;
917    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
918    sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
919    sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
920    sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
921
922    /*
923     * If we are not at the root, then to distinguish a reparse 
924     *  point from a mount point, we must call FindFirstFile() to
925     *  get the WIN32_FIND_DATA, which has the bit that indicates
926     *  that this directory is a mount point -- aren't Win32 APIs
927     *  wonderful? (sarcasm).  The code exists in the statDir
928     *  subroutine.
929     */
930    if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && 
931         file[1] == ':' && file[2] != 0) {
932       statDir(file, sb);
933    }
934    Dmsg3(dbglvl, "sizino=%d ino=%lld file=%s\n", sizeof(sb->st_ino),
935                        (long long)sb->st_ino, file);
936    return 0;
937 }
938
939 /*
940  * We write our own ftruncate because the one in the
941  *  Microsoft library mrcrt.dll does not truncate
942  *  files greater than 2GB.
943  *  KES - May 2007
944  */
945 int win32_ftruncate(int fd, int64_t length) 
946 {
947    /* Set point we want to truncate file */
948    __int64 pos = _lseeki64(fd, (__int64)length, SEEK_SET);
949
950    if (pos != (__int64)length) {
951       errno = EACCES;         /* truncation failed, get out */
952       return -1;
953    }
954
955    /* Truncate file */
956    if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0) {
957       errno = b_errno_win32;
958       return -1;
959    }
960    errno = 0;
961    return 0;
962 }
963
964 int fcntl(int fd, int cmd, long arg)
965 {
966    int rval = 0;
967
968    switch (cmd) {
969    case F_GETFL:
970       rval = O_NONBLOCK;
971       break;
972
973    case F_SETFL:
974       rval = 0;
975       break;
976
977    default:
978       errno = EINVAL;
979       rval = -1;
980       break;
981    }
982
983    return rval;
984 }
985
986 int
987 lstat(const char *file, struct stat *sb)
988 {
989    return stat(file, sb);
990 }
991
992 void
993 sleep(int sec)
994 {
995    Sleep(sec * 1000);
996 }
997
998 int
999 geteuid(void)
1000 {
1001    return 0;
1002 }
1003
1004 int
1005 execvp(const char *, char *[]) {
1006    errno = ENOSYS;
1007    return -1;
1008 }
1009
1010
1011 int
1012 fork(void)
1013 {
1014    errno = ENOSYS;
1015    return -1;
1016 }
1017
1018 int
1019 pipe(int[])
1020 {
1021    errno = ENOSYS;
1022    return -1;
1023 }
1024
1025 int
1026 waitpid(int, int*, int)
1027 {
1028    errno = ENOSYS;
1029    return -1;
1030 }
1031
1032 int
1033 readlink(const char *, char *, int)
1034 {
1035    errno = ENOSYS;
1036    return -1;
1037 }
1038
1039
1040 #ifndef HAVE_MINGW
1041 int
1042 strcasecmp(const char *s1, const char *s2)
1043 {
1044    register int ch1, ch2;
1045
1046    if (s1==s2)
1047       return 0;       /* strings are equal if same object. */
1048    else if (!s1)
1049       return -1;
1050    else if (!s2)
1051       return 1;
1052    do {
1053       ch1 = *s1;
1054       ch2 = *s2;
1055       s1++;
1056       s2++;
1057    } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
1058
1059    return(ch1 - ch2);
1060 }
1061 #endif //HAVE_MINGW
1062
1063 int
1064 strncasecmp(const char *s1, const char *s2, int len)
1065 {
1066    register int ch1 = 0, ch2 = 0;
1067
1068    if (s1==s2)
1069       return 0;       /* strings are equal if same object. */
1070    else if (!s1)
1071       return -1;
1072    else if (!s2)
1073       return 1;
1074
1075    while (len--) {
1076       ch1 = *s1;
1077       ch2 = *s2;
1078       s1++;
1079       s2++;
1080       if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
1081    }
1082
1083    return (ch1 - ch2);
1084 }
1085
1086 int
1087 gettimeofday(struct timeval *tv, struct timezone *)
1088 {
1089     SYSTEMTIME now;
1090     FILETIME tmp;
1091
1092     GetSystemTime(&now);
1093
1094     if (tv == NULL) {
1095        errno = EINVAL;
1096        return -1;
1097     }
1098     if (!SystemTimeToFileTime(&now, &tmp)) {
1099        errno = b_errno_win32;
1100        return -1;
1101     }
1102
1103     int64_t _100nsec = tmp.dwHighDateTime;
1104     _100nsec <<= 32;
1105     _100nsec |= tmp.dwLowDateTime;
1106     _100nsec -= WIN32_FILETIME_ADJUST;
1107
1108     tv->tv_sec = (long)(_100nsec / 10000000);
1109     tv->tv_usec = (long)((_100nsec % 10000000)/10);
1110     return 0;
1111
1112 }
1113
1114 /* 
1115  * Write in Windows System log 
1116  */
1117 extern "C" void syslog(int type, const char *fmt, ...) 
1118 {
1119    va_list   arg_ptr;
1120    int len, maxlen;
1121    POOLMEM *msg;
1122
1123    msg = get_pool_memory(PM_EMSG);
1124
1125    for (;;) {
1126       maxlen = sizeof_pool_memory(msg) - 1;
1127       va_start(arg_ptr, fmt);
1128       len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
1129       va_end(arg_ptr);
1130       if (len < 0 || len >= (maxlen-5)) {
1131          msg = realloc_pool_memory(msg, maxlen + maxlen/2);
1132          continue;
1133       }
1134       break;
1135    }
1136    LogErrorMsg((const char *)msg);
1137    free_memory(msg);
1138 }
1139
1140 void
1141 closelog()
1142 {
1143 }
1144
1145 struct passwd *
1146 getpwuid(uid_t)
1147 {
1148     return NULL;
1149 }
1150
1151 struct group *
1152 getgrgid(uid_t)
1153 {
1154     return NULL;
1155 }
1156
1157 // implement opendir/readdir/closedir on top of window's API
1158
1159 typedef struct _dir
1160 {
1161     WIN32_FIND_DATAA data_a;    // window's file info (ansii version)
1162     WIN32_FIND_DATAW data_w;    // window's file info (wchar version)
1163     const char *spec;           // the directory we're traversing
1164     HANDLE      dirh;           // the search handle
1165     BOOL        valid_a;        // the info in data_a field is valid
1166     BOOL        valid_w;        // the info in data_w field is valid
1167     UINT32      offset;         // pseudo offset for d_off
1168 } _dir;
1169
1170 DIR *
1171 opendir(const char *path)
1172 {
1173     /* enough space for VSS !*/
1174     int max_len = strlen(path) + MAX_PATH;
1175     char *tspec = NULL;
1176     _dir *rval = NULL;
1177     if (path == NULL) {
1178        errno = ENOENT;
1179        return NULL;
1180     }
1181
1182     Dmsg1(dbglvl, "Opendir path=%s\n", path);
1183     rval = (_dir *)malloc(sizeof(_dir));
1184     if (!rval) {
1185        goto err;
1186     }
1187     memset (rval, 0, sizeof (_dir));
1188
1189     tspec = (char *)malloc(max_len);
1190     if (!tspec) { 
1191        goto err;
1192     }
1193
1194     conv_unix_to_vss_win32_path(path, tspec, max_len);
1195     Dmsg1(dbglvl, "win32 path=%s\n", tspec);
1196
1197     // add backslash only if there is none yet (think of c:\)
1198     if (tspec[strlen(tspec)-1] != '\\')
1199       bstrncat(tspec, "\\*", max_len);
1200     else
1201       bstrncat(tspec, "*", max_len);
1202
1203     rval->spec = tspec;
1204
1205     // convert to wchar_t
1206     if (p_FindFirstFileW) {
1207       POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
1208       make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec);
1209
1210       rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
1211
1212       free_pool_memory(pwcBuf);
1213
1214       if (rval->dirh != INVALID_HANDLE_VALUE)
1215         rval->valid_w = 1;
1216     } else if (p_FindFirstFileA) {
1217       rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
1218
1219       if (rval->dirh != INVALID_HANDLE_VALUE)
1220         rval->valid_a = 1;
1221     } else goto err;
1222
1223
1224     Dmsg3(dbglvl, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
1225           path, rval->spec, rval->dirh);
1226
1227     rval->offset = 0;
1228     if (rval->dirh == INVALID_HANDLE_VALUE)
1229         goto err;
1230
1231     if (rval->valid_w) {
1232       Dmsg1(dbglvl, "\tFirstFile=%s\n", rval->data_w.cFileName);
1233     }
1234
1235     if (rval->valid_a) {
1236       Dmsg1(dbglvl, "\tFirstFile=%s\n", rval->data_a.cFileName);
1237     }
1238
1239     return (DIR *)rval;
1240
1241 err:
1242     if (rval) {
1243        free(rval);
1244     }
1245     if (tspec) {
1246        free(tspec);
1247     }
1248     errno = b_errno_win32;
1249     return NULL;
1250 }
1251
1252 int
1253 closedir(DIR *dirp)
1254 {
1255     _dir *dp = (_dir *)dirp;
1256     FindClose(dp->dirh);
1257     free((void *)dp->spec);
1258     free((void *)dp);
1259     return 0;
1260 }
1261
1262 /*
1263   typedef struct _WIN32_FIND_DATA {
1264     DWORD dwFileAttributes;
1265     FILETIME ftCreationTime;
1266     FILETIME ftLastAccessTime;
1267     FILETIME ftLastWriteTime;
1268     DWORD nFileSizeHigh;
1269     DWORD nFileSizeLow;
1270     DWORD dwReserved0;
1271     DWORD dwReserved1;
1272     TCHAR cFileName[MAX_PATH];
1273     TCHAR cAlternateFileName[14];
1274 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1275 */
1276
1277 static int
1278 copyin(struct dirent &dp, const char *fname)
1279 {
1280     dp.d_ino = 0;
1281     dp.d_reclen = 0;
1282     char *cp = dp.d_name;
1283     while (*fname) {
1284         *cp++ = *fname++;
1285         dp.d_reclen++;
1286     }
1287         *cp = 0;
1288     return dp.d_reclen;
1289 }
1290
1291 int
1292 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1293 {
1294     _dir *dp = (_dir *)dirp;
1295     if (dp->valid_w || dp->valid_a) {
1296       entry->d_off = dp->offset;
1297
1298       // copy unicode
1299       if (dp->valid_w) {
1300          char szBuf[MAX_PATH_UTF8+1];
1301          wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1302          dp->offset += copyin(*entry, szBuf);
1303       } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1304          dp->offset += copyin(*entry, dp->data_a.cFileName);
1305       }
1306
1307       *result = entry;              /* return entry address */
1308       Dmsg4(dbglvl, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1309             dirp, entry->d_name, entry->d_reclen, entry->d_off);
1310     } else {
1311 //      Dmsg0(dbglvl, "readdir_r !valid\n");
1312         errno = b_errno_win32;
1313         return -1;
1314     }
1315
1316     // get next file, try unicode first
1317     if (p_FindNextFileW)
1318        dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1319     else if (p_FindNextFileA)
1320        dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1321     else {
1322        dp->valid_a = FALSE;
1323        dp->valid_w = FALSE;
1324     }
1325
1326     return 0;
1327 }
1328
1329 /*
1330  * Dotted IP address to network address
1331  *
1332  * Returns 1 if  OK
1333  *         0 on error
1334  */
1335 int
1336 inet_aton(const char *a, struct in_addr *inp)
1337 {
1338    const char *cp = a;
1339    uint32_t acc = 0, tmp = 0;
1340    int dotc = 0;
1341
1342    if (!isdigit(*cp)) {         /* first char must be digit */
1343       return 0;                 /* error */
1344    }
1345    do {
1346       if (isdigit(*cp)) {
1347          tmp = (tmp * 10) + (*cp -'0');
1348       } else if (*cp == '.' || *cp == 0) {
1349          if (tmp > 255) {
1350             return 0;           /* error */
1351          }
1352          acc = (acc << 8) + tmp;
1353          dotc++;
1354          tmp = 0;
1355       } else {
1356          return 0;              /* error */
1357       }
1358    } while (*cp++ != 0);
1359    if (dotc != 4) {              /* want 3 .'s plus EOS */
1360       return 0;                  /* error */
1361    }
1362    inp->s_addr = htonl(acc);     /* store addr in network format */
1363    return 1;
1364 }
1365
1366 int
1367 nanosleep(const struct timespec *req, struct timespec *rem)
1368 {
1369     if (rem)
1370         rem->tv_sec = rem->tv_nsec = 0;
1371     Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1372     return 0;
1373 }
1374
1375 void
1376 init_signals(void terminate(int sig))
1377 {
1378
1379 }
1380
1381 void
1382 init_stack_dump(void)
1383 {
1384
1385 }
1386
1387
1388 long
1389 pathconf(const char *path, int name)
1390 {
1391     switch(name) {
1392     case _PC_PATH_MAX :
1393         if (strncmp(path, "\\\\?\\", 4) == 0)
1394             return 32767;
1395     case _PC_NAME_MAX :
1396         return 255;
1397     }
1398     errno = ENOSYS;
1399     return -1;
1400 }
1401
1402 int
1403 WSA_Init(void)
1404 {
1405     WORD wVersionRequested = MAKEWORD( 1, 1);
1406     WSADATA wsaData;
1407
1408     int err = WSAStartup(wVersionRequested, &wsaData);
1409
1410
1411     if (err != 0) {
1412         printf("Can not start Windows Sockets\n");
1413         errno = ENOSYS;
1414         return -1;
1415     }
1416
1417     return 0;
1418 }
1419
1420 static DWORD fill_attribute(DWORD attr, mode_t mode)
1421 {
1422    Dmsg1(dbglvl, "  before attr=%lld\n", (uint64_t) attr);
1423    /* Use Bacula mappings define in stat() above */
1424    if (mode & (S_IRUSR|S_IRGRP|S_IROTH)) { // If file is readable
1425       attr &= ~FILE_ATTRIBUTE_READONLY;    // then this is not READONLY
1426    } else {
1427       attr |= FILE_ATTRIBUTE_READONLY;
1428    }
1429    if (mode & S_ISVTX) {                   // The sticky bit <=> HIDDEN 
1430       attr |= FILE_ATTRIBUTE_HIDDEN;
1431    } else {
1432       attr &= ~FILE_ATTRIBUTE_HIDDEN;
1433    }
1434    if (mode & S_IRWXO) {              // Other can read/write/execute ?
1435       attr &= ~FILE_ATTRIBUTE_SYSTEM; // => Not system
1436    } else {
1437       attr |= FILE_ATTRIBUTE_SYSTEM;
1438    }
1439    Dmsg1(dbglvl, "  after attr=%lld\n", (uint64_t)attr);
1440    return attr;
1441 }
1442
1443 int win32_chmod(const char *path, mode_t mode)
1444 {
1445    bool ret=false;
1446    DWORD attr;
1447
1448    Dmsg2(dbglvl, "win32_chmod(path=%s mode=%lld)\n", path, (uint64_t)mode);
1449    if (p_GetFileAttributesW) {
1450       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1451       make_win32_path_UTF8_2_wchar(&pwszBuf, path);
1452
1453       attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
1454       if (attr != INVALID_FILE_ATTRIBUTES) {
1455          /* Use Bacula mappings define in stat() above */
1456          attr = fill_attribute(attr, mode);
1457          ret = p_SetFileAttributesW((LPCWSTR)pwszBuf, attr);
1458       }
1459       free_pool_memory(pwszBuf);
1460       Dmsg0(dbglvl, "Leave win32_chmod. AttributesW\n");
1461    } else if (p_GetFileAttributesA) {
1462       attr = p_GetFileAttributesA(path);
1463       if (attr != INVALID_FILE_ATTRIBUTES) {
1464          attr = fill_attribute(attr, mode);
1465          ret = p_SetFileAttributesA(path, attr);
1466       }
1467       Dmsg0(dbglvl, "Leave win32_chmod did AttributesA\n");
1468    } else {
1469       Dmsg0(dbglvl, "Leave win32_chmod did nothing\n");
1470    }
1471     
1472    if (!ret) {
1473       const char *err = errorString();
1474       Dmsg2(dbglvl, "Get/SetFileAttributes(%s): %s\n", path, err);
1475       LocalFree((void *)err);
1476       errno = b_errno_win32;
1477       return -1;
1478    }
1479    return 0;
1480 }
1481
1482
1483 int
1484 win32_chdir(const char *dir)
1485 {
1486    if (p_SetCurrentDirectoryW) {
1487       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1488       make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1489
1490       BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1491       
1492       free_pool_memory(pwszBuf);
1493
1494       if (!b) {
1495          errno = b_errno_win32;
1496          return -1;
1497       }
1498    } else if (p_SetCurrentDirectoryA) {
1499       if (0 == p_SetCurrentDirectoryA(dir)) {
1500          errno = b_errno_win32;
1501          return -1;
1502       }
1503    } else {
1504       return -1;
1505    }
1506
1507    return 0;
1508 }
1509
1510 int
1511 win32_mkdir(const char *dir)
1512 {
1513    Dmsg1(dbglvl, "enter win32_mkdir. dir=%s\n", dir);
1514    if (p_wmkdir){
1515       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1516       make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1517
1518       int n = p_wmkdir((LPCWSTR)pwszBuf);
1519       free_pool_memory(pwszBuf);
1520       Dmsg0(dbglvl, "Leave win32_mkdir did wmkdir\n");
1521       return n;
1522    }
1523
1524    Dmsg0(dbglvl, "Leave win32_mkdir did _mkdir\n");
1525    return _mkdir(dir);
1526 }
1527
1528
1529 char *
1530 win32_getcwd(char *buf, int maxlen)
1531 {
1532    int n=0;
1533
1534    if (p_GetCurrentDirectoryW) {
1535       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1536       pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1537
1538       n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1539       if (n!=0)
1540          n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1541       free_pool_memory(pwszBuf);
1542
1543    } else if (p_GetCurrentDirectoryA)
1544       n = p_GetCurrentDirectoryA(maxlen, buf);
1545
1546    if (n == 0 || n > maxlen) return NULL;
1547
1548    if (n+1 > maxlen) return NULL;
1549    if (n != 3) {
1550        buf[n] = '\\';
1551        buf[n+1] = 0;
1552    }
1553    return buf;
1554 }
1555
1556 int
1557 win32_fputs(const char *string, FILE *stream)
1558 {
1559    /* we use WriteConsoleA / WriteConsoleA
1560       so we can be sure that unicode support works on win32.
1561       with fallback if something fails
1562    */
1563
1564    HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1565    if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1566        p_MultiByteToWideChar && (stream == stdout)) {
1567
1568       POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1569
1570       DWORD dwCharsWritten;
1571       DWORD dwChars;
1572
1573       dwChars = UTF8_2_wchar(&pwszBuf, string);
1574
1575       /* try WriteConsoleW */
1576       if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1577          free_pool_memory(pwszBuf);
1578          return dwCharsWritten;
1579       }
1580
1581       /* convert to local codepage and try WriteConsoleA */
1582       POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1583       pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1584
1585       dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR)pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1586       free_pool_memory(pwszBuf);
1587
1588       if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1589          free_pool_memory(pszBuf);
1590          return dwCharsWritten;
1591       }
1592       free_pool_memory(pszBuf);
1593    }
1594    /* Fall back */
1595    return fputs(string, stream);
1596 }
1597
1598 char*
1599 win32_cgets (char* buffer, int len)
1600 {
1601    /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1602       from the win32 console and fallback if seomething fails */
1603
1604    HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1605    if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1606       DWORD dwRead;
1607       wchar_t wszBuf[1024];
1608       char  szBuf[1024];
1609
1610       /* nt and unicode conversion */
1611       if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1612
1613          /* null terminate at end */
1614          if (wszBuf[dwRead-1] == L'\n') {
1615             wszBuf[dwRead-1] = L'\0';
1616             dwRead --;
1617          }
1618
1619          if (wszBuf[dwRead-1] == L'\r') {
1620             wszBuf[dwRead-1] = L'\0';
1621             dwRead --;
1622          }
1623
1624          wchar_2_UTF8(buffer, wszBuf, len);
1625          return buffer;
1626       }
1627
1628       /* win 9x and unicode conversion */
1629       if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1630
1631          /* null terminate at end */
1632          if (szBuf[dwRead-1] == L'\n') {
1633             szBuf[dwRead-1] = L'\0';
1634             dwRead --;
1635          }
1636
1637          if (szBuf[dwRead-1] == L'\r') {
1638             szBuf[dwRead-1] = L'\0';
1639             dwRead --;
1640          }
1641
1642          /* convert from ansii to wchar_t */
1643          p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1644          /* convert from wchar_t to UTF-8 */
1645          if (wchar_2_UTF8(buffer, wszBuf, len))
1646             return buffer;
1647       }
1648    }
1649
1650    /* fallback */
1651    if (fgets(buffer, len, stdin))
1652       return buffer;
1653    else
1654       return NULL;
1655 }
1656
1657 int
1658 win32_unlink(const char *filename)
1659 {
1660    int nRetCode;
1661    if (p_wunlink) {
1662       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1663       make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1664
1665       nRetCode = _wunlink((LPCWSTR) pwszBuf);
1666
1667       /*
1668        * special case if file is readonly,
1669        * we retry but unset attribute before
1670        */
1671       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1672          DWORD dwAttr =  p_GetFileAttributesW((LPCWSTR)pwszBuf);
1673          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1674             if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1675                nRetCode = _wunlink((LPCWSTR) pwszBuf);
1676                /* reset to original if it didn't help */
1677                if (nRetCode == -1)
1678                   p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1679             }
1680          }
1681       }
1682       free_pool_memory(pwszBuf);
1683    } else {
1684       nRetCode = _unlink(filename);
1685
1686       /* special case if file is readonly,
1687       we retry but unset attribute before */
1688       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1689          DWORD dwAttr =  p_GetFileAttributesA(filename);
1690          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1691             if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1692                nRetCode = _unlink(filename);
1693                /* reset to original if it didn't help */
1694                if (nRetCode == -1)
1695                   p_SetFileAttributesA(filename, dwAttr);
1696             }
1697          }
1698       }
1699    }
1700    return nRetCode;
1701 }
1702
1703
1704 #include "mswinver.h"
1705
1706 char WIN_VERSION_LONG[64];
1707 char WIN_VERSION[32];
1708 char WIN_RAWVERSION[32];
1709
1710 class winver {
1711 public:
1712     winver(void);
1713 };
1714
1715 static winver INIT;                     // cause constructor to be called before main()
1716
1717
1718 winver::winver(void)
1719 {
1720     const char *version = "";
1721     const char *platform = "";
1722     OSVERSIONINFO osvinfo;
1723     osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1724
1725     // Get the current OS version
1726     if (!GetVersionEx(&osvinfo)) {
1727         version = "Unknown";
1728         platform = "Unknown";
1729     }
1730         const int ver = _mkversion(osvinfo.dwPlatformId,
1731                                    osvinfo.dwMajorVersion,
1732                                    osvinfo.dwMinorVersion);
1733         snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1734         switch (ver)
1735         {
1736         case MS_WINDOWS_95: (version =  "Windows 95"); break;
1737         case MS_WINDOWS_98: (version =  "Windows 98"); break;
1738         case MS_WINDOWS_ME: (version =  "Windows ME"); break;
1739         case MS_WINDOWS_NT4:(version =  "Windows NT 4.0"); platform = "NT"; break;
1740         case MS_WINDOWS_2K: (version =  "Windows 2000");platform = "NT"; break;
1741         case MS_WINDOWS_XP: (version =  "Windows XP");platform = "NT"; break;
1742         case MS_WINDOWS_S2003: (version =  "Windows Server 2003");platform = "NT"; break;
1743         default: version = WIN_RAWVERSION; break;
1744         }
1745
1746     bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1747     snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1748              platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1749
1750 #if 0
1751     HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1752     CloseHandle(h);
1753 #endif
1754 #if 0
1755     BPIPE *b = open_bpipe("ls -l", 10, "r");
1756     char buf[1024];
1757     while (!feof(b->rfd)) {
1758         fgets(buf, sizeof(buf), b->rfd);
1759     }
1760     close_bpipe(b);
1761 #endif
1762 }
1763
1764 BOOL CreateChildProcess(VOID);
1765 VOID WriteToPipe(VOID);
1766 VOID ReadFromPipe(VOID);
1767 VOID ErrorExit(LPCSTR);
1768 VOID ErrMsg(LPTSTR, BOOL);
1769
1770 /**
1771  * Check for a quoted path,  if an absolute path name is given and it contains
1772  * spaces it will need to be quoted.  i.e.  "c:/Program Files/foo/bar.exe"
1773  * CreateProcess() says the best way to ensure proper results with executables
1774  * with spaces in path or filename is to quote the string.
1775  */
1776 const char *
1777 getArgv0(const char *cmdline)
1778 {
1779
1780     int inquote = 0;
1781     const char *cp;
1782     for (cp = cmdline; *cp; cp++)
1783     {
1784         if (*cp == '"') {
1785             inquote = !inquote;
1786         }
1787         if (!inquote && isspace(*cp))
1788             break;
1789     }
1790
1791
1792     int len = cp - cmdline;
1793     char *rval = (char *)malloc(len+1);
1794
1795     cp = cmdline;
1796     char *rp = rval;
1797
1798     while (len--)
1799         *rp++ = *cp++;
1800
1801     *rp = 0;
1802     return rval;
1803 }
1804
1805 /*
1806  * Extracts the executable or script name from the first string in 
1807  * cmdline.
1808  *
1809  * If the name contains blanks then it must be quoted with double quotes,
1810  * otherwise quotes are optional.  If the name contains blanks then it 
1811  * will be converted to a short name.
1812  *
1813  * The optional quotes will be removed.  The result is copied to a malloc'ed
1814  * buffer and returned through the pexe argument.  The pargs parameter is set
1815  * to the address of the character in cmdline located after the name.
1816  *
1817  * The malloc'ed buffer returned in *pexe must be freed by the caller.
1818  */
1819 bool
1820 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1821 {
1822    const char *pExeStart = NULL;    /* Start of executable name in cmdline */
1823    const char *pExeEnd = NULL;      /* Character after executable name (separator) */
1824
1825    const char *pBasename = NULL;    /* Character after last path separator */
1826    const char *pExtension = NULL;   /* Period at start of extension */
1827
1828    const char *current = cmdline;
1829
1830    bool bQuoted = false;
1831
1832    /* Skip initial whitespace */
1833
1834    while (*current == ' ' || *current == '\t')
1835    {
1836       current++;
1837    }
1838
1839    /* Calculate start of name and determine if quoted */
1840
1841    if (*current == '"') {
1842       pExeStart = ++current;
1843       bQuoted = true;
1844    } else {
1845       pExeStart = current;
1846       bQuoted = false;
1847    }
1848
1849    *pargs = NULL;
1850    *pexe = NULL;
1851
1852    /* 
1853     * Scan command line looking for path separators (/ and \\) and the 
1854     * terminator, either a quote or a blank.  The location of the 
1855     * extension is also noted.
1856     */
1857
1858    for ( ; *current != '\0'; current++)
1859    {
1860       if (*current == '.') {
1861          pExtension = current;
1862       } else if (IsPathSeparator(*current) && current[1] != '\0') {
1863          pBasename = &current[1];
1864          pExtension = NULL;
1865       }
1866
1867       /* Check for terminator, either quote or blank */
1868       if (bQuoted) {
1869          if (*current != '"') {
1870             continue;
1871          }
1872       } else {
1873          if (*current != ' ') {
1874             continue;
1875          }
1876       }
1877
1878       /*
1879        * Hit terminator, remember end of name (address of terminator) and 
1880        * start of arguments 
1881        */
1882       pExeEnd = current;
1883
1884       if (bQuoted && *current == '"') {
1885          *pargs = &current[1];
1886       } else {
1887          *pargs = current;
1888       }
1889
1890       break;
1891    }
1892
1893    if (pBasename == NULL) {
1894       pBasename = pExeStart;
1895    }
1896
1897    if (pExeEnd == NULL) {
1898       pExeEnd = current;
1899    }
1900
1901    if (*pargs == NULL)
1902    {
1903       *pargs = current;
1904    }
1905
1906    bool bHasPathSeparators = pExeStart != pBasename;
1907
1908    /* We have pointers to all the useful parts of the name */
1909
1910    /* Default extensions in the order cmd.exe uses to search */
1911
1912    static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
1913    DWORD dwBasePathLength = pExeEnd - pExeStart;
1914
1915    DWORD dwAltNameLength = 0;
1916    char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1917    char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1918
1919    pPathname[MAX_PATHLENGTH] = '\0';
1920    pAltPathname[MAX_PATHLENGTH] = '\0';
1921
1922    memcpy(pPathname, pExeStart, dwBasePathLength);
1923    pPathname[dwBasePathLength] = '\0';
1924
1925    if (pExtension == NULL) {
1926       /* Try appending extensions */
1927       for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
1928
1929          if (!bHasPathSeparators) {
1930             /* There are no path separators, search in the standard locations */
1931             dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
1932             if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1933                memcpy(pPathname, pAltPathname, dwAltNameLength);
1934                pPathname[dwAltNameLength] = '\0';
1935                break;
1936             }
1937          } else {
1938             bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
1939             if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) {
1940                break;
1941             }
1942             pPathname[dwBasePathLength] = '\0';
1943          }
1944       }
1945    } else if (!bHasPathSeparators) {
1946       /* There are no path separators, search in the standard locations */
1947       dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
1948       if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) {
1949          memcpy(pPathname, pAltPathname, dwAltNameLength);
1950          pPathname[dwAltNameLength] = '\0';
1951       }
1952    }
1953
1954    if (strchr(pPathname, ' ') != NULL) {
1955       dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH);
1956
1957       if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1958          *pexe = (char *)malloc(dwAltNameLength + 1);
1959          if (*pexe == NULL) {
1960             return false;
1961          }
1962          memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
1963       }
1964    }
1965
1966    if (*pexe == NULL) {
1967       DWORD dwPathnameLength = strlen(pPathname);
1968       *pexe = (char *)malloc(dwPathnameLength + 1);
1969       if (*pexe == NULL) {
1970          return false;
1971       }
1972       memcpy(*pexe, pPathname, dwPathnameLength + 1);
1973    }
1974
1975    return true;
1976 }
1977
1978 /**
1979  * Create the process with WCHAR API
1980  */
1981 static BOOL
1982 CreateChildProcessW(const char *comspec, const char *cmdLine,
1983                     PROCESS_INFORMATION *hProcInfo,
1984                     HANDLE in, HANDLE out, HANDLE err)
1985 {
1986    STARTUPINFOW siStartInfo;
1987    BOOL bFuncRetn = FALSE;
1988
1989    // Set up members of the STARTUPINFO structure.
1990    ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
1991    siStartInfo.cb = sizeof(siStartInfo);
1992    // setup new process to use supplied handles for stdin,stdout,stderr
1993
1994    siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1995    siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
1996
1997    siStartInfo.hStdInput = in;
1998    siStartInfo.hStdOutput = out;
1999    siStartInfo.hStdError = err;
2000    
2001    // Convert argument to WCHAR
2002    POOLMEM *cmdLine_wchar = get_pool_memory(PM_FNAME);
2003    POOLMEM *comspec_wchar = get_pool_memory(PM_FNAME);
2004
2005    UTF8_2_wchar(&cmdLine_wchar, cmdLine);
2006    UTF8_2_wchar(&comspec_wchar, comspec);
2007
2008    // Create the child process.
2009    Dmsg2(dbglvl, "Calling CreateProcess(%s, %s, ...)\n", comspec_wchar, cmdLine_wchar);
2010
2011    // try to execute program
2012    bFuncRetn = p_CreateProcessW((WCHAR*)comspec_wchar,
2013                                 (WCHAR*)cmdLine_wchar,// command line
2014                                 NULL,      // process security attributes
2015                                 NULL,      // primary thread security attributes
2016                                 TRUE,      // handles are inherited
2017                                 0,         // creation flags
2018                                 NULL,      // use parent's environment
2019                                 NULL,      // use parent's current directory
2020                                 &siStartInfo,  // STARTUPINFO pointer
2021                                 hProcInfo);   // receives PROCESS_INFORMATION
2022    free_pool_memory(cmdLine_wchar);
2023    free_pool_memory(comspec_wchar);
2024
2025    return bFuncRetn;
2026 }
2027
2028
2029 /**
2030  * Create the process with ANSI API
2031  */
2032 static BOOL
2033 CreateChildProcessA(const char *comspec, char *cmdLine,
2034                     PROCESS_INFORMATION *hProcInfo,
2035                     HANDLE in, HANDLE out, HANDLE err)
2036 {
2037    STARTUPINFOA siStartInfo;
2038    BOOL bFuncRetn = FALSE;
2039
2040    // Set up members of the STARTUPINFO structure.
2041    ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
2042    siStartInfo.cb = sizeof(siStartInfo);
2043    // setup new process to use supplied handles for stdin,stdout,stderr
2044    siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
2045    siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
2046
2047    siStartInfo.hStdInput = in;
2048    siStartInfo.hStdOutput = out;
2049    siStartInfo.hStdError = err;
2050
2051    // Create the child process.
2052    Dmsg2(dbglvl, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
2053
2054    // try to execute program
2055    bFuncRetn = p_CreateProcessA(comspec,
2056                                 cmdLine,  // command line
2057                                 NULL,     // process security attributes
2058                                 NULL,     // primary thread security attributes
2059                                 TRUE,     // handles are inherited
2060                                 0,        // creation flags
2061                                 NULL,     // use parent's environment
2062                                 NULL,     // use parent's current directory
2063                                 &siStartInfo,// STARTUPINFO pointer
2064                                 hProcInfo);// receives PROCESS_INFORMATION
2065    return bFuncRetn;
2066 }
2067
2068 /**
2069  * OK, so it would seem CreateProcess only handles true executables:
2070  * .com or .exe files.  So grab $COMSPEC value and pass command line to it.
2071  */
2072 HANDLE
2073 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
2074 {
2075    static const char *comspec = NULL;
2076    PROCESS_INFORMATION piProcInfo;
2077    BOOL bFuncRetn = FALSE;
2078
2079    if (!p_CreateProcessA || !p_CreateProcessW)
2080       return INVALID_HANDLE_VALUE;
2081
2082    if (comspec == NULL) 
2083       comspec = getenv("COMSPEC");
2084    if (comspec == NULL) // should never happen
2085       return INVALID_HANDLE_VALUE;
2086
2087    // Set up members of the PROCESS_INFORMATION structure.
2088    ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
2089
2090    // if supplied handles are not used the send a copy of our STD_HANDLE
2091    // as appropriate
2092    if (in == INVALID_HANDLE_VALUE)
2093       in = GetStdHandle(STD_INPUT_HANDLE);
2094
2095    if (out == INVALID_HANDLE_VALUE)
2096       out = GetStdHandle(STD_OUTPUT_HANDLE);
2097
2098    if (err == INVALID_HANDLE_VALUE)
2099       err = GetStdHandle(STD_ERROR_HANDLE);
2100
2101    char *exeFile;
2102    const char *argStart;
2103
2104    if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
2105       return INVALID_HANDLE_VALUE;
2106    }
2107
2108    POOL_MEM cmdLine(PM_FNAME);
2109    Mmsg(cmdLine, "%s /c %s%s", comspec, exeFile, argStart);
2110
2111    free(exeFile);
2112
2113    // New function disabled
2114    if (p_CreateProcessW && p_MultiByteToWideChar) {
2115       bFuncRetn = CreateChildProcessW(comspec, cmdLine.c_str(), &piProcInfo,
2116                                       in, out, err);
2117    } else {
2118       bFuncRetn = CreateChildProcessA(comspec, cmdLine.c_str(), &piProcInfo,
2119                                       in, out, err);
2120    }
2121
2122    if (bFuncRetn == 0) {
2123       ErrorExit("CreateProcess failed\n");
2124       const char *err = errorString();
2125       Dmsg3(dbglvl, "CreateProcess(%s, %s, ...)=%s\n",comspec,cmdLine.c_str(),err);
2126       LocalFree((void *)err);
2127       return INVALID_HANDLE_VALUE;
2128    }
2129    // we don't need a handle on the process primary thread so we close
2130    // this now.
2131    CloseHandle(piProcInfo.hThread);
2132    return piProcInfo.hProcess;
2133 }
2134
2135 void
2136 ErrorExit (LPCSTR lpszMessage)
2137 {
2138     Dmsg1(0, "%s", lpszMessage);
2139 }
2140
2141
2142 /*
2143 typedef struct s_bpipe {
2144    pid_t worker_pid;
2145    time_t worker_stime;
2146    int wait;
2147    btimer_t *timer_id;
2148    FILE *rfd;
2149    FILE *wfd;
2150 } BPIPE;
2151 */
2152
2153 static void
2154 CloseIfValid(HANDLE handle)
2155 {
2156     if (handle != INVALID_HANDLE_VALUE)
2157         CloseHandle(handle);
2158 }
2159
2160 BPIPE *
2161 open_bpipe(char *prog, int wait, const char *mode)
2162 {
2163     HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
2164         hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
2165         hInputFile;
2166
2167     SECURITY_ATTRIBUTES saAttr;
2168
2169     BOOL fSuccess;
2170
2171     hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
2172         hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
2173         hInputFile = INVALID_HANDLE_VALUE;
2174
2175     BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
2176     memset((void *)bpipe, 0, sizeof(BPIPE));
2177
2178     int mode_read = (mode[0] == 'r');
2179     int mode_write = (mode[0] == 'w' || mode[1] == 'w');
2180
2181
2182     // Set the bInheritHandle flag so pipe handles are inherited.
2183
2184     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
2185     saAttr.bInheritHandle = TRUE;
2186     saAttr.lpSecurityDescriptor = NULL;
2187
2188     if (mode_read) {
2189
2190         // Create a pipe for the child process's STDOUT.
2191         if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
2192             ErrorExit("Stdout pipe creation failed\n");
2193             goto cleanup;
2194         }
2195         // Create noninheritable read handle and close the inheritable read
2196         // handle.
2197
2198         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
2199                                    GetCurrentProcess(), &hChildStdoutRdDup , 0,
2200                                    FALSE,
2201                                    DUPLICATE_SAME_ACCESS);
2202         if ( !fSuccess ) {
2203             ErrorExit("DuplicateHandle failed");
2204             goto cleanup;
2205         }
2206
2207         CloseHandle(hChildStdoutRd);
2208         hChildStdoutRd = INVALID_HANDLE_VALUE;
2209     }
2210
2211     if (mode_write) {
2212
2213         // Create a pipe for the child process's STDIN.
2214
2215         if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
2216             ErrorExit("Stdin pipe creation failed\n");
2217             goto cleanup;
2218         }
2219
2220         // Duplicate the write handle to the pipe so it is not inherited.
2221         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
2222                                    GetCurrentProcess(), &hChildStdinWrDup,
2223                                    0,
2224                                    FALSE,                  // not inherited
2225                                    DUPLICATE_SAME_ACCESS);
2226         if (!fSuccess) {
2227             ErrorExit("DuplicateHandle failed");
2228             goto cleanup;
2229         }
2230
2231         CloseHandle(hChildStdinWr);
2232         hChildStdinWr = INVALID_HANDLE_VALUE;
2233     }
2234     // spawn program with redirected handles as appropriate
2235     bpipe->worker_pid = (pid_t)
2236         CreateChildProcess(prog,             // commandline
2237                            hChildStdinRd,    // stdin HANDLE
2238                            hChildStdoutWr,   // stdout HANDLE
2239                            hChildStdoutWr);  // stderr HANDLE
2240
2241     if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
2242         goto cleanup;
2243
2244     bpipe->wait = wait;
2245     bpipe->worker_stime = time(NULL);
2246
2247     if (mode_read) {
2248         CloseHandle(hChildStdoutWr); // close our write side so when
2249                                      // process terminates we can
2250                                      // detect eof.
2251         // ugly but convert WIN32 HANDLE to FILE*
2252         int rfd = _open_osfhandle((intptr_t)hChildStdoutRdDup, O_RDONLY | O_BINARY);
2253         if (rfd >= 0) {
2254            bpipe->rfd = _fdopen(rfd, "rb");
2255         }
2256     }
2257     if (mode_write) {
2258         CloseHandle(hChildStdinRd); // close our read side so as not
2259                                     // to interfre with child's copy
2260         // ugly but convert WIN32 HANDLE to FILE*
2261         int wfd = _open_osfhandle((intptr_t)hChildStdinWrDup, O_WRONLY | O_BINARY);
2262         if (wfd >= 0) {
2263            bpipe->wfd = _fdopen(wfd, "wb");
2264         }
2265     }
2266
2267     if (wait > 0) {
2268         bpipe->timer_id = start_child_timer(NULL, bpipe->worker_pid, wait);
2269     }
2270
2271     return bpipe;
2272
2273 cleanup:
2274
2275     CloseIfValid(hChildStdoutRd);
2276     CloseIfValid(hChildStdoutRdDup);
2277     CloseIfValid(hChildStdinWr);
2278     CloseIfValid(hChildStdinWrDup);
2279
2280     free((void *) bpipe);
2281     errno = b_errno_win32;            /* do GetLastError() for error code */
2282     return NULL;
2283 }
2284
2285
2286 int
2287 kill(int pid, int signal)
2288 {
2289    int rval = 0;
2290    if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
2291       rval = -1;
2292       errno = b_errno_win32;
2293    }
2294    CloseHandle((HANDLE)pid);
2295    return rval;
2296 }
2297
2298
2299 int
2300 close_bpipe(BPIPE *bpipe)
2301 {
2302    int rval = 0;
2303    int32_t remaining_wait = bpipe->wait;
2304
2305    /* Close pipes */
2306    if (bpipe->rfd) {
2307       fclose(bpipe->rfd);
2308       bpipe->rfd = NULL;
2309    }
2310    if (bpipe->wfd) {
2311       fclose(bpipe->wfd);
2312       bpipe->wfd = NULL;
2313    }
2314
2315    if (remaining_wait == 0) {         /* wait indefinitely */
2316       remaining_wait = INT32_MAX;
2317    }
2318    for ( ;; ) {
2319       DWORD exitCode;
2320       if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
2321          const char *err = errorString();
2322          rval = b_errno_win32;
2323          Dmsg1(dbglvl, "GetExitCode error %s\n", err);
2324          LocalFree((void *)err);
2325          break;
2326       }
2327       if (exitCode == STILL_ACTIVE) {
2328          if (remaining_wait <= 0) {
2329             rval = ETIME;             /* timed out */
2330             break;
2331          }
2332          bmicrosleep(1, 0);           /* wait one second */
2333          remaining_wait--;
2334       } else if (exitCode != 0) {
2335          /* Truncate exit code as it doesn't seem to be correct */
2336          rval = (exitCode & 0xFF) | b_errno_exit;
2337          break;
2338       } else {
2339          break;                       /* Shouldn't get here */
2340       }
2341    }
2342
2343    if (bpipe->timer_id) {
2344        stop_child_timer(bpipe->timer_id);
2345    }
2346    if (bpipe->rfd) fclose(bpipe->rfd);
2347    if (bpipe->wfd) fclose(bpipe->wfd);
2348    free((void *)bpipe);
2349    return rval;
2350 }
2351
2352 int
2353 close_wpipe(BPIPE *bpipe)
2354 {
2355     int result = 1;
2356
2357     if (bpipe->wfd) {
2358         fflush(bpipe->wfd);
2359         if (fclose(bpipe->wfd) != 0) {
2360             result = 0;
2361         }
2362         bpipe->wfd = NULL;
2363     }
2364     return result;
2365 }
2366
2367 #ifndef MINGW64
2368 int
2369 utime(const char *fname, struct utimbuf *times)
2370 {
2371     FILETIME acc, mod;
2372     char tmpbuf[5000];
2373
2374     conv_unix_to_vss_win32_path(fname, tmpbuf, 5000);
2375
2376     cvt_utime_to_ftime(times->actime, acc);
2377     cvt_utime_to_ftime(times->modtime, mod);
2378
2379     HANDLE h = INVALID_HANDLE_VALUE;
2380
2381     if (p_CreateFileW) {
2382        POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2383        make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
2384
2385        h = p_CreateFileW((LPCWSTR)pwszBuf,
2386                         FILE_WRITE_ATTRIBUTES,
2387                         FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2388                         NULL,
2389                         OPEN_EXISTING,
2390                         FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2391                         NULL);
2392
2393        free_pool_memory(pwszBuf);
2394     } else if (p_CreateFileA) {
2395        h = p_CreateFileA(tmpbuf,
2396                         FILE_WRITE_ATTRIBUTES,
2397                         FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2398                         NULL,
2399                         OPEN_EXISTING,
2400                         FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2401                         NULL);
2402     }
2403
2404     if (h == INVALID_HANDLE_VALUE) {
2405        const char *err = errorString();
2406        Dmsg2(dbglvl, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2407        LocalFree((void *)err);
2408        errno = b_errno_win32;
2409        return -1;
2410     }
2411
2412     int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2413     CloseHandle(h);
2414     if (rval == -1) {
2415        errno = b_errno_win32;
2416     }
2417     return rval;
2418 }
2419 #endif
2420
2421 #if 0
2422 int
2423 file_open(const char *file, int flags, int mode)
2424 {
2425    DWORD access = 0;
2426    DWORD shareMode = 0;
2427    DWORD create = 0;
2428    DWORD msflags = 0;
2429    HANDLE foo = INVALID_HANDLE_VALUE;
2430    const char *remap = file;
2431
2432    if (flags & O_WRONLY) access = GENERIC_WRITE;
2433    else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2434    else access = GENERIC_READ;
2435
2436    if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2437       create = CREATE_NEW;
2438    else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2439       create = CREATE_ALWAYS;
2440    else if (flags & O_CREAT)
2441       create = OPEN_ALWAYS;
2442    else if (flags & O_TRUNC)
2443       create = TRUNCATE_EXISTING;
2444    else 
2445       create = OPEN_EXISTING;
2446
2447    shareMode = 0;
2448
2449    if (flags & O_APPEND) {
2450       printf("open...APPEND not implemented yet.");
2451       exit(-1);
2452    }
2453
2454    if (p_CreateFileW) {
2455       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2456       make_win32_path_UTF8_2_wchar(&pwszBuf, file);
2457
2458       foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
2459       free_pool_memory(pwszBuf);
2460    } else if (p_CreateFileA)
2461       foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
2462
2463    if (INVALID_HANDLE_VALUE == foo) {
2464       errno = b_errno_win32;
2465       return (int)-1;
2466    }
2467    return (int)foo;
2468
2469 }
2470
2471
2472 int
2473 file_close(int fd)
2474 {
2475     if (!CloseHandle((HANDLE)fd)) {
2476         errno = b_errno_win32;
2477         return -1;
2478     }
2479
2480     return 0;
2481 }
2482
2483 ssize_t
2484 file_write(int fd, const void *data, ssize_t len)
2485 {
2486     BOOL status;
2487     DWORD bwrite;
2488     status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2489     if (status) return bwrite;
2490     errno = b_errno_win32;
2491     return -1;
2492 }
2493
2494
2495 ssize_t
2496 file_read(int fd, void *data, ssize_t len)
2497 {
2498     BOOL status;
2499     DWORD bread;
2500
2501     status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2502     if (status) return bread;
2503     errno = b_errno_win32;
2504     return -1;
2505 }
2506
2507 boffset_t
2508 file_seek(int fd, boffset_t offset, int whence)
2509 {
2510     DWORD method = 0;
2511     DWORD val;
2512     LONG  offset_low = (LONG)offset;
2513     LONG  offset_high = (LONG)(offset >> 32);
2514
2515     switch (whence) {
2516     case SEEK_SET :
2517         method = FILE_BEGIN;
2518         break;
2519     case SEEK_CUR:
2520         method = FILE_CURRENT;
2521         break;
2522     case SEEK_END:
2523         method = FILE_END;
2524         break;
2525     default:
2526         errno = EINVAL;
2527         return -1;
2528     }
2529
2530
2531     if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
2532        errno = b_errno_win32;
2533        return -1;
2534     }
2535     /* ***FIXME*** I doubt this works right */
2536     return val;
2537 }
2538
2539 int
2540 file_dup2(int, int)
2541 {
2542     errno = ENOSYS;
2543     return -1;
2544 }
2545 #endif
2546
2547 #ifdef xxx
2548 /* 
2549  * Emulation of mmap and unmmap for tokyo dbm
2550  */
2551 void *mmap(void *start, size_t length, int prot, int flags,
2552            int fd, off_t offset)
2553 {
2554    DWORD fm_access = 0;
2555    DWORD mv_access = 0;
2556    HANDLE h;
2557    HANDLE mv;
2558
2559    if (length == 0) {
2560       return MAP_FAILED;
2561    }
2562    if (!fd) {
2563       return MAP_FAILED;
2564    }
2565
2566    if (flags & PROT_WRITE) {
2567       fm_access |= PAGE_READWRITE;
2568    } else if (flags & PROT_READ) {
2569       fm_access |= PAGE_READONLY;
2570    }
2571    
2572    if (flags & PROT_READ) {
2573       mv_access |= FILE_MAP_READ;
2574    }
2575    if (flags & PROT_WRITE) {
2576       mv_access |= FILE_MAP_WRITE;
2577    }
2578
2579    h = CreateFileMapping((HANDLE)_get_osfhandle (fd), 
2580                          NULL /* security */, 
2581                          fm_access, 
2582                          0 /* MaximumSizeHigh */, 
2583                          0 /* MaximumSizeLow */, 
2584                          NULL /* name of the file mapping object */);
2585
2586    if (!h || h == INVALID_HANDLE_VALUE) {
2587       return MAP_FAILED;
2588    }
2589
2590    mv = MapViewOfFile(h, mv_access, 
2591                       0 /* offset hi */, 
2592                       0 /* offset lo */,
2593                       length);
2594    CloseHandle(h);
2595
2596    if (!mv || mv == INVALID_HANDLE_VALUE) {
2597       return MAP_FAILED;
2598    }
2599
2600    return (void *) mv;
2601 }
2602
2603 int munmap(void *start, size_t length)
2604 {
2605    if (!start) {
2606       return -1;
2607    }
2608    UnmapViewOfFile(start);
2609    return 0;
2610 }
2611 #endif
2612
2613 #ifdef HAVE_MINGW
2614 /* syslog function, added by Nicolas Boichat */
2615 void openlog(const char *ident, int option, int facility) {}  
2616 #endif //HAVE_MINGW
2617
2618 /* Log an error message */
2619 void LogErrorMsg(const char *message)
2620 {
2621    HANDLE eventHandler;
2622    const char *strings[2];
2623
2624    /* Use the OS event logging to log the error */
2625    eventHandler = RegisterEventSource(NULL, "Bacula");
2626
2627    strings[0] = _("\n\nBacula ERROR: ");
2628    strings[1] = message;
2629
2630    if (eventHandler) {
2631       ReportEvent(eventHandler, EVENTLOG_ERROR_TYPE,
2632               0,                      /* category */
2633               0,                      /* ID */
2634               NULL,                   /* SID */
2635               2,                      /* Number of strings */
2636               0,                      /* raw data size */
2637               (const char **)strings, /* error strings */
2638               NULL);                  /* raw data */
2639       DeregisterEventSource(eventHandler);
2640    }
2641 }