1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8 
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 //                              -*- Mode: C++ -*-
20 // compat.cpp -- compatibilty layer to make bacula-fd run
21 //               natively under windows
22 //
23 // Copyright transferred from Raider Solutions, Inc to
24 //   Kern Sibbald and John Walker by express permission.
25 //
26 // Author          : Christopher S. Hull
27 // Created On      : Sat Jan 31 15:55:00 2004
28 
29 #include "bacula.h"
30 #include "compat.h"
31 #include "jcr.h"
32 #include "findlib/find.h"
33 
34 /* Note, if you want to see what Windows variables and structures
35  * are defined, bacula.h includes <windows.h>, which is found in:
36  *
37  *   cross-tools/mingw32/mingw32/include
38  * or
39  *   cross-tools/mingw-w64/x86_64-pc-mingw32/include
40  *
41  * depending on whether we are building the 32 bit version or
42  * the 64 bit version.
43  */
44 
45 static const int dbglvl = 500;
46 
47 #define b_errno_win32 (1<<29)
48 
49 #define MAX_PATHLENGTH  1024
50 
51 /**
52    UTF-8 to UCS2 path conversion is expensive,
53    so we cache the conversion. During backup the
54    conversion is called 3 times (lstat, attribs, open),
55    by using the cache this is reduced to 1 time
56  */
57 static POOLMEM *g_pWin32ConvUTF8Cache = NULL;
58 static POOLMEM *g_pWin32ConvUCS2Cache = NULL;
59 static DWORD g_dwWin32ConvUTF8strlen = 0;
60 static pthread_mutex_t Win32Convmutex = PTHREAD_MUTEX_INITIALIZER;
61 
62 /* Forward referenced functions */
63 static const char *errorString(void);
64 
65 /* The following functions are available only in the FileDaemon with VSS
66  * These functions uses the VSSObject to resolve a Path to a Snapshot Path,
67  * the VSSObject is available "per job", and some jobs such as Restore or Verify
68  * may not have a VSSObject.
69  */
70 
default_VSSPathConverter()71 static BOOL default_VSSPathConverter()
72 {
73    return false;
74 }
75 
76 static t_pVSSPathConvert   g_pVSSPathConvert = NULL;
77 static t_pVSSPathConvertW  g_pVSSPathConvertW = NULL;
78 static t_pVSSPathConverter g_pVSSPathConverter = default_VSSPathConverter; /* To know if we can use the VSSPath functions */
79 
80 
SetVSSPathConvert(t_pVSSPathConverter pPathConverter,t_pVSSPathConvert pPathConvert,t_pVSSPathConvertW pPathConvertW)81 void SetVSSPathConvert(t_pVSSPathConverter pPathConverter, t_pVSSPathConvert pPathConvert, t_pVSSPathConvertW pPathConvertW)
82 {
83    g_pVSSPathConvert = pPathConvert;
84    g_pVSSPathConvertW = pPathConvertW;
85    g_pVSSPathConverter = pPathConverter;
86 }
87 
Win32ConvInitCache()88 static void Win32ConvInitCache()
89 {
90    if (g_pWin32ConvUTF8Cache) {
91       return;
92    }
93    g_pWin32ConvUTF8Cache = get_pool_memory(PM_FNAME);
94    g_pWin32ConvUCS2Cache = get_pool_memory(PM_FNAME);
95 }
96 
Win32ConvCleanupCache()97 void Win32ConvCleanupCache()
98 {
99    P(Win32Convmutex);
100    if (g_pWin32ConvUTF8Cache) {
101       free_pool_memory(g_pWin32ConvUTF8Cache);
102       g_pWin32ConvUTF8Cache = NULL;
103    }
104 
105    if (g_pWin32ConvUCS2Cache) {
106       free_pool_memory(g_pWin32ConvUCS2Cache);
107       g_pWin32ConvUCS2Cache = NULL;
108    }
109 
110    g_dwWin32ConvUTF8strlen = 0;
111    V(Win32Convmutex);
112 }
113 
114 
115 /* to allow the usage of the original version in this file here */
116 #undef fputs
117 
118 
119 //#define USE_WIN32_COMPAT_IO 1
120 #define USE_WIN32_32KPATHCONVERSION 1
121 
122 extern DWORD   g_platform_id;
123 extern DWORD   g_MinorVersion;
124 
125 /* From Microsoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970 */
126 #ifdef HAVE_MINGW
127 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL
128 #else
129 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
130 #endif
131 
132 #define WIN32_FILETIME_SCALE  10000000             // 100ns/second
133 
134 /**
135  * Convert POSIX like UTF-8 path into Windows UTF-8 path (replace '/' with '\\')
136  * and add the \\?\ prefix or a "VSS" prefix if VSS snapshot exists
137  * don't convert to UTF-16-LE
138  */
conv_unix_to_vss_win32_path(const char * name,char * win32_name,DWORD dwSize)139 static void conv_unix_to_vss_win32_path(const char *name, char *win32_name, DWORD dwSize)
140 {
141     const char *fname = name;
142     char *tname = win32_name;
143 
144     Dmsg0(dbglvl, "Enter convert_unix_to_win32_path\n");
145 
146     if (IsPathSeparator(name[0]) &&
147         IsPathSeparator(name[1]) &&
148         name[2] == '.' &&
149         IsPathSeparator(name[3])) {
150 
151         *win32_name++ = '\\';
152         *win32_name++ = '\\';
153         *win32_name++ = '.';
154         *win32_name++ = '\\';
155 
156         name += 4;
157     } else if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS && !g_pVSSPathConverter()) {
158         /* allow path to be 32767 bytes */
159         *win32_name++ = '\\';
160         *win32_name++ = '\\';
161         *win32_name++ = '?';
162         *win32_name++ = '\\';
163     }
164 
165     while (*name) {
166         /** Check for Unix separator and convert to Win32 */
167         if (name[0] == '/' && name[1] == '/') {  /* double slash? */
168            name++;                               /* yes, skip first one */
169         }
170         if (*name == '/') {
171             *win32_name++ = '\\';     /* convert char */
172         /* If Win32 separator that is "quoted", remove quote */
173         } else if (*name == '\\' && name[1] == '\\') {
174             *win32_name++ = '\\';
175             name++;                   /* skip first \ */
176         } else {
177             *win32_name++ = *name;    /* copy character */
178         }
179         name++;
180     }
181     /** Strip any trailing slash, if we stored something
182      * but leave "c:\" with backslash (root directory case
183      */
184     if (*fname != 0 && win32_name[-1] == '\\' && strlen (fname) != 3) {
185         win32_name[-1] = 0;
186     } else {
187         *win32_name = 0;
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 */
unix_name_to_win32(POOLMEM ** win32_name,const char * name)194 void unix_name_to_win32(POOLMEM **win32_name, const 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 normalize a wchar Windows path:
206  *  - make the path absolute if relative
207  *  - prefix the path with r"\\?\" but keep r"\\.\" prefix untouched
208  *  - convert any '/' into '\\'
209  * A device path starting with \\.\ is left untouched and pBIsRawPath is set
210  * Prefixing the path with \\?\ allow to use 32K characters long paths.
211  *
212  * samples:
213  * c:\path\file -> \\?\c:\path\file
214  * path\file -> \\?\c:\path\file
215  *
216  *        created 02/27/2006 Thorsten Engel
217  *
218  * This is a "universal" function that does more than what Bacula need,
219  * like handling relative path using the CWD.
220  */
221 static void
norm_wchar_win32_path(POOLMEM ** pszUCSPath,BOOL * pBIsRawPath)222 norm_wchar_win32_path(POOLMEM **pszUCSPath, BOOL *pBIsRawPath /*= NULL*/)
223 {
224 
225    Dmsg1(dbglvl, "Enter norm_wchar_win32_path %ls\n", *pszUCSPath);
226    if (pBIsRawPath) {
227       *pBIsRawPath = FALSE;              /* Initialize, set later */
228    }
229 
230    wchar_t *name = (wchar_t *)*pszUCSPath;
231    wchar_t *pwszBuf = (wchar_t *)get_pool_memory(PM_FNAME);
232    wchar_t *pwszCurDirBuf = (wchar_t *)get_pool_memory(PM_FNAME);
233    DWORD dwCurDirPathSize = 0;
234 
235    /* get buffer with enough size (name+max 6. wchars+1 null terminator */
236    DWORD dwBufCharsNeeded = (wcslen(name)+7);
237    pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
238 
239    /* it is important to make absolute paths, so we add drive and
240     *  current path if necessary
241     */
242 
243    BOOL bAddDrive = TRUE;
244    BOOL bAddCurrentPath = TRUE;
245    BOOL bAddPrefix = TRUE;
246 
247    if (IsWPathSeparator(name[0]) && IsWPathSeparator(name[1])
248        && (name[2] == L'?' || name[2] == L'.') && IsWPathSeparator(name[3])) {
249       /* already starting with \\?\ or \\.\ */
250       bAddDrive = FALSE;
251       bAddCurrentPath = FALSE;
252       bAddPrefix = FALSE;
253       if (pBIsRawPath && name[2] == L'.') {
254          /* the Win32 Device NameSpace like '\\.\PhysicalDrive0' */
255          *pBIsRawPath = TRUE;
256       }
257    } else if (iswalpha(name[0]) && name[1] == L':' && IsWPathSeparator(name[2])) {
258       /* path begins with a drive letter, it is absolute */
259       bAddDrive = FALSE;
260       bAddCurrentPath = FALSE;
261    } else if (IsWPathSeparator(name[0])) {
262       /* path is absolute */
263       bAddCurrentPath = FALSE;
264    }
265 
266    /* is path relative to itself?, if yes, skip ./ */
267    if (name[0] == L'.' && IsWPathSeparator(name[1])) {
268       name += 2;
269    }
270 
271    /* get current path if needed */
272    if (bAddDrive || bAddCurrentPath) {
273       if (p_GetCurrentDirectoryW &&
274             (dwCurDirPathSize = p_GetCurrentDirectoryW(0, NULL)) > 0) {
275          /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
276          pwszCurDirBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszCurDirBuf, (dwCurDirPathSize+1)*sizeof(wchar_t));
277          p_GetCurrentDirectoryW(dwCurDirPathSize, pwszCurDirBuf);
278       } else {
279          /* we have no info for doing so */
280          bAddDrive = FALSE;
281          bAddCurrentPath = FALSE;
282          bAddPrefix = FALSE;
283       }
284    }
285 
286    int nParseOffset = 0;
287 
288    /* add 4 bytes header */
289    if (bAddPrefix) {
290       nParseOffset = 4;
291       wcscpy(pwszBuf, L"\\\\?\\");
292    }
293 
294    /* add drive if needed */
295    if (bAddDrive && !bAddCurrentPath) {
296       wchar_t szDrive[3];
297 
298       if (IsWPathSeparator(pwszCurDirBuf[0]) &&
299           IsWPathSeparator(pwszCurDirBuf[1]) &&
300           pwszCurDirBuf[2] == L'?' &&
301           IsWPathSeparator(pwszCurDirBuf[3])) {
302          /* copy drive character */
303          szDrive[0] = pwszCurDirBuf[4];
304       } else {
305          /* copy drive character */
306          szDrive[0] = pwszCurDirBuf[0];
307       }
308 
309       szDrive[1] = L':';
310       szDrive[2] = L'\0';
311 
312       wcscat(pwszBuf, szDrive);
313       nParseOffset +=2;
314    }
315 
316    /* add path if needed */
317    if (bAddCurrentPath) {
318       /* the 1 add. character is for the eventually added backslash */
319       dwBufCharsNeeded += dwCurDirPathSize+1;
320       pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
321       /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
322 
323       if (IsWPathSeparator(pwszCurDirBuf[0]) &&
324           IsWPathSeparator(pwszCurDirBuf[1]) &&
325           pwszCurDirBuf[2] == L'?' &&
326           IsWPathSeparator(pwszCurDirBuf[3])) {
327          /* copy complete string */
328          wcscpy(pwszBuf, pwszCurDirBuf);
329       } else {
330          /* append path  */
331          wcscat(pwszBuf, pwszCurDirBuf);
332       }
333 
334       nParseOffset = wcslen((LPCWSTR) pwszBuf);
335 
336       /* check if path ends with backslash, if not, add one */
337       if (!IsWPathSeparator(pwszBuf[nParseOffset-1])) {
338          wcscat(pwszBuf, L"\\");
339          nParseOffset++;
340       }
341    }
342 
343    wchar_t *win32_name = &pwszBuf[nParseOffset];
344    wchar_t *name_start = name;
345 
346    while (*name) {
347       /* Check for Unix separator and convert to Win32, eliminating
348        * duplicate separators.
349        */
350       if (IsWPathSeparator(*name)) {
351          *win32_name++ = L'\\';     /* convert char */
352 
353          /* Eliminate consecutive slashes, but not at the start so that
354           * \\.\ still works.
355           */
356          if (name_start != name && IsWPathSeparator(name[1])) {
357             name++;
358          }
359       } else {
360          *win32_name++ = *name;    /* copy character */
361       }
362       name++;
363    }
364 
365    /* null terminate string */
366    *win32_name = L'\0';
367 
368    free_pool_memory(*pszUCSPath);
369    free_pool_memory((POOLMEM *)pwszCurDirBuf);
370 
371    Dmsg1(dbglvl, "Leave norm_wchar_win32_path=%ls\n", pwszBuf);
372    *pszUCSPath = (POOLMEM *)pwszBuf;
373 }
374 
375 /*
376  * Both functions wchar_path_2_wutf8() and wutf8_path_2_wchar() convert file path
377  * between Windows UTF16-LE and Bacula UTF8.
378  * Both function use WideCharToMultiByte() and WideCharToMultiByte() but
379  * support invalid UTF16 input. Invalid UTF16 char are encoded into valid
380  * UTF8 string using the WUTF8_ESCAPE char ('*') that is not allowed into
381  * Windows path. The valid UTF8 path is decoded back into the same invalid
382  * UTF16 path. WUTF8_ESCAPE are also escaped just in case.
383  * The encoded path is valid UTF8 and it can be manipulate by Bacula it as any
384  * other path.
385  * This trick allows to restore these files on most POSIX and Windows systems.
386  * The main improvement is that the FileDaemon was not able to backup these
387  * files with invalid char because the code that navigate inside the directory
388  * tree use UTF8 and the conversion back to UTF16 (to open the file) was
389  * generating a path different of the original one that was not existing.
390  *
391  * Use these functions only for windows path. Don't use them for other strings
392  * that could hold WUTF8_ESCAPE chars.
393  *
394  * return the length of the output string including the null terminator
395  * or 0 for any error
396  */
397 static int WUTF8_ESCAPE='*';
398 static wchar_t WUTF8_WCHAR_ESCAPE=L'*';
399 
400 #ifndef WC_ERR_INVALID_CHARS
401  #define WC_ERR_INVALID_CHARS 0x00000080 // Windows constant
402 #endif
403 
wchar_path_2_wutf8(POOLMEM ** pszUTF,const wchar_t * pszUCS)404 int wchar_path_2_wutf8(POOLMEM **pszUTF, const wchar_t *pszUCS)
405 {
406    if (!p_WideCharToMultiByte) {
407       return 0;
408    }
409    // WC_ERR_INVALID_CHARS=0x00000080
410    // ERROR_NO_UNICODE_TRANSLATION=1113
411    int buflen = p_WideCharToMultiByte(CP_UTF8,WC_ERR_INVALID_CHARS,pszUCS,-1,NULL,0,NULL,NULL);
412    if (buflen > 0) {
413       /* no invalid char: buflen is always > 0 because it counts the final '\0' */
414       *pszUTF = check_pool_memory_size(*pszUTF, buflen);
415       buflen = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,*pszUTF,buflen,NULL,NULL);
416       if (strchr(*pszUTF, WUTF8_ESCAPE)==NULL) {
417          // No WUTF8_ESCAPE char to escape
418          return buflen;
419       }
420 // IF WE GO BELOW THIS LINE, this is because a Windows file name holds an invalid
421 // char or an unexpected char WUTF8_ESCAPE
422    } else {
423       buflen = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,NULL,0,NULL,NULL);
424       *pszUTF = check_pool_memory_size(*pszUTF, buflen);
425       buflen = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,*pszUTF,buflen,NULL,NULL);
426    }
427    // pszUCS is an invalid UTF-16-LE string,
428    // let WideCharToMultiByte() replace all invalid char with U+FFFD
429    // then count the number of U+FFFD (aka \xef\xbf\xbd in utf8)
430    for (char *p=*pszUTF; p!=NULL && *p!='\0'; p++) {
431       p=strstr(p, "\xef\xbf\xbd");
432       if (p == NULL) {
433          break;
434       }
435       buflen += 2; // enlarge the buffer to replace "\xef\xbf\xbd" with "*XXXXX"
436    }
437    // count the number of WUTF8_ESCAPE to escape them
438    for (char *p=*pszUTF; p!=NULL && *p!='\0'; p++) {
439       p=strchr(p, WUTF8_ESCAPE);
440       if (p == NULL) {
441          break;
442       }
443       buflen += 1; // enlarge the buffer to escape WUTF8_ESCAPE
444    }
445 
446    // enlarge the buffer to hold the escape sequence
447    *pszUTF = check_pool_memory_size(*pszUTF, buflen);
448    // Decode the UTF16 char by char using section
449    // "2.2 Decoding UTF-16" at http://www.ietf.org/rfc/rfc2781.txt
450    const wchar_t *s = pszUCS;
451    char *d = *pszUTF;
452    while (*s != 0) {
453       if (*s == WUTF8_WCHAR_ESCAPE) {
454          *d++ = WUTF8_ESCAPE;
455          *d++ = WUTF8_ESCAPE;
456          buflen -= 2;
457          s++;
458          continue;
459       } else if (*s<0xd800 || *s>0xdfff) {
460          // single Unicode scalar value
461          int r = p_WideCharToMultiByte(CP_UTF8,0,s,1,d,buflen,NULL,NULL);
462          if (r == 0) {
463             Dmsg1(0, "Unexpected error for single unicode char wchar_off=%ld\n", s-pszUCS);
464             return 0; // Unexpected error
465          }
466          buflen -= r;
467          d += r;
468          s++;
469          continue;
470       } else if (0xd800<=*s && *s<=0xdbff && 0xdc00<=*(s+1) && *(s+1)<=0xdfff) {
471          // we have a surrogate of 2 valid 16bits chars
472          int r = p_WideCharToMultiByte(CP_UTF8,0,s,2,d,buflen,NULL,NULL);
473          if (r == 0) {
474             Dmsg1(0, "Unexpected error for surrogate of 2 valid 16bits char wchar_off=%ld\n", s-pszUCS);
475          }
476          buflen -= r;
477          d += r;
478          s += 2;
479          continue;
480       }
481       // Use WUTF8_ESCAPE char to escape the invalid char
482       int r = bsnprintf(d, buflen, "%c%04x", (int)WUTF8_ESCAPE, (int)*s);
483       if (r != 5) {
484          Dmsg2(0, "Unexpected error buffer too small 1 %d %s\n", r, d);
485          return 0; // Unexpected error, buffer too small !
486       }
487       buflen -= r;
488       d += r;
489       s++;
490    }
491    if (buflen <= 0) {
492       Dmsg0(0, "Unexpected error buffer too small 2\n");
493       return 0; // Unexpected error, buffer too small !
494    }
495    *d = '\0';
496    d++;
497    buflen--;
498    return d-*pszUTF;
499 }
500 
501 /* Do the inverse of function wchar_path_2_wutf8()
502  * return the number of wchar_t written including the final '\0'
503  * or O if any error
504  */
wutf8_path_2_wchar(POOLMEM ** ppszUCS,const char * pszUTF)505 int wutf8_path_2_wchar(POOLMEM **ppszUCS, const char *pszUTF)
506 {
507    if (!p_MultiByteToWideChar) {
508       return 0;
509    }
510    DWORD cchSize = (strlen(pszUTF)+1);
511    *ppszUCS = check_pool_memory_size(*ppszUCS, cchSize*sizeof(wchar_t));
512    int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
513    ASSERT (nRet > 0);
514    if (strchr(pszUTF, WUTF8_WCHAR_ESCAPE) == NULL) {
515       /* their is no WUTF8_ESCAPE char in the string, process the all string at once */
516       /* strlen of UTF8+1 is enough */
517       return nRet;
518    }
519 // IF WE GO BELOW THIS LINE, this is because the original Windows file name
520 // was holding an invalid char or an unexpected char WUTF8_ESCAPE
521    wchar_t *s=(wchar_t *)*ppszUCS; // source
522    wchar_t *d=(wchar_t *)*ppszUCS; // destination is smaller than source
523    int n = 0;
524    while (*s != L'\0') {
525       if (*s == WUTF8_WCHAR_ESCAPE && *(s+1) == WUTF8_WCHAR_ESCAPE) {
526          // two WUTF8_WCHAR_ESCAPE in a row, copy one and drop the other
527          *d++ = *s++;
528          s++;
529          n++;
530       }  else if (*s == WUTF8_WCHAR_ESCAPE) {
531          // replace the the encoded '*WXYZ' char into its code point '\0xWXYZ'
532          wchar_t w = 0;
533          int val;
534          s++;
535          for (int i = 0; i < 4; i++) {
536             if (*s == L'\0') {
537                Dmsg0(0, "unexpected WUTF8_WCHAR_ESCAPE at end of the string!\n");
538                return 0;
539             }
540             if (L'0' <= *s && *s <= L'9') {
541                val=*s-L'0';
542             } else if (L'a' <= *s && *s <= L'f') {
543                val=*s-L'a'+10;
544             } else if (L'A' <= *s && *s <= L'F') {
545                val=*s-L'A'+10;
546             } else {
547                Dmsg0(0, "a WUTF8_WCHAR_ESCAPE should be followed by 4 hexa digits!\n");
548                return 0;
549             }
550             w = (w << 4) | val;
551             s++;
552          }
553          *d++=w;
554          n++;
555       } else {
556          *d++ = *s++;
557          n++;
558       }
559    }
560    *d = L'\0';
561    n++;
562    return n;
563 }
564 
565 /*
566  * Convert from WCHAR (UTF-16-LE) to UTF-8
567  * Don't use this function for path, use wchar_path_2_wutf8() instead
568  */
569 int
wchar_2_UTF8(POOLMEM ** pszUTF,const wchar_t * pszUCS)570 wchar_2_UTF8(POOLMEM **pszUTF, const wchar_t *pszUCS)
571 {
572    /**
573     * The return value is the number of bytes written to the buffer.
574     * The number includes the byte for the null terminator.
575     */
576 
577    if (p_WideCharToMultiByte) {
578       int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,NULL,0,NULL,NULL);
579       *pszUTF = check_pool_memory_size(*pszUTF, nRet);
580       return p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,*pszUTF,nRet,NULL,NULL);
581 
582    }
583    return 0;
584 }
585 
586 /*
587  * Convert from WCHAR (UTF-16-LE) to UTF-8
588  * Don't use this function for path, use wchar_path_2_wutf8() instead
589  */
590 int
wchar_2_UTF8(char * pszUTF,const wchar_t * pszUCS,int cchChar)591 wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
592 {
593    /**
594     * The return value is the number of bytes written to the buffer.
595     * The number includes the byte for the null terminator.
596     */
597 
598    if (p_WideCharToMultiByte) {
599       int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
600       ASSERT (nRet > 0);
601       return nRet;
602    }
603    return 0;
604 }
605 
606 /*
607 * Don't use this function for path, use wchar_path_2_wutf8() instead
608 */
609 int
UTF8_2_wchar(POOLMEM ** ppszUCS,const char * pszUTF)610 UTF8_2_wchar(POOLMEM **ppszUCS, const char *pszUTF)
611 {
612    /* the return value is the number of wide characters written to the buffer. */
613    /* convert null terminated string from utf-8 to ucs2, enlarge buffer if necessary */
614 
615    if (p_MultiByteToWideChar) {
616       /* strlen of UTF8 +1 is enough */
617       DWORD cchSize = (strlen(pszUTF)+1);
618       *ppszUCS = check_pool_memory_size(*ppszUCS, cchSize*sizeof (wchar_t));
619 
620       int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
621       ASSERT (nRet > 0);
622       return nRet;
623    }
624    return 0;
625 }
626 
627 #if 0
628 // not used anywhere
629 void
630 wchar_win32_path(const char *name, wchar_t *win32_name)
631 {
632     const char *fname = name;
633     while (*name) {
634         /* Check for Unix separator and convert to Win32 */
635         if (*name == '/') {
636             *win32_name++ = '\\';     /* convert char */
637         /* If Win32 separated that is "quoted", remove quote */
638         } else if (*name == '\\' && name[1] == '\\') {
639             *win32_name++ = '\\';
640             name++;                   /* skip first \ */
641         } else {
642             *win32_name++ = *name;    /* copy character */
643         }
644         name++;
645     }
646     /* Strip any trailing slash, if we stored something */
647     if (*fname != 0 && win32_name[-1] == '\\') {
648         win32_name[-1] = 0;
649     } else {
650         *win32_name = 0;
651     }
652 }
653 #endif
654 
655 /*
656  * Convert a WUTF8 path into a normalized wchar windows path
657  * Get the result from cache
658  * or
659  * call wutf8_path_2_wchar() and norm_wchar_win32_path()
660  * and save the result in cache
661  */
662 int
make_win32_path_UTF8_2_wchar(POOLMEM ** pszUCS,const char * pszUTF,BOOL * pBIsRawPath)663 make_win32_path_UTF8_2_wchar(POOLMEM **pszUCS, const char *pszUTF, BOOL* pBIsRawPath /*= NULL*/)
664 {
665    P(Win32Convmutex);
666    /* if we find the utf8 string in cache, we use the cached wchar version. */
667    if (!g_pWin32ConvUTF8Cache) {
668       Win32ConvInitCache();
669    } else if (bstrcmp(pszUTF, g_pWin32ConvUTF8Cache)) {
670       /* Return cached value */
671       int32_t nBufSize = sizeof_pool_memory(g_pWin32ConvUCS2Cache);
672       *pszUCS = check_pool_memory_size(*pszUCS, nBufSize);
673       wcscpy((LPWSTR) *pszUCS, (LPWSTR)g_pWin32ConvUCS2Cache);
674       V(Win32Convmutex);
675       return nBufSize / sizeof (WCHAR);
676    }
677 
678    /* convert from utf-8 to wchar */
679    int nRet = wutf8_path_2_wchar(pszUCS, pszUTF);
680 
681 #ifdef USE_WIN32_32KPATHCONVERSION
682    /* add \\?\ to support 32K long filepaths */
683    norm_wchar_win32_path(pszUCS, pBIsRawPath);
684 #else
685    if (pBIsRawPath)
686       *pBIsRawPath = FALSE;
687 #endif
688 
689    /* populate cache */
690    g_pWin32ConvUCS2Cache = check_pool_memory_size(g_pWin32ConvUCS2Cache, sizeof_pool_memory(*pszUCS));
691    wcscpy((LPWSTR) g_pWin32ConvUCS2Cache, (LPWSTR) *pszUCS);
692 
693    g_dwWin32ConvUTF8strlen = strlen(pszUTF);
694    g_pWin32ConvUTF8Cache = check_pool_memory_size(g_pWin32ConvUTF8Cache, g_dwWin32ConvUTF8strlen+2);
695    bstrncpy(g_pWin32ConvUTF8Cache, pszUTF, g_dwWin32ConvUTF8strlen+1);
696    V(Win32Convmutex);
697 
698    return nRet;
699 }
700 
701 #if !defined(_MSC_VER) || (_MSC_VER < 1400) // VC8+
umask(int)702 int umask(int)
703 {
704    return 0;
705 }
706 #endif
707 
708 #ifndef LOAD_WITH_ALTERED_SEARCH_PATH
709 #define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008
710 #endif
711 
dlopen(const char * file,int mode)712 void *dlopen(const char *file, int mode)
713 {
714    void *handle;
715 
716    handle = LoadLibraryEx(file, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
717    return handle;
718 }
719 
dlsym(void * handle,const char * name)720 void *dlsym(void *handle, const char *name)
721 {
722    void *symaddr;
723    symaddr = (void *)GetProcAddress((HMODULE)handle, name);
724    return symaddr;
725 }
726 
dlclose(void * handle)727 int dlclose(void *handle)
728 {
729    if (handle && !FreeLibrary((HMODULE)handle)) {
730       errno = b_errno_win32;
731       return 1;        /* failed */
732    }
733    return 0;           /* OK */
734 }
735 
dlerror(void)736 char *dlerror(void)
737 {
738    static char buf[200];
739    const char *err = errorString();
740    bstrncpy(buf, (char *)err, sizeof(buf));
741    LocalFree((void *)err);
742    return buf;
743 }
744 
fcntl(int fd,int cmd)745 int fcntl(int fd, int cmd)
746 {
747    return 0;
748 }
749 
chown(const char * k,uid_t,gid_t)750 int chown(const char *k, uid_t, gid_t)
751 {
752    return 0;
753 }
754 
lchown(const char * k,uid_t,gid_t)755 int lchown(const char *k, uid_t, gid_t)
756 {
757    return 0;
758 }
759 
760 long int
random(void)761 random(void)
762 {
763     return rand();
764 }
765 
766 void
srandom(unsigned int seed)767 srandom(unsigned int seed)
768 {
769    srand(seed);
770 }
771 // /////////////////////////////////////////////////////////////////
772 // convert from Windows concept of time to Unix concept of time
773 // /////////////////////////////////////////////////////////////////
774 void
cvt_utime_to_ftime(const time_t & time,FILETIME & wintime)775 cvt_utime_to_ftime(const time_t  &time, FILETIME &wintime)
776 {
777    uint64_t mstime = time;
778    mstime *= WIN32_FILETIME_SCALE;
779    mstime += WIN32_FILETIME_ADJUST;
780 
781 #if defined(_MSC_VER)
782    wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
783 #else
784    wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL);
785 #endif
786    wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
787 }
788 
789 time_t
cvt_ftime_to_utime(const FILETIME & time)790 cvt_ftime_to_utime(const FILETIME &time)
791 {
792     uint64_t mstime = time.dwHighDateTime;
793     mstime <<= 32;
794     mstime |= time.dwLowDateTime;
795 
796     mstime -= WIN32_FILETIME_ADJUST;
797     mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
798 
799     return (time_t) (mstime & 0xffffffff);
800 }
801 
errorString(void)802 static const char *errorString(void)
803 {
804    LPVOID lpMsgBuf;
805 
806    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
807                  FORMAT_MESSAGE_FROM_SYSTEM |
808                  FORMAT_MESSAGE_IGNORE_INSERTS,
809                  NULL,
810                  GetLastError(),
811                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
812                  (LPTSTR) &lpMsgBuf,
813                  0,
814                  NULL);
815 
816    /* Strip any \r or \n */
817    char *rval = (char *) lpMsgBuf;
818    char *cp = strchr(rval, '\r');
819    if (cp != NULL) {
820       *cp = 0;
821    } else {
822       cp = strchr(rval, '\n');
823       if (cp != NULL)
824          *cp = 0;
825    }
826    return rval;
827 }
828 
829 /* retrieve information about reparse point
830  * the HANDLE must have been open with flag FILE_FLAG_OPEN_REPARSE_POINT
831  * return value can be any of
832  * -1 for error
833  *  0 this is not a M$ reparse point, BUT it can be reparse point !!!!
834  * WIN32_REPARSE_POINT Can be any reparse point, but not one of the following
835  * WIN32_MOUNT_POINT   A Volume mounted in a directory
836  * WIN32_JUNCTION_POINT A special type of symlink to a directory
837  * WIN32_SYMLINK_POINT A symlink to a file or a directory (look for FILE_ATTRIBUTE_DIRECTORY )
838  */
win_get_reparse_point(HANDLE h,DWORD * reparse_tag=NULL,POOLMEM ** reparse=NULL)839 static int win_get_reparse_point(HANDLE h, DWORD *reparse_tag=NULL, POOLMEM **reparse=NULL)
840 {
841    int ret = WIN32_REPARSE_NONE;
842    char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
843    REPARSE_DATA_BUFFER *rdata = (REPARSE_DATA_BUFFER *)buffer;
844 
845    // Query the reparse data
846    DWORD dwRetLen;
847    BOOL r = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, rdata, sizeof(buffer), &dwRetLen, NULL);
848    if (r == FALSE)
849    {
850       Dmsg1(0, "DeviceIoControl error=%ld\n", GetLastError());
851       return -1;
852    }
853 
854    if (reparse_tag != NULL) {
855       *reparse_tag = rdata->ReparseTag;
856    }
857    if (IsReparseTagMicrosoft(rdata->ReparseTag))
858    {
859       if (rdata->ReparseTag == IO_REPARSE_TAG_SYMLINK)
860       {
861          if (reparse != NULL) {
862             wchar_path_2_wutf8(reparse,
863                   (wchar_t *)&rdata->SymbolicLinkReparseBuffer.PathBuffer[rdata->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t)]);
864          }
865          ret = WIN32_SYMLINK_POINT;
866          goto bailout;
867       } else if (rdata->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
868          POOLMEM *path = NULL;
869          POOLMEM **rpath = reparse;
870          if (rpath == NULL) {
871             path = get_pool_memory(PM_FNAME);
872             rpath = &path;
873          }
874          wchar_path_2_wutf8(rpath,
875                (wchar_t *)&rdata->MountPointReparseBuffer.PathBuffer[rdata->MountPointReparseBuffer.SubstituteNameOffset / sizeof(wchar_t)]);
876          ret = (strncasecmp(*rpath, "\\??\\Volume{", 11) == 0)?WIN32_MOUNT_POINT:WIN32_JUNCTION_POINT;
877          if (path != NULL) {
878             free_pool_memory(path);
879          }
880          goto bailout;
881       }
882       ret = WIN32_REPARSE_POINT;
883       goto bailout;
884    }
885    else
886    {
887       // Not a Microsoft-reparse point
888       ret = WIN32_REPARSE_NONE;
889    }
890 bailout:
891    return ret;
892 }
893 
win_get_reparse_point(const wchar_t * path,DWORD * reparse_tag=NULL,POOLMEM ** reparse=NULL)894 static int win_get_reparse_point(const wchar_t *path, DWORD *reparse_tag=NULL, POOLMEM **reparse=NULL)
895 {
896    HANDLE h = CreateFileW(path, FILE_READ_EA,
897                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
898                 NULL, OPEN_EXISTING,
899                 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
900    if (h == INVALID_HANDLE_VALUE) {
901       return -1;
902    }
903    int type = win_get_reparse_point(h, reparse_tag, reparse);
904    CloseHandle(h);
905    return type;
906 }
907 
win_get_reparse_point(const char * path,DWORD * reparse_tag=NULL,POOLMEM ** reparse=NULL)908 static int win_get_reparse_point(const char *path, DWORD *reparse_tag=NULL, POOLMEM **reparse=NULL)
909 {
910    POOL_MEM wpath(PM_FNAME);
911    make_win32_path_UTF8_2_wchar(&wpath.addr(), path);
912 
913    return win_get_reparse_point((wchar_t*)wpath.c_str(), reparse_tag, reparse);
914 }
915 
916 /* Convert Windows file attributes into a "unix" st_mode */
attribute_to_mode(DWORD FileAttributes)917 static uint16_t attribute_to_mode(DWORD FileAttributes)
918 {
919    uint16_t st_mode = 0777;               /* start with everything */
920    if (FileAttributes & FILE_ATTRIBUTE_READONLY)
921       st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
922    if (FileAttributes & FILE_ATTRIBUTE_SYSTEM)
923       st_mode &= ~S_IRWXO; /* remove everything for other */
924    if (FileAttributes & FILE_ATTRIBUTE_HIDDEN)
925       st_mode |= S_ISVTX; /* use sticky bit -> hidden */
926    if (FileAttributes & FILE_ATTRIBUTE_ENCRYPTED)
927       st_mode |= S_ISGID; /* use set group ID -> encrypted */
928    if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
929       st_mode |= S_IFDIR;
930    } else {
931       st_mode |= S_IFREG;
932    }
933    return st_mode;
934 }
935 
936 /* fill in sb with Windows attributes */
attributes_to_stat(struct stat * sb,DWORD FileAttributes,DWORD FileSizeHigh,DWORD FileSizeLow,const FILETIME & LastAccessTime,const FILETIME & LastWriteTime)937 static void attributes_to_stat(struct stat *sb, DWORD FileAttributes,
938       DWORD FileSizeHigh, DWORD FileSizeLow,
939       const FILETIME &LastAccessTime, const FILETIME &LastWriteTime)
940 {
941    sb->st_mode = attribute_to_mode(FileAttributes);
942    sb->st_fattrs = FileAttributes;
943 
944    sb->st_size = FileSizeHigh;
945    sb->st_size <<= 32;
946    sb->st_size |= FileSizeLow;
947 
948    sb->st_blksize = 4096;
949 
950    sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
951 
952    sb->st_atime = cvt_ftime_to_utime(LastAccessTime);
953    sb->st_mtime = cvt_ftime_to_utime(LastWriteTime);
954    sb->st_ctime = MAX(sb->st_mtime, sb->st_ctime);
955 }
956 #if 0
957 /*
958  * This is only called for directories, and is used to get the directory
959  *  attributes and find out if we have a junction point or a mount point
960  *  or other kind of "funny" directory.
961  *  Notice: Python use CreateFileW() and GetFileInformationByHandle()
962  *  to get this information instead and fallback to FindFirstFile()
963  */
964 static int
965 statDir(const char *file, struct stat *sb, POOLMEM **readlnk=NULL)
966 {
967    WIN32_FIND_DATAW info_w;       // window's file info
968    HANDLE h = INVALID_HANDLE_VALUE;
969 
970    /*
971     * Oh, cool, another exception: Microsoft doesn't let us do
972     *  FindFile operations on a Drive, so simply fake root attributes.
973     *  We could try CreateFileW() and GetFileInformationByHandle()
974     */
975    if (file[1] == ':' && file[2] == 0) {
976       time_t now = time(NULL);
977       Dmsg1(dbglvl, "faking ROOT attrs(%s).\n", file);
978       sb->st_mode = S_IFDIR;
979       sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
980       sb->st_ctime = now;    /* File change time (inode change...) */
981       sb->st_mtime = now;    /* File modify time */
982       sb->st_atime = now;    /* File access time */
983       sb->st_rdev = 0;
984       return 0;
985     }
986 
987    POOL_MEM pwszBuf(PM_FNAME);
988    make_win32_path_UTF8_2_wchar(&pwszBuf.addr(), file);
989 
990    Dmsg1(dbglvl, "FindFirstFileW=%s\n", file);
991    h = p_FindFirstFileW((LPCWSTR)pwszBuf.c_str(), &info_w);
992 
993    if (h == INVALID_HANDLE_VALUE) {
994       const char *err = errorString();
995       /*
996        * Note, in creating leading paths, it is normal that
997        * the file does not exist.
998        */
999       Dmsg2(2099, "FindFirstFile(%s):%s\n", file, err);
1000       LocalFree((void *)err);
1001       errno = b_errno_win32;
1002       return -1;
1003    }
1004 
1005    FindClose(h);
1006 
1007    attributes_to_stat(sb, info_w.dwFileAttributes,
1008          info_w.nFileSizeHigh, info_w.nFileSizeLow,
1009          info_w.ftLastAccessTime, info_w.ftLastWriteTime);
1010 
1011    Dmsg2(200, "Fattrs=0x%x st_mode=0x%x\n", sb->st_fattrs, sb->st_mode);
1012    /*
1013     * Store reparse/mount point info in st_rdev.  Note a
1014     *  Win32 reparse point (junction point) is like a link
1015     *  though it can have many properties (directory link,
1016     *  soft link, hard link, HSM, ...
1017     *  A mount point is a reparse point where another volume
1018     *  is mounted, so it is like a Unix mount point (change of
1019     *  filesystem).
1020     */
1021    if (info_w.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1022       sb->st_rdev = WIN32_MOUNT_POINT;
1023    } else {
1024       sb->st_rdev = 0;
1025    }
1026    /* This is a lot of work just to know that it is deduped */
1027    if (info_w.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
1028        (info_w.dwReserved0 & IO_REPARSE_TAG_DEDUP)) {
1029       sb->st_fattrs |= FILE_ATTRIBUTE_DEDUP;  /* add our own bit */
1030    }
1031    if ((info_w.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
1032         (info_w.dwReserved0 & IO_REPARSE_TAG_MOUNT_POINT)) {
1033       sb->st_rdev = WIN32_MOUNT_POINT;           /* mount point */
1034       /*
1035        * Now to find out if the directory is a mount point or
1036        * a reparse point, we must do a song and a dance.
1037        * Explicitly open the file to read the reparse point, then
1038        * call DeviceIoControl to find out if it points to a Volume
1039        * or to a directory.
1040        */
1041       h = CreateFileW((LPCWSTR)pwszBuf.c_str(), GENERIC_READ,
1042              FILE_SHARE_READ, NULL, OPEN_EXISTING,
1043              FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
1044              NULL);
1045       if (h != INVALID_HANDLE_VALUE) {
1046          char dummy[1000];
1047          REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)dummy;
1048          rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
1049          DWORD bytes;
1050          bool ok;
1051          ok = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT,
1052                  NULL, 0,                           /* in buffer, bytes */
1053                  (LPVOID)rdb, (DWORD)sizeof(dummy), /* out buffer, btyes */
1054                  (LPDWORD)&bytes, (LPOVERLAPPED)0);
1055          if (ok) {
1056             POOLMEM *utf8 = get_pool_memory(PM_NAME);
1057             wchar_path_2_wutf8(&utf8, (wchar_t *)rdb->SymbolicLinkReparseBuffer.PathBuffer);
1058             Dmsg2(dbglvl, "Junction %s points to: %s\n", file, utf8);
1059             if (strncasecmp(utf8, "\\??\\volume{", 11) == 0) {
1060                Dmsg2(dbglvl, "FIRST MOUNT POINT %s points to: %s remove code for SECOND\n", file, utf8);
1061                sb->st_rdev = WIN32_MOUNT_POINT;
1062             } else if (strncasecmp(utf8, "\\\\?\\volume{", 11) == 0) {
1063                /* Alain: I think this one is the right one !!!! */
1064                Dmsg2(dbglvl, "SECOND MOUNT POINT %s points to: %s remove code for FIRST\n", file, utf8);
1065                sb->st_rdev = WIN32_MOUNT_POINT;
1066             } else {
1067                /* It points to a directory so we ignore it. */
1068                sb->st_rdev = WIN32_JUNCTION_POINT;
1069             }
1070             /* If requested, store the link for future use */
1071             if (readlnk) {
1072                pm_strcpy(readlnk, utf8);
1073             }
1074             free_pool_memory(utf8);
1075          }
1076          CloseHandle(h);
1077       } else {
1078          Dmsg1(dbglvl, "Invalid handle from CreateFile(%s)\n", file);
1079       }
1080    }
1081    Dmsg2(dbglvl, "st_rdev=%d file=%s\n", sb->st_rdev, file);
1082    sb->st_ctime = MAX(sb->st_mtime, sb->st_ctime);
1083    /* Note ctime is last change time -- not creation time */
1084    Dmsg2(200, "Fattrs=0x%x st_mode=0x%x\n", sb->st_fattrs, sb->st_mode);
1085 
1086    return 0;
1087 }
1088 #endif
1089 
1090 /* On success, readlink() returns the number of bytes placed in  buf.   On
1091  * error, -1 is returned and errno is set to indicate the error.
1092  *
1093  * TODO: Still need to activate the readlink() call in find_one.c
1094  *       by returning a S_ISLNK(st_mode) compatible flag.
1095  */
1096 int
readlink(const char * path,char * buf,int bufsiz)1097 readlink(const char *path, char *buf, int bufsiz)
1098 {
1099    int ret=-1;
1100    POOLMEM *lnk = get_pool_memory(PM_FNAME);
1101    *lnk = 0;
1102    int type = win_get_reparse_point(path, NULL, &lnk);
1103    if (type == WIN32_SYMLINK_POINT) {
1104       ret = bstrncpy(buf, lnk, bufsiz) - buf - 1; // Don't count the last \0
1105    }
1106    free_pool_memory(lnk);
1107    return ret;
1108 }
1109 
1110 /* symlink() shall return 0; otherwise, it shall return -1 and set errno to
1111  * indicate the error.
1112  */
1113 int
symlink(const char * path1,const char * path2)1114 symlink(const char *path1, const char *path2)
1115 {
1116    int ret = 0;
1117    struct stat st;
1118    DWORD isdir = 0;
1119 
1120    if (stat(path1, &st) == 0) {
1121       if (st.st_mode & S_IFDIR) {
1122          isdir=1;
1123       }
1124    } else {
1125       Dmsg1(200, "Cannot find the source directory %s\n", path1);
1126       return -1;
1127    }
1128 
1129    if (!p_CreateSymbolicLinkW) {
1130       Dmsg0(200, "No implementation of CreateSymbolicLink available\n");
1131       return -1;
1132    }
1133 
1134    POOL_MEM pwszBuf1(PM_FNAME);
1135    POOL_MEM pwszBuf2(PM_FNAME);
1136 
1137    make_win32_path_UTF8_2_wchar(&pwszBuf1.addr(), path1);
1138    make_win32_path_UTF8_2_wchar(&pwszBuf2.addr(), path2);
1139 
1140    Dmsg2(dbglvl, "Trying to symlink (%s -> %s)\n", path1, path2);
1141 
1142    if (!p_CreateSymbolicLinkW((LPCWSTR)pwszBuf2.c_str(), (LPCWSTR)pwszBuf1.c_str(), isdir)) {
1143       const char *err = errorString();
1144       Dmsg3(200, "Cannot create symlink (%s -> %s):%s\n", path1, path2, err);
1145       LocalFree((void *)err);
1146       errno = b_errno_win32;
1147       ret = -1;
1148    }
1149 
1150    return ret;
1151 }
1152 
1153 /* Do a stat() on a valid HANDLE (opened with CreateFile()) */
hstat(HANDLE h,struct stat * sb)1154 int hstat(HANDLE h, struct stat *sb)
1155 {
1156    BY_HANDLE_FILE_INFORMATION info;
1157 
1158    if (!GetFileInformationByHandle(h, &info)) {
1159        const char *err = errorString();
1160        Dmsg1(dbglvl, "GetfileInformationByHandle: %s\n", err);
1161        LocalFree((void *)err);
1162        errno = b_errno_win32;
1163        return -1;
1164    }
1165 
1166    /* We should modify only variables that are modified in stat()
1167     * everything else should be carefully tested.
1168     */
1169 
1170    /* When turned on, we see a lot of messages such as
1171     * C:/PerfLogs is a different filesystem. Will not descend from C:/ into it.
1172     */
1173    //sb->st_dev = info.dwVolumeSerialNumber;
1174 
1175    /* The st_ino is not used in stat() */
1176    sb->st_ino = info.nFileIndexHigh;
1177    sb->st_ino <<= 32;
1178    sb->st_ino |= info.nFileIndexLow;
1179 
1180    sb->st_nlink = 1;
1181 #if 0                           // We don't have the link() call right now
1182    // TODO: something with CreateHardLinkFunc()
1183    sb->st_nlink = (short)info.nNumberOfLinks;
1184    if (sb->st_nlink > 1) {
1185       Dmsg1(dbglvl,  "st_nlink=%d\n", sb->st_nlink);
1186    }
1187 #endif
1188    attributes_to_stat(sb, info.dwFileAttributes,
1189          info.nFileSizeHigh, info.nFileSizeLow,
1190          info.ftLastAccessTime, info.ftLastWriteTime);
1191 
1192    /* Get the ChangeTime information with an other API, when attributes are modified
1193     * the ChangeTime is modified while CreationTime and WriteTime are not
1194     */
1195    FILE_BASIC_INFO file_basic_info;
1196    if (p_GetFileInformationByHandleEx &&
1197        p_GetFileInformationByHandleEx(h, FileBasicInfo, &file_basic_info, sizeof(file_basic_info))) {
1198       FILETIME *pftChangeTime = (FILETIME *)&file_basic_info.ChangeTime;
1199       sb->st_ctime = cvt_ftime_to_utime(*pftChangeTime);
1200       sb->st_ctime = MAX(sb->st_mtime, sb->st_ctime);
1201    }
1202 
1203    /* Use st_rdev to store reparse attribute */
1204    if  (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1205       DWORD reparse_tag;
1206       sb->st_rdev = WIN32_REPARSE_POINT;
1207       int type = win_get_reparse_point(h, &reparse_tag);
1208       if (type == WIN32_MOUNT_POINT || type == WIN32_JUNCTION_POINT) {
1209          sb->st_rdev = type;
1210          if (!(sb->st_mode & S_IFDIR)) {
1211             Pmsg1(0, "A reparse point of type %d is expected to be a directory\n", type);
1212             ASSERTD(FALSE, "A mount point or a junction should be a directory\n");
1213          }
1214       } else if (type == WIN32_SYMLINK_POINT) {
1215          sb->st_rdev = type;
1216       }
1217    }
1218    Dmsg3(dbglvl, "st_rdev=%d sizino=%d ino=%lld\n", sb->st_rdev, sizeof(sb->st_ino),
1219       (long long)sb->st_ino);
1220 
1221    Dmsg2(200, "Fattrs=0x%x st_mode=0x%x\n", sb->st_fattrs, sb->st_mode);
1222    return 0;
1223 }
1224 
1225 /* add a trailing "\\" to a "naked" drive letter like "X:"
1226  * expect a wchar_t path */
sanitize_drive_root(POOLMEM * & wpath)1227 void sanitize_drive_root(POOLMEM *&wpath)
1228 {
1229    wchar_t *p=(wchar_t *)wpath;
1230    if (p[1] == L':' && p[2] == L'\0') {
1231       wpath = check_pool_memory_size(wpath, (wcslen((wchar_t*)wpath)+1)*sizeof(wchar_t));
1232       wcscat((wchar_t *)wpath, L"\\");
1233    }
1234 }
1235 
1236 /*
1237  * stat() don't like path like:
1238  * - c:
1239  * - \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy5
1240  * You must add a trailing '\'
1241  */
stat(const char * file,struct stat * sb)1242 int stat(const char *file, struct stat *sb)
1243 {
1244    WIN32_FILE_ATTRIBUTE_DATA data;
1245 
1246    errno = 0;
1247    /* We do the first try with a file HANDLER, because we want to use the
1248     * ChangeTime that is only available with GetFileInformationByHandleEx
1249     */
1250    POOL_MEM pwszBuf(PM_FNAME);
1251    make_win32_path_UTF8_2_wchar(&pwszBuf.addr(), file);
1252    sanitize_drive_root(pwszBuf.addr());
1253 
1254 #if 0
1255    ret = stat2((wchar_t *)pwszBuf.c_str(), sb);
1256 
1257    if (!ret) {
1258       return ret;
1259    }
1260 
1261    if (!p_GetFileAttributesExW) {
1262       return -1;
1263    }
1264    /* We were not able to open a filehandler on the file to get attributes,
1265     * so we try with the name. It may happen for example with encrypted files.
1266     */
1267 #endif
1268    memset(sb, 0, sizeof(*sb));
1269    BOOL b = p_GetFileAttributesExW((LPCWSTR)pwszBuf.c_str(), GetFileExInfoStandard, &data);
1270 
1271    if (!b) {
1272       const char *err = errorString();
1273       Dmsg3(dbglvl, "GetFileAttributesExW(%s):%s %ls\n", file, err, pwszBuf.c_str());
1274       LocalFree((void *)err);
1275       return -1;
1276    }
1277 
1278    attributes_to_stat(sb, data.dwFileAttributes,
1279          data.nFileSizeHigh, data.nFileSizeLow,
1280          data.ftLastAccessTime, data.ftLastWriteTime);
1281 
1282    /* Use st_rdev to store reparse attribute */
1283    sb->st_rdev = (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? WIN32_REPARSE_POINT : 0;
1284 
1285    sb->st_nlink = 1;
1286    sb->st_ctime = sb->st_mtime;
1287 
1288    if  (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1289 #if 0
1290       WIN32_FIND_DATAW info_w;
1291       HANDLE h = p_FindFirstFileW((LPCWSTR)pwszBuf.c_str(), &info_w);
1292 
1293       sb->st_rdev = WIN32_REPARSE_POINT;
1294       if (h == INVALID_HANDLE_VALUE) {
1295          const char *err = errorString();
1296          /*
1297           * Note, in creating leading paths, it is normal that
1298           * the file does not exist.
1299           */
1300          Dmsg2(2099, "FindFirstFile(%s):%s\n", file, err);
1301          LocalFree((void *)err);
1302          errno = b_errno_win32;
1303          return -1;
1304       }
1305       FindClose(h);
1306 #endif
1307 
1308       DWORD reparse_tag;
1309       int type = win_get_reparse_point((wchar_t*)pwszBuf.c_str(), &reparse_tag);
1310 #ifndef DO_WE_NEED_THAT // ?????
1311       if (reparse_tag & IO_REPARSE_TAG_DEDUP) {
1312          sb->st_fattrs |= FILE_ATTRIBUTE_DEDUP;  /* add our own bit */
1313       }
1314 #endif
1315       Dmsg1(dbglvl, "reparse_point type=%d\n", type);
1316       if (type == WIN32_MOUNT_POINT || type == WIN32_JUNCTION_POINT) {
1317          sb->st_rdev = type;
1318          if (!(sb->st_mode & S_IFDIR)) {
1319             Pmsg1(0, "A reparse point of type %d is expected to be a directory\n", type);
1320             ASSERTD(FALSE, "A mount point or a junction should be a directory\n");
1321          }
1322       } else if (type == WIN32_SYMLINK_POINT) {
1323          sb->st_rdev = type;
1324       }
1325    }
1326    Dmsg4(dbglvl, "sizino=%d ino=%lld file=%s rdev=%d\n", sizeof(sb->st_ino),
1327                        (long long)sb->st_ino, file, sb->st_rdev);
1328    Dmsg2(200, "Fattrs=0x%x st_mode=0x%x\n", sb->st_fattrs, sb->st_mode);
1329    return 0;
1330 }
1331 
1332 int
fstat(intptr_t fd,struct stat * sb)1333 fstat(intptr_t fd, struct stat *sb)
1334 {
1335    return hstat((HANDLE)_get_osfhandle(fd), sb);
1336 }
1337 
1338 /*
1339  * We write our own ftruncate because the one in the
1340  *  Microsoft library mrcrt.dll does not truncate
1341  *  files greater than 2GB.
1342  *  KES - May 2007
1343  */
win32_ftruncate(int fd,int64_t length)1344 int win32_ftruncate(int fd, int64_t length)
1345 {
1346    /* Set point we want to truncate file */
1347    __int64 pos = _lseeki64(fd, (__int64)length, SEEK_SET);
1348 
1349    if (pos != (__int64)length) {
1350       errno = EACCES;         /* truncation failed, get out */
1351       return -1;
1352    }
1353 
1354    /* Truncate file */
1355    if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0) {
1356       errno = b_errno_win32;
1357       return -1;
1358    }
1359    errno = 0;
1360    return 0;
1361 }
1362 
win_flock_hold(HANDLE fhandle,int non_blocking,int exclusive)1363 int win_flock_hold(HANDLE fhandle, int non_blocking, int exclusive) {
1364    DWORD file_lower, file_upper;
1365    file_lower = GetFileSize(fhandle, &file_upper);
1366    OVERLAPPED ov;
1367    memset(&ov, 0, sizeof ov);
1368    int flags = 0;
1369 
1370    if (non_blocking) {
1371       flags |= LOCKFILE_FAIL_IMMEDIATELY;
1372    }
1373 
1374    if (exclusive) {
1375       flags |= LOCKFILE_EXCLUSIVE_LOCK;
1376    }
1377 
1378    /* Lock the whole file */
1379    return LockFileEx(fhandle, flags, 0, file_lower, file_upper, &ov);
1380 }
1381 
win_flock_release(HANDLE fhandle)1382 int win_flock_release(HANDLE fhandle) {
1383    DWORD size_lower, size_upper;
1384    size_lower = GetFileSize(fhandle, &size_upper);
1385    return UnlockFile(fhandle, 0, 0, size_lower, size_upper);
1386 }
1387 
flock(int fd,int operation)1388 int flock(int fd, int operation)
1389 {
1390    DWORD success;
1391    HANDLE fhandle = (HANDLE) _get_osfhandle(fd);
1392 
1393    if (fhandle == INVALID_HANDLE_VALUE) {
1394       errno = EBADF;
1395       return -1;
1396    }
1397 
1398    int nb_flag = operation & LOCK_NB;
1399    operation &= ~LOCK_NB;
1400 
1401    switch (operation) {
1402       case LOCK_SH:
1403          success = win_flock_hold(fhandle, nb_flag, 0);
1404          break;
1405       case LOCK_EX:
1406          success = win_flock_hold(fhandle, nb_flag, 1);
1407          break;
1408       case LOCK_UN:
1409          success = win_flock_release(fhandle);
1410          break;
1411       default:
1412          errno = EINVAL;
1413          return -1;
1414    }
1415 
1416    if (!success) {
1417       DWORD err = GetLastError();
1418       switch (err) {
1419          case ERROR_LOCK_VIOLATION:
1420             errno = EAGAIN;
1421             break;
1422          case ERROR_NOT_ENOUGH_MEMORY:
1423             errno = ENOMEM;
1424             break;
1425          case ERROR_BAD_COMMAND:
1426             errno = EINVAL;
1427             break;
1428          default:
1429             errno = err;
1430       }
1431 
1432       return -1;
1433    }
1434 
1435    return 0;
1436 }
1437 
fcntl(int fd,int cmd,long arg)1438 int fcntl(int fd, int cmd, long arg)
1439 {
1440    int rval = 0;
1441 
1442    switch (cmd) {
1443    case F_GETFL:
1444       rval = O_NONBLOCK;
1445       break;
1446 
1447    case F_SETFL:
1448       rval = 0;
1449       break;
1450 
1451    default:
1452       errno = EINVAL;
1453       rval = -1;
1454       break;
1455    }
1456 
1457    return rval;
1458 }
1459 
1460 int
lstat(const char * file,struct stat * sb)1461 lstat(const char *file, struct stat *sb)
1462 {
1463    return stat(file, sb);
1464 }
1465 
1466 void
sleep(int sec)1467 sleep(int sec)
1468 {
1469    Sleep(sec * 1000);
1470 }
1471 
1472 int
geteuid(void)1473 geteuid(void)
1474 {
1475    return 0;
1476 }
1477 
1478 int
execvp(const char *,char * [])1479 execvp(const char *, char *[]) {
1480    errno = ENOSYS;
1481    return -1;
1482 }
1483 
1484 
1485 int
fork(void)1486 fork(void)
1487 {
1488    errno = ENOSYS;
1489    return -1;
1490 }
1491 
1492 int
pipe(int[])1493 pipe(int[])
1494 {
1495    errno = ENOSYS;
1496    return -1;
1497 }
1498 
1499 int
waitpid(int,int *,int)1500 waitpid(int, int*, int)
1501 {
1502    errno = ENOSYS;
1503    return -1;
1504 }
1505 
1506 #ifndef HAVE_MINGW
1507 int
strcasecmp(const char * s1,const char * s2)1508 strcasecmp(const char *s1, const char *s2)
1509 {
1510    register int ch1, ch2;
1511 
1512    if (s1==s2)
1513       return 0;       /* strings are equal if same object. */
1514    else if (!s1)
1515       return -1;
1516    else if (!s2)
1517       return 1;
1518    do {
1519       ch1 = *s1;
1520       ch2 = *s2;
1521       s1++;
1522       s2++;
1523    } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
1524 
1525    return(ch1 - ch2);
1526 }
1527 #endif //HAVE_MINGW
1528 
1529 int
strncasecmp(const char * s1,const char * s2,int len)1530 strncasecmp(const char *s1, const char *s2, int len)
1531 {
1532    register int ch1 = 0, ch2 = 0;
1533 
1534    if (s1==s2)
1535       return 0;       /* strings are equal if same object. */
1536    else if (!s1)
1537       return -1;
1538    else if (!s2)
1539       return 1;
1540 
1541    while (len--) {
1542       ch1 = *s1;
1543       ch2 = *s2;
1544       s1++;
1545       s2++;
1546       if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
1547    }
1548 
1549    return (ch1 - ch2);
1550 }
1551 
1552 int
gettimeofday(struct timeval * tv,struct timezone *)1553 gettimeofday(struct timeval *tv, struct timezone *)
1554 {
1555     SYSTEMTIME now;
1556     FILETIME tmp;
1557 
1558     GetSystemTime(&now);
1559 
1560     if (tv == NULL) {
1561        errno = EINVAL;
1562        return -1;
1563     }
1564     if (!SystemTimeToFileTime(&now, &tmp)) {
1565        errno = b_errno_win32;
1566        return -1;
1567     }
1568 
1569     int64_t _100nsec = tmp.dwHighDateTime;
1570     _100nsec <<= 32;
1571     _100nsec |= tmp.dwLowDateTime;
1572     _100nsec -= WIN32_FILETIME_ADJUST;
1573 
1574     tv->tv_sec = (long)(_100nsec / 10000000);
1575     tv->tv_usec = (long)((_100nsec % 10000000)/10);
1576     return 0;
1577 
1578 }
1579 
1580 /*
1581  * Write in Windows System log
1582  */
syslog(int type,const char * fmt,...)1583 void syslog(int type, const char *fmt, ...)
1584 {
1585    va_list   arg_ptr;
1586    int len, maxlen;
1587    POOLMEM *msg;
1588 
1589    msg = get_pool_memory(PM_EMSG);
1590 
1591    for (;;) {
1592       maxlen = sizeof_pool_memory(msg) - 1;
1593       va_start(arg_ptr, fmt);
1594       len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
1595       va_end(arg_ptr);
1596       if (len < 0 || len >= (maxlen-5)) {
1597          msg = realloc_pool_memory(msg, maxlen + maxlen/2);
1598          continue;
1599       }
1600       break;
1601    }
1602    LogErrorMsg((const char *)msg);
1603    free_memory(msg);
1604 }
1605 
1606 void
closelog()1607 closelog()
1608 {
1609 }
1610 
1611 struct passwd *
getpwuid(uid_t)1612 getpwuid(uid_t)
1613 {
1614     return NULL;
1615 }
1616 
1617 struct group *
getgrgid(uid_t)1618 getgrgid(uid_t)
1619 {
1620     return NULL;
1621 }
1622 
1623 // implement opendir/readdir/closedir on top of window's API
1624 
1625 typedef struct _dir
1626 {
1627     WIN32_FIND_DATAW data_w;    // window's file info (wchar version)
1628     POOLMEM     *spec;           // the directory we're traversing
1629     HANDLE      dirh;           // the search handle
1630     bool        call_findnextfile; // use FindFirstFile data first
1631 } _dir;
1632 
1633 DIR *
opendir(const char * path)1634 opendir(const char *path)
1635 {
1636     /* enough space for VSS !*/
1637     _dir *rval = NULL;
1638     POOL_MEM pwcBuf(PM_FNAME);
1639 
1640     if (path == NULL) {
1641        errno = ENOENT;
1642        return NULL;
1643     }
1644     if (!p_FindFirstFileW || !p_FindNextFileW) {
1645        errno = ENOMEM;
1646        return NULL;
1647     }
1648 
1649     Dmsg1(10, "Opendir path=%s\n", path);
1650     rval = (_dir *)get_pool_memory(PM_FNAME);
1651     rval = (_dir *)check_pool_memory_size((POOLMEM *)rval, sizeof(_dir));
1652     memset (rval, 0, sizeof (_dir));
1653 
1654     rval->spec = get_pool_memory(PM_FNAME);
1655     pm_strcpy(rval->spec, path);
1656 
1657     // convert to wchar_t
1658     make_win32_path_UTF8_2_wchar(&pwcBuf.addr(), path);
1659 
1660     // Add a "*" or "\\*" to the path, see documentation of FindFirstFile()
1661     // Do it after the call to make_win32_path_UTF8_2_wchar() that escape '*'
1662     int len = wcslen((wchar_t*)pwcBuf.c_str());
1663     pwcBuf.check_size((len+2)*sizeof(wchar_t));
1664     wchar_t *p = (wchar_t*)pwcBuf.c_str();
1665     if (p[len-1] != L'\\') {
1666        p[len++] = L'\\';
1667     }
1668     p[len++] = L'*';
1669     p[len] = L'\0';
1670     Dmsg2(10, "opendir XXX=%ls %s\n", p, path);
1671 
1672     rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf.c_str(), &rval->data_w);
1673     rval->call_findnextfile = false;
1674 
1675     if (rval->dirh == INVALID_HANDLE_VALUE) {
1676        if (GetLastError() == ERROR_FILE_NOT_FOUND) {
1677           /* the directory is empty, continue with an INVALID_HANDLE_VALUE handle */
1678           rval->data_w.cFileName[0]='\0';
1679        } else {
1680           goto err;
1681        }
1682     }
1683     Dmsg4(10, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %p cFileName=%ls\n",
1684           path, rval->spec, rval->dirh, rval->data_w.cFileName);
1685 
1686     return (DIR *)rval;
1687 
1688 err:
1689     if (rval) {
1690        if (rval->spec) {
1691           free_pool_memory(rval->spec);
1692        }
1693        free_pool_memory((POOLMEM *)rval);
1694     }
1695     errno = b_errno_win32;
1696     return NULL;
1697 }
1698 
1699 int
closedir(DIR * dirp)1700 closedir(DIR *dirp)
1701 {
1702     _dir *dp = (_dir *)dirp;
1703     if (dp->dirh != INVALID_HANDLE_VALUE) {
1704        FindClose(dp->dirh);
1705     }
1706     free_pool_memory(dp->spec);
1707     free_pool_memory((POOLMEM *)dp);
1708     return 0;
1709 }
1710 
1711 /*
1712   typedef struct _WIN32_FIND_DATA {
1713     DWORD dwFileAttributes;
1714     FILETIME ftCreationTime;
1715     FILETIME ftLastAccessTime;
1716     FILETIME ftLastWriteTime;
1717     DWORD nFileSizeHigh;
1718     DWORD nFileSizeLow;
1719     DWORD dwReserved0;
1720     DWORD dwReserved1;
1721     TCHAR cFileName[MAX_PATH];
1722     TCHAR cAlternateFileName[14];
1723 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1724 */
1725 
breaddir(DIR * dirp,POOLMEM * & dname)1726 int breaddir(DIR *dirp, POOLMEM *&dname)
1727 {
1728    _dir *dp = (_dir *)dirp;
1729 
1730    if (dirp == NULL) {
1731       errno = EBADF;
1732       return EBADF;
1733    }
1734 
1735    if (dp->call_findnextfile) {
1736       if (p_FindNextFileW(dp->dirh, &dp->data_w)) {
1737       } else {
1738          if (GetLastError() == ERROR_NO_MORE_FILES) {
1739             Dmsg1(dbglvl, "breaddir(%p) ERROR_NO_MORE_FILES\n", dirp);
1740             return -1; // end of directory reached
1741          } else {
1742             errno = b_errno_win32;
1743             return b_errno_win32;
1744          }
1745       }
1746     } else {
1747        // use data from FindFirstFile first then next time call FindNextFileW
1748        if (dp->dirh == INVALID_HANDLE_VALUE) {
1749           return -1; // the directory is empty, no "." nor ".." (special case)
1750        }
1751        dp->call_findnextfile = true;
1752     }
1753     wchar_path_2_wutf8(&dname, dp->data_w.cFileName);
1754     Dmsg2(10, "breaddir %ls => %s\n", dp->data_w.cFileName, dname);
1755     return 0;
1756 }
1757 
1758 /*
1759  * Dotted IP address to network address
1760  *
1761  * Returns 1 if  OK
1762  *         0 on error
1763  */
1764 int
inet_aton(const char * a,struct in_addr * inp)1765 inet_aton(const char *a, struct in_addr *inp)
1766 {
1767    const char *cp = a;
1768    uint32_t acc = 0, tmp = 0;
1769    int dotc = 0;
1770 
1771    if (!isdigit(*cp)) {         /* first char must be digit */
1772       return 0;                 /* error */
1773    }
1774    do {
1775       if (isdigit(*cp)) {
1776          tmp = (tmp * 10) + (*cp -'0');
1777       } else if (*cp == '.' || *cp == 0) {
1778          if (tmp > 255) {
1779             return 0;           /* error */
1780          }
1781          acc = (acc << 8) + tmp;
1782          dotc++;
1783          tmp = 0;
1784       } else {
1785          return 0;              /* error */
1786       }
1787    } while (*cp++ != 0);
1788    if (dotc != 4) {              /* want 3 .'s plus EOS */
1789       return 0;                  /* error */
1790    }
1791    inp->s_addr = htonl(acc);     /* store addr in network format */
1792    return 1;
1793 }
1794 
1795 
1796 /*
1797  *    Convert from presentation format (which usually means ASCII printable)
1798  *     to network format (which is usually some kind of binary format).
1799  * return:
1800  *    1 if the address was valid for the specified address family
1801  *    0 if the address wasn't valid (`dst' is untouched in this case)
1802  */
1803 int
binet_pton(int af,const char * src,void * dst)1804 binet_pton(int af, const char *src, void *dst)
1805 {
1806    switch (af) {
1807    case AF_INET:
1808    case AF_INET6:
1809       if (p_InetPton) {
1810          return p_InetPton(af, src, dst);
1811       }
1812       return 0;
1813    default:
1814       return 0;
1815    }
1816 }
1817 
1818 
1819 int
nanosleep(const struct timespec * req,struct timespec * rem)1820 nanosleep(const struct timespec *req, struct timespec *rem)
1821 {
1822     if (rem)
1823         rem->tv_sec = rem->tv_nsec = 0;
1824     Sleep((req->tv_sec * 1000) + (req->tv_nsec/1000000));
1825     return 0;
1826 }
1827 
1828 void
init_signals(void terminate (int sig))1829 init_signals(void terminate(int sig))
1830 {
1831 
1832 }
1833 
1834 void
init_stack_dump(void)1835 init_stack_dump(void)
1836 {
1837 
1838 }
1839 
1840 
1841 long
pathconf(const char * path,int name)1842 pathconf(const char *path, int name)
1843 {
1844     switch(name) {
1845     case _PC_PATH_MAX :
1846         if (strncmp(path, "\\\\?\\", 4) == 0)
1847             return 32767;
1848     case _PC_NAME_MAX :
1849         return 255;
1850     }
1851     errno = ENOSYS;
1852     return -1;
1853 }
1854 
1855 int
WSA_Init(void)1856 WSA_Init(void)
1857 {
1858     WORD wVersionRequested = MAKEWORD(2, 2);
1859     WSADATA wsaData;
1860 
1861     int err = WSAStartup(wVersionRequested, &wsaData);
1862     if (err != 0) {
1863        wVersionRequested = MAKEWORD(2, 0);
1864        err = WSAStartup(wVersionRequested, &wsaData);
1865        if (err != 0) {
1866           wVersionRequested = MAKEWORD(1, 1);
1867           err = WSAStartup(wVersionRequested, &wsaData);
1868        }
1869     }
1870 
1871     if (err != 0) {
1872         printf("Can not start Windows Sockets\n");
1873         errno = ENOSYS;
1874         return -1;
1875     }
1876 
1877     return 0;
1878 }
1879 
fill_attribute(DWORD attr,mode_t mode)1880 static DWORD fill_attribute(DWORD attr, mode_t mode)
1881 {
1882    Dmsg1(dbglvl, "  before attr=%lld\n", (uint64_t) attr);
1883    /* Use Bacula mappings define in stat() above */
1884    if (mode & (S_IRUSR|S_IRGRP|S_IROTH)) { // If file is readable
1885       attr &= ~FILE_ATTRIBUTE_READONLY;    // then this is not READONLY
1886    } else {
1887       attr |= FILE_ATTRIBUTE_READONLY;
1888    }
1889    if (mode & S_ISVTX) {                   // The sticky bit <=> HIDDEN
1890       attr |= FILE_ATTRIBUTE_HIDDEN;
1891    } else {
1892       attr &= ~FILE_ATTRIBUTE_HIDDEN;
1893    }
1894    if (mode & S_ISGID) {                   // The set group ID <=> ENCRYPTED
1895       attr |= FILE_ATTRIBUTE_ENCRYPTED;
1896    } else {
1897       attr &= ~FILE_ATTRIBUTE_ENCRYPTED;
1898    }
1899    if (mode & S_IRWXO) {              // Other can read/write/execute ?
1900       attr &= ~FILE_ATTRIBUTE_SYSTEM; // => Not system
1901    } else {
1902       attr |= FILE_ATTRIBUTE_SYSTEM;
1903    }
1904    Dmsg1(dbglvl, "  after attr=%lld\n", (uint64_t)attr);
1905    return attr;
1906 }
1907 
win32_chmod(const char * path,mode_t mode)1908 int win32_chmod(const char *path, mode_t mode)
1909 {
1910    bool ret=false;
1911    DWORD attr;
1912 
1913    Dmsg2(dbglvl, "win32_chmod(path=%s mode=%lld)\n", path, (uint64_t)mode);
1914    POOL_MEM pwszBuf(PM_FNAME);
1915    make_win32_path_UTF8_2_wchar(&pwszBuf.addr(), path);
1916 
1917    attr = p_GetFileAttributesW((LPCWSTR) pwszBuf.c_str());
1918    if (attr != INVALID_FILE_ATTRIBUTES) {
1919       /* Use Bacula mappings define in stat() above */
1920       attr = fill_attribute(attr, mode);
1921       ret = p_SetFileAttributesW((LPCWSTR)pwszBuf.c_str(), attr);
1922    }
1923    Dmsg0(dbglvl, "Leave win32_chmod. AttributesW\n");
1924 
1925    if (!ret) {
1926       const char *err = errorString();
1927       Dmsg2(dbglvl, "Get/SetFileAttributes(%s): %s\n", path, err);
1928       LocalFree((void *)err);
1929       errno = b_errno_win32;
1930       return -1;
1931    }
1932    return 0;
1933 }
1934 
1935 
1936 int
win32_chdir(const char * dir)1937 win32_chdir(const char *dir)
1938 {
1939    POOL_MEM pwszBuf(PM_FNAME);
1940    make_win32_path_UTF8_2_wchar(&pwszBuf.addr(), dir);
1941 
1942    BOOL b=p_SetCurrentDirectoryW && p_SetCurrentDirectoryW((LPCWSTR)pwszBuf.c_str());
1943 
1944    if (!b) {
1945       errno = b_errno_win32;
1946       return -1;
1947    }
1948 
1949    return 0;
1950 }
1951 
1952 int
win32_mkdir(const char * dir)1953 win32_mkdir(const char *dir)
1954 {
1955    Dmsg1(dbglvl, "enter win32_mkdir. dir=%s\n", dir);
1956    if (p_wmkdir){
1957       POOL_MEM pwszBuf(PM_FNAME);
1958       make_win32_path_UTF8_2_wchar(&pwszBuf.addr(), dir);
1959 
1960       int n = p_wmkdir((LPCWSTR)pwszBuf.c_str());
1961       Dmsg0(dbglvl, "Leave win32_mkdir did wmkdir\n");
1962       return n;
1963    }
1964 
1965    Dmsg0(dbglvl, "Leave win32_mkdir did _mkdir\n");
1966    return _mkdir(dir);
1967 }
1968 
1969 
1970 char *
win32_getcwd(char * buf,int maxlen)1971 win32_getcwd(char *buf, int maxlen)
1972 {
1973    if (!p_GetCurrentDirectoryW) {
1974       return NULL;
1975    }
1976    POOL_MEM pwszBuf(PM_FNAME);
1977    pwszBuf.check_size(maxlen*sizeof(wchar_t));
1978 
1979    if (0 == p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf.c_str())) {
1980       return NULL;
1981    }
1982 
1983    POOL_MEM wtf8(PM_FNAME);
1984    int n = wchar_path_2_wutf8(&wtf8.addr(), (wchar_t *)pwszBuf.c_str());
1985    memcpy(buf, wtf8.c_str(), n<maxlen?n:maxlen);
1986    if (buf[n-2] != '\\') {
1987       // Add a trailing '\'
1988       if (n+1 > maxlen) {
1989          return NULL;
1990       }
1991       buf[n-1] = '\\';
1992       buf[n] = 0;
1993    }
1994    return buf;
1995 }
1996 
1997 int
win32_fputs(const char * string,FILE * stream)1998 win32_fputs(const char *string, FILE *stream)
1999 {
2000    /* we use WriteConsoleA / WriteConsoleA
2001       so we can be sure that unicode support works on win32.
2002       with fallback if something fails
2003    */
2004 
2005    HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
2006    if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
2007        p_MultiByteToWideChar && (stream == stdout)) {
2008 
2009       POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
2010 
2011       DWORD dwCharsWritten;
2012       DWORD dwChars;
2013 
2014       dwChars = UTF8_2_wchar(&pwszBuf, string);
2015 
2016       /* try WriteConsoleW */
2017       if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
2018          free_pool_memory(pwszBuf);
2019          return dwCharsWritten;
2020       }
2021 
2022       /* convert to local codepage and try WriteConsoleA */
2023       POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
2024       pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
2025 
2026       dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR)pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
2027       free_pool_memory(pwszBuf);
2028 
2029       if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
2030          free_pool_memory(pszBuf);
2031          return dwCharsWritten;
2032       }
2033       free_pool_memory(pszBuf);
2034    }
2035    /* Fall back */
2036    return fputs(string, stream);
2037 }
2038 
2039 char*
win32_cgets(char * buffer,int len)2040 win32_cgets (char* buffer, int len)
2041 {
2042    /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
2043       from the win32 console and fallback if something fails */
2044 
2045    HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
2046    if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
2047       DWORD dwRead;
2048       wchar_t wszBuf[1024];
2049       char  szBuf[1024];
2050 
2051       /* nt and unicode conversion */
2052       if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
2053 
2054          /* null terminate at end */
2055          if (wszBuf[dwRead-1] == L'\n') {
2056             wszBuf[dwRead-1] = L'\0';
2057             dwRead --;
2058          }
2059 
2060          if (wszBuf[dwRead-1] == L'\r') {
2061             wszBuf[dwRead-1] = L'\0';
2062             dwRead --;
2063          }
2064 
2065          wchar_2_UTF8(buffer, wszBuf, len);
2066          return buffer;
2067       }
2068 
2069       /* win 9x and unicode conversion */
2070       if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
2071 
2072          /* null terminate at end */
2073          if (szBuf[dwRead-1] == L'\n') {
2074             szBuf[dwRead-1] = L'\0';
2075             dwRead --;
2076          }
2077 
2078          if (szBuf[dwRead-1] == L'\r') {
2079             szBuf[dwRead-1] = L'\0';
2080             dwRead --;
2081          }
2082 
2083          /* convert from ansii to wchar_t */
2084          p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
2085          /* convert from wchar_t to UTF-8 */
2086          if (wchar_2_UTF8(buffer, wszBuf, len))
2087             return buffer;
2088       }
2089    }
2090 
2091    /* fallback */
2092    if (fgets(buffer, len, stdin))
2093       return buffer;
2094    else
2095       return NULL;
2096 }
2097 
2098 int
win32_unlink(const char * filename)2099 win32_unlink(const char *filename)
2100 {
2101    int nRetCode;
2102    if (p_wunlink) {
2103       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2104       make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
2105 
2106       nRetCode = _wunlink((LPCWSTR) pwszBuf);
2107 
2108       /*
2109        * special case if file is readonly,
2110        * we retry but unset attribute before
2111        */
2112       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
2113          DWORD dwAttr =  p_GetFileAttributesW((LPCWSTR)pwszBuf);
2114          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
2115             if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
2116                nRetCode = _wunlink((LPCWSTR) pwszBuf);
2117                /* reset to original if it didn't help */
2118                if (nRetCode == -1)
2119                   p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
2120             }
2121          }
2122       }
2123       free_pool_memory(pwszBuf);
2124    } else {
2125       nRetCode = _unlink(filename);
2126 
2127       /* special case if file is readonly,
2128       we retry but unset attribute before */
2129       if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
2130          DWORD dwAttr =  p_GetFileAttributesA(filename);
2131          if (dwAttr != INVALID_FILE_ATTRIBUTES) {
2132             if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
2133                nRetCode = _unlink(filename);
2134                /* reset to original if it didn't help */
2135                if (nRetCode == -1)
2136                   p_SetFileAttributesA(filename, dwAttr);
2137             }
2138          }
2139       }
2140    }
2141    return nRetCode;
2142 }
2143 
2144 
2145 #include "mswinver.h"
2146 
2147 char WIN_VERSION_LONG[64];
2148 char WIN_VERSION[32];
2149 char WIN_RAWVERSION[32];
2150 
2151 class winver {
2152 public:
2153     winver(void);
2154 };
2155 
2156 static winver INIT;                     // cause constructor to be called before main()
2157 
2158 
winver(void)2159 winver::winver(void)
2160 {
2161     const char *version = "";
2162     const char *platform = "";
2163     OSVERSIONINFO osvinfo;
2164     osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
2165 
2166     // Get the current OS version
2167     if (!GetVersionEx(&osvinfo)) {
2168         version = "Unknown";
2169         platform = "Unknown";
2170     }
2171         const int ver = _mkversion(osvinfo.dwPlatformId,
2172                                    osvinfo.dwMajorVersion,
2173                                    osvinfo.dwMinorVersion);
2174         snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
2175         switch (ver)
2176         {
2177         case MS_WINDOWS_95: (version =  "Windows 95"); break;
2178         case MS_WINDOWS_98: (version =  "Windows 98"); break;
2179         case MS_WINDOWS_ME: (version =  "Windows ME"); break;
2180         case MS_WINDOWS_NT4:(version =  "Windows NT 4.0"); platform = "NT"; break;
2181         case MS_WINDOWS_2K: (version =  "Windows 2000");platform = "NT"; break;
2182         case MS_WINDOWS_XP: (version =  "Windows XP");platform = "NT"; break;
2183         case MS_WINDOWS_S2003: (version =  "Windows Server 2003");platform = "NT"; break;
2184         default: version = WIN_RAWVERSION; break;
2185         }
2186 
2187     bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
2188     snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
2189              platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
2190 
2191 #if 0
2192     HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2193     CloseHandle(h);
2194 #endif
2195 #if 0
2196     BPIPE *b = open_bpipe("ls -l", 10, "r");
2197     char buf[1024];
2198     while (!feof(b->rfd)) {
2199         fgets(buf, sizeof(buf), b->rfd);
2200     }
2201     close_bpipe(b);
2202 #endif
2203 }
2204 
2205 BOOL CreateChildProcess(VOID);
2206 VOID WriteToPipe(VOID);
2207 VOID ReadFromPipe(VOID);
2208 VOID ErrorExit(LPCSTR);
2209 VOID ErrMsg(LPTSTR, BOOL);
2210 
2211 /**
2212  * Check for a quoted path,  if an absolute path name is given and it contains
2213  * spaces it will need to be quoted.  i.e.  "c:/Program Files/foo/bar.exe"
2214  * CreateProcess() says the best way to ensure proper results with executables
2215  * with spaces in path or filename is to quote the string.
2216  */
2217 const char *
getArgv0(const char * cmdline)2218 getArgv0(const char *cmdline)
2219 {
2220 
2221     int inquote = 0;
2222     const char *cp;
2223     for (cp = cmdline; *cp; cp++)
2224     {
2225         if (*cp == '"') {
2226             inquote = !inquote;
2227         }
2228         if (!inquote && isspace(*cp))
2229             break;
2230     }
2231 
2232 
2233     int len = cp - cmdline;
2234     char *rval = (char *)malloc(len+1);
2235 
2236     cp = cmdline;
2237     char *rp = rval;
2238 
2239     while (len--)
2240         *rp++ = *cp++;
2241 
2242     *rp = 0;
2243     return rval;
2244 }
2245 
2246 /*
2247  * Extracts the executable or script name from the first string in
2248  * cmdline.
2249  *
2250  * If the name contains blanks then it must be quoted with double quotes,
2251  * otherwise quotes are optional.  If the name contains blanks then it
2252  * will be converted to a short name.
2253  *
2254  * The optional quotes will be removed.  The result is copied to a malloc'ed
2255  * buffer and returned through the pexe argument.  The pargs parameter is set
2256  * to the address of the character in cmdline located after the name.
2257  *
2258  * The malloc'ed buffer returned in *pexe must be freed by the caller.
2259  */
2260 bool
GetApplicationName(const char * cmdline,char ** pexe,const char ** pargs)2261 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
2262 {
2263    const char *pExeStart = NULL;    /* Start of executable name in cmdline */
2264    const char *pExeEnd = NULL;      /* Character after executable name (separator) */
2265 
2266    const char *pBasename = NULL;    /* Character after last path separator */
2267    const char *pExtension = NULL;   /* Period at start of extension */
2268 
2269    const char *current = cmdline;
2270 
2271    bool bQuoted = false;
2272 
2273    /* Skip initial whitespace */
2274 
2275    while (*current == ' ' || *current == '\t')
2276    {
2277       current++;
2278    }
2279 
2280    /* Calculate start of name and determine if quoted */
2281 
2282    if (*current == '"') {
2283       pExeStart = ++current;
2284       bQuoted = true;
2285    } else {
2286       pExeStart = current;
2287       bQuoted = false;
2288    }
2289 
2290    *pargs = NULL;
2291    *pexe = NULL;
2292 
2293    /*
2294     * Scan command line looking for path separators (/ and \\) and the
2295     * terminator, either a quote or a blank.  The location of the
2296     * extension is also noted.
2297     */
2298 
2299    for ( ; *current != '\0'; current++)
2300    {
2301       if (*current == '.') {
2302          pExtension = current;
2303       } else if (IsPathSeparator(*current) && current[1] != '\0') {
2304          pBasename = &current[1];
2305          pExtension = NULL;
2306       }
2307 
2308       /* Check for terminator, either quote or blank */
2309       if (bQuoted) {
2310          if (*current != '"') {
2311             continue;
2312          }
2313       } else {
2314          if (*current != ' ') {
2315             continue;
2316          }
2317       }
2318 
2319       /*
2320        * Hit terminator, remember end of name (address of terminator) and
2321        * start of arguments
2322        */
2323       pExeEnd = current;
2324 
2325       if (bQuoted && *current == '"') {
2326          *pargs = &current[1];
2327       } else {
2328          *pargs = current;
2329       }
2330 
2331       break;
2332    }
2333 
2334    if (pBasename == NULL) {
2335       pBasename = pExeStart;
2336    }
2337 
2338    if (pExeEnd == NULL) {
2339       pExeEnd = current;
2340    }
2341 
2342    if (*pargs == NULL)
2343    {
2344       *pargs = current;
2345    }
2346 
2347    bool bHasPathSeparators = pExeStart != pBasename;
2348 
2349    /* We have pointers to all the useful parts of the name */
2350 
2351    /* Default extensions in the order cmd.exe uses to search */
2352 
2353    static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
2354    DWORD dwBasePathLength = pExeEnd - pExeStart;
2355 
2356    DWORD dwAltNameLength = 0;
2357    char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
2358    char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
2359 
2360    pPathname[MAX_PATHLENGTH] = '\0';
2361    pAltPathname[MAX_PATHLENGTH] = '\0';
2362 
2363    memcpy(pPathname, pExeStart, dwBasePathLength);
2364    pPathname[dwBasePathLength] = '\0';
2365 
2366    if (pExtension == NULL) {
2367       /* Try appending extensions */
2368       for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
2369 
2370          if (!bHasPathSeparators) {
2371             /* There are no path separators, search in the standard locations */
2372             dwAltNameLength = SearchPathA(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
2373             if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
2374                memcpy(pPathname, pAltPathname, dwAltNameLength);
2375                pPathname[dwAltNameLength] = '\0';
2376                break;
2377             }
2378          } else {
2379             bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
2380             if (GetFileAttributesA(pPathname) != INVALID_FILE_ATTRIBUTES) {
2381                break;
2382             }
2383             pPathname[dwBasePathLength] = '\0';
2384          }
2385       }
2386    } else if (!bHasPathSeparators) {
2387       /* There are no path separators, search in the standard locations */
2388       dwAltNameLength = SearchPathA(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
2389       if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) {
2390          memcpy(pPathname, pAltPathname, dwAltNameLength);
2391          pPathname[dwAltNameLength] = '\0';
2392       }
2393    }
2394 
2395    if (strchr(pPathname, ' ') != NULL) {
2396       dwAltNameLength = GetShortPathNameA(pPathname, pAltPathname, MAX_PATHLENGTH);
2397 
2398       if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
2399          *pexe = (char *)malloc(dwAltNameLength + 1);
2400          if (*pexe == NULL) {
2401             return false;
2402          }
2403          memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
2404       }
2405    }
2406 
2407    if (*pexe == NULL) {
2408       DWORD dwPathnameLength = strlen(pPathname);
2409       *pexe = (char *)malloc(dwPathnameLength + 1);
2410       if (*pexe == NULL) {
2411          return false;
2412       }
2413       memcpy(*pexe, pPathname, dwPathnameLength + 1);
2414    }
2415 
2416    return true;
2417 }
2418 
2419 /**
2420  * Create the process with WCHAR API
2421  */
2422 static BOOL
CreateChildProcessW(const char * comspec,const char * cmdLine,PROCESS_INFORMATION * hProcInfo,HANDLE in,HANDLE out,HANDLE err)2423 CreateChildProcessW(const char *comspec, const char *cmdLine,
2424                     PROCESS_INFORMATION *hProcInfo,
2425                     HANDLE in, HANDLE out, HANDLE err)
2426 {
2427    STARTUPINFOW siStartInfo;
2428    BOOL bFuncRetn = FALSE;
2429 
2430    // Set up members of the STARTUPINFO structure.
2431    ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
2432    siStartInfo.cb = sizeof(siStartInfo);
2433    // setup new process to use supplied handles for stdin,stdout,stderr
2434 
2435    siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
2436    siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
2437 
2438    siStartInfo.hStdInput = in;
2439    siStartInfo.hStdOutput = out;
2440    siStartInfo.hStdError = err;
2441 
2442    // Convert argument to WCHAR
2443    POOLMEM *cmdLine_wchar = get_pool_memory(PM_FNAME);
2444    POOLMEM *comspec_wchar = get_pool_memory(PM_FNAME);
2445 
2446    UTF8_2_wchar(&cmdLine_wchar, cmdLine);
2447    UTF8_2_wchar(&comspec_wchar, comspec);
2448 
2449    // Create the child process.
2450    Dmsg2(dbglvl, "Calling CreateProcess(%s, %s, ...)\n", comspec_wchar, cmdLine_wchar);
2451 
2452    // try to execute program
2453    bFuncRetn = p_CreateProcessW((WCHAR*)comspec_wchar,
2454                                 (WCHAR*)cmdLine_wchar,// command line
2455                                 NULL,      // process security attributes
2456                                 NULL,      // primary thread security attributes
2457                                 TRUE,      // handles are inherited
2458                                 0,         // creation flags
2459                                 NULL,      // use parent's environment
2460                                 NULL,      // use parent's current directory
2461                                 &siStartInfo,  // STARTUPINFO pointer
2462                                 hProcInfo);   // receives PROCESS_INFORMATION
2463    free_pool_memory(cmdLine_wchar);
2464    free_pool_memory(comspec_wchar);
2465 
2466    return bFuncRetn;
2467 }
2468 
2469 
2470 /**
2471  * Create the process with ANSI API
2472  */
2473 static BOOL
CreateChildProcessA(const char * comspec,char * cmdLine,PROCESS_INFORMATION * hProcInfo,HANDLE in,HANDLE out,HANDLE err)2474 CreateChildProcessA(const char *comspec, char *cmdLine,
2475                     PROCESS_INFORMATION *hProcInfo,
2476                     HANDLE in, HANDLE out, HANDLE err)
2477 {
2478    STARTUPINFOA siStartInfo;
2479    BOOL bFuncRetn = FALSE;
2480 
2481    // Set up members of the STARTUPINFO structure.
2482    ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
2483    siStartInfo.cb = sizeof(siStartInfo);
2484    // setup new process to use supplied handles for stdin,stdout,stderr
2485    siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
2486    siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
2487 
2488    siStartInfo.hStdInput = in;
2489    siStartInfo.hStdOutput = out;
2490    siStartInfo.hStdError = err;
2491 
2492    // Create the child process.
2493    Dmsg2(dbglvl, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
2494 
2495    // try to execute program
2496    bFuncRetn = p_CreateProcessA(comspec,
2497                                 cmdLine,  // command line
2498                                 NULL,     // process security attributes
2499                                 NULL,     // primary thread security attributes
2500                                 TRUE,     // handles are inherited
2501                                 0,        // creation flags
2502                                 NULL,     // use parent's environment
2503                                 NULL,     // use parent's current directory
2504                                 &siStartInfo,// STARTUPINFO pointer
2505                                 hProcInfo);// receives PROCESS_INFORMATION
2506    return bFuncRetn;
2507 }
2508 
2509 /**
2510  * OK, so it would seem CreateProcess only handles true executables:
2511  * .com or .exe files.  So grab $COMSPEC value and pass command line to it.
2512  */
2513 HANDLE
CreateChildProcess(const char * cmdline,HANDLE in,HANDLE out,HANDLE err)2514 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
2515 {
2516    static const char *comspec = NULL;
2517    PROCESS_INFORMATION piProcInfo;
2518    BOOL bFuncRetn = FALSE;
2519 
2520    if (!p_CreateProcessA || !p_CreateProcessW)
2521       return INVALID_HANDLE_VALUE;
2522 
2523    if (comspec == NULL)
2524       comspec = getenv("COMSPEC");
2525    if (comspec == NULL) // should never happen
2526       return INVALID_HANDLE_VALUE;
2527 
2528    // Set up members of the PROCESS_INFORMATION structure.
2529    ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
2530 
2531    // if supplied handles are not used the send a copy of our STD_HANDLE
2532    // as appropriate
2533    if (in == INVALID_HANDLE_VALUE)
2534       in = GetStdHandle(STD_INPUT_HANDLE);
2535 
2536    if (out == INVALID_HANDLE_VALUE)
2537       out = GetStdHandle(STD_OUTPUT_HANDLE);
2538 
2539    if (err == INVALID_HANDLE_VALUE)
2540       err = GetStdHandle(STD_ERROR_HANDLE);
2541 
2542    char *exeFile;
2543    const char *argStart;
2544 
2545    if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
2546       return INVALID_HANDLE_VALUE;
2547    }
2548 
2549    POOL_MEM cmdLine(PM_FNAME);
2550    Mmsg(cmdLine, "%s /c \"%s\"%s", comspec, exeFile, argStart);
2551 
2552    free(exeFile);
2553 
2554    // New function disabled
2555    if (p_CreateProcessW && p_MultiByteToWideChar) {
2556       bFuncRetn = CreateChildProcessW(comspec, cmdLine.c_str(), &piProcInfo,
2557                                       in, out, err);
2558    } else {
2559       bFuncRetn = CreateChildProcessA(comspec, cmdLine.c_str(), &piProcInfo,
2560                                       in, out, err);
2561    }
2562 
2563    if (bFuncRetn == 0) {
2564       ErrorExit("CreateProcess failed\n");
2565       Dmsg2(dbglvl, "  CreateProcess(%s, %s) failed\n",comspec,cmdLine.c_str());
2566       return INVALID_HANDLE_VALUE;
2567    }
2568    // we don't need a handle on the process primary thread so we close
2569    // this now.
2570    CloseHandle(piProcInfo.hThread);
2571    return piProcInfo.hProcess;
2572 }
2573 
2574 void
ErrorExit(LPCSTR lpszMessage)2575 ErrorExit (LPCSTR lpszMessage)
2576 {
2577     const char *err = errorString();
2578     Dmsg2(dbglvl, "%s: %s", lpszMessage, err);
2579     LocalFree((void *)err);
2580     errno = b_errno_win32;
2581 }
2582 
2583 
2584 /*
2585 typedef struct s_bpipe {
2586    pid_t worker_pid;
2587    time_t worker_stime;
2588    int wait;
2589    btimer_t *timer_id;
2590    FILE *rfd;
2591    FILE *wfd;
2592 } BPIPE;
2593 */
2594 
2595 static void
CloseHandleIfValid(HANDLE handle)2596 CloseHandleIfValid(HANDLE handle)
2597 {
2598     if (handle != INVALID_HANDLE_VALUE) {
2599         CloseHandle(handle);
2600     }
2601 }
2602 
2603 #define MODE_READ 1
2604 #define MODE_WRITE 2
2605 #define MODE_SHELL 4
2606 #define MODE_STDERR 8
2607 
2608 BPIPE *
open_bpipe(char * prog,int wait,const char * mode,char * envp[])2609 open_bpipe(char *prog, int wait, const char *mode, char *envp[])
2610 {
2611     HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
2612         hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
2613         hChildStderrRd, hChildStderrWr, hChildStderrRdDup,
2614         hInputFile;
2615 
2616     SECURITY_ATTRIBUTES saAttr;
2617 
2618     BOOL fSuccess;
2619 
2620     hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
2621         hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
2622         hChildStderrRd = hChildStderrWr = hChildStderrRdDup =
2623         hInputFile = INVALID_HANDLE_VALUE;
2624 
2625     BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
2626     memset((void *)bpipe, 0, sizeof(BPIPE));
2627 
2628     int mode_map(0);
2629     if (strchr(mode,'r')) mode_map|=MODE_READ;
2630     if (strchr(mode,'w')) mode_map|=MODE_WRITE;
2631     if (strchr(mode,'s')) mode_map|=MODE_SHELL;
2632     if (strchr(mode,'e')) mode_map|=MODE_STDERR;
2633 
2634     // Set the bInheritHandle flag so pipe handles are inherited.
2635     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
2636     saAttr.bInheritHandle = TRUE;
2637     saAttr.lpSecurityDescriptor = NULL;
2638 
2639     if (mode_map & MODE_READ) {
2640 
2641         // Create a pipe for the child process's STDOUT.
2642         if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
2643             ErrorExit("Stdout pipe creation failed\n");
2644             goto cleanup;
2645         }
2646         // Create noninheritable read handle and close the inheritable read
2647         // handle.
2648 
2649         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
2650                                    GetCurrentProcess(), &hChildStdoutRdDup , 0,
2651                                    FALSE,
2652                                    DUPLICATE_SAME_ACCESS);
2653         if ( !fSuccess ) {
2654             ErrorExit("DuplicateHandle failed");
2655             goto cleanup;
2656         }
2657 
2658         CloseHandle(hChildStdoutRd);
2659         hChildStdoutRd = INVALID_HANDLE_VALUE;
2660     }
2661 
2662     if (mode_map & MODE_STDERR) {
2663 
2664         // Create a pipe for the child process's STDOUT.
2665         if (! CreatePipe(&hChildStderrRd, &hChildStderrWr, &saAttr, 0)) {
2666             ErrorExit("Stderr pipe creation failed\n");
2667             goto cleanup;
2668         }
2669         // Create noninheritable read handle and close the inheritable read
2670         // handle.
2671 
2672         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStderrRd,
2673                                    GetCurrentProcess(), &hChildStderrRdDup , 0,
2674                                    FALSE,
2675                                    DUPLICATE_SAME_ACCESS);
2676         if ( !fSuccess ) {
2677             ErrorExit("DuplicateHandle failed");
2678             goto cleanup;
2679         }
2680 
2681         CloseHandle(hChildStderrRd);
2682         hChildStderrRd = INVALID_HANDLE_VALUE;
2683     }
2684 
2685     if (mode_map & MODE_WRITE) {
2686 
2687         // Create a pipe for the child process's STDIN.
2688 
2689         if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
2690             ErrorExit("Stdin pipe creation failed\n");
2691             goto cleanup;
2692         }
2693 
2694         // Duplicate the write handle to the pipe so it is not inherited.
2695         fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
2696                                    GetCurrentProcess(), &hChildStdinWrDup,
2697                                    0,
2698                                    FALSE,                  // not inherited
2699                                    DUPLICATE_SAME_ACCESS);
2700         if (!fSuccess) {
2701             ErrorExit("DuplicateHandle failed");
2702             goto cleanup;
2703         }
2704 
2705         CloseHandle(hChildStdinWr);
2706         hChildStdinWr = INVALID_HANDLE_VALUE;
2707     }
2708     // spawn program with redirected handles as appropriate
2709     bpipe->worker_pid = (pid_t)
2710         CreateChildProcess(prog,             // commandline
2711                            hChildStdinRd,    // stdin HANDLE
2712                            hChildStdoutWr,   // stdout HANDLE
2713                            (mode_map & MODE_STDERR) ? hChildStderrWr:hChildStdoutWr);  // stderr HANDLE
2714 
2715     if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE) {
2716        ErrorExit("CreateChildProcess failed");
2717        goto cleanup;
2718     }
2719 
2720     bpipe->wait = wait;
2721     bpipe->worker_stime = time(NULL);
2722 
2723     if (mode_map & MODE_READ) {
2724         CloseHandle(hChildStdoutWr); // close our write side so when
2725                                      // process terminates we can
2726                                      // detect eof.
2727         // ugly but convert WIN32 HANDLE to FILE*
2728         int rfd = _open_osfhandle((intptr_t)hChildStdoutRdDup, O_RDONLY | O_BINARY);
2729         if (rfd >= 0) {
2730            bpipe->rfd = _fdopen(rfd, "rb");
2731         }
2732     }
2733     if (mode_map & MODE_STDERR) {
2734         CloseHandle(hChildStderrWr); // close our write side so when
2735                                      // process terminates we can
2736                                      // detect eof.
2737         // ugly but convert WIN32 HANDLE to FILE*
2738         int rfd = _open_osfhandle((intptr_t)hChildStderrRdDup, O_RDONLY | O_BINARY);
2739         if (rfd >= 0) {
2740            bpipe->efd = _fdopen(rfd, "rb");
2741         }
2742     }
2743     if (mode_map & MODE_WRITE) {
2744         CloseHandle(hChildStdinRd); // close our read side so as not
2745                                     // to interfre with child's copy
2746         // ugly but convert WIN32 HANDLE to FILE*
2747         int wfd = _open_osfhandle((intptr_t)hChildStdinWrDup, O_WRONLY | O_BINARY);
2748         if (wfd >= 0) {
2749            bpipe->wfd = _fdopen(wfd, "wb");
2750         }
2751     }
2752 
2753     if (wait > 0) {
2754         bpipe->timer_id = start_child_timer(NULL, bpipe->worker_pid, wait);
2755     }
2756 
2757     return bpipe;
2758 
2759 cleanup:
2760 
2761     CloseHandleIfValid(hChildStdoutWr);
2762     CloseHandleIfValid(hChildStdoutRd);
2763     CloseHandleIfValid(hChildStdoutRdDup);
2764     CloseHandleIfValid(hChildStderrWr);
2765     CloseHandleIfValid(hChildStderrRd);
2766     CloseHandleIfValid(hChildStderrRdDup);
2767     CloseHandleIfValid(hChildStdinWr);
2768     CloseHandleIfValid(hChildStdinRd);
2769     CloseHandleIfValid(hChildStdinWrDup);
2770 
2771     free((void *)bpipe);
2772     errno = b_errno_win32;            /* do GetLastError() for error code */
2773     return NULL;
2774 }
2775 
2776 
2777 int
kill(pid_t pid,int signal)2778 kill(pid_t pid, int signal)
2779 {
2780    int rval = 0;
2781    if (!TerminateProcess((HANDLE)pid, (UINT)signal)) {
2782       rval = -1;
2783       errno = b_errno_win32;
2784    }
2785    CloseHandle((HANDLE)pid);
2786    return rval;
2787 }
2788 
2789 
2790 int
close_bpipe(BPIPE * bpipe)2791 close_bpipe(BPIPE *bpipe)
2792 {
2793    int rval = 0;
2794    int32_t remaining_wait = bpipe->wait;
2795 
2796    /* Close pipes */
2797    if (bpipe->rfd) {
2798       fclose(bpipe->rfd);
2799       bpipe->rfd = NULL;
2800    }
2801    if (bpipe->efd) {
2802       fclose(bpipe->efd);
2803       bpipe->efd = NULL;
2804    }
2805    if (bpipe->wfd) {
2806       fclose(bpipe->wfd);
2807       bpipe->wfd = NULL;
2808    }
2809 
2810    if (remaining_wait == 0) {         /* wait indefinitely */
2811       remaining_wait = INT32_MAX;
2812    }
2813    for ( ;; ) {
2814       DWORD exitCode;
2815       if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
2816          const char *err = errorString();
2817          rval = b_errno_win32;
2818          Dmsg1(dbglvl, "GetExitCode error %s\n", err);
2819          LocalFree((void *)err);
2820          break;
2821       }
2822       if (exitCode == STILL_ACTIVE) {
2823          if (remaining_wait <= 0) {
2824             rval = ETIME;             /* timed out */
2825             break;
2826          }
2827          bmicrosleep(1, 0);           /* wait one second */
2828          remaining_wait--;
2829       } else if (exitCode != 0) {
2830          /* Truncate exit code as it doesn't seem to be correct */
2831          rval = (exitCode & 0xFF) | b_errno_exit;
2832          break;
2833       } else {
2834          break;                       /* Shouldn't get here */
2835       }
2836    }
2837 
2838    if (bpipe->timer_id) {
2839        stop_child_timer(bpipe->timer_id);
2840    }
2841    if (bpipe->rfd) fclose(bpipe->rfd);
2842    if (bpipe->efd) fclose(bpipe->efd);
2843    if (bpipe->wfd) fclose(bpipe->wfd);
2844    free((void *)bpipe);
2845    return rval;
2846 }
2847 
2848 int
close_wpipe(BPIPE * bpipe)2849 close_wpipe(BPIPE *bpipe)
2850 {
2851     int result = 1;
2852 
2853     if (bpipe->wfd) {
2854         fflush(bpipe->wfd);
2855         if (fclose(bpipe->wfd) != 0) {
2856             result = 0;
2857         }
2858         bpipe->wfd = NULL;
2859     }
2860     return result;
2861 }
2862 
2863 /* Close the stderror pipe only */
close_epipe(BPIPE * bpipe)2864 int close_epipe(BPIPE *bpipe)
2865 {
2866    int stat = 1;
2867 
2868    if (bpipe->efd) {
2869       if (fclose(bpipe->efd) != 0) {
2870          stat = 0;
2871       }
2872       bpipe->efd = NULL;
2873    }
2874    return stat;
2875 }
2876 
2877 #ifndef MINGW64
2878 int
utime(const char * fname,struct utimbuf * times)2879 utime(const char *fname, struct utimbuf *times)
2880 {
2881     FILETIME acc, mod;
2882     char tmpbuf[5000];
2883     POOL_MEM pwszBuf(PM_FNAME);
2884 
2885     cvt_utime_to_ftime(times->actime, acc);
2886     cvt_utime_to_ftime(times->modtime, mod);
2887 
2888     make_win32_path_UTF8_2_wchar(&pwszBuf.addr(), fname);
2889 
2890     HANDLE h = p_CreateFileW((LPCWSTR)pwszBuf.c_str(),
2891                      FILE_WRITE_ATTRIBUTES,
2892                      FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2893                      NULL,
2894                      OPEN_EXISTING,
2895                      FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2896                      NULL);
2897 
2898     if (h == INVALID_HANDLE_VALUE) {
2899        const char *err = errorString();
2900        Dmsg2(dbglvl, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2901        LocalFree((void *)err);
2902        errno = b_errno_win32;
2903        return -1;
2904     }
2905 
2906     int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2907     CloseHandle(h);
2908     if (rval == -1) {
2909        errno = b_errno_win32;
2910     }
2911     return rval;
2912 }
2913 #endif
2914 
2915 #if 0
2916 int
2917 file_open(const char *file, int flags, int mode)
2918 {
2919    DWORD access = 0;
2920    DWORD shareMode = 0;
2921    DWORD create = 0;
2922    DWORD msflags = 0;
2923    HANDLE foo = INVALID_HANDLE_VALUE;
2924    const char *remap = file;
2925 
2926    if (flags & O_WRONLY) access = GENERIC_WRITE;
2927    else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2928    else access = GENERIC_READ;
2929 
2930    if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2931       create = CREATE_NEW;
2932    else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2933       create = CREATE_ALWAYS;
2934    else if (flags & O_CREAT)
2935       create = OPEN_ALWAYS;
2936    else if (flags & O_TRUNC)
2937       create = TRUNCATE_EXISTING;
2938    else
2939       create = OPEN_EXISTING;
2940 
2941    shareMode = 0;
2942 
2943    if (flags & O_APPEND) {
2944       printf("open...APPEND not implemented yet.");
2945       exit(-1);
2946    }
2947 
2948    POOL_MEM pwszBuf(PM_FNAME);
2949    make_win32_path_UTF8_2_wchar(&pwszBuf.addr(), file);
2950    foo = p_CreateFileW((LPCWSTR) pwszBuf.c_str(), access, shareMode, NULL, create, msflags, NULL);
2951 
2952    if (INVALID_HANDLE_VALUE == foo) {
2953       errno = b_errno_win32;
2954       return (int)-1;
2955    }
2956    return (int)foo;
2957 
2958 }
2959 
2960 
2961 int
2962 file_close(int fd)
2963 {
2964     if (!CloseHandle((HANDLE)fd)) {
2965         errno = b_errno_win32;
2966         return -1;
2967     }
2968 
2969     return 0;
2970 }
2971 
2972 ssize_t
2973 file_write(int fd, const void *data, ssize_t len)
2974 {
2975     BOOL status;
2976     DWORD bwrite;
2977     status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2978     if (status) return bwrite;
2979     errno = b_errno_win32;
2980     return -1;
2981 }
2982 
2983 
2984 ssize_t
2985 file_read(int fd, void *data, ssize_t len)
2986 {
2987     BOOL status;
2988     DWORD bread;
2989 
2990     status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2991     if (status) return bread;
2992     errno = b_errno_win32;
2993     return -1;
2994 }
2995 
2996 boffset_t
2997 file_seek(int fd, boffset_t offset, int whence)
2998 {
2999     DWORD method = 0;
3000     DWORD val;
3001     LONG  offset_low = (LONG)offset;
3002     LONG  offset_high = (LONG)(offset >> 32);
3003 
3004     switch (whence) {
3005     case SEEK_SET :
3006         method = FILE_BEGIN;
3007         break;
3008     case SEEK_CUR:
3009         method = FILE_CURRENT;
3010         break;
3011     case SEEK_END:
3012         method = FILE_END;
3013         break;
3014     default:
3015         errno = EINVAL;
3016         return -1;
3017     }
3018 
3019 
3020     if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
3021        errno = b_errno_win32;
3022        return -1;
3023     }
3024     /* ***FIXME*** I doubt this works right */
3025     return val;
3026 }
3027 
3028 int
3029 file_dup2(int, int)
3030 {
3031     errno = ENOSYS;
3032     return -1;
3033 }
3034 #endif
3035 
3036 #ifdef xxx
3037 /*
3038  * Emulation of mmap and unmmap for tokyo dbm
3039  */
mmap(void * start,size_t length,int prot,int flags,int fd,off_t offset)3040 void *mmap(void *start, size_t length, int prot, int flags,
3041            int fd, off_t offset)
3042 {
3043    DWORD fm_access = 0;
3044    DWORD mv_access = 0;
3045    HANDLE h;
3046    HANDLE mv;
3047 
3048    if (length == 0) {
3049       return MAP_FAILED;
3050    }
3051    if (!fd) {
3052       return MAP_FAILED;
3053    }
3054 
3055    if (flags & PROT_WRITE) {
3056       fm_access |= PAGE_READWRITE;
3057    } else if (flags & PROT_READ) {
3058       fm_access |= PAGE_READONLY;
3059    }
3060 
3061    if (flags & PROT_READ) {
3062       mv_access |= FILE_MAP_READ;
3063    }
3064    if (flags & PROT_WRITE) {
3065       mv_access |= FILE_MAP_WRITE;
3066    }
3067 
3068    h = CreateFileMapping((HANDLE)_get_osfhandle (fd),
3069                          NULL /* security */,
3070                          fm_access,
3071                          0 /* MaximumSizeHigh */,
3072                          0 /* MaximumSizeLow */,
3073                          NULL /* name of the file mapping object */);
3074 
3075    if (!h || h == INVALID_HANDLE_VALUE) {
3076       return MAP_FAILED;
3077    }
3078 
3079    mv = MapViewOfFile(h, mv_access,
3080                       0 /* offset hi */,
3081                       0 /* offset lo */,
3082                       length);
3083    CloseHandle(h);
3084 
3085    if (!mv || mv == INVALID_HANDLE_VALUE) {
3086       return MAP_FAILED;
3087    }
3088 
3089    return (void *) mv;
3090 }
3091 
munmap(void * start,size_t length)3092 int munmap(void *start, size_t length)
3093 {
3094    if (!start) {
3095       return -1;
3096    }
3097    UnmapViewOfFile(start);
3098    return 0;
3099 }
3100 #endif
3101 
3102 #ifdef HAVE_MINGW
3103 /* syslog function, added by Nicolas Boichat */
openlog(const char * ident,int option,int facility)3104 void openlog(const char *ident, int option, int facility) {}
3105 #endif //HAVE_MINGW
3106 
3107 /* Log an error message */
LogErrorMsg(const char * message)3108 void LogErrorMsg(const char *message)
3109 {
3110    HANDLE eventHandler;
3111    const char *strings[2];
3112 
3113    /* Use the OS event logging to log the error */
3114    eventHandler = RegisterEventSource(NULL, "Bacula");
3115 
3116    strings[0] = _("\n\nBacula ERROR: ");
3117    strings[1] = message;
3118 
3119    if (eventHandler) {
3120       ReportEvent(eventHandler, EVENTLOG_ERROR_TYPE,
3121               0,                      /* category */
3122               0,                      /* ID */
3123               NULL,                   /* SID */
3124               2,                      /* Number of strings */
3125               0,                      /* raw data size */
3126               (const char **)strings, /* error strings */
3127               NULL);                  /* raw data */
3128       DeregisterEventSource(eventHandler);
3129    }
3130 }
3131 
mkstemp(char * t)3132 int mkstemp(char *t)
3133 {
3134    char *filename = mktemp(t);
3135    if (filename == NULL) {
3136       return -1;
3137    }
3138    return open(filename, O_RDWR | O_CREAT, 0600);
3139 }
3140 
malloc_trim(int)3141 void malloc_trim(int)
3142 {
3143    if (p_EmptyWorkingSet) {
3144       HANDLE hProcess = GetCurrentProcess();
3145       if (!p_EmptyWorkingSet(hProcess)) {
3146          const char *err = errorString();
3147          Dmsg1(dbglvl, "EmptyWorkingSet() = %s\n", err);
3148          LocalFree((void *)err);
3149       }
3150       CloseHandle( hProcess );
3151    }
3152 }
3153 
3154 /*
3155  * get win32 memory information.
3156  *    when buf is NULL then it return the process WorkingSetSize (used as Unix heap) only.
3157  */
get_memory_info(char * buf,int buflen)3158 uint64_t get_memory_info(char *buf, int buflen)
3159 {
3160    char ed1[50], ed2[50], ed3[50], ed4[50];
3161    uint64_t ret=0;
3162    HANDLE hProcess = GetCurrentProcess();
3163    PROCESS_MEMORY_COUNTERS pmc;
3164 
3165    if (!buf) {
3166       return ret;
3167    }
3168    if (buf){
3169       buf[0] = '\0';
3170    }
3171    if (p_GetProcessMemoryInfo) {
3172       if (p_GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc))) {
3173          if (buf){
3174             bsnprintf(buf, buflen,
3175                       "WorkingSetSize: %s QuotaPagedPoolUsage: %s QuotaNonPagedPoolUsage: %s PagefileUsage: %s",
3176                       edit_uint64_with_commas(pmc.WorkingSetSize, ed1),
3177                       edit_uint64_with_commas(pmc.QuotaPagedPoolUsage, ed2),
3178                       edit_uint64_with_commas(pmc.QuotaNonPagedPoolUsage, ed3),
3179                       edit_uint64_with_commas(pmc.PagefileUsage, ed4));
3180          }
3181          ret = pmc.WorkingSetSize;
3182 
3183       } else {
3184          const char *err = errorString();
3185          bsnprintf(buf, buflen, "%s", err);
3186          LocalFree((void *)err);
3187       }
3188    }
3189 
3190    CloseHandle( hProcess );
3191    return ret;
3192 }
3193 
3194 /* normalize path provided by the fileset File directive
3195  * "f:" -> "f:/" add a ':' to "relative" to drive path
3196  */
win32_normalize_fileset_path(POOLMEM * & fname)3197 void win32_normalize_fileset_path(POOLMEM *&fname)
3198 {
3199    if (isalpha(fname[0]) && fname[1] == ':' && fname[2] == '\0') {
3200       fname = check_pool_memory_size(fname, 3);
3201       fname[2]='/';
3202       fname[3]='\0';
3203    }
3204 }
3205 
3206 /*
3207 int test_wchar(const wchar_t *st, const char *comment)
3208 {
3209    int err=0;
3210    char ascii[4096];
3211    char hexa[4096];
3212    POOL_MEM name(PM_FNAME);
3213    POOL_MEM name2(PM_FNAME);
3214 
3215    name.strcpy("");
3216    name2.strcpy("");
3217    int owsl=wcslen(st);
3218    printf(" ----- %s -- %s ----- %s\n", asciidump((char*)st, 2*owsl, ascii, sizeof(ascii)), hexdump((char*)st, 2*owsl, hexa, sizeof(hexa)), comment);
3219    int l=wchar_path_2_wutf8(&name.addr(), st);
3220    int sl=strlen(name.c_str());
3221    printf(" \t=> len=%d(%d+1) -- %s -- %s -- \n", l, sl, asciidump(name.c_str(), l, ascii, sizeof(ascii)), hexdump(name.c_str(), l, hexa, sizeof(hexa)));
3222    int wl=wutf8_path_2_wchar(&name2.addr(), name.c_str());
3223    int wsl=wcslen((wchar_t *)name2.c_str());
3224    printf(" \t<= len=%d(%d+1) -- %s -- %s -- \n", wl, wsl, asciidump(name2.c_str(), wl, ascii, sizeof(ascii)), hexdump(name2.c_str(), wl, hexa, sizeof(hexa)));
3225    if (memcmp((wchar_t *)name2.c_str(), st, 2*(wcslen(st)+1))!=0 ||
3226          owsl != wsl || l!=sl+1) {
3227       err=1;
3228       printf(" \tERROR !!!!!!!!!!\n");
3229    } else {
3230       printf(" \tOK\n");
3231    }
3232    return err;
3233 }
3234 
3235 int test_all_wchar()
3236 {
3237    printf("test_all_wchar\n");
3238    test_wchar(L"Hello world", "Hello world (valid)");
3239    test_wchar(L"Hello*world", "must escape * in the middle");
3240    test_wchar(L"*Hello**world*", "must escape * in the middle");
3241    test_wchar(L"Hello\x63dfworld", "Hello world with a strange char in the middle");
3242    test_wchar(L"Hello\xdf63world", "Hello world with invalid char in the middle");
3243    test_wchar((const wchar_t*)"\x41\x00\x63\xd9\x63\xdd\x42\x00\x00\x00", "A<valide surrogate>B");
3244    test_wchar((const wchar_t*)"\x41\x00\x63\xdf\x42\x00\x00\x00", "A<invalid single char>B");
3245    test_wchar((const wchar_t*)"\x41\x00\x63\xdc\x63\xdd\x42\x00\x00\x00", "A<w1 is out of 0xD800 and 0xDBFF>B");
3246    test_wchar((const wchar_t*)"\x41\x00\x63\xd8\x63\x63\x42\x00\x00\x00", "A<w2 is out of 0xDC00 and 0xDBFF but only w1 will be escaped>B");
3247    return 0;
3248 }
3249 */
3250