2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2007 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 two of the GNU General Public
10 License as published by the Free Software Foundation plus additions
11 that are listed in the file LICENSE.
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 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 John Walker.
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
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 win32_ftruncate(int fd, int64_t length)
820 /* Set point we want to truncate file */
821 __int64 pos = _lseeki64(fd, (__int64)length, SEEK_SET);
823 if (pos != (__int64)length) {
824 errno = EACCES; /* truncation failed, get out */
829 if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0) {
830 errno = b_errno_win32;
837 int fcntl(int fd, int cmd, long arg)
860 lstat(const char *file, struct stat *sb)
862 return stat(file, sb);
878 execvp(const char *, char *[]) {
899 waitpid(int, int*, int)
906 readlink(const char *, char *, int)
915 strcasecmp(const char *s1, const char *s2)
917 register int ch1, ch2;
920 return 0; /* strings are equal if same object. */
930 } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
937 strncasecmp(const char *s1, const char *s2, int len)
939 register int ch1 = 0, ch2 = 0;
942 return 0; /* strings are equal if same object. */
953 if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
960 gettimeofday(struct timeval *tv, struct timezone *)
970 if (!SystemTimeToFileTime(&now, &tmp)) {
971 errno = b_errno_win32;
975 int64_t _100nsec = tmp.dwHighDateTime;
977 _100nsec |= tmp.dwLowDateTime;
978 _100nsec -= WIN32_FILETIME_ADJUST;
980 tv->tv_sec =(long) (_100nsec / 10000000);
981 tv->tv_usec = (long) ((_100nsec % 10000000)/10);
986 /* For apcupsd this is in src/lib/wincompat.c */
987 extern "C" void syslog(int type, const char *fmt, ...)
989 /*#ifndef HAVE_CONSOLE
990 MessageBox(NULL, msg, "Bacula", MB_OK);
1011 // implement opendir/readdir/closedir on top of window's API
1015 WIN32_FIND_DATAA data_a; // window's file info (ansii version)
1016 WIN32_FIND_DATAW data_w; // window's file info (wchar version)
1017 const char *spec; // the directory we're traversing
1018 HANDLE dirh; // the search handle
1019 BOOL valid_a; // the info in data_a field is valid
1020 BOOL valid_w; // the info in data_w field is valid
1021 UINT32 offset; // pseudo offset for d_off
1025 opendir(const char *path)
1027 /* enough space for VSS !*/
1028 int max_len = strlen(path) + MAX_PATH;
1035 Dmsg1(100, "Opendir path=%s\n", path);
1036 rval = (_dir *)malloc(sizeof(_dir));
1037 memset (rval, 0, sizeof (_dir));
1038 if (rval == NULL) return NULL;
1039 char *tspec = (char *)malloc(max_len);
1040 if (tspec == NULL) return NULL;
1042 conv_unix_to_win32_path(path, tspec, max_len);
1043 Dmsg1(100, "win32 path=%s\n", tspec);
1045 // add backslash only if there is none yet (think of c:\)
1046 if (tspec[strlen(tspec)-1] != '\\')
1047 bstrncat(tspec, "\\*", max_len);
1049 bstrncat(tspec, "*", max_len);
1053 // convert to wchar_t
1054 if (p_FindFirstFileW) {
1055 POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
1056 make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec);
1058 rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
1060 free_pool_memory(pwcBuf);
1062 if (rval->dirh != INVALID_HANDLE_VALUE)
1064 } else if (p_FindFirstFileA) {
1065 rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
1067 if (rval->dirh != INVALID_HANDLE_VALUE)
1072 Dmsg3(99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
1073 path, rval->spec, rval->dirh);
1076 if (rval->dirh == INVALID_HANDLE_VALUE)
1079 if (rval->valid_w) {
1080 Dmsg1(99, "\tFirstFile=%s\n", rval->data_w.cFileName);
1083 if (rval->valid_a) {
1084 Dmsg1(99, "\tFirstFile=%s\n", rval->data_a.cFileName);
1090 free((void *)rval->spec);
1092 errno = b_errno_win32;
1099 _dir *dp = (_dir *)dirp;
1100 FindClose(dp->dirh);
1101 free((void *)dp->spec);
1107 typedef struct _WIN32_FIND_DATA {
1108 DWORD dwFileAttributes;
1109 FILETIME ftCreationTime;
1110 FILETIME ftLastAccessTime;
1111 FILETIME ftLastWriteTime;
1112 DWORD nFileSizeHigh;
1116 TCHAR cFileName[MAX_PATH];
1117 TCHAR cAlternateFileName[14];
1118 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1122 copyin(struct dirent &dp, const char *fname)
1126 char *cp = dp.d_name;
1136 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1138 _dir *dp = (_dir *)dirp;
1139 if (dp->valid_w || dp->valid_a) {
1140 entry->d_off = dp->offset;
1144 char szBuf[MAX_PATH_UTF8+1];
1145 wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1146 dp->offset += copyin(*entry, szBuf);
1147 } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1148 dp->offset += copyin(*entry, dp->data_a.cFileName);
1151 *result = entry; /* return entry address */
1152 Dmsg4(99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1153 dirp, entry->d_name, entry->d_reclen, entry->d_off);
1155 // Dmsg0(99, "readdir_r !valid\n");
1156 errno = b_errno_win32;
1160 // get next file, try unicode first
1161 if (p_FindNextFileW)
1162 dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1163 else if (p_FindNextFileA)
1164 dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1166 dp->valid_a = FALSE;
1167 dp->valid_w = FALSE;
1174 * Dotted IP address to network address
1180 inet_aton(const char *a, struct in_addr *inp)
1183 uint32_t acc = 0, tmp = 0;
1186 if (!isdigit(*cp)) { /* first char must be digit */
1187 return 0; /* error */
1191 tmp = (tmp * 10) + (*cp -'0');
1192 } else if (*cp == '.' || *cp == 0) {
1194 return 0; /* error */
1196 acc = (acc << 8) + tmp;
1200 return 0; /* error */
1202 } while (*cp++ != 0);
1203 if (dotc != 4) { /* want 3 .'s plus EOS */
1204 return 0; /* error */
1206 inp->s_addr = htonl(acc); /* store addr in network format */
1211 nanosleep(const struct timespec *req, struct timespec *rem)
1214 rem->tv_sec = rem->tv_nsec = 0;
1215 Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1220 init_signals(void terminate(int sig))
1226 init_stack_dump(void)
1233 pathconf(const char *path, int name)
1237 if (strncmp(path, "\\\\?\\", 4) == 0)
1249 WORD wVersionRequested = MAKEWORD( 1, 1);
1252 int err = WSAStartup(wVersionRequested, &wsaData);
1256 printf("Can not start Windows Sockets\n");
1266 win32_chdir(const char *dir)
1268 if (p_SetCurrentDirectoryW) {
1269 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1270 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1272 BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1274 free_pool_memory(pwszBuf);
1277 errno = b_errno_win32;
1281 else if (p_SetCurrentDirectoryA) {
1282 if (0 == p_SetCurrentDirectoryA(dir)) {
1283 errno = b_errno_win32;
1293 win32_mkdir(const char *dir)
1296 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1297 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1299 int n = p_wmkdir((LPCWSTR)pwszBuf);
1300 free_pool_memory(pwszBuf);
1309 win32_getcwd(char *buf, int maxlen)
1313 if (p_GetCurrentDirectoryW) {
1314 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1315 pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1317 n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1319 n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1320 free_pool_memory(pwszBuf);
1322 } else if (p_GetCurrentDirectoryA)
1323 n = p_GetCurrentDirectoryA(maxlen, buf);
1325 if (n == 0 || n > maxlen) return NULL;
1327 if (n+1 > maxlen) return NULL;
1336 win32_fputs(const char *string, FILE *stream)
1338 /* we use WriteConsoleA / WriteConsoleA
1339 so we can be sure that unicode support works on win32.
1340 with fallback if something fails
1343 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1344 if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1345 p_MultiByteToWideChar && (stream == stdout)) {
1347 POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1349 DWORD dwCharsWritten;
1352 dwChars = UTF8_2_wchar(&pwszBuf, string);
1354 /* try WriteConsoleW */
1355 if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1356 free_pool_memory(pwszBuf);
1357 return dwCharsWritten;
1360 /* convert to local codepage and try WriteConsoleA */
1361 POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1362 pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1364 dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR) pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1365 free_pool_memory(pwszBuf);
1367 if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1368 free_pool_memory(pszBuf);
1369 return dwCharsWritten;
1373 return fputs(string, stream);
1377 win32_cgets (char* buffer, int len)
1379 /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1380 from the win32 console and fallback if seomething fails */
1382 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1383 if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1385 wchar_t wszBuf[1024];
1388 /* nt and unicode conversion */
1389 if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1391 /* null terminate at end */
1392 if (wszBuf[dwRead-1] == L'\n') {
1393 wszBuf[dwRead-1] = L'\0';
1397 if (wszBuf[dwRead-1] == L'\r') {
1398 wszBuf[dwRead-1] = L'\0';
1402 wchar_2_UTF8(buffer, wszBuf, len);
1406 /* win 9x and unicode conversion */
1407 if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1409 /* null terminate at end */
1410 if (szBuf[dwRead-1] == L'\n') {
1411 szBuf[dwRead-1] = L'\0';
1415 if (szBuf[dwRead-1] == L'\r') {
1416 szBuf[dwRead-1] = L'\0';
1420 /* convert from ansii to wchar_t */
1421 p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1422 /* convert from wchar_t to UTF-8 */
1423 if (wchar_2_UTF8(buffer, wszBuf, len))
1429 if (fgets(buffer, len, stdin))
1436 win32_unlink(const char *filename)
1440 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1441 make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1443 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1445 /* special case if file is readonly,
1446 we retry but unset attribute before */
1447 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1448 DWORD dwAttr = p_GetFileAttributesW((LPCWSTR)pwszBuf);
1449 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1450 if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1451 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1452 /* reset to original if it didn't help */
1454 p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1458 free_pool_memory(pwszBuf);
1460 nRetCode = _unlink(filename);
1462 /* special case if file is readonly,
1463 we retry but unset attribute before */
1464 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1465 DWORD dwAttr = p_GetFileAttributesA(filename);
1466 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1467 if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1468 nRetCode = _unlink(filename);
1469 /* reset to original if it didn't help */
1471 p_SetFileAttributesA(filename, dwAttr);
1480 #include "mswinver.h"
1482 char WIN_VERSION_LONG[64];
1483 char WIN_VERSION[32];
1484 char WIN_RAWVERSION[32];
1491 static winver INIT; // cause constructor to be called before main()
1494 winver::winver(void)
1496 const char *version = "";
1497 const char *platform = "";
1498 OSVERSIONINFO osvinfo;
1499 osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1501 // Get the current OS version
1502 if (!GetVersionEx(&osvinfo)) {
1503 version = "Unknown";
1504 platform = "Unknown";
1506 const int ver = _mkversion(osvinfo.dwPlatformId,
1507 osvinfo.dwMajorVersion,
1508 osvinfo.dwMinorVersion);
1509 snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1512 case MS_WINDOWS_95: (version = "Windows 95"); break;
1513 case MS_WINDOWS_98: (version = "Windows 98"); break;
1514 case MS_WINDOWS_ME: (version = "Windows ME"); break;
1515 case MS_WINDOWS_NT4:(version = "Windows NT 4.0"); platform = "NT"; break;
1516 case MS_WINDOWS_2K: (version = "Windows 2000");platform = "NT"; break;
1517 case MS_WINDOWS_XP: (version = "Windows XP");platform = "NT"; break;
1518 case MS_WINDOWS_S2003: (version = "Windows Server 2003");platform = "NT"; break;
1519 default: version = WIN_RAWVERSION; break;
1522 bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1523 snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1524 platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1527 HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1531 BPIPE *b = open_bpipe("ls -l", 10, "r");
1533 while (!feof(b->rfd)) {
1534 fgets(buf, sizeof(buf), b->rfd);
1540 BOOL CreateChildProcess(VOID);
1541 VOID WriteToPipe(VOID);
1542 VOID ReadFromPipe(VOID);
1543 VOID ErrorExit(LPCSTR);
1544 VOID ErrMsg(LPTSTR, BOOL);
1547 * Check for a quoted path, if an absolute path name is given and it contains
1548 * spaces it will need to be quoted. i.e. "c:/Program Files/foo/bar.exe"
1549 * CreateProcess() says the best way to ensure proper results with executables
1550 * with spaces in path or filename is to quote the string.
1553 getArgv0(const char *cmdline)
1558 for (cp = cmdline; *cp; cp++)
1563 if (!inquote && isspace(*cp))
1568 int len = cp - cmdline;
1569 char *rval = (char *)malloc(len+1);
1582 * Extracts the executable or script name from the first string in
1585 * If the name contains blanks then it must be quoted with double quotes,
1586 * otherwise quotes are optional. If the name contains blanks then it
1587 * will be converted to a short name.
1589 * The optional quotes will be removed. The result is copied to a malloc'ed
1590 * buffer and returned through the pexe argument. The pargs parameter is set
1591 * to the address of the character in cmdline located after the name.
1593 * The malloc'ed buffer returned in *pexe must be freed by the caller.
1596 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1598 const char *pExeStart = NULL; /* Start of executable name in cmdline */
1599 const char *pExeEnd = NULL; /* Character after executable name (separator) */
1601 const char *pBasename = NULL; /* Character after last path separator */
1602 const char *pExtension = NULL; /* Period at start of extension */
1604 const char *current = cmdline;
1606 bool bQuoted = false;
1608 /* Skip initial whitespace */
1610 while (*current == ' ' || *current == '\t')
1615 /* Calculate start of name and determine if quoted */
1617 if (*current == '"') {
1618 pExeStart = ++current;
1621 pExeStart = current;
1629 * Scan command line looking for path separators (/ and \\) and the
1630 * terminator, either a quote or a blank. The location of the
1631 * extension is also noted.
1634 for ( ; *current != '\0'; current++)
1636 if (*current == '.') {
1637 pExtension = current;
1638 } else if (IsPathSeparator(*current) && current[1] != '\0') {
1639 pBasename = ¤t[1];
1643 /* Check for terminator, either quote or blank */
1645 if (*current != '"') {
1649 if (*current != ' ') {
1655 * Hit terminator, remember end of name (address of terminator) and
1656 * start of arguments
1660 if (bQuoted && *current == '"') {
1661 *pargs = ¤t[1];
1669 if (pBasename == NULL) {
1670 pBasename = pExeStart;
1673 if (pExeEnd == NULL) {
1682 bool bHasPathSeparators = pExeStart != pBasename;
1684 /* We have pointers to all the useful parts of the name */
1686 /* Default extensions in the order cmd.exe uses to search */
1688 static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
1689 DWORD dwBasePathLength = pExeEnd - pExeStart;
1691 DWORD dwAltNameLength = 0;
1692 char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1693 char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1695 pPathname[MAX_PATHLENGTH] = '\0';
1696 pAltPathname[MAX_PATHLENGTH] = '\0';
1698 memcpy(pPathname, pExeStart, dwBasePathLength);
1699 pPathname[dwBasePathLength] = '\0';
1701 if (pExtension == NULL) {
1702 /* Try appending extensions */
1703 for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
1705 if (!bHasPathSeparators) {
1706 /* There are no path separators, search in the standard locations */
1707 dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
1708 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1709 memcpy(pPathname, pAltPathname, dwAltNameLength);
1710 pPathname[dwAltNameLength] = '\0';
1714 bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
1715 if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) {
1718 pPathname[dwBasePathLength] = '\0';
1721 } else if (!bHasPathSeparators) {
1722 /* There are no path separators, search in the standard locations */
1723 dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
1724 if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) {
1725 memcpy(pPathname, pAltPathname, dwAltNameLength);
1726 pPathname[dwAltNameLength] = '\0';
1730 if (strchr(pPathname, ' ') != NULL) {
1731 dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH);
1733 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1734 *pexe = (char *)malloc(dwAltNameLength + 1);
1735 if (*pexe == NULL) {
1738 memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
1742 if (*pexe == NULL) {
1743 DWORD dwPathnameLength = strlen(pPathname);
1744 *pexe = (char *)malloc(dwPathnameLength + 1);
1745 if (*pexe == NULL) {
1748 memcpy(*pexe, pPathname, dwPathnameLength + 1);
1755 * OK, so it would seem CreateProcess only handles true executables:
1756 * .com or .exe files. So grab $COMSPEC value and pass command line to it.
1759 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1761 static const char *comspec = NULL;
1762 PROCESS_INFORMATION piProcInfo;
1763 STARTUPINFOA siStartInfo;
1764 BOOL bFuncRetn = FALSE;
1766 if (comspec == NULL) {
1767 comspec = getenv("COMSPEC");
1769 if (comspec == NULL) // should never happen
1770 return INVALID_HANDLE_VALUE;
1772 // Set up members of the PROCESS_INFORMATION structure.
1773 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1775 // Set up members of the STARTUPINFO structure.
1777 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1778 siStartInfo.cb = sizeof(STARTUPINFO);
1779 // setup new process to use supplied handles for stdin,stdout,stderr
1780 // if supplied handles are not used the send a copy of our STD_HANDLE
1782 siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1783 siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
1785 if (in != INVALID_HANDLE_VALUE)
1786 siStartInfo.hStdInput = in;
1788 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1790 if (out != INVALID_HANDLE_VALUE)
1791 siStartInfo.hStdOutput = out;
1793 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1794 if (err != INVALID_HANDLE_VALUE)
1795 siStartInfo.hStdError = err;
1797 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1799 // Create the child process.
1802 const char *argStart;
1804 if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
1805 return INVALID_HANDLE_VALUE;
1808 int cmdLen = strlen(comspec) + 4 + strlen(exeFile) + strlen(argStart) + 1;
1810 char *cmdLine = (char *)alloca(cmdLen);
1812 snprintf(cmdLine, cmdLen, "%s /c %s%s", comspec, exeFile, argStart);
1816 Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
1818 // try to execute program
1819 bFuncRetn = CreateProcessA(comspec,
1820 cmdLine, // command line
1821 NULL, // process security attributes
1822 NULL, // primary thread security attributes
1823 TRUE, // handles are inherited
1824 0, // creation flags
1825 NULL, // use parent's environment
1826 NULL, // use parent's current directory
1827 &siStartInfo, // STARTUPINFO pointer
1828 &piProcInfo); // receives PROCESS_INFORMATION
1830 if (bFuncRetn == 0) {
1831 ErrorExit("CreateProcess failed\n");
1832 const char *err = errorString();
1833 Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n", comspec, cmdLine, err);
1834 LocalFree((void *)err);
1835 return INVALID_HANDLE_VALUE;
1837 // we don't need a handle on the process primary thread so we close
1839 CloseHandle(piProcInfo.hThread);
1841 return piProcInfo.hProcess;
1846 ErrorExit (LPCSTR lpszMessage)
1848 Dmsg1(0, "%s", lpszMessage);
1853 typedef struct s_bpipe {
1855 time_t worker_stime;
1864 CloseIfValid(HANDLE handle)
1866 if (handle != INVALID_HANDLE_VALUE)
1867 CloseHandle(handle);
1871 open_bpipe(char *prog, int wait, const char *mode)
1873 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1874 hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1877 SECURITY_ATTRIBUTES saAttr;
1881 hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1882 hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1883 hInputFile = INVALID_HANDLE_VALUE;
1885 BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1886 memset((void *)bpipe, 0, sizeof(BPIPE));
1888 int mode_read = (mode[0] == 'r');
1889 int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1892 // Set the bInheritHandle flag so pipe handles are inherited.
1894 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1895 saAttr.bInheritHandle = TRUE;
1896 saAttr.lpSecurityDescriptor = NULL;
1900 // Create a pipe for the child process's STDOUT.
1901 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1902 ErrorExit("Stdout pipe creation failed\n");
1905 // Create noninheritable read handle and close the inheritable read
1908 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1909 GetCurrentProcess(), &hChildStdoutRdDup , 0,
1911 DUPLICATE_SAME_ACCESS);
1913 ErrorExit("DuplicateHandle failed");
1917 CloseHandle(hChildStdoutRd);
1918 hChildStdoutRd = INVALID_HANDLE_VALUE;
1923 // Create a pipe for the child process's STDIN.
1925 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1926 ErrorExit("Stdin pipe creation failed\n");
1930 // Duplicate the write handle to the pipe so it is not inherited.
1931 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
1932 GetCurrentProcess(), &hChildStdinWrDup,
1934 FALSE, // not inherited
1935 DUPLICATE_SAME_ACCESS);
1937 ErrorExit("DuplicateHandle failed");
1941 CloseHandle(hChildStdinWr);
1942 hChildStdinWr = INVALID_HANDLE_VALUE;
1944 // spawn program with redirected handles as appropriate
1945 bpipe->worker_pid = (pid_t)
1946 CreateChildProcess(prog, // commandline
1947 hChildStdinRd, // stdin HANDLE
1948 hChildStdoutWr, // stdout HANDLE
1949 hChildStdoutWr); // stderr HANDLE
1951 if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1955 bpipe->worker_stime = time(NULL);
1958 CloseHandle(hChildStdoutWr); // close our write side so when
1959 // process terminates we can
1961 // ugly but convert WIN32 HANDLE to FILE*
1962 int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY | O_BINARY);
1964 bpipe->rfd = _fdopen(rfd, "rb");
1968 CloseHandle(hChildStdinRd); // close our read side so as not
1969 // to interfre with child's copy
1970 // ugly but convert WIN32 HANDLE to FILE*
1971 int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY | O_BINARY);
1973 bpipe->wfd = _fdopen(wfd, "wb");
1978 bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
1985 CloseIfValid(hChildStdoutRd);
1986 CloseIfValid(hChildStdoutRdDup);
1987 CloseIfValid(hChildStdinWr);
1988 CloseIfValid(hChildStdinWrDup);
1990 free((void *) bpipe);
1991 errno = b_errno_win32; /* do GetLastError() for error code */
1997 kill(int pid, int signal)
2000 if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
2002 errno = b_errno_win32;
2004 CloseHandle((HANDLE)pid);
2010 close_bpipe(BPIPE *bpipe)
2013 int32_t remaining_wait = bpipe->wait;
2025 if (remaining_wait == 0) { /* wait indefinitely */
2026 remaining_wait = INT32_MAX;
2030 if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
2031 const char *err = errorString();
2032 rval = b_errno_win32;
2033 Dmsg1(0, "GetExitCode error %s\n", err);
2034 LocalFree((void *)err);
2037 if (exitCode == STILL_ACTIVE) {
2038 if (remaining_wait <= 0) {
2039 rval = ETIME; /* timed out */
2042 bmicrosleep(1, 0); /* wait one second */
2044 } else if (exitCode != 0) {
2045 /* Truncate exit code as it doesn't seem to be correct */
2046 rval = (exitCode & 0xFF) | b_errno_exit;
2049 break; /* Shouldn't get here */
2053 if (bpipe->timer_id) {
2054 stop_child_timer(bpipe->timer_id);
2056 if (bpipe->rfd) fclose(bpipe->rfd);
2057 if (bpipe->wfd) fclose(bpipe->wfd);
2058 free((void *)bpipe);
2063 close_wpipe(BPIPE *bpipe)
2069 if (fclose(bpipe->wfd) != 0) {
2077 #include "findlib/find.h"
2080 utime(const char *fname, struct utimbuf *times)
2085 conv_unix_to_win32_path(fname, tmpbuf, 5000);
2087 cvt_utime_to_ftime(times->actime, acc);
2088 cvt_utime_to_ftime(times->modtime, mod);
2090 HANDLE h = INVALID_HANDLE_VALUE;
2092 if (p_CreateFileW) {
2093 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2094 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
2096 h = p_CreateFileW((LPCWSTR)pwszBuf,
2097 FILE_WRITE_ATTRIBUTES,
2098 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2101 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2104 free_pool_memory(pwszBuf);
2105 } else if (p_CreateFileA) {
2106 h = p_CreateFileA(tmpbuf,
2107 FILE_WRITE_ATTRIBUTES,
2108 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2111 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2115 if (h == INVALID_HANDLE_VALUE) {
2116 const char *err = errorString();
2117 Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2118 LocalFree((void *)err);
2119 errno = b_errno_win32;
2123 int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2126 errno = b_errno_win32;
2133 file_open(const char *file, int flags, int mode)
2136 DWORD shareMode = 0;
2139 HANDLE foo = INVALID_HANDLE_VALUE;
2140 const char *remap = file;
2142 if (flags & O_WRONLY) access = GENERIC_WRITE;
2143 else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2144 else access = GENERIC_READ;
2146 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2147 create = CREATE_NEW;
2148 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2149 create = CREATE_ALWAYS;
2150 else if (flags & O_CREAT)
2151 create = OPEN_ALWAYS;
2152 else if (flags & O_TRUNC)
2153 create = TRUNCATE_EXISTING;
2155 create = OPEN_EXISTING;
2159 if (flags & O_APPEND) {
2160 printf("open...APPEND not implemented yet.");
2164 if (p_CreateFileW) {
2165 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2166 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
2168 foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
2169 free_pool_memory(pwszBuf);
2170 } else if (p_CreateFileA)
2171 foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
2173 if (INVALID_HANDLE_VALUE == foo) {
2174 errno = b_errno_win32;
2185 if (!CloseHandle((HANDLE)fd)) {
2186 errno = b_errno_win32;
2194 file_write(int fd, const void *data, ssize_t len)
2198 status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2199 if (status) return bwrite;
2200 errno = b_errno_win32;
2206 file_read(int fd, void *data, ssize_t len)
2211 status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2212 if (status) return bread;
2213 errno = b_errno_win32;
2218 file_seek(int fd, boffset_t offset, int whence)
2222 LONG offset_low = (LONG)offset;
2223 LONG offset_high = (LONG)(offset >> 32);
2227 method = FILE_BEGIN;
2230 method = FILE_CURRENT;
2241 if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
2242 errno = b_errno_win32;
2245 /* ***FIXME*** I doubt this works right */
2258 /* syslog function, added by Nicolas Boichat */
2259 void openlog(const char *ident, int option, int facility) {}