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