2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2010 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 // compat.cpp -- compatibilty layer to make bacula-fd run
30 // natively under windows
32 // Copyright transferred from Raider Solutions, Inc to
33 // Kern Sibbald and John Walker by express permission.
35 // Author : Christopher S. Hull
36 // Created On : Sat Jan 31 15:55:00 2004
42 #include "findlib/find.h"
44 /* Note, if you want to see what Windows variables and structures
45 * are defined, bacula.h includes <windows.h>, which is found in:
47 * cross-tools/mingw32/mingw32/include
49 * cross-tools/mingw-w64/x86_64-pc-mingw32/include
51 * depending on whether we are building the 32 bit version or
55 static const int dbglvl = 500;
57 #define b_errno_win32 (1<<29)
59 #define MAX_PATHLENGTH 1024
62 UTF-8 to UCS2 path conversion is expensive,
63 so we cache the conversion. During backup the
64 conversion is called 3 times (lstat, attribs, open),
65 by using the cache this is reduced to 1 time
67 static POOLMEM *g_pWin32ConvUTF8Cache = NULL;
68 static POOLMEM *g_pWin32ConvUCS2Cache = NULL;
69 static DWORD g_dwWin32ConvUTF8strlen = 0;
70 static pthread_mutex_t Win32Convmutex = PTHREAD_MUTEX_INITIALIZER;
72 static t_pVSSPathConvert g_pVSSPathConvert;
73 static t_pVSSPathConvertW g_pVSSPathConvertW;
75 /* Forward referenced functions */
76 static const char *errorString(void);
79 void SetVSSPathConvert(t_pVSSPathConvert pPathConvert, t_pVSSPathConvertW pPathConvertW)
81 g_pVSSPathConvert = pPathConvert;
82 g_pVSSPathConvertW = pPathConvertW;
85 static void Win32ConvInitCache()
87 if (g_pWin32ConvUTF8Cache) {
90 g_pWin32ConvUTF8Cache = get_pool_memory(PM_FNAME);
91 g_pWin32ConvUCS2Cache = get_pool_memory(PM_FNAME);
94 void Win32ConvCleanupCache()
97 if (g_pWin32ConvUTF8Cache) {
98 free_pool_memory(g_pWin32ConvUTF8Cache);
99 g_pWin32ConvUTF8Cache = NULL;
102 if (g_pWin32ConvUCS2Cache) {
103 free_pool_memory(g_pWin32ConvUCS2Cache);
104 g_pWin32ConvUCS2Cache = NULL;
107 g_dwWin32ConvUTF8strlen = 0;
112 /* to allow the usage of the original version in this file here */
116 //#define USE_WIN32_COMPAT_IO 1
117 #define USE_WIN32_32KPATHCONVERSION 1
119 extern DWORD g_platform_id;
120 extern DWORD g_MinorVersion;
122 /* From Microsoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970 */
124 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL
126 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
129 #define WIN32_FILETIME_SCALE 10000000 // 100ns/second
132 * Convert from UTF-8 to VSS Windows path/file
133 * Used by compatibility layer for Unix system calls
135 static void conv_unix_to_vss_win32_path(const char *name, char *win32_name, DWORD dwSize)
137 const char *fname = name;
138 char *tname = win32_name;
140 Dmsg0(dbglvl, "Enter convert_unix_to_win32_path\n");
142 if (IsPathSeparator(name[0]) &&
143 IsPathSeparator(name[1]) &&
145 IsPathSeparator(name[3])) {
147 *win32_name++ = '\\';
148 *win32_name++ = '\\';
150 *win32_name++ = '\\';
153 } else if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS &&
154 g_pVSSPathConvert == NULL) {
155 /* allow path to be 32767 bytes */
156 *win32_name++ = '\\';
157 *win32_name++ = '\\';
159 *win32_name++ = '\\';
163 /** Check for Unix separator and convert to Win32 */
164 if (name[0] == '/' && name[1] == '/') { /* double slash? */
165 name++; /* yes, skip first one */
168 *win32_name++ = '\\'; /* convert char */
169 /* If Win32 separator that is "quoted", remove quote */
170 } else if (*name == '\\' && name[1] == '\\') {
171 *win32_name++ = '\\';
172 name++; /* skip first \ */
174 *win32_name++ = *name; /* copy character */
178 /** Strip any trailing slash, if we stored something
179 * but leave "c:\" with backslash (root directory case
181 if (*fname != 0 && win32_name[-1] == '\\' && strlen (fname) != 3) {
187 /** here we convert to VSS specific file name which
188 can get longer because VSS will make something like
189 \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
190 from c:\bacula\uninstall.exe
192 Dmsg1(dbglvl, "path=%s\n", tname);
193 if (g_pVSSPathConvert != NULL) {
194 POOLMEM *pszBuf = get_pool_memory (PM_FNAME);
195 pszBuf = check_pool_memory_size(pszBuf, dwSize);
196 bstrncpy(pszBuf, tname, strlen(tname)+1);
197 g_pVSSPathConvert(pszBuf, tname, dwSize);
198 free_pool_memory(pszBuf);
201 Dmsg1(dbglvl, "Leave cvt_u_to_win32_path path=%s\n", tname);
204 /** Conversion of a Unix filename to a Win32 filename */
205 void unix_name_to_win32(POOLMEM **win32_name, char *name)
207 /* One extra byte should suffice, but we double it */
208 /* add MAX_PATH bytes for VSS shadow copy name */
209 DWORD dwSize = 2*strlen(name)+MAX_PATH;
210 *win32_name = check_pool_memory_size(*win32_name, dwSize);
211 conv_unix_to_vss_win32_path(name, *win32_name, dwSize);
216 * This function expects an UCS-encoded standard wchar_t in pszUCSPath and
217 * will complete the input path to an absolue path of the form \\?\c:\path\file
219 * With this trick, it is possible to have 32K characters long paths.
221 * Optionally one can use pBIsRawPath to determine id pszUCSPath contains a path
222 * to a raw windows partition.
224 * created 02/27/2006 Thorsten Engel
227 make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/)
230 Dmsg0(dbglvl, "Enter wchar_win32_path\n");
232 *pBIsRawPath = FALSE; /* Initialize, set later */
235 if (!p_GetCurrentDirectoryW) {
236 Dmsg0(dbglvl, "Leave wchar_win32_path no change \n");
240 wchar_t *name = (wchar_t *)pszUCSPath;
242 /* if it has already the desired form, exit without changes */
243 if (wcslen(name) > 3 && wcsncmp(name, L"\\\\?\\", 4) == 0) {
244 Dmsg0(dbglvl, "Leave wchar_win32_path no change \n");
248 wchar_t *pwszBuf = (wchar_t *)get_pool_memory(PM_FNAME);
249 wchar_t *pwszCurDirBuf = (wchar_t *)get_pool_memory(PM_FNAME);
250 DWORD dwCurDirPathSize = 0;
252 /* get buffer with enough size (name+max 6. wchars+1 null terminator */
253 DWORD dwBufCharsNeeded = (wcslen(name)+7);
254 pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
256 /* add \\?\ to support 32K long filepaths
257 it is important to make absolute paths, so we add drive and
258 current path if necessary */
260 BOOL bAddDrive = TRUE;
261 BOOL bAddCurrentPath = TRUE;
262 BOOL bAddPrefix = TRUE;
264 /* does path begin with drive? if yes, it is absolute */
265 if (iswalpha(name[0]) && name[1] == ':' && IsPathSeparator(name[2])) {
267 bAddCurrentPath = FALSE;
270 /* is path absolute? */
271 if (IsPathSeparator(name[0]))
272 bAddCurrentPath = FALSE;
274 /* is path relative to itself?, if yes, skip ./ */
275 if (name[0] == '.' && IsPathSeparator(name[1])) {
279 /* is path of form '//./'? */
280 if (IsPathSeparator(name[0]) &&
281 IsPathSeparator(name[1]) &&
283 IsPathSeparator(name[3])) {
285 bAddCurrentPath = FALSE;
292 int nParseOffset = 0;
294 /* add 4 bytes header */
297 wcscpy(pwszBuf, L"\\\\?\\");
300 /* get current path if needed */
301 if (bAddDrive || bAddCurrentPath) {
302 dwCurDirPathSize = p_GetCurrentDirectoryW(0, NULL);
303 if (dwCurDirPathSize > 0) {
304 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
305 pwszCurDirBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszCurDirBuf, (dwCurDirPathSize+1)*sizeof(wchar_t));
306 p_GetCurrentDirectoryW(dwCurDirPathSize, pwszCurDirBuf);
308 /* we have no info for doing so */
310 bAddCurrentPath = FALSE;
315 /* add drive if needed */
316 if (bAddDrive && !bAddCurrentPath) {
319 if (IsPathSeparator(pwszCurDirBuf[0]) &&
320 IsPathSeparator(pwszCurDirBuf[1]) &&
321 pwszCurDirBuf[2] == '?' &&
322 IsPathSeparator(pwszCurDirBuf[3])) {
323 /* copy drive character */
324 szDrive[0] = pwszCurDirBuf[4];
326 /* copy drive character */
327 szDrive[0] = pwszCurDirBuf[0];
333 wcscat(pwszBuf, szDrive);
337 /* add path if needed */
338 if (bAddCurrentPath) {
339 /* the 1 add. character is for the eventually added backslash */
340 dwBufCharsNeeded += dwCurDirPathSize+1;
341 pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
342 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
344 if (IsPathSeparator(pwszCurDirBuf[0]) &&
345 IsPathSeparator(pwszCurDirBuf[1]) &&
346 pwszCurDirBuf[2] == '?' &&
347 IsPathSeparator(pwszCurDirBuf[3])) {
348 /* copy complete string */
349 wcscpy(pwszBuf, pwszCurDirBuf);
352 wcscat(pwszBuf, pwszCurDirBuf);
355 nParseOffset = wcslen((LPCWSTR) pwszBuf);
357 /* check if path ends with backslash, if not, add one */
358 if (!IsPathSeparator(pwszBuf[nParseOffset-1])) {
359 wcscat(pwszBuf, L"\\");
364 wchar_t *win32_name = &pwszBuf[nParseOffset];
365 wchar_t *name_start = name;
368 /* Check for Unix separator and convert to Win32, eliminating
369 * duplicate separators.
371 if (IsPathSeparator(*name)) {
372 *win32_name++ = '\\'; /* convert char */
374 /* Eliminate consecutive slashes, but not at the start so that
377 if (name_start != name && IsPathSeparator(name[1])) {
381 *win32_name++ = *name; /* copy character */
386 /* null terminate string */
389 /* here we convert to VSS specific file name which
390 * can get longer because VSS will make something like
391 * \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
392 * from c:\bacula\uninstall.exe
394 if (g_pVSSPathConvertW != NULL) {
395 /* is output buffer large enough? */
396 pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf,
397 (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
398 /* create temp. buffer */
399 wchar_t *pszBuf = (wchar_t *)get_pool_memory(PM_FNAME);
400 pszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pszBuf,
401 (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
406 wcsncpy(pszBuf, &pwszBuf[nParseOffset], wcslen(pwszBuf)+1-nParseOffset);
407 g_pVSSPathConvertW(pszBuf, pwszBuf, dwBufCharsNeeded+MAX_PATH);
408 free_pool_memory((POOLMEM *)pszBuf);
411 free_pool_memory(pszUCSPath);
412 free_pool_memory((POOLMEM *)pwszCurDirBuf);
414 Dmsg1(dbglvl, "Leave wchar_win32_path=%s\n", pwszBuf);
415 return (POOLMEM *)pwszBuf;
419 * Convert from WCHAR (UCS) to UTF-8
422 wchar_2_UTF8(POOLMEM **pszUTF, const wchar_t *pszUCS)
425 * The return value is the number of bytes written to the buffer.
426 * The number includes the byte for the null terminator.
429 if (p_WideCharToMultiByte) {
430 int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,NULL,0,NULL,NULL);
431 *pszUTF = check_pool_memory_size(*pszUTF, nRet);
432 return p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,*pszUTF,nRet,NULL,NULL);
440 * Convert from WCHAR (UCS) to UTF-8
443 wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
446 * The return value is the number of bytes written to the buffer.
447 * The number includes the byte for the null terminator.
450 if (p_WideCharToMultiByte) {
451 int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
460 UTF8_2_wchar(POOLMEM **ppszUCS, const char *pszUTF)
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 */
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));
470 int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
480 wchar_win32_path(const char *name, wchar_t *win32_name)
482 const char *fname = name;
484 /* Check for Unix separator and convert to Win32 */
486 *win32_name++ = '\\'; /* convert char */
487 /* If Win32 separated that is "quoted", remove quote */
488 } else if (*name == '\\' && name[1] == '\\') {
489 *win32_name++ = '\\';
490 name++; /* skip first \ */
492 *win32_name++ = *name; /* copy character */
496 /* Strip any trailing slash, if we stored something */
497 if (*fname != 0 && win32_name[-1] == '\\') {
505 make_win32_path_UTF8_2_wchar(POOLMEM **pszUCS, const char *pszUTF, BOOL* pBIsRawPath /*= NULL*/)
508 /* if we find the utf8 string in cache, we use the cached ucs2 version.
509 we compare the stringlength first (quick check) and then compare the content.
511 if (!g_pWin32ConvUTF8Cache) {
512 Win32ConvInitCache();
513 } else if (g_dwWin32ConvUTF8strlen == strlen(pszUTF)) {
514 if (bstrcmp(pszUTF, g_pWin32ConvUTF8Cache)) {
515 /* Return cached value */
516 int32_t nBufSize = sizeof_pool_memory(g_pWin32ConvUCS2Cache);
517 *pszUCS = check_pool_memory_size(*pszUCS, nBufSize);
518 wcscpy((LPWSTR) *pszUCS, (LPWSTR)g_pWin32ConvUCS2Cache);
520 return nBufSize / sizeof (WCHAR);
524 /* helper to convert from utf-8 to UCS-2 and to complete a path for 32K path syntax */
525 int nRet = UTF8_2_wchar(pszUCS, pszUTF);
527 #ifdef USE_WIN32_32KPATHCONVERSION
528 /* add \\?\ to support 32K long filepaths */
529 *pszUCS = make_wchar_win32_path(*pszUCS, pBIsRawPath);
532 *pBIsRawPath = FALSE;
536 g_pWin32ConvUCS2Cache = check_pool_memory_size(g_pWin32ConvUCS2Cache, sizeof_pool_memory(*pszUCS));
537 wcscpy((LPWSTR) g_pWin32ConvUCS2Cache, (LPWSTR) *pszUCS);
539 g_dwWin32ConvUTF8strlen = strlen(pszUTF);
540 g_pWin32ConvUTF8Cache = check_pool_memory_size(g_pWin32ConvUTF8Cache, g_dwWin32ConvUTF8strlen+2);
541 bstrncpy(g_pWin32ConvUTF8Cache, pszUTF, g_dwWin32ConvUTF8strlen+1);
547 #if !defined(_MSC_VER) || (_MSC_VER < 1400) // VC8+
554 #ifndef LOAD_WITH_ALTERED_SEARCH_PATH
555 #define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008
558 void *dlopen(const char *file, int mode)
562 handle = LoadLibraryEx(file, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
566 void *dlsym(void *handle, const char *name)
569 symaddr = (void *)GetProcAddress((HMODULE)handle, name);
573 int dlclose(void *handle)
575 if (handle && !FreeLibrary((HMODULE)handle)) {
576 errno = b_errno_win32;
577 return 1; /* failed */
584 static char buf[200];
585 const char *err = errorString();
586 bstrncpy(buf, (char *)err, sizeof(buf));
587 LocalFree((void *)err);
591 int fcntl(int fd, int cmd)
596 int chown(const char *k, uid_t, gid_t)
601 int lchown(const char *k, uid_t, gid_t)
613 srandom(unsigned int seed)
617 // /////////////////////////////////////////////////////////////////
618 // convert from Windows concept of time to Unix concept of time
619 // /////////////////////////////////////////////////////////////////
621 cvt_utime_to_ftime(const time_t &time, FILETIME &wintime)
623 uint64_t mstime = time;
624 mstime *= WIN32_FILETIME_SCALE;
625 mstime += WIN32_FILETIME_ADJUST;
627 #if defined(_MSC_VER)
628 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
630 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL);
632 wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
636 cvt_ftime_to_utime(const FILETIME &time)
638 uint64_t mstime = time.dwHighDateTime;
640 mstime |= time.dwLowDateTime;
642 mstime -= WIN32_FILETIME_ADJUST;
643 mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
645 return (time_t) (mstime & 0xffffffff);
648 static const char *errorString(void)
652 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
653 FORMAT_MESSAGE_FROM_SYSTEM |
654 FORMAT_MESSAGE_IGNORE_INSERTS,
657 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
662 /* Strip any \r or \n */
663 char *rval = (char *) lpMsgBuf;
664 char *cp = strchr(rval, '\r');
668 cp = strchr(rval, '\n');
677 * This is only called for directories, and is used to get the directory
678 * attributes and find out if we have a junction point or a mount point
679 * or other kind of "funny" directory.
682 statDir(const char *file, struct stat *sb)
684 WIN32_FIND_DATAW info_w; // window's file info
685 WIN32_FIND_DATAA info_a; // window's file info
687 // cache some common vars to make code more transparent
688 DWORD *pdwFileAttributes;
689 DWORD *pnFileSizeHigh;
690 DWORD *pnFileSizeLow;
692 FILETIME *pftLastAccessTime;
693 FILETIME *pftLastWriteTime;
694 FILETIME *pftCreationTime;
695 HANDLE h = INVALID_HANDLE_VALUE;
698 * Oh, cool, another exception: Microsoft doesn't let us do
699 * FindFile operations on a Drive, so simply fake root attibutes.
701 if (file[1] == ':' && file[2] == 0) {
702 time_t now = time(NULL);
703 Dmsg1(dbglvl, "faking ROOT attrs(%s).\n", file);
704 sb->st_mode = S_IFDIR;
705 sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
715 if (p_FindFirstFileW) {
716 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
717 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
719 Dmsg1(dbglvl, "FindFirstFileW=%s\n", file);
720 h = p_FindFirstFileW((LPCWSTR)pwszBuf, &info_w);
721 free_pool_memory(pwszBuf);
723 pdwFileAttributes = &info_w.dwFileAttributes;
724 pdwReserved0 = &info_w.dwReserved0;
725 pnFileSizeHigh = &info_w.nFileSizeHigh;
726 pnFileSizeLow = &info_w.nFileSizeLow;
727 pftLastAccessTime = &info_w.ftLastAccessTime;
728 pftLastWriteTime = &info_w.ftLastWriteTime;
729 pftCreationTime = &info_w.ftCreationTime;
732 } else if (p_FindFirstFileA) {
733 Dmsg1(dbglvl, "FindFirstFileA=%s\n", file);
734 h = p_FindFirstFileA(file, &info_a);
736 pdwFileAttributes = &info_a.dwFileAttributes;
737 pdwReserved0 = &info_a.dwReserved0;
738 pnFileSizeHigh = &info_a.nFileSizeHigh;
739 pnFileSizeLow = &info_a.nFileSizeLow;
740 pftLastAccessTime = &info_a.ftLastAccessTime;
741 pftLastWriteTime = &info_a.ftLastWriteTime;
742 pftCreationTime = &info_a.ftCreationTime;
744 Dmsg0(dbglvl, "No findFirstFile A or W found\n");
747 if (h == INVALID_HANDLE_VALUE) {
748 const char *err = errorString();
750 * Note, in creating leading paths, it is normal that
751 * the file does not exist.
753 Dmsg2(2099, "FindFirstFile(%s):%s\n", file, err);
754 LocalFree((void *)err);
755 errno = b_errno_win32;
761 sb->st_mode = 0777; /* start with everything */
762 if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
763 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
764 if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
765 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
766 if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
767 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
768 sb->st_mode |= S_IFDIR;
771 * Store reparse/mount point info in st_rdev. Note a
772 * Win32 reparse point (junction point) is like a link
773 * though it can have many properties (directory link,
774 * soft link, hard link, HSM, ...
775 * A mount point is a reparse point where another volume
776 * is mounted, so it is like a Unix mount point (change of
779 if (*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
780 sb->st_rdev = WIN32_MOUNT_POINT;
784 if ((*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
785 (*pdwReserved0 & IO_REPARSE_TAG_MOUNT_POINT)) {
786 sb->st_rdev = WIN32_MOUNT_POINT; /* mount point */
788 * Now to find out if the directory is a mount point or
789 * a reparse point, we must do a song and a dance.
790 * Explicitly open the file to read the reparse point, then
791 * call DeviceIoControl to find out if it points to a Volume
794 h = INVALID_HANDLE_VALUE;
795 if (p_GetFileAttributesW) {
796 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
797 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
799 h = CreateFileW((LPCWSTR)pwszBuf, GENERIC_READ,
800 FILE_SHARE_READ, NULL, OPEN_EXISTING,
801 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
804 free_pool_memory(pwszBuf);
805 } else if (p_GetFileAttributesA) {
806 h = CreateFileA(file, GENERIC_READ,
807 FILE_SHARE_READ, NULL, OPEN_EXISTING,
808 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
811 if (h != INVALID_HANDLE_VALUE) {
813 REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)dummy;
814 rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
817 ok = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT,
818 NULL, 0, /* in buffer, bytes */
819 (LPVOID)rdb, (DWORD)sizeof(dummy), /* out buffer, btyes */
820 (LPDWORD)&bytes, (LPOVERLAPPED)0);
822 POOLMEM *utf8 = get_pool_memory(PM_NAME);
823 wchar_2_UTF8(&utf8, (wchar_t *)rdb->SymbolicLinkReparseBuffer.PathBuffer);
824 Dmsg2(dbglvl, "Junction %s points to: %s\n", file, utf8);
825 if (strncasecmp(utf8, "\\??\\volume{", 11) == 0) {
826 sb->st_rdev = WIN32_MOUNT_POINT;
828 /* It points to a directory so we ignore it. */
829 sb->st_rdev = WIN32_JUNCTION_POINT;
831 free_pool_memory(utf8);
835 Dmsg1(dbglvl, "Invalid handle from CreateFile(%s)\n", file);
838 Dmsg2(dbglvl, "st_rdev=%d file=%s\n", sb->st_rdev, file);
839 sb->st_size = *pnFileSizeHigh;
841 sb->st_size |= *pnFileSizeLow;
842 sb->st_blksize = 4096;
843 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
845 sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
846 sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
847 sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
853 fstat(intptr_t fd, struct stat *sb)
855 BY_HANDLE_FILE_INFORMATION info;
857 if (!GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
858 const char *err = errorString();
859 Dmsg1(2099, "GetfileInformationByHandle: %s\n", err);
860 LocalFree((void *)err);
861 errno = b_errno_win32;
865 sb->st_dev = info.dwVolumeSerialNumber;
866 sb->st_ino = info.nFileIndexHigh;
868 sb->st_ino |= info.nFileIndexLow;
869 sb->st_nlink = (short)info.nNumberOfLinks;
870 if (sb->st_nlink > 1) {
871 Dmsg1(dbglvl, "st_nlink=%d\n", sb->st_nlink);
874 sb->st_mode = 0777; /* start with everything */
875 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
876 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
877 if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
878 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
879 if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
880 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
881 sb->st_mode |= S_IFREG;
883 /* Use st_rdev to store reparse attribute */
884 if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
885 sb->st_rdev = WIN32_REPARSE_POINT;
887 Dmsg3(dbglvl, "st_rdev=%d sizino=%d ino=%lld\n", sb->st_rdev, sizeof(sb->st_ino),
888 (long long)sb->st_ino);
890 sb->st_size = info.nFileSizeHigh;
892 sb->st_size |= info.nFileSizeLow;
893 sb->st_blksize = 4096;
894 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
895 sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
896 sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
897 sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
903 stat2(const char *file, struct stat *sb)
905 HANDLE h = INVALID_HANDLE_VALUE;
908 conv_unix_to_vss_win32_path(file, tmpbuf, 5000);
910 DWORD attr = (DWORD)-1;
912 if (p_GetFileAttributesW) {
913 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
914 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
916 attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
918 h = CreateFileW((LPCWSTR)pwszBuf, GENERIC_READ,
919 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
921 free_pool_memory(pwszBuf);
922 } else if (p_GetFileAttributesA) {
923 attr = p_GetFileAttributesA(tmpbuf);
924 h = CreateFileA(tmpbuf, GENERIC_READ,
925 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
928 if (attr == (DWORD)-1) {
929 const char *err = errorString();
930 Dmsg2(2099, "GetFileAttributes(%s): %s\n", tmpbuf, err);
931 LocalFree((void *)err);
932 if (h != INVALID_HANDLE_VALUE) {
935 errno = b_errno_win32;
939 if (h == INVALID_HANDLE_VALUE) {
940 const char *err = errorString();
941 Dmsg2(2099, "Cannot open file for stat (%s):%s\n", tmpbuf, err);
942 LocalFree((void *)err);
943 errno = b_errno_win32;
947 rval = fstat((intptr_t)h, sb);
950 if (attr & FILE_ATTRIBUTE_DIRECTORY &&
951 file[1] == ':' && file[2] != 0) {
952 rval = statDir(file, sb);
958 stat(const char *file, struct stat *sb)
960 WIN32_FILE_ATTRIBUTE_DATA data;
963 memset(sb, 0, sizeof(*sb));
965 if (p_GetFileAttributesExW) {
966 /* dynamically allocate enough space for UCS2 filename */
967 POOLMEM *pwszBuf = get_pool_memory(PM_FNAME);
968 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
970 BOOL b = p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, &data);
971 free_pool_memory(pwszBuf);
974 return stat2(file, sb);
977 } else if (p_GetFileAttributesExA) {
978 if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
979 return stat2(file, sb);
982 return stat2(file, sb);
985 sb->st_mode = 0777; /* start with everything */
986 if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
987 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
989 if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
990 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
992 if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
993 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
995 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
996 sb->st_mode |= S_IFDIR;
998 sb->st_mode |= S_IFREG;
1001 /* Use st_rdev to store reparse attribute */
1002 sb->st_rdev = (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0;
1005 sb->st_size = data.nFileSizeHigh;
1007 sb->st_size |= data.nFileSizeLow;
1008 sb->st_blksize = 4096;
1009 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
1010 sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
1011 sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
1012 sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
1015 * If we are not at the root, then to distinguish a reparse
1016 * point from a mount point, we must call FindFirstFile() to
1017 * get the WIN32_FIND_DATA, which has the bit that indicates
1018 * that this directory is a mount point -- aren't Win32 APIs
1019 * wonderful? (sarcasm). The code exists in the statDir
1022 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
1023 file[1] == ':' && file[2] != 0) {
1026 Dmsg3(dbglvl, "sizino=%d ino=%lld file=%s\n", sizeof(sb->st_ino),
1027 (long long)sb->st_ino, file);
1032 * We write our own ftruncate because the one in the
1033 * Microsoft library mrcrt.dll does not truncate
1034 * files greater than 2GB.
1037 int win32_ftruncate(int fd, int64_t length)
1039 /* Set point we want to truncate file */
1040 __int64 pos = _lseeki64(fd, (__int64)length, SEEK_SET);
1042 if (pos != (__int64)length) {
1043 errno = EACCES; /* truncation failed, get out */
1048 if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0) {
1049 errno = b_errno_win32;
1056 int fcntl(int fd, int cmd, long arg)
1079 lstat(const char *file, struct stat *sb)
1081 return stat(file, sb);
1097 execvp(const char *, char *[]) {
1118 waitpid(int, int*, int)
1125 readlink(const char *, char *, int)
1134 strcasecmp(const char *s1, const char *s2)
1136 register int ch1, ch2;
1139 return 0; /* strings are equal if same object. */
1149 } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
1156 strncasecmp(const char *s1, const char *s2, int len)
1158 register int ch1 = 0, ch2 = 0;
1161 return 0; /* strings are equal if same object. */
1172 if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
1179 gettimeofday(struct timeval *tv, struct timezone *)
1184 GetSystemTime(&now);
1190 if (!SystemTimeToFileTime(&now, &tmp)) {
1191 errno = b_errno_win32;
1195 int64_t _100nsec = tmp.dwHighDateTime;
1197 _100nsec |= tmp.dwLowDateTime;
1198 _100nsec -= WIN32_FILETIME_ADJUST;
1200 tv->tv_sec = (long)(_100nsec / 10000000);
1201 tv->tv_usec = (long)((_100nsec % 10000000)/10);
1207 * Write in Windows System log
1209 extern "C" void syslog(int type, const char *fmt, ...)
1215 msg = get_pool_memory(PM_EMSG);
1218 maxlen = sizeof_pool_memory(msg) - 1;
1219 va_start(arg_ptr, fmt);
1220 len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
1222 if (len < 0 || len >= (maxlen-5)) {
1223 msg = realloc_pool_memory(msg, maxlen + maxlen/2);
1228 LogErrorMsg((const char *)msg);
1249 // implement opendir/readdir/closedir on top of window's API
1253 WIN32_FIND_DATAA data_a; // window's file info (ansii version)
1254 WIN32_FIND_DATAW data_w; // window's file info (wchar version)
1255 const char *spec; // the directory we're traversing
1256 HANDLE dirh; // the search handle
1257 BOOL valid_a; // the info in data_a field is valid
1258 BOOL valid_w; // the info in data_w field is valid
1259 UINT32 offset; // pseudo offset for d_off
1263 opendir(const char *path)
1265 /* enough space for VSS !*/
1266 int max_len = strlen(path) + MAX_PATH;
1274 Dmsg1(dbglvl, "Opendir path=%s\n", path);
1275 rval = (_dir *)malloc(sizeof(_dir));
1279 memset (rval, 0, sizeof (_dir));
1281 tspec = (char *)malloc(max_len);
1286 conv_unix_to_vss_win32_path(path, tspec, max_len);
1287 Dmsg1(dbglvl, "win32 path=%s\n", tspec);
1289 // add backslash only if there is none yet (think of c:\)
1290 if (tspec[strlen(tspec)-1] != '\\')
1291 bstrncat(tspec, "\\*", max_len);
1293 bstrncat(tspec, "*", max_len);
1297 // convert to wchar_t
1298 if (p_FindFirstFileW) {
1299 POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
1300 make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec);
1302 rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
1304 free_pool_memory(pwcBuf);
1306 if (rval->dirh != INVALID_HANDLE_VALUE)
1308 } else if (p_FindFirstFileA) {
1309 rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
1311 if (rval->dirh != INVALID_HANDLE_VALUE)
1316 Dmsg3(dbglvl, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
1317 path, rval->spec, rval->dirh);
1320 if (rval->dirh == INVALID_HANDLE_VALUE)
1323 if (rval->valid_w) {
1324 Dmsg1(dbglvl, "\tFirstFile=%s\n", rval->data_w.cFileName);
1327 if (rval->valid_a) {
1328 Dmsg1(dbglvl, "\tFirstFile=%s\n", rval->data_a.cFileName);
1340 errno = b_errno_win32;
1347 _dir *dp = (_dir *)dirp;
1348 FindClose(dp->dirh);
1349 free((void *)dp->spec);
1355 typedef struct _WIN32_FIND_DATA {
1356 DWORD dwFileAttributes;
1357 FILETIME ftCreationTime;
1358 FILETIME ftLastAccessTime;
1359 FILETIME ftLastWriteTime;
1360 DWORD nFileSizeHigh;
1364 TCHAR cFileName[MAX_PATH];
1365 TCHAR cAlternateFileName[14];
1366 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1370 copyin(struct dirent &dp, const char *fname)
1374 char *cp = dp.d_name;
1384 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1386 _dir *dp = (_dir *)dirp;
1387 if (dp->valid_w || dp->valid_a) {
1388 entry->d_off = dp->offset;
1392 POOLMEM *szBuf = get_pool_memory(PM_NAME);
1393 wchar_2_UTF8(&szBuf, dp->data_w.cFileName);
1394 dp->offset += copyin(*entry, szBuf);
1395 free_pool_memory(szBuf);
1396 } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1397 dp->offset += copyin(*entry, dp->data_a.cFileName);
1400 *result = entry; /* return entry address */
1401 Dmsg4(dbglvl, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1402 dirp, entry->d_name, entry->d_reclen, entry->d_off);
1404 // Dmsg0(dbglvl, "readdir_r !valid\n");
1405 errno = b_errno_win32;
1409 // get next file, try unicode first
1410 if (p_FindNextFileW)
1411 dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1412 else if (p_FindNextFileA)
1413 dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1415 dp->valid_a = FALSE;
1416 dp->valid_w = FALSE;
1423 * Dotted IP address to network address
1429 inet_aton(const char *a, struct in_addr *inp)
1432 uint32_t acc = 0, tmp = 0;
1435 if (!isdigit(*cp)) { /* first char must be digit */
1436 return 0; /* error */
1440 tmp = (tmp * 10) + (*cp -'0');
1441 } else if (*cp == '.' || *cp == 0) {
1443 return 0; /* error */
1445 acc = (acc << 8) + tmp;
1449 return 0; /* error */
1451 } while (*cp++ != 0);
1452 if (dotc != 4) { /* want 3 .'s plus EOS */
1453 return 0; /* error */
1455 inp->s_addr = htonl(acc); /* store addr in network format */
1460 nanosleep(const struct timespec *req, struct timespec *rem)
1463 rem->tv_sec = rem->tv_nsec = 0;
1464 Sleep((req->tv_sec * 1000) + (req->tv_nsec/1000000));
1469 init_signals(void terminate(int sig))
1475 init_stack_dump(void)
1482 pathconf(const char *path, int name)
1486 if (strncmp(path, "\\\\?\\", 4) == 0)
1498 WORD wVersionRequested = MAKEWORD( 1, 1);
1501 int err = WSAStartup(wVersionRequested, &wsaData);
1505 printf("Can not start Windows Sockets\n");
1513 static DWORD fill_attribute(DWORD attr, mode_t mode)
1515 Dmsg1(dbglvl, " before attr=%lld\n", (uint64_t) attr);
1516 /* Use Bacula mappings define in stat() above */
1517 if (mode & (S_IRUSR|S_IRGRP|S_IROTH)) { // If file is readable
1518 attr &= ~FILE_ATTRIBUTE_READONLY; // then this is not READONLY
1520 attr |= FILE_ATTRIBUTE_READONLY;
1522 if (mode & S_ISVTX) { // The sticky bit <=> HIDDEN
1523 attr |= FILE_ATTRIBUTE_HIDDEN;
1525 attr &= ~FILE_ATTRIBUTE_HIDDEN;
1527 if (mode & S_IRWXO) { // Other can read/write/execute ?
1528 attr &= ~FILE_ATTRIBUTE_SYSTEM; // => Not system
1530 attr |= FILE_ATTRIBUTE_SYSTEM;
1532 Dmsg1(dbglvl, " after attr=%lld\n", (uint64_t)attr);
1536 int win32_chmod(const char *path, mode_t mode)
1541 Dmsg2(dbglvl, "win32_chmod(path=%s mode=%lld)\n", path, (uint64_t)mode);
1542 if (p_GetFileAttributesW) {
1543 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1544 make_win32_path_UTF8_2_wchar(&pwszBuf, path);
1546 attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
1547 if (attr != INVALID_FILE_ATTRIBUTES) {
1548 /* Use Bacula mappings define in stat() above */
1549 attr = fill_attribute(attr, mode);
1550 ret = p_SetFileAttributesW((LPCWSTR)pwszBuf, attr);
1552 free_pool_memory(pwszBuf);
1553 Dmsg0(dbglvl, "Leave win32_chmod. AttributesW\n");
1554 } else if (p_GetFileAttributesA) {
1555 attr = p_GetFileAttributesA(path);
1556 if (attr != INVALID_FILE_ATTRIBUTES) {
1557 attr = fill_attribute(attr, mode);
1558 ret = p_SetFileAttributesA(path, attr);
1560 Dmsg0(dbglvl, "Leave win32_chmod did AttributesA\n");
1562 Dmsg0(dbglvl, "Leave win32_chmod did nothing\n");
1566 const char *err = errorString();
1567 Dmsg2(dbglvl, "Get/SetFileAttributes(%s): %s\n", path, err);
1568 LocalFree((void *)err);
1569 errno = b_errno_win32;
1577 win32_chdir(const char *dir)
1579 if (p_SetCurrentDirectoryW) {
1580 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1581 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1583 BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1585 free_pool_memory(pwszBuf);
1588 errno = b_errno_win32;
1591 } else if (p_SetCurrentDirectoryA) {
1592 if (0 == p_SetCurrentDirectoryA(dir)) {
1593 errno = b_errno_win32;
1604 win32_mkdir(const char *dir)
1606 Dmsg1(dbglvl, "enter win32_mkdir. dir=%s\n", dir);
1608 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1609 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1611 int n = p_wmkdir((LPCWSTR)pwszBuf);
1612 free_pool_memory(pwszBuf);
1613 Dmsg0(dbglvl, "Leave win32_mkdir did wmkdir\n");
1617 Dmsg0(dbglvl, "Leave win32_mkdir did _mkdir\n");
1623 win32_getcwd(char *buf, int maxlen)
1627 if (p_GetCurrentDirectoryW) {
1628 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1629 pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1631 n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1633 n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1634 free_pool_memory(pwszBuf);
1636 } else if (p_GetCurrentDirectoryA)
1637 n = p_GetCurrentDirectoryA(maxlen, buf);
1639 if (n <= 0 || n > maxlen) return NULL;
1641 if (n+1 > maxlen) return NULL;
1650 win32_fputs(const char *string, FILE *stream)
1652 /* we use WriteConsoleA / WriteConsoleA
1653 so we can be sure that unicode support works on win32.
1654 with fallback if something fails
1657 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1658 if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1659 p_MultiByteToWideChar && (stream == stdout)) {
1661 POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1663 DWORD dwCharsWritten;
1666 dwChars = UTF8_2_wchar(&pwszBuf, string);
1668 /* try WriteConsoleW */
1669 if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1670 free_pool_memory(pwszBuf);
1671 return dwCharsWritten;
1674 /* convert to local codepage and try WriteConsoleA */
1675 POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1676 pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1678 dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR)pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1679 free_pool_memory(pwszBuf);
1681 if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1682 free_pool_memory(pszBuf);
1683 return dwCharsWritten;
1685 free_pool_memory(pszBuf);
1688 return fputs(string, stream);
1692 win32_cgets (char* buffer, int len)
1694 /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1695 from the win32 console and fallback if seomething fails */
1697 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1698 if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1700 wchar_t wszBuf[1024];
1703 /* nt and unicode conversion */
1704 if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1706 /* null terminate at end */
1707 if (wszBuf[dwRead-1] == L'\n') {
1708 wszBuf[dwRead-1] = L'\0';
1712 if (wszBuf[dwRead-1] == L'\r') {
1713 wszBuf[dwRead-1] = L'\0';
1717 wchar_2_UTF8(buffer, wszBuf, len);
1721 /* win 9x and unicode conversion */
1722 if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1724 /* null terminate at end */
1725 if (szBuf[dwRead-1] == L'\n') {
1726 szBuf[dwRead-1] = L'\0';
1730 if (szBuf[dwRead-1] == L'\r') {
1731 szBuf[dwRead-1] = L'\0';
1735 /* convert from ansii to wchar_t */
1736 p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1737 /* convert from wchar_t to UTF-8 */
1738 if (wchar_2_UTF8(buffer, wszBuf, len))
1744 if (fgets(buffer, len, stdin))
1751 win32_unlink(const char *filename)
1755 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1756 make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1758 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1761 * special case if file is readonly,
1762 * we retry but unset attribute before
1764 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1765 DWORD dwAttr = p_GetFileAttributesW((LPCWSTR)pwszBuf);
1766 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1767 if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1768 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1769 /* reset to original if it didn't help */
1771 p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1775 free_pool_memory(pwszBuf);
1777 nRetCode = _unlink(filename);
1779 /* special case if file is readonly,
1780 we retry but unset attribute before */
1781 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1782 DWORD dwAttr = p_GetFileAttributesA(filename);
1783 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1784 if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1785 nRetCode = _unlink(filename);
1786 /* reset to original if it didn't help */
1788 p_SetFileAttributesA(filename, dwAttr);
1797 #include "mswinver.h"
1799 char WIN_VERSION_LONG[64];
1800 char WIN_VERSION[32];
1801 char WIN_RAWVERSION[32];
1808 static winver INIT; // cause constructor to be called before main()
1811 winver::winver(void)
1813 const char *version = "";
1814 const char *platform = "";
1815 OSVERSIONINFO osvinfo;
1816 osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1818 // Get the current OS version
1819 if (!GetVersionEx(&osvinfo)) {
1820 version = "Unknown";
1821 platform = "Unknown";
1823 const int ver = _mkversion(osvinfo.dwPlatformId,
1824 osvinfo.dwMajorVersion,
1825 osvinfo.dwMinorVersion);
1826 snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1829 case MS_WINDOWS_95: (version = "Windows 95"); break;
1830 case MS_WINDOWS_98: (version = "Windows 98"); break;
1831 case MS_WINDOWS_ME: (version = "Windows ME"); break;
1832 case MS_WINDOWS_NT4:(version = "Windows NT 4.0"); platform = "NT"; break;
1833 case MS_WINDOWS_2K: (version = "Windows 2000");platform = "NT"; break;
1834 case MS_WINDOWS_XP: (version = "Windows XP");platform = "NT"; break;
1835 case MS_WINDOWS_S2003: (version = "Windows Server 2003");platform = "NT"; break;
1836 default: version = WIN_RAWVERSION; break;
1839 bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1840 snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1841 platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1844 HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1848 BPIPE *b = open_bpipe("ls -l", 10, "r");
1850 while (!feof(b->rfd)) {
1851 fgets(buf, sizeof(buf), b->rfd);
1857 BOOL CreateChildProcess(VOID);
1858 VOID WriteToPipe(VOID);
1859 VOID ReadFromPipe(VOID);
1860 VOID ErrorExit(LPCSTR);
1861 VOID ErrMsg(LPTSTR, BOOL);
1864 * Check for a quoted path, if an absolute path name is given and it contains
1865 * spaces it will need to be quoted. i.e. "c:/Program Files/foo/bar.exe"
1866 * CreateProcess() says the best way to ensure proper results with executables
1867 * with spaces in path or filename is to quote the string.
1870 getArgv0(const char *cmdline)
1875 for (cp = cmdline; *cp; cp++)
1880 if (!inquote && isspace(*cp))
1885 int len = cp - cmdline;
1886 char *rval = (char *)malloc(len+1);
1899 * Extracts the executable or script name from the first string in
1902 * If the name contains blanks then it must be quoted with double quotes,
1903 * otherwise quotes are optional. If the name contains blanks then it
1904 * will be converted to a short name.
1906 * The optional quotes will be removed. The result is copied to a malloc'ed
1907 * buffer and returned through the pexe argument. The pargs parameter is set
1908 * to the address of the character in cmdline located after the name.
1910 * The malloc'ed buffer returned in *pexe must be freed by the caller.
1913 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1915 const char *pExeStart = NULL; /* Start of executable name in cmdline */
1916 const char *pExeEnd = NULL; /* Character after executable name (separator) */
1918 const char *pBasename = NULL; /* Character after last path separator */
1919 const char *pExtension = NULL; /* Period at start of extension */
1921 const char *current = cmdline;
1923 bool bQuoted = false;
1925 /* Skip initial whitespace */
1927 while (*current == ' ' || *current == '\t')
1932 /* Calculate start of name and determine if quoted */
1934 if (*current == '"') {
1935 pExeStart = ++current;
1938 pExeStart = current;
1946 * Scan command line looking for path separators (/ and \\) and the
1947 * terminator, either a quote or a blank. The location of the
1948 * extension is also noted.
1951 for ( ; *current != '\0'; current++)
1953 if (*current == '.') {
1954 pExtension = current;
1955 } else if (IsPathSeparator(*current) && current[1] != '\0') {
1956 pBasename = ¤t[1];
1960 /* Check for terminator, either quote or blank */
1962 if (*current != '"') {
1966 if (*current != ' ') {
1972 * Hit terminator, remember end of name (address of terminator) and
1973 * start of arguments
1977 if (bQuoted && *current == '"') {
1978 *pargs = ¤t[1];
1986 if (pBasename == NULL) {
1987 pBasename = pExeStart;
1990 if (pExeEnd == NULL) {
1999 bool bHasPathSeparators = pExeStart != pBasename;
2001 /* We have pointers to all the useful parts of the name */
2003 /* Default extensions in the order cmd.exe uses to search */
2005 static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
2006 DWORD dwBasePathLength = pExeEnd - pExeStart;
2008 DWORD dwAltNameLength = 0;
2009 char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
2010 char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
2012 pPathname[MAX_PATHLENGTH] = '\0';
2013 pAltPathname[MAX_PATHLENGTH] = '\0';
2015 memcpy(pPathname, pExeStart, dwBasePathLength);
2016 pPathname[dwBasePathLength] = '\0';
2018 if (pExtension == NULL) {
2019 /* Try appending extensions */
2020 for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
2022 if (!bHasPathSeparators) {
2023 /* There are no path separators, search in the standard locations */
2024 dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
2025 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
2026 memcpy(pPathname, pAltPathname, dwAltNameLength);
2027 pPathname[dwAltNameLength] = '\0';
2031 bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
2032 if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) {
2035 pPathname[dwBasePathLength] = '\0';
2038 } else if (!bHasPathSeparators) {
2039 /* There are no path separators, search in the standard locations */
2040 dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
2041 if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) {
2042 memcpy(pPathname, pAltPathname, dwAltNameLength);
2043 pPathname[dwAltNameLength] = '\0';
2047 if (strchr(pPathname, ' ') != NULL) {
2048 dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH);
2050 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
2051 *pexe = (char *)malloc(dwAltNameLength + 1);
2052 if (*pexe == NULL) {
2055 memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
2059 if (*pexe == NULL) {
2060 DWORD dwPathnameLength = strlen(pPathname);
2061 *pexe = (char *)malloc(dwPathnameLength + 1);
2062 if (*pexe == NULL) {
2065 memcpy(*pexe, pPathname, dwPathnameLength + 1);
2072 * Create the process with WCHAR API
2075 CreateChildProcessW(const char *comspec, const char *cmdLine,
2076 PROCESS_INFORMATION *hProcInfo,
2077 HANDLE in, HANDLE out, HANDLE err)
2079 STARTUPINFOW siStartInfo;
2080 BOOL bFuncRetn = FALSE;
2082 // Set up members of the STARTUPINFO structure.
2083 ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
2084 siStartInfo.cb = sizeof(siStartInfo);
2085 // setup new process to use supplied handles for stdin,stdout,stderr
2087 siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
2088 siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
2090 siStartInfo.hStdInput = in;
2091 siStartInfo.hStdOutput = out;
2092 siStartInfo.hStdError = err;
2094 // Convert argument to WCHAR
2095 POOLMEM *cmdLine_wchar = get_pool_memory(PM_FNAME);
2096 POOLMEM *comspec_wchar = get_pool_memory(PM_FNAME);
2098 UTF8_2_wchar(&cmdLine_wchar, cmdLine);
2099 UTF8_2_wchar(&comspec_wchar, comspec);
2101 // Create the child process.
2102 Dmsg2(dbglvl, "Calling CreateProcess(%s, %s, ...)\n", comspec_wchar, cmdLine_wchar);
2104 // try to execute program
2105 bFuncRetn = p_CreateProcessW((WCHAR*)comspec_wchar,
2106 (WCHAR*)cmdLine_wchar,// command line
2107 NULL, // process security attributes
2108 NULL, // primary thread security attributes
2109 TRUE, // handles are inherited
2110 0, // creation flags
2111 NULL, // use parent's environment
2112 NULL, // use parent's current directory
2113 &siStartInfo, // STARTUPINFO pointer
2114 hProcInfo); // receives PROCESS_INFORMATION
2115 free_pool_memory(cmdLine_wchar);
2116 free_pool_memory(comspec_wchar);
2123 * Create the process with ANSI API
2126 CreateChildProcessA(const char *comspec, char *cmdLine,
2127 PROCESS_INFORMATION *hProcInfo,
2128 HANDLE in, HANDLE out, HANDLE err)
2130 STARTUPINFOA siStartInfo;
2131 BOOL bFuncRetn = FALSE;
2133 // Set up members of the STARTUPINFO structure.
2134 ZeroMemory( &siStartInfo, sizeof(siStartInfo) );
2135 siStartInfo.cb = sizeof(siStartInfo);
2136 // setup new process to use supplied handles for stdin,stdout,stderr
2137 siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
2138 siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
2140 siStartInfo.hStdInput = in;
2141 siStartInfo.hStdOutput = out;
2142 siStartInfo.hStdError = err;
2144 // Create the child process.
2145 Dmsg2(dbglvl, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
2147 // try to execute program
2148 bFuncRetn = p_CreateProcessA(comspec,
2149 cmdLine, // command line
2150 NULL, // process security attributes
2151 NULL, // primary thread security attributes
2152 TRUE, // handles are inherited
2153 0, // creation flags
2154 NULL, // use parent's environment
2155 NULL, // use parent's current directory
2156 &siStartInfo,// STARTUPINFO pointer
2157 hProcInfo);// receives PROCESS_INFORMATION
2162 * OK, so it would seem CreateProcess only handles true executables:
2163 * .com or .exe files. So grab $COMSPEC value and pass command line to it.
2166 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
2168 static const char *comspec = NULL;
2169 PROCESS_INFORMATION piProcInfo;
2170 BOOL bFuncRetn = FALSE;
2172 if (!p_CreateProcessA || !p_CreateProcessW)
2173 return INVALID_HANDLE_VALUE;
2175 if (comspec == NULL)
2176 comspec = getenv("COMSPEC");
2177 if (comspec == NULL) // should never happen
2178 return INVALID_HANDLE_VALUE;
2180 // Set up members of the PROCESS_INFORMATION structure.
2181 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
2183 // if supplied handles are not used the send a copy of our STD_HANDLE
2185 if (in == INVALID_HANDLE_VALUE)
2186 in = GetStdHandle(STD_INPUT_HANDLE);
2188 if (out == INVALID_HANDLE_VALUE)
2189 out = GetStdHandle(STD_OUTPUT_HANDLE);
2191 if (err == INVALID_HANDLE_VALUE)
2192 err = GetStdHandle(STD_ERROR_HANDLE);
2195 const char *argStart;
2197 if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
2198 return INVALID_HANDLE_VALUE;
2201 POOL_MEM cmdLine(PM_FNAME);
2202 Mmsg(cmdLine, "%s /c %s%s", comspec, exeFile, argStart);
2206 // New function disabled
2207 if (p_CreateProcessW && p_MultiByteToWideChar) {
2208 bFuncRetn = CreateChildProcessW(comspec, cmdLine.c_str(), &piProcInfo,
2211 bFuncRetn = CreateChildProcessA(comspec, cmdLine.c_str(), &piProcInfo,
2215 if (bFuncRetn == 0) {
2216 ErrorExit("CreateProcess failed\n");
2217 const char *err = errorString();
2218 Dmsg3(dbglvl, "CreateProcess(%s, %s, ...)=%s\n",comspec,cmdLine.c_str(),err);
2219 LocalFree((void *)err);
2220 return INVALID_HANDLE_VALUE;
2222 // we don't need a handle on the process primary thread so we close
2224 CloseHandle(piProcInfo.hThread);
2225 return piProcInfo.hProcess;
2229 ErrorExit (LPCSTR lpszMessage)
2231 Dmsg1(0, "%s", lpszMessage);
2236 typedef struct s_bpipe {
2238 time_t worker_stime;
2247 CloseHandleIfValid(HANDLE handle)
2249 if (handle != INVALID_HANDLE_VALUE) {
2250 CloseHandle(handle);
2255 open_bpipe(char *prog, int wait, const char *mode)
2257 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
2258 hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
2261 SECURITY_ATTRIBUTES saAttr;
2265 hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
2266 hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
2267 hInputFile = INVALID_HANDLE_VALUE;
2269 BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
2270 memset((void *)bpipe, 0, sizeof(BPIPE));
2272 int mode_read = (mode[0] == 'r');
2273 int mode_write = (mode[0] == 'w' || mode[1] == 'w');
2276 // Set the bInheritHandle flag so pipe handles are inherited.
2278 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
2279 saAttr.bInheritHandle = TRUE;
2280 saAttr.lpSecurityDescriptor = NULL;
2284 // Create a pipe for the child process's STDOUT.
2285 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
2286 ErrorExit("Stdout pipe creation failed\n");
2289 // Create noninheritable read handle and close the inheritable read
2292 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
2293 GetCurrentProcess(), &hChildStdoutRdDup , 0,
2295 DUPLICATE_SAME_ACCESS);
2297 ErrorExit("DuplicateHandle failed");
2301 CloseHandle(hChildStdoutRd);
2302 hChildStdoutRd = INVALID_HANDLE_VALUE;
2307 // Create a pipe for the child process's STDIN.
2309 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
2310 ErrorExit("Stdin pipe creation failed\n");
2314 // Duplicate the write handle to the pipe so it is not inherited.
2315 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
2316 GetCurrentProcess(), &hChildStdinWrDup,
2318 FALSE, // not inherited
2319 DUPLICATE_SAME_ACCESS);
2321 ErrorExit("DuplicateHandle failed");
2325 CloseHandle(hChildStdinWr);
2326 hChildStdinWr = INVALID_HANDLE_VALUE;
2328 // spawn program with redirected handles as appropriate
2329 bpipe->worker_pid = (pid_t)
2330 CreateChildProcess(prog, // commandline
2331 hChildStdinRd, // stdin HANDLE
2332 hChildStdoutWr, // stdout HANDLE
2333 hChildStdoutWr); // stderr HANDLE
2335 if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
2339 bpipe->worker_stime = time(NULL);
2342 CloseHandle(hChildStdoutWr); // close our write side so when
2343 // process terminates we can
2345 // ugly but convert WIN32 HANDLE to FILE*
2346 int rfd = _open_osfhandle((intptr_t)hChildStdoutRdDup, O_RDONLY | O_BINARY);
2348 bpipe->rfd = _fdopen(rfd, "rb");
2352 CloseHandle(hChildStdinRd); // close our read side so as not
2353 // to interfre with child's copy
2354 // ugly but convert WIN32 HANDLE to FILE*
2355 int wfd = _open_osfhandle((intptr_t)hChildStdinWrDup, O_WRONLY | O_BINARY);
2357 bpipe->wfd = _fdopen(wfd, "wb");
2362 bpipe->timer_id = start_child_timer(NULL, bpipe->worker_pid, wait);
2369 CloseHandleIfValid(hChildStdoutRd);
2370 CloseHandleIfValid(hChildStdoutRdDup);
2371 CloseHandleIfValid(hChildStdinWr);
2372 CloseHandleIfValid(hChildStdinWrDup);
2374 free((void *)bpipe);
2375 errno = b_errno_win32; /* do GetLastError() for error code */
2381 kill(int pid, int signal)
2384 if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
2386 errno = b_errno_win32;
2388 CloseHandle((HANDLE)pid);
2394 close_bpipe(BPIPE *bpipe)
2397 int32_t remaining_wait = bpipe->wait;
2409 if (remaining_wait == 0) { /* wait indefinitely */
2410 remaining_wait = INT32_MAX;
2414 if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
2415 const char *err = errorString();
2416 rval = b_errno_win32;
2417 Dmsg1(dbglvl, "GetExitCode error %s\n", err);
2418 LocalFree((void *)err);
2421 if (exitCode == STILL_ACTIVE) {
2422 if (remaining_wait <= 0) {
2423 rval = ETIME; /* timed out */
2426 bmicrosleep(1, 0); /* wait one second */
2428 } else if (exitCode != 0) {
2429 /* Truncate exit code as it doesn't seem to be correct */
2430 rval = (exitCode & 0xFF) | b_errno_exit;
2433 break; /* Shouldn't get here */
2437 if (bpipe->timer_id) {
2438 stop_child_timer(bpipe->timer_id);
2440 if (bpipe->rfd) fclose(bpipe->rfd);
2441 if (bpipe->wfd) fclose(bpipe->wfd);
2442 free((void *)bpipe);
2447 close_wpipe(BPIPE *bpipe)
2453 if (fclose(bpipe->wfd) != 0) {
2463 utime(const char *fname, struct utimbuf *times)
2468 conv_unix_to_vss_win32_path(fname, tmpbuf, 5000);
2470 cvt_utime_to_ftime(times->actime, acc);
2471 cvt_utime_to_ftime(times->modtime, mod);
2473 HANDLE h = INVALID_HANDLE_VALUE;
2475 if (p_CreateFileW) {
2476 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2477 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
2479 h = p_CreateFileW((LPCWSTR)pwszBuf,
2480 FILE_WRITE_ATTRIBUTES,
2481 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2484 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2487 free_pool_memory(pwszBuf);
2488 } else if (p_CreateFileA) {
2489 h = p_CreateFileA(tmpbuf,
2490 FILE_WRITE_ATTRIBUTES,
2491 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2494 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2498 if (h == INVALID_HANDLE_VALUE) {
2499 const char *err = errorString();
2500 Dmsg2(dbglvl, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2501 LocalFree((void *)err);
2502 errno = b_errno_win32;
2506 int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2509 errno = b_errno_win32;
2517 file_open(const char *file, int flags, int mode)
2520 DWORD shareMode = 0;
2523 HANDLE foo = INVALID_HANDLE_VALUE;
2524 const char *remap = file;
2526 if (flags & O_WRONLY) access = GENERIC_WRITE;
2527 else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2528 else access = GENERIC_READ;
2530 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2531 create = CREATE_NEW;
2532 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2533 create = CREATE_ALWAYS;
2534 else if (flags & O_CREAT)
2535 create = OPEN_ALWAYS;
2536 else if (flags & O_TRUNC)
2537 create = TRUNCATE_EXISTING;
2539 create = OPEN_EXISTING;
2543 if (flags & O_APPEND) {
2544 printf("open...APPEND not implemented yet.");
2548 if (p_CreateFileW) {
2549 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2550 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
2552 foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
2553 free_pool_memory(pwszBuf);
2554 } else if (p_CreateFileA)
2555 foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
2557 if (INVALID_HANDLE_VALUE == foo) {
2558 errno = b_errno_win32;
2569 if (!CloseHandle((HANDLE)fd)) {
2570 errno = b_errno_win32;
2578 file_write(int fd, const void *data, ssize_t len)
2582 status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2583 if (status) return bwrite;
2584 errno = b_errno_win32;
2590 file_read(int fd, void *data, ssize_t len)
2595 status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2596 if (status) return bread;
2597 errno = b_errno_win32;
2602 file_seek(int fd, boffset_t offset, int whence)
2606 LONG offset_low = (LONG)offset;
2607 LONG offset_high = (LONG)(offset >> 32);
2611 method = FILE_BEGIN;
2614 method = FILE_CURRENT;
2625 if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
2626 errno = b_errno_win32;
2629 /* ***FIXME*** I doubt this works right */
2643 * Emulation of mmap and unmmap for tokyo dbm
2645 void *mmap(void *start, size_t length, int prot, int flags,
2646 int fd, off_t offset)
2648 DWORD fm_access = 0;
2649 DWORD mv_access = 0;
2660 if (flags & PROT_WRITE) {
2661 fm_access |= PAGE_READWRITE;
2662 } else if (flags & PROT_READ) {
2663 fm_access |= PAGE_READONLY;
2666 if (flags & PROT_READ) {
2667 mv_access |= FILE_MAP_READ;
2669 if (flags & PROT_WRITE) {
2670 mv_access |= FILE_MAP_WRITE;
2673 h = CreateFileMapping((HANDLE)_get_osfhandle (fd),
2674 NULL /* security */,
2676 0 /* MaximumSizeHigh */,
2677 0 /* MaximumSizeLow */,
2678 NULL /* name of the file mapping object */);
2680 if (!h || h == INVALID_HANDLE_VALUE) {
2684 mv = MapViewOfFile(h, mv_access,
2690 if (!mv || mv == INVALID_HANDLE_VALUE) {
2697 int munmap(void *start, size_t length)
2702 UnmapViewOfFile(start);
2708 /* syslog function, added by Nicolas Boichat */
2709 void openlog(const char *ident, int option, int facility) {}
2712 /* Log an error message */
2713 void LogErrorMsg(const char *message)
2715 HANDLE eventHandler;
2716 const char *strings[2];
2718 /* Use the OS event logging to log the error */
2719 eventHandler = RegisterEventSource(NULL, "Bacula");
2721 strings[0] = _("\n\nBacula ERROR: ");
2722 strings[1] = message;
2725 ReportEvent(eventHandler, EVENTLOG_ERROR_TYPE,
2729 2, /* Number of strings */
2730 0, /* raw data size */
2731 (const char **)strings, /* error strings */
2732 NULL); /* raw data */
2733 DeregisterEventSource(eventHandler);
2738 * Don't allow OS to suspend while backup running
2739 * Note, the OS automatically tracks these for each thread
2741 void prevent_os_suspensions()
2744 // SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
2747 void allow_os_suspensions()
2749 // SetThreadExecutionState(ES_CONTINUOUS);