2 // compat.cpp -- compatibilty layer to make bacula-fd run
3 // natively under windows
5 // Copyright transferred from Raider Solutions, Inc to
6 // Kern Sibbald and John Walker by express permission.
8 // Author : Christopher S. Hull
9 // Created On : Sat Jan 31 15:55:00 2004
12 Bacula® - The Network Backup Solution
14 Copyright (C) 2004-2006 Free Software Foundation Europe e.V.
16 The main author of Bacula is Kern Sibbald, with contributions from
17 many others, a complete list can be found in the file AUTHORS.
18 This program is Free Software; you can redistribute it and/or
19 modify it under the terms of version two of the GNU General Public
20 License as published by the Free Software Foundation plus additions
21 that are listed in the file LICENSE.
23 This program is distributed in the hope that it will be useful, but
24 WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 General Public License for more details.
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
33 Bacula® is a registered trademark of John Walker.
34 The licensor of Bacula is the Free Software Foundation Europe
35 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
36 Switzerland, email:ftf@fsfeurope.org.
44 #define b_errno_win32 (1<<29)
46 #define MAX_PATHLENGTH 1024
48 /* UTF-8 to UCS2 path conversion is expensive,
49 so we cache the conversion. During backup the
50 conversion is called 3 times (lstat, attribs, open),
51 by using the cache this is reduced to 1 time */
53 static POOLMEM *g_pWin32ConvUTF8Cache = get_pool_memory (PM_FNAME);
54 static POOLMEM *g_pWin32ConvUCS2Cache = get_pool_memory (PM_FNAME);
55 static DWORD g_dwWin32ConvUTF8strlen = 0;
56 static pthread_mutex_t Win32Convmutex = PTHREAD_MUTEX_INITIALIZER;
58 static t_pVSSPathConvert g_pVSSPathConvert;
59 static t_pVSSPathConvertW g_pVSSPathConvertW;
61 void SetVSSPathConvert(t_pVSSPathConvert pPathConvert, t_pVSSPathConvertW pPathConvertW)
63 g_pVSSPathConvert = pPathConvert;
64 g_pVSSPathConvertW = pPathConvertW;
67 void Win32ConvCleanupCache()
69 if (g_pWin32ConvUTF8Cache) {
70 free_pool_memory(g_pWin32ConvUTF8Cache);
71 g_pWin32ConvUTF8Cache = NULL;
74 if (g_pWin32ConvUCS2Cache) {
75 free_pool_memory(g_pWin32ConvUCS2Cache);
76 g_pWin32ConvUCS2Cache = NULL;
79 g_dwWin32ConvUTF8strlen = 0;
83 /* to allow the usage of the original version in this file here */
87 //#define USE_WIN32_COMPAT_IO 1
88 #define USE_WIN32_32KPATHCONVERSION 1
90 extern DWORD g_platform_id;
91 extern DWORD g_MinorVersion;
93 // from MicroSoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970
95 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL
97 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
100 #define WIN32_FILETIME_SCALE 10000000 // 100ns/second
102 void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize)
104 const char *fname = name;
105 char *tname = win32_name;
107 Dmsg0(100, "Enter convert_unix_to_win32_path\n");
109 if (IsPathSeparator(name[0]) &&
110 IsPathSeparator(name[1]) &&
112 IsPathSeparator(name[3])) {
114 *win32_name++ = '\\';
115 *win32_name++ = '\\';
117 *win32_name++ = '\\';
120 } else if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS &&
121 g_pVSSPathConvert == NULL) {
122 /* allow path to be 32767 bytes */
123 *win32_name++ = '\\';
124 *win32_name++ = '\\';
126 *win32_name++ = '\\';
130 /* Check for Unix separator and convert to Win32 */
131 if (name[0] == '/' && name[1] == '/') { /* double slash? */
132 name++; /* yes, skip first one */
135 *win32_name++ = '\\'; /* convert char */
136 /* If Win32 separator that is "quoted", remove quote */
137 } else if (*name == '\\' && name[1] == '\\') {
138 *win32_name++ = '\\';
139 name++; /* skip first \ */
141 *win32_name++ = *name; /* copy character */
145 /* Strip any trailing slash, if we stored something */
146 /* but leave "c:\" with backslash (root directory case */
147 if (*fname != 0 && win32_name[-1] == '\\' && strlen (fname) != 3) {
153 /* here we convert to VSS specific file name which
154 can get longer because VSS will make something like
155 \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
156 from c:\bacula\uninstall.exe
158 Dmsg1(100, "path=%s\n", tname);
159 if (g_pVSSPathConvert != NULL) {
160 POOLMEM *pszBuf = get_pool_memory (PM_FNAME);
161 pszBuf = check_pool_memory_size(pszBuf, dwSize);
162 bstrncpy(pszBuf, tname, strlen(tname)+1);
163 g_pVSSPathConvert(pszBuf, tname, dwSize);
164 free_pool_memory(pszBuf);
167 Dmsg1(100, "Leave cvt_u_to_win32_path path=%s\n", tname);
170 /* Conversion of a Unix filename to a Win32 filename */
171 void unix_name_to_win32(POOLMEM **win32_name, char *name)
173 /* One extra byte should suffice, but we double it */
174 /* add MAX_PATH bytes for VSS shadow copy name */
175 DWORD dwSize = 2*strlen(name)+MAX_PATH;
176 *win32_name = check_pool_memory_size(*win32_name, dwSize);
177 conv_unix_to_win32_path(name, *win32_name, dwSize);
181 make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/)
183 /* created 02/27/2006 Thorsten Engel
185 * This function expects an UCS-encoded standard wchar_t in pszUCSPath and
186 * will complete the input path to an absolue path of the form \\?\c:\path\file
188 * With this trick, it is possible to have 32K characters long paths.
190 * Optionally one can use pBIsRawPath to determine id pszUCSPath contains a path
191 * to a raw windows partition.
194 Dmsg0(100, "Enter wchar_win32_path\n");
196 *pBIsRawPath = FALSE; /* Initialize, set later */
199 if (!p_GetCurrentDirectoryW) {
200 Dmsg0(100, "Leave wchar_win32_path no change \n");
204 wchar_t *name = (wchar_t *)pszUCSPath;
206 /* if it has already the desired form, exit without changes */
207 if (wcslen(name) > 3 && wcsncmp(name, L"\\\\?\\", 4) == 0) {
208 Dmsg0(100, "Leave wchar_win32_path no change \n");
212 wchar_t *pwszBuf = (wchar_t *)get_pool_memory(PM_FNAME);
213 wchar_t *pwszCurDirBuf = (wchar_t *)get_pool_memory(PM_FNAME);
214 DWORD dwCurDirPathSize = 0;
216 /* get buffer with enough size (name+max 6. wchars+1 null terminator */
217 DWORD dwBufCharsNeeded = (wcslen(name)+7);
218 pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
220 /* add \\?\ to support 32K long filepaths
221 it is important to make absolute paths, so we add drive and
222 current path if necessary */
224 BOOL bAddDrive = TRUE;
225 BOOL bAddCurrentPath = TRUE;
226 BOOL bAddPrefix = TRUE;
228 /* does path begin with drive? if yes, it is absolute */
229 if (iswalpha(name[0]) && name[1] == ':' && IsPathSeparator(name[2])) {
231 bAddCurrentPath = FALSE;
234 /* is path absolute? */
235 if (IsPathSeparator(name[0]))
236 bAddCurrentPath = FALSE;
238 /* is path relative to itself?, if yes, skip ./ */
239 if (name[0] == '.' && IsPathSeparator(name[1])) {
243 /* is path of form '//./'? */
244 if (IsPathSeparator(name[0]) &&
245 IsPathSeparator(name[1]) &&
247 IsPathSeparator(name[3])) {
249 bAddCurrentPath = FALSE;
256 int nParseOffset = 0;
258 /* add 4 bytes header */
261 wcscpy(pwszBuf, L"\\\\?\\");
264 /* get current path if needed */
265 if (bAddDrive || bAddCurrentPath) {
266 dwCurDirPathSize = p_GetCurrentDirectoryW(0, NULL);
267 if (dwCurDirPathSize > 0) {
268 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
269 pwszCurDirBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszCurDirBuf, (dwCurDirPathSize+1)*sizeof(wchar_t));
270 p_GetCurrentDirectoryW(dwCurDirPathSize, pwszCurDirBuf);
272 /* we have no info for doing so */
274 bAddCurrentPath = FALSE;
279 /* add drive if needed */
280 if (bAddDrive && !bAddCurrentPath) {
283 if (IsPathSeparator(pwszCurDirBuf[0]) &&
284 IsPathSeparator(pwszCurDirBuf[1]) &&
285 pwszCurDirBuf[2] == '?' &&
286 IsPathSeparator(pwszCurDirBuf[3])) {
287 /* copy drive character */
288 szDrive[0] = pwszCurDirBuf[4];
290 /* copy drive character */
291 szDrive[0] = pwszCurDirBuf[0];
297 wcscat(pwszBuf, szDrive);
301 /* add path if needed */
302 if (bAddCurrentPath) {
303 /* the 1 add. character is for the eventually added backslash */
304 dwBufCharsNeeded += dwCurDirPathSize+1;
305 pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
306 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
308 if (IsPathSeparator(pwszCurDirBuf[0]) &&
309 IsPathSeparator(pwszCurDirBuf[1]) &&
310 pwszCurDirBuf[2] == '?' &&
311 IsPathSeparator(pwszCurDirBuf[3])) {
312 /* copy complete string */
313 wcscpy(pwszBuf, pwszCurDirBuf);
316 wcscat(pwszBuf, pwszCurDirBuf);
319 nParseOffset = wcslen((LPCWSTR) pwszBuf);
321 /* check if path ends with backslash, if not, add one */
322 if (!IsPathSeparator(pwszBuf[nParseOffset-1])) {
323 wcscat(pwszBuf, L"\\");
328 wchar_t *win32_name = &pwszBuf[nParseOffset];
329 wchar_t *name_start = name;
332 /* Check for Unix separator and convert to Win32, eliminating
333 * duplicate separators.
335 if (IsPathSeparator(*name)) {
336 *win32_name++ = '\\'; /* convert char */
338 /* Eliminate consecutive slashes, but not at the start so that
341 if (name_start != name && IsPathSeparator(name[1])) {
345 *win32_name++ = *name; /* copy character */
350 /* null terminate string */
353 /* here we convert to VSS specific file name which
354 * can get longer because VSS will make something like
355 * \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
356 * from c:\bacula\uninstall.exe
358 if (g_pVSSPathConvertW != NULL) {
359 /* is output buffer large enough? */
360 pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf,
361 (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
362 /* create temp. buffer */
363 wchar_t *pszBuf = (wchar_t *)get_pool_memory(PM_FNAME);
364 pszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pszBuf,
365 (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
370 wcsncpy(pszBuf, &pwszBuf[nParseOffset], wcslen(pwszBuf)+1-nParseOffset);
371 g_pVSSPathConvertW(pszBuf, pwszBuf, dwBufCharsNeeded+MAX_PATH);
372 free_pool_memory((POOLMEM *)pszBuf);
375 free_pool_memory(pszUCSPath);
376 free_pool_memory((POOLMEM *)pwszCurDirBuf);
378 Dmsg1(100, "Leave wchar_win32_path=%s\n", pwszBuf);
379 return (POOLMEM *)pwszBuf;
383 wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
385 /* the return value is the number of bytes written to the buffer.
386 The number includes the byte for the null terminator. */
388 if (p_WideCharToMultiByte) {
389 int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
398 UTF8_2_wchar(POOLMEM **ppszUCS, const char *pszUTF)
400 /* the return value is the number of wide characters written to the buffer. */
401 /* convert null terminated string from utf-8 to ucs2, enlarge buffer if necessary */
403 if (p_MultiByteToWideChar) {
404 /* strlen of UTF8 +1 is enough */
405 DWORD cchSize = (strlen(pszUTF)+1);
406 *ppszUCS = check_pool_memory_size(*ppszUCS, cchSize*sizeof (wchar_t));
408 int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
418 wchar_win32_path(const char *name, wchar_t *win32_name)
420 const char *fname = name;
422 /* Check for Unix separator and convert to Win32 */
424 *win32_name++ = '\\'; /* convert char */
425 /* If Win32 separated that is "quoted", remove quote */
426 } else if (*name == '\\' && name[1] == '\\') {
427 *win32_name++ = '\\';
428 name++; /* skip first \ */
430 *win32_name++ = *name; /* copy character */
434 /* Strip any trailing slash, if we stored something */
435 if (*fname != 0 && win32_name[-1] == '\\') {
443 make_win32_path_UTF8_2_wchar(POOLMEM **pszUCS, const char *pszUTF, BOOL* pBIsRawPath /*= NULL*/)
446 /* if we find the utf8 string in cache, we use the cached ucs2 version.
447 we compare the stringlength first (quick check) and then compare the content.
449 if (g_dwWin32ConvUTF8strlen == strlen(pszUTF)) {
450 if (bstrcmp(pszUTF, g_pWin32ConvUTF8Cache)) {
451 int32_t nBufSize = sizeof_pool_memory(g_pWin32ConvUCS2Cache);
452 *pszUCS = check_pool_memory_size(*pszUCS, nBufSize);
453 wcscpy((LPWSTR) *pszUCS, (LPWSTR) g_pWin32ConvUCS2Cache);
455 return nBufSize / sizeof (WCHAR);
459 /* helper to convert from utf-8 to UCS-2 and to complete a path for 32K path syntax */
460 int nRet = UTF8_2_wchar(pszUCS, pszUTF);
462 #ifdef USE_WIN32_32KPATHCONVERSION
463 /* add \\?\ to support 32K long filepaths */
464 *pszUCS = make_wchar_win32_path(*pszUCS, pBIsRawPath);
467 *pBIsRawPath = FALSE;
471 g_pWin32ConvUCS2Cache = check_pool_memory_size(g_pWin32ConvUCS2Cache, sizeof_pool_memory(*pszUCS));
472 wcscpy((LPWSTR) g_pWin32ConvUCS2Cache, (LPWSTR) *pszUCS);
474 g_dwWin32ConvUTF8strlen = strlen(pszUTF);
475 g_pWin32ConvUTF8Cache = check_pool_memory_size(g_pWin32ConvUTF8Cache, g_dwWin32ConvUTF8strlen+1);
476 bstrncpy(g_pWin32ConvUTF8Cache, pszUTF, g_dwWin32ConvUTF8strlen+1);
482 #if !defined(_MSC_VER) || (_MSC_VER < 1400) // VC8+
489 int fcntl(int fd, int cmd)
494 int chmod(const char *, mode_t)
499 int chown(const char *k, uid_t, gid_t)
504 int lchown(const char *k, uid_t, gid_t)
516 srandom(unsigned int seed)
520 // /////////////////////////////////////////////////////////////////
521 // convert from Windows concept of time to Unix concept of time
522 // /////////////////////////////////////////////////////////////////
524 cvt_utime_to_ftime(const time_t &time, FILETIME &wintime)
526 uint64_t mstime = time;
527 mstime *= WIN32_FILETIME_SCALE;
528 mstime += WIN32_FILETIME_ADJUST;
530 #if defined(_MSC_VER)
531 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
533 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL);
535 wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
539 cvt_ftime_to_utime(const FILETIME &time)
541 uint64_t mstime = time.dwHighDateTime;
543 mstime |= time.dwLowDateTime;
545 mstime -= WIN32_FILETIME_ADJUST;
546 mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
548 return (time_t) (mstime & 0xffffffff);
556 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
557 FORMAT_MESSAGE_FROM_SYSTEM |
558 FORMAT_MESSAGE_IGNORE_INSERTS,
561 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
566 /* Strip any \r or \n */
567 char *rval = (char *) lpMsgBuf;
568 char *cp = strchr(rval, '\r');
572 cp = strchr(rval, '\n');
581 statDir(const char *file, struct stat *sb)
583 WIN32_FIND_DATAW info_w; // window's file info
584 WIN32_FIND_DATAA info_a; // window's file info
586 // cache some common vars to make code more transparent
587 DWORD* pdwFileAttributes;
588 DWORD* pnFileSizeHigh;
589 DWORD* pnFileSizeLow;
590 FILETIME* pftLastAccessTime;
591 FILETIME* pftLastWriteTime;
592 FILETIME* pftCreationTime;
594 if (file[1] == ':' && file[2] == 0) {
595 Dmsg1(99, "faking ROOT attrs(%s).\n", file);
596 sb->st_mode = S_IFDIR;
597 sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
604 HANDLE h = INVALID_HANDLE_VALUE;
606 // use unicode or ascii
607 if (p_FindFirstFileW) {
608 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
609 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
611 h = p_FindFirstFileW((LPCWSTR) pwszBuf, &info_w);
612 free_pool_memory(pwszBuf);
614 pdwFileAttributes = &info_w.dwFileAttributes;
615 pnFileSizeHigh = &info_w.nFileSizeHigh;
616 pnFileSizeLow = &info_w.nFileSizeLow;
617 pftLastAccessTime = &info_w.ftLastAccessTime;
618 pftLastWriteTime = &info_w.ftLastWriteTime;
619 pftCreationTime = &info_w.ftCreationTime;
621 else if (p_FindFirstFileA) {
622 h = p_FindFirstFileA(file, &info_a);
624 pdwFileAttributes = &info_a.dwFileAttributes;
625 pnFileSizeHigh = &info_a.nFileSizeHigh;
626 pnFileSizeLow = &info_a.nFileSizeLow;
627 pftLastAccessTime = &info_a.ftLastAccessTime;
628 pftLastWriteTime = &info_a.ftLastWriteTime;
629 pftCreationTime = &info_a.ftCreationTime;
632 if (h == INVALID_HANDLE_VALUE) {
633 const char *err = errorString();
634 Dmsg2(99, "FindFirstFile(%s):%s\n", file, err);
635 LocalFree((void *)err);
636 errno = b_errno_win32;
640 sb->st_mode = 0777; /* start with everything */
641 if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
642 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
643 if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
644 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
645 if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
646 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
647 sb->st_mode |= S_IFDIR;
649 sb->st_size = *pnFileSizeHigh;
651 sb->st_size |= *pnFileSizeLow;
652 sb->st_blksize = 4096;
653 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
655 sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
656 sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
657 sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
664 fstat(int fd, struct stat *sb)
666 BY_HANDLE_FILE_INFORMATION info;
669 if (!GetFileInformationByHandle((HANDLE)fd, &info)) {
670 const char *err = errorString();
671 Dmsg2(99, "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
672 LocalFree((void *)err);
673 errno = b_errno_win32;
677 sb->st_dev = info.dwVolumeSerialNumber;
678 sb->st_ino = info.nFileIndexHigh;
680 sb->st_ino |= info.nFileIndexLow;
681 sb->st_nlink = (short)info.nNumberOfLinks;
682 if (sb->st_nlink > 1) {
683 Dmsg1(99, "st_nlink=%d\n", sb->st_nlink);
686 sb->st_mode = 0777; /* start with everything */
687 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
688 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
689 if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
690 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
691 if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
692 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
693 sb->st_mode |= S_IFREG;
695 sb->st_size = info.nFileSizeHigh;
697 sb->st_size |= info.nFileSizeLow;
698 sb->st_blksize = 4096;
699 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
700 sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
701 sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
702 sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
708 stat2(const char *file, struct stat *sb)
713 conv_unix_to_win32_path(file, tmpbuf, 1024);
715 DWORD attr = (DWORD)-1;
717 if (p_GetFileAttributesW) {
718 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
719 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
721 attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
722 free_pool_memory(pwszBuf);
723 } else if (p_GetFileAttributesA) {
724 attr = p_GetFileAttributesA(tmpbuf);
727 if (attr == (DWORD)-1) {
728 const char *err = errorString();
729 Dmsg2(99, "GetFileAttributes(%s): %s\n", tmpbuf, err);
730 LocalFree((void *)err);
731 errno = b_errno_win32;
735 if (attr & FILE_ATTRIBUTE_DIRECTORY)
736 return statDir(tmpbuf, sb);
738 h = CreateFileA(tmpbuf, GENERIC_READ,
739 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
741 if (h == INVALID_HANDLE_VALUE) {
742 const char *err = errorString();
743 Dmsg2(99, "Cannot open file for stat (%s):%s\n", tmpbuf, err);
744 LocalFree((void *)err);
745 errno = b_errno_win32;
749 rval = fstat((int)h, sb);
756 stat(const char *file, struct stat *sb)
758 WIN32_FILE_ATTRIBUTE_DATA data;
762 memset(sb, 0, sizeof(*sb));
764 /* why not allow win 95 to use p_GetFileAttributesExA ?
765 * this function allows _some_ open files to be stat'ed
766 * if (g_platform_id == VER_PLATFORM_WIN32_WINDOWS) {
767 * return stat2(file, sb);
771 if (p_GetFileAttributesExW) {
772 /* dynamically allocate enough space for UCS2 filename */
773 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
774 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
776 BOOL b = p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, &data);
777 free_pool_memory(pwszBuf);
780 return stat2(file, sb);
782 } else if (p_GetFileAttributesExA) {
783 if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
784 return stat2(file, sb);
787 return stat2(file, sb);
790 sb->st_mode = 0777; /* start with everything */
791 if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
792 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
794 if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
795 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
797 if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
798 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
800 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
801 sb->st_mode |= S_IFDIR;
803 sb->st_mode |= S_IFREG;
807 sb->st_size = data.nFileSizeHigh;
809 sb->st_size |= data.nFileSizeLow;
810 sb->st_blksize = 4096;
811 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
812 sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
813 sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
814 sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
818 int fcntl(int fd, int cmd, long arg)
841 lstat(const char *file, struct stat *sb)
843 return stat(file, sb);
859 execvp(const char *, char *[]) {
880 waitpid(int, int*, int)
887 readlink(const char *, char *, int)
896 strcasecmp(const char *s1, const char *s2)
898 register int ch1, ch2;
901 return 0; /* strings are equal if same object. */
911 } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
918 strncasecmp(const char *s1, const char *s2, int len)
920 register int ch1 = 0, ch2 = 0;
923 return 0; /* strings are equal if same object. */
934 if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
941 gettimeofday(struct timeval *tv, struct timezone *)
951 if (!SystemTimeToFileTime(&now, &tmp)) {
952 errno = b_errno_win32;
956 int64_t _100nsec = tmp.dwHighDateTime;
958 _100nsec |= tmp.dwLowDateTime;
959 _100nsec -= WIN32_FILETIME_ADJUST;
961 tv->tv_sec =(long) (_100nsec / 10000000);
962 tv->tv_usec = (long) ((_100nsec % 10000000)/10);
967 /* For apcupsd this is in src/lib/wincompat.c */
968 extern "C" void syslog(int type, const char *fmt, ...)
970 /*#ifndef HAVE_CONSOLE
971 MessageBox(NULL, msg, "Bacula", MB_OK);
992 // implement opendir/readdir/closedir on top of window's API
996 WIN32_FIND_DATAA data_a; // window's file info (ansii version)
997 WIN32_FIND_DATAW data_w; // window's file info (wchar version)
998 const char *spec; // the directory we're traversing
999 HANDLE dirh; // the search handle
1000 BOOL valid_a; // the info in data_a field is valid
1001 BOOL valid_w; // the info in data_w field is valid
1002 UINT32 offset; // pseudo offset for d_off
1006 opendir(const char *path)
1008 /* enough space for VSS !*/
1009 int max_len = strlen(path) + MAX_PATH;
1016 Dmsg1(100, "Opendir path=%s\n", path);
1017 rval = (_dir *)malloc(sizeof(_dir));
1018 memset (rval, 0, sizeof (_dir));
1019 if (rval == NULL) return NULL;
1020 char *tspec = (char *)malloc(max_len);
1021 if (tspec == NULL) return NULL;
1023 conv_unix_to_win32_path(path, tspec, max_len);
1024 Dmsg1(100, "win32 path=%s\n", tspec);
1026 // add backslash only if there is none yet (think of c:\)
1027 if (tspec[strlen(tspec)-1] != '\\')
1028 bstrncat(tspec, "\\*", max_len);
1030 bstrncat(tspec, "*", max_len);
1034 // convert to wchar_t
1035 if (p_FindFirstFileW) {
1036 POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
1037 make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec);
1039 rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
1041 free_pool_memory(pwcBuf);
1043 if (rval->dirh != INVALID_HANDLE_VALUE)
1045 } else if (p_FindFirstFileA) {
1046 rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
1048 if (rval->dirh != INVALID_HANDLE_VALUE)
1053 Dmsg3(99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
1054 path, rval->spec, rval->dirh);
1057 if (rval->dirh == INVALID_HANDLE_VALUE)
1060 if (rval->valid_w) {
1061 Dmsg1(99, "\tFirstFile=%s\n", rval->data_w.cFileName);
1064 if (rval->valid_a) {
1065 Dmsg1(99, "\tFirstFile=%s\n", rval->data_a.cFileName);
1071 free((void *)rval->spec);
1073 errno = b_errno_win32;
1080 _dir *dp = (_dir *)dirp;
1081 FindClose(dp->dirh);
1082 free((void *)dp->spec);
1088 typedef struct _WIN32_FIND_DATA {
1089 DWORD dwFileAttributes;
1090 FILETIME ftCreationTime;
1091 FILETIME ftLastAccessTime;
1092 FILETIME ftLastWriteTime;
1093 DWORD nFileSizeHigh;
1097 TCHAR cFileName[MAX_PATH];
1098 TCHAR cAlternateFileName[14];
1099 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1103 copyin(struct dirent &dp, const char *fname)
1107 char *cp = dp.d_name;
1117 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1119 _dir *dp = (_dir *)dirp;
1120 if (dp->valid_w || dp->valid_a) {
1121 entry->d_off = dp->offset;
1125 char szBuf[MAX_PATH_UTF8+1];
1126 wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1127 dp->offset += copyin(*entry, szBuf);
1128 } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1129 dp->offset += copyin(*entry, dp->data_a.cFileName);
1132 *result = entry; /* return entry address */
1133 Dmsg4(99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1134 dirp, entry->d_name, entry->d_reclen, entry->d_off);
1136 // Dmsg0(99, "readdir_r !valid\n");
1137 errno = b_errno_win32;
1141 // get next file, try unicode first
1142 if (p_FindNextFileW)
1143 dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1144 else if (p_FindNextFileA)
1145 dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1147 dp->valid_a = FALSE;
1148 dp->valid_w = FALSE;
1155 * Dotted IP address to network address
1161 inet_aton(const char *a, struct in_addr *inp)
1164 uint32_t acc = 0, tmp = 0;
1167 if (!isdigit(*cp)) { /* first char must be digit */
1168 return 0; /* error */
1172 tmp = (tmp * 10) + (*cp -'0');
1173 } else if (*cp == '.' || *cp == 0) {
1175 return 0; /* error */
1177 acc = (acc << 8) + tmp;
1181 return 0; /* error */
1183 } while (*cp++ != 0);
1184 if (dotc != 4) { /* want 3 .'s plus EOS */
1185 return 0; /* error */
1187 inp->s_addr = htonl(acc); /* store addr in network format */
1192 nanosleep(const struct timespec *req, struct timespec *rem)
1195 rem->tv_sec = rem->tv_nsec = 0;
1196 Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1201 init_signals(void terminate(int sig))
1207 init_stack_dump(void)
1214 pathconf(const char *path, int name)
1218 if (strncmp(path, "\\\\?\\", 4) == 0)
1230 WORD wVersionRequested = MAKEWORD( 1, 1);
1233 int err = WSAStartup(wVersionRequested, &wsaData);
1237 printf("Can not start Windows Sockets\n");
1247 win32_chdir(const char *dir)
1249 if (p_SetCurrentDirectoryW) {
1250 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1251 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1253 BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1255 free_pool_memory(pwszBuf);
1258 errno = b_errno_win32;
1262 else if (p_SetCurrentDirectoryA) {
1263 if (0 == p_SetCurrentDirectoryA(dir)) {
1264 errno = b_errno_win32;
1274 win32_mkdir(const char *dir)
1277 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1278 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1280 int n = p_wmkdir((LPCWSTR)pwszBuf);
1281 free_pool_memory(pwszBuf);
1290 win32_getcwd(char *buf, int maxlen)
1294 if (p_GetCurrentDirectoryW) {
1295 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1296 pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1298 n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1300 n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1301 free_pool_memory(pwszBuf);
1303 } else if (p_GetCurrentDirectoryA)
1304 n = p_GetCurrentDirectoryA(maxlen, buf);
1306 if (n == 0 || n > maxlen) return NULL;
1308 if (n+1 > maxlen) return NULL;
1317 win32_fputs(const char *string, FILE *stream)
1319 /* we use WriteConsoleA / WriteConsoleA
1320 so we can be sure that unicode support works on win32.
1321 with fallback if something fails
1324 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1325 if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1326 p_MultiByteToWideChar && (stream == stdout)) {
1328 POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1330 DWORD dwCharsWritten;
1333 dwChars = UTF8_2_wchar(&pwszBuf, string);
1335 /* try WriteConsoleW */
1336 if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1337 free_pool_memory(pwszBuf);
1338 return dwCharsWritten;
1341 /* convert to local codepage and try WriteConsoleA */
1342 POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1343 pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1345 dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR) pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1346 free_pool_memory(pwszBuf);
1348 if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1349 free_pool_memory(pszBuf);
1350 return dwCharsWritten;
1354 return fputs(string, stream);
1358 win32_cgets (char* buffer, int len)
1360 /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1361 from the win32 console and fallback if seomething fails */
1363 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1364 if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1366 wchar_t wszBuf[1024];
1369 /* nt and unicode conversion */
1370 if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1372 /* null terminate at end */
1373 if (wszBuf[dwRead-1] == L'\n') {
1374 wszBuf[dwRead-1] = L'\0';
1378 if (wszBuf[dwRead-1] == L'\r') {
1379 wszBuf[dwRead-1] = L'\0';
1383 wchar_2_UTF8(buffer, wszBuf, len);
1387 /* win 9x and unicode conversion */
1388 if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1390 /* null terminate at end */
1391 if (szBuf[dwRead-1] == L'\n') {
1392 szBuf[dwRead-1] = L'\0';
1396 if (szBuf[dwRead-1] == L'\r') {
1397 szBuf[dwRead-1] = L'\0';
1401 /* convert from ansii to wchar_t */
1402 p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1403 /* convert from wchar_t to UTF-8 */
1404 if (wchar_2_UTF8(buffer, wszBuf, len))
1410 if (fgets(buffer, len, stdin))
1417 win32_unlink(const char *filename)
1421 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1422 make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1424 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1426 /* special case if file is readonly,
1427 we retry but unset attribute before */
1428 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1429 DWORD dwAttr = p_GetFileAttributesW((LPCWSTR)pwszBuf);
1430 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1431 if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1432 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1433 /* reset to original if it didn't help */
1435 p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1439 free_pool_memory(pwszBuf);
1441 nRetCode = _unlink(filename);
1443 /* special case if file is readonly,
1444 we retry but unset attribute before */
1445 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1446 DWORD dwAttr = p_GetFileAttributesA(filename);
1447 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1448 if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1449 nRetCode = _unlink(filename);
1450 /* reset to original if it didn't help */
1452 p_SetFileAttributesA(filename, dwAttr);
1461 #include "mswinver.h"
1463 char WIN_VERSION_LONG[64];
1464 char WIN_VERSION[32];
1465 char WIN_RAWVERSION[32];
1472 static winver INIT; // cause constructor to be called before main()
1475 winver::winver(void)
1477 const char *version = "";
1478 const char *platform = "";
1479 OSVERSIONINFO osvinfo;
1480 osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1482 // Get the current OS version
1483 if (!GetVersionEx(&osvinfo)) {
1484 version = "Unknown";
1485 platform = "Unknown";
1487 const int ver = _mkversion(osvinfo.dwPlatformId,
1488 osvinfo.dwMajorVersion,
1489 osvinfo.dwMinorVersion);
1490 snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1493 case MS_WINDOWS_95: (version = "Windows 95"); break;
1494 case MS_WINDOWS_98: (version = "Windows 98"); break;
1495 case MS_WINDOWS_ME: (version = "Windows ME"); break;
1496 case MS_WINDOWS_NT4:(version = "Windows NT 4.0"); platform = "NT"; break;
1497 case MS_WINDOWS_2K: (version = "Windows 2000");platform = "NT"; break;
1498 case MS_WINDOWS_XP: (version = "Windows XP");platform = "NT"; break;
1499 case MS_WINDOWS_S2003: (version = "Windows Server 2003");platform = "NT"; break;
1500 default: version = WIN_RAWVERSION; break;
1503 bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1504 snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1505 platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1508 HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1512 BPIPE *b = open_bpipe("ls -l", 10, "r");
1514 while (!feof(b->rfd)) {
1515 fgets(buf, sizeof(buf), b->rfd);
1521 BOOL CreateChildProcess(VOID);
1522 VOID WriteToPipe(VOID);
1523 VOID ReadFromPipe(VOID);
1524 VOID ErrorExit(LPCSTR);
1525 VOID ErrMsg(LPTSTR, BOOL);
1528 * Check for a quoted path, if an absolute path name is given and it contains
1529 * spaces it will need to be quoted. i.e. "c:/Program Files/foo/bar.exe"
1530 * CreateProcess() says the best way to ensure proper results with executables
1531 * with spaces in path or filename is to quote the string.
1534 getArgv0(const char *cmdline)
1539 for (cp = cmdline; *cp; cp++)
1544 if (!inquote && isspace(*cp))
1549 int len = cp - cmdline;
1550 char *rval = (char *)malloc(len+1);
1563 * Extracts the executable or script name from the first string in
1566 * If the name contains blanks then it must be quoted with double quotes,
1567 * otherwise quotes are optional. If the name contains blanks then it
1568 * will be converted to a short name.
1570 * The optional quotes will be removed. The result is copied to a malloc'ed
1571 * buffer and returned through the pexe argument. The pargs parameter is set
1572 * to the address of the character in cmdline located after the name.
1574 * The malloc'ed buffer returned in *pexe must be freed by the caller.
1577 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1579 const char *pExeStart = NULL; /* Start of executable name in cmdline */
1580 const char *pExeEnd = NULL; /* Character after executable name (separator) */
1582 const char *pBasename = NULL; /* Character after last path separator */
1583 const char *pExtension = NULL; /* Period at start of extension */
1585 const char *current = cmdline;
1587 bool bQuoted = false;
1589 /* Skip initial whitespace */
1591 while (*current == ' ' || *current == '\t')
1596 /* Calculate start of name and determine if quoted */
1598 if (*current == '"') {
1599 pExeStart = ++current;
1602 pExeStart = current;
1610 * Scan command line looking for path separators (/ and \\) and the
1611 * terminator, either a quote or a blank. The location of the
1612 * extension is also noted.
1615 for ( ; *current != '\0'; current++)
1617 if (*current == '.') {
1618 pExtension = current;
1619 } else if (IsPathSeparator(*current) && current[1] != '\0') {
1620 pBasename = ¤t[1];
1624 /* Check for terminator, either quote or blank */
1626 if (*current != '"') {
1630 if (*current != ' ') {
1636 * Hit terminator, remember end of name (address of terminator) and
1637 * start of arguments
1641 if (bQuoted && *current == '"') {
1642 *pargs = ¤t[1];
1650 if (pBasename == NULL) {
1651 pBasename = pExeStart;
1654 if (pExeEnd == NULL) {
1663 bool bHasPathSeparators = pExeStart != pBasename;
1665 /* We have pointers to all the useful parts of the name */
1667 /* Default extensions in the order cmd.exe uses to search */
1669 static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
1670 DWORD dwBasePathLength = pExeEnd - pExeStart;
1672 DWORD dwAltNameLength = 0;
1673 char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1674 char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1676 pPathname[MAX_PATHLENGTH] = '\0';
1677 pAltPathname[MAX_PATHLENGTH] = '\0';
1679 memcpy(pPathname, pExeStart, dwBasePathLength);
1680 pPathname[dwBasePathLength] = '\0';
1682 if (pExtension == NULL) {
1683 /* Try appending extensions */
1684 for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
1686 if (!bHasPathSeparators) {
1687 /* There are no path separators, search in the standard locations */
1688 dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
1689 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1690 memcpy(pPathname, pAltPathname, dwAltNameLength);
1691 pPathname[dwAltNameLength] = '\0';
1695 bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
1696 if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) {
1699 pPathname[dwBasePathLength] = '\0';
1702 } else if (!bHasPathSeparators) {
1703 /* There are no path separators, search in the standard locations */
1704 dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
1705 if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) {
1706 memcpy(pPathname, pAltPathname, dwAltNameLength);
1707 pPathname[dwAltNameLength] = '\0';
1711 if (strchr(pPathname, ' ') != NULL) {
1712 dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH);
1714 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1715 *pexe = (char *)malloc(dwAltNameLength + 1);
1716 if (*pexe == NULL) {
1719 memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
1723 if (*pexe == NULL) {
1724 DWORD dwPathnameLength = strlen(pPathname);
1725 *pexe = (char *)malloc(dwPathnameLength + 1);
1726 if (*pexe == NULL) {
1729 memcpy(*pexe, pPathname, dwPathnameLength + 1);
1736 * OK, so it would seem CreateProcess only handles true executables:
1737 * .com or .exe files. So grab $COMSPEC value and pass command line to it.
1740 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1742 static const char *comspec = NULL;
1743 PROCESS_INFORMATION piProcInfo;
1744 STARTUPINFOA siStartInfo;
1745 BOOL bFuncRetn = FALSE;
1747 if (comspec == NULL) {
1748 comspec = getenv("COMSPEC");
1750 if (comspec == NULL) // should never happen
1751 return INVALID_HANDLE_VALUE;
1753 // Set up members of the PROCESS_INFORMATION structure.
1754 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1756 // Set up members of the STARTUPINFO structure.
1758 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1759 siStartInfo.cb = sizeof(STARTUPINFO);
1760 // setup new process to use supplied handles for stdin,stdout,stderr
1761 // if supplied handles are not used the send a copy of our STD_HANDLE
1763 siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1764 siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
1766 if (in != INVALID_HANDLE_VALUE)
1767 siStartInfo.hStdInput = in;
1769 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1771 if (out != INVALID_HANDLE_VALUE)
1772 siStartInfo.hStdOutput = out;
1774 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1775 if (err != INVALID_HANDLE_VALUE)
1776 siStartInfo.hStdError = err;
1778 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1780 // Create the child process.
1783 const char *argStart;
1785 if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
1786 return INVALID_HANDLE_VALUE;
1789 int cmdLen = strlen(comspec) + 4 + strlen(exeFile) + strlen(argStart) + 1;
1791 char *cmdLine = (char *)alloca(cmdLen);
1793 snprintf(cmdLine, cmdLen, "%s /c %s%s", comspec, exeFile, argStart);
1797 Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
1799 // try to execute program
1800 bFuncRetn = CreateProcessA(comspec,
1801 cmdLine, // command line
1802 NULL, // process security attributes
1803 NULL, // primary thread security attributes
1804 TRUE, // handles are inherited
1805 0, // creation flags
1806 NULL, // use parent's environment
1807 NULL, // use parent's current directory
1808 &siStartInfo, // STARTUPINFO pointer
1809 &piProcInfo); // receives PROCESS_INFORMATION
1811 if (bFuncRetn == 0) {
1812 ErrorExit("CreateProcess failed\n");
1813 const char *err = errorString();
1814 Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n", comspec, cmdLine, err);
1815 LocalFree((void *)err);
1816 return INVALID_HANDLE_VALUE;
1818 // we don't need a handle on the process primary thread so we close
1820 CloseHandle(piProcInfo.hThread);
1822 return piProcInfo.hProcess;
1827 ErrorExit (LPCSTR lpszMessage)
1829 Dmsg1(0, "%s", lpszMessage);
1834 typedef struct s_bpipe {
1836 time_t worker_stime;
1845 CloseIfValid(HANDLE handle)
1847 if (handle != INVALID_HANDLE_VALUE)
1848 CloseHandle(handle);
1852 open_bpipe(char *prog, int wait, const char *mode)
1854 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1855 hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1858 SECURITY_ATTRIBUTES saAttr;
1862 hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1863 hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1864 hInputFile = INVALID_HANDLE_VALUE;
1866 BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1867 memset((void *)bpipe, 0, sizeof(BPIPE));
1869 int mode_read = (mode[0] == 'r');
1870 int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1873 // Set the bInheritHandle flag so pipe handles are inherited.
1875 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1876 saAttr.bInheritHandle = TRUE;
1877 saAttr.lpSecurityDescriptor = NULL;
1881 // Create a pipe for the child process's STDOUT.
1882 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1883 ErrorExit("Stdout pipe creation failed\n");
1886 // Create noninheritable read handle and close the inheritable read
1889 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1890 GetCurrentProcess(), &hChildStdoutRdDup , 0,
1892 DUPLICATE_SAME_ACCESS);
1894 ErrorExit("DuplicateHandle failed");
1898 CloseHandle(hChildStdoutRd);
1899 hChildStdoutRd = INVALID_HANDLE_VALUE;
1904 // Create a pipe for the child process's STDIN.
1906 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1907 ErrorExit("Stdin pipe creation failed\n");
1911 // Duplicate the write handle to the pipe so it is not inherited.
1912 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
1913 GetCurrentProcess(), &hChildStdinWrDup,
1915 FALSE, // not inherited
1916 DUPLICATE_SAME_ACCESS);
1918 ErrorExit("DuplicateHandle failed");
1922 CloseHandle(hChildStdinWr);
1923 hChildStdinWr = INVALID_HANDLE_VALUE;
1925 // spawn program with redirected handles as appropriate
1926 bpipe->worker_pid = (pid_t)
1927 CreateChildProcess(prog, // commandline
1928 hChildStdinRd, // stdin HANDLE
1929 hChildStdoutWr, // stdout HANDLE
1930 hChildStdoutWr); // stderr HANDLE
1932 if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1936 bpipe->worker_stime = time(NULL);
1939 CloseHandle(hChildStdoutWr); // close our write side so when
1940 // process terminates we can
1942 // ugly but convert WIN32 HANDLE to FILE*
1943 int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY | O_BINARY);
1945 bpipe->rfd = _fdopen(rfd, "rb");
1949 CloseHandle(hChildStdinRd); // close our read side so as not
1950 // to interfre with child's copy
1951 // ugly but convert WIN32 HANDLE to FILE*
1952 int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY | O_BINARY);
1954 bpipe->wfd = _fdopen(wfd, "wb");
1959 bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
1966 CloseIfValid(hChildStdoutRd);
1967 CloseIfValid(hChildStdoutRdDup);
1968 CloseIfValid(hChildStdinWr);
1969 CloseIfValid(hChildStdinWrDup);
1971 free((void *) bpipe);
1972 errno = b_errno_win32; /* do GetLastError() for error code */
1978 kill(int pid, int signal)
1981 if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
1983 errno = b_errno_win32;
1985 CloseHandle((HANDLE)pid);
1991 close_bpipe(BPIPE *bpipe)
1994 int32_t remaining_wait = bpipe->wait;
2006 if (remaining_wait == 0) { /* wait indefinitely */
2007 remaining_wait = INT32_MAX;
2011 if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
2012 const char *err = errorString();
2013 rval = b_errno_win32;
2014 Dmsg1(0, "GetExitCode error %s\n", err);
2015 LocalFree((void *)err);
2018 if (exitCode == STILL_ACTIVE) {
2019 if (remaining_wait <= 0) {
2020 rval = ETIME; /* timed out */
2023 bmicrosleep(1, 0); /* wait one second */
2025 } else if (exitCode != 0) {
2026 /* Truncate exit code as it doesn't seem to be correct */
2027 rval = (exitCode & 0xFF) | b_errno_exit;
2030 break; /* Shouldn't get here */
2034 if (bpipe->timer_id) {
2035 stop_child_timer(bpipe->timer_id);
2037 if (bpipe->rfd) fclose(bpipe->rfd);
2038 if (bpipe->wfd) fclose(bpipe->wfd);
2039 free((void *)bpipe);
2044 close_wpipe(BPIPE *bpipe)
2050 if (fclose(bpipe->wfd) != 0) {
2058 #include "findlib/find.h"
2061 utime(const char *fname, struct utimbuf *times)
2066 conv_unix_to_win32_path(fname, tmpbuf, 5000);
2068 cvt_utime_to_ftime(times->actime, acc);
2069 cvt_utime_to_ftime(times->modtime, mod);
2071 HANDLE h = INVALID_HANDLE_VALUE;
2073 if (p_CreateFileW) {
2074 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2075 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
2077 h = p_CreateFileW((LPCWSTR)pwszBuf,
2078 FILE_WRITE_ATTRIBUTES,
2079 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2082 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2085 free_pool_memory(pwszBuf);
2086 } else if (p_CreateFileA) {
2087 h = p_CreateFileA(tmpbuf,
2088 FILE_WRITE_ATTRIBUTES,
2089 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2092 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2096 if (h == INVALID_HANDLE_VALUE) {
2097 const char *err = errorString();
2098 Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2099 LocalFree((void *)err);
2100 errno = b_errno_win32;
2104 int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2107 errno = b_errno_win32;
2114 file_open(const char *file, int flags, int mode)
2117 DWORD shareMode = 0;
2120 HANDLE foo = INVALID_HANDLE_VALUE;
2121 const char *remap = file;
2123 if (flags & O_WRONLY) access = GENERIC_WRITE;
2124 else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2125 else access = GENERIC_READ;
2127 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2128 create = CREATE_NEW;
2129 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2130 create = CREATE_ALWAYS;
2131 else if (flags & O_CREAT)
2132 create = OPEN_ALWAYS;
2133 else if (flags & O_TRUNC)
2134 create = TRUNCATE_EXISTING;
2136 create = OPEN_EXISTING;
2140 if (flags & O_APPEND) {
2141 printf("open...APPEND not implemented yet.");
2145 if (p_CreateFileW) {
2146 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2147 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
2149 foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
2150 free_pool_memory(pwszBuf);
2151 } else if (p_CreateFileA)
2152 foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
2154 if (INVALID_HANDLE_VALUE == foo) {
2155 errno = b_errno_win32;
2166 if (!CloseHandle((HANDLE)fd)) {
2167 errno = b_errno_win32;
2175 file_write(int fd, const void *data, ssize_t len)
2179 status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2180 if (status) return bwrite;
2181 errno = b_errno_win32;
2187 file_read(int fd, void *data, ssize_t len)
2192 status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2193 if (status) return bread;
2194 errno = b_errno_win32;
2199 file_seek(int fd, boffset_t offset, int whence)
2203 LONG offset_low = (LONG)offset;
2204 LONG offset_high = (LONG)(offset >> 32);
2208 method = FILE_BEGIN;
2211 method = FILE_CURRENT;
2222 if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
2223 errno = b_errno_win32;
2226 /* ***FIXME*** I doubt this works right */
2239 /* syslog function, added by Nicolas Boichat */
2240 void openlog(const char *ident, int option, int facility) {}