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;
1371 free_pool_memory(pszBuf);
1374 return fputs(string, stream);
1378 win32_cgets (char* buffer, int len)
1380 /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1381 from the win32 console and fallback if seomething fails */
1383 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1384 if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1386 wchar_t wszBuf[1024];
1389 /* nt and unicode conversion */
1390 if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1392 /* null terminate at end */
1393 if (wszBuf[dwRead-1] == L'\n') {
1394 wszBuf[dwRead-1] = L'\0';
1398 if (wszBuf[dwRead-1] == L'\r') {
1399 wszBuf[dwRead-1] = L'\0';
1403 wchar_2_UTF8(buffer, wszBuf, len);
1407 /* win 9x and unicode conversion */
1408 if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1410 /* null terminate at end */
1411 if (szBuf[dwRead-1] == L'\n') {
1412 szBuf[dwRead-1] = L'\0';
1416 if (szBuf[dwRead-1] == L'\r') {
1417 szBuf[dwRead-1] = L'\0';
1421 /* convert from ansii to wchar_t */
1422 p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1423 /* convert from wchar_t to UTF-8 */
1424 if (wchar_2_UTF8(buffer, wszBuf, len))
1430 if (fgets(buffer, len, stdin))
1437 win32_unlink(const char *filename)
1441 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1442 make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1444 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1446 /* special case if file is readonly,
1447 we retry but unset attribute before */
1448 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1449 DWORD dwAttr = p_GetFileAttributesW((LPCWSTR)pwszBuf);
1450 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1451 if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1452 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1453 /* reset to original if it didn't help */
1455 p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1459 free_pool_memory(pwszBuf);
1461 nRetCode = _unlink(filename);
1463 /* special case if file is readonly,
1464 we retry but unset attribute before */
1465 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1466 DWORD dwAttr = p_GetFileAttributesA(filename);
1467 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1468 if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1469 nRetCode = _unlink(filename);
1470 /* reset to original if it didn't help */
1472 p_SetFileAttributesA(filename, dwAttr);
1481 #include "mswinver.h"
1483 char WIN_VERSION_LONG[64];
1484 char WIN_VERSION[32];
1485 char WIN_RAWVERSION[32];
1492 static winver INIT; // cause constructor to be called before main()
1495 winver::winver(void)
1497 const char *version = "";
1498 const char *platform = "";
1499 OSVERSIONINFO osvinfo;
1500 osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1502 // Get the current OS version
1503 if (!GetVersionEx(&osvinfo)) {
1504 version = "Unknown";
1505 platform = "Unknown";
1507 const int ver = _mkversion(osvinfo.dwPlatformId,
1508 osvinfo.dwMajorVersion,
1509 osvinfo.dwMinorVersion);
1510 snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1513 case MS_WINDOWS_95: (version = "Windows 95"); break;
1514 case MS_WINDOWS_98: (version = "Windows 98"); break;
1515 case MS_WINDOWS_ME: (version = "Windows ME"); break;
1516 case MS_WINDOWS_NT4:(version = "Windows NT 4.0"); platform = "NT"; break;
1517 case MS_WINDOWS_2K: (version = "Windows 2000");platform = "NT"; break;
1518 case MS_WINDOWS_XP: (version = "Windows XP");platform = "NT"; break;
1519 case MS_WINDOWS_S2003: (version = "Windows Server 2003");platform = "NT"; break;
1520 default: version = WIN_RAWVERSION; break;
1523 bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1524 snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1525 platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1528 HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1532 BPIPE *b = open_bpipe("ls -l", 10, "r");
1534 while (!feof(b->rfd)) {
1535 fgets(buf, sizeof(buf), b->rfd);
1541 BOOL CreateChildProcess(VOID);
1542 VOID WriteToPipe(VOID);
1543 VOID ReadFromPipe(VOID);
1544 VOID ErrorExit(LPCSTR);
1545 VOID ErrMsg(LPTSTR, BOOL);
1548 * Check for a quoted path, if an absolute path name is given and it contains
1549 * spaces it will need to be quoted. i.e. "c:/Program Files/foo/bar.exe"
1550 * CreateProcess() says the best way to ensure proper results with executables
1551 * with spaces in path or filename is to quote the string.
1554 getArgv0(const char *cmdline)
1559 for (cp = cmdline; *cp; cp++)
1564 if (!inquote && isspace(*cp))
1569 int len = cp - cmdline;
1570 char *rval = (char *)malloc(len+1);
1583 * Extracts the executable or script name from the first string in
1586 * If the name contains blanks then it must be quoted with double quotes,
1587 * otherwise quotes are optional. If the name contains blanks then it
1588 * will be converted to a short name.
1590 * The optional quotes will be removed. The result is copied to a malloc'ed
1591 * buffer and returned through the pexe argument. The pargs parameter is set
1592 * to the address of the character in cmdline located after the name.
1594 * The malloc'ed buffer returned in *pexe must be freed by the caller.
1597 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1599 const char *pExeStart = NULL; /* Start of executable name in cmdline */
1600 const char *pExeEnd = NULL; /* Character after executable name (separator) */
1602 const char *pBasename = NULL; /* Character after last path separator */
1603 const char *pExtension = NULL; /* Period at start of extension */
1605 const char *current = cmdline;
1607 bool bQuoted = false;
1609 /* Skip initial whitespace */
1611 while (*current == ' ' || *current == '\t')
1616 /* Calculate start of name and determine if quoted */
1618 if (*current == '"') {
1619 pExeStart = ++current;
1622 pExeStart = current;
1630 * Scan command line looking for path separators (/ and \\) and the
1631 * terminator, either a quote or a blank. The location of the
1632 * extension is also noted.
1635 for ( ; *current != '\0'; current++)
1637 if (*current == '.') {
1638 pExtension = current;
1639 } else if (IsPathSeparator(*current) && current[1] != '\0') {
1640 pBasename = ¤t[1];
1644 /* Check for terminator, either quote or blank */
1646 if (*current != '"') {
1650 if (*current != ' ') {
1656 * Hit terminator, remember end of name (address of terminator) and
1657 * start of arguments
1661 if (bQuoted && *current == '"') {
1662 *pargs = ¤t[1];
1670 if (pBasename == NULL) {
1671 pBasename = pExeStart;
1674 if (pExeEnd == NULL) {
1683 bool bHasPathSeparators = pExeStart != pBasename;
1685 /* We have pointers to all the useful parts of the name */
1687 /* Default extensions in the order cmd.exe uses to search */
1689 static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
1690 DWORD dwBasePathLength = pExeEnd - pExeStart;
1692 DWORD dwAltNameLength = 0;
1693 char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1694 char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1696 pPathname[MAX_PATHLENGTH] = '\0';
1697 pAltPathname[MAX_PATHLENGTH] = '\0';
1699 memcpy(pPathname, pExeStart, dwBasePathLength);
1700 pPathname[dwBasePathLength] = '\0';
1702 if (pExtension == NULL) {
1703 /* Try appending extensions */
1704 for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
1706 if (!bHasPathSeparators) {
1707 /* There are no path separators, search in the standard locations */
1708 dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
1709 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1710 memcpy(pPathname, pAltPathname, dwAltNameLength);
1711 pPathname[dwAltNameLength] = '\0';
1715 bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
1716 if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) {
1719 pPathname[dwBasePathLength] = '\0';
1722 } else if (!bHasPathSeparators) {
1723 /* There are no path separators, search in the standard locations */
1724 dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
1725 if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) {
1726 memcpy(pPathname, pAltPathname, dwAltNameLength);
1727 pPathname[dwAltNameLength] = '\0';
1731 if (strchr(pPathname, ' ') != NULL) {
1732 dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH);
1734 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1735 *pexe = (char *)malloc(dwAltNameLength + 1);
1736 if (*pexe == NULL) {
1739 memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
1743 if (*pexe == NULL) {
1744 DWORD dwPathnameLength = strlen(pPathname);
1745 *pexe = (char *)malloc(dwPathnameLength + 1);
1746 if (*pexe == NULL) {
1749 memcpy(*pexe, pPathname, dwPathnameLength + 1);
1756 * OK, so it would seem CreateProcess only handles true executables:
1757 * .com or .exe files. So grab $COMSPEC value and pass command line to it.
1760 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1762 static const char *comspec = NULL;
1763 PROCESS_INFORMATION piProcInfo;
1764 STARTUPINFOA siStartInfo;
1765 BOOL bFuncRetn = FALSE;
1767 if (comspec == NULL) {
1768 comspec = getenv("COMSPEC");
1770 if (comspec == NULL) // should never happen
1771 return INVALID_HANDLE_VALUE;
1773 // Set up members of the PROCESS_INFORMATION structure.
1774 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1776 // Set up members of the STARTUPINFO structure.
1778 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1779 siStartInfo.cb = sizeof(STARTUPINFO);
1780 // setup new process to use supplied handles for stdin,stdout,stderr
1781 // if supplied handles are not used the send a copy of our STD_HANDLE
1783 siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1784 siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
1786 if (in != INVALID_HANDLE_VALUE)
1787 siStartInfo.hStdInput = in;
1789 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1791 if (out != INVALID_HANDLE_VALUE)
1792 siStartInfo.hStdOutput = out;
1794 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1795 if (err != INVALID_HANDLE_VALUE)
1796 siStartInfo.hStdError = err;
1798 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1800 // Create the child process.
1803 const char *argStart;
1805 if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
1806 return INVALID_HANDLE_VALUE;
1809 int cmdLen = strlen(comspec) + 4 + strlen(exeFile) + strlen(argStart) + 1;
1811 char *cmdLine = (char *)alloca(cmdLen);
1813 snprintf(cmdLine, cmdLen, "%s /c %s%s", comspec, exeFile, argStart);
1817 Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
1819 // try to execute program
1820 bFuncRetn = CreateProcessA(comspec,
1821 cmdLine, // command line
1822 NULL, // process security attributes
1823 NULL, // primary thread security attributes
1824 TRUE, // handles are inherited
1825 0, // creation flags
1826 NULL, // use parent's environment
1827 NULL, // use parent's current directory
1828 &siStartInfo, // STARTUPINFO pointer
1829 &piProcInfo); // receives PROCESS_INFORMATION
1831 if (bFuncRetn == 0) {
1832 ErrorExit("CreateProcess failed\n");
1833 const char *err = errorString();
1834 Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n", comspec, cmdLine, err);
1835 LocalFree((void *)err);
1836 return INVALID_HANDLE_VALUE;
1838 // we don't need a handle on the process primary thread so we close
1840 CloseHandle(piProcInfo.hThread);
1842 return piProcInfo.hProcess;
1847 ErrorExit (LPCSTR lpszMessage)
1849 Dmsg1(0, "%s", lpszMessage);
1854 typedef struct s_bpipe {
1856 time_t worker_stime;
1865 CloseIfValid(HANDLE handle)
1867 if (handle != INVALID_HANDLE_VALUE)
1868 CloseHandle(handle);
1872 open_bpipe(char *prog, int wait, const char *mode)
1874 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1875 hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1878 SECURITY_ATTRIBUTES saAttr;
1882 hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1883 hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1884 hInputFile = INVALID_HANDLE_VALUE;
1886 BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1887 memset((void *)bpipe, 0, sizeof(BPIPE));
1889 int mode_read = (mode[0] == 'r');
1890 int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1893 // Set the bInheritHandle flag so pipe handles are inherited.
1895 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1896 saAttr.bInheritHandle = TRUE;
1897 saAttr.lpSecurityDescriptor = NULL;
1901 // Create a pipe for the child process's STDOUT.
1902 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1903 ErrorExit("Stdout pipe creation failed\n");
1906 // Create noninheritable read handle and close the inheritable read
1909 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1910 GetCurrentProcess(), &hChildStdoutRdDup , 0,
1912 DUPLICATE_SAME_ACCESS);
1914 ErrorExit("DuplicateHandle failed");
1918 CloseHandle(hChildStdoutRd);
1919 hChildStdoutRd = INVALID_HANDLE_VALUE;
1924 // Create a pipe for the child process's STDIN.
1926 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1927 ErrorExit("Stdin pipe creation failed\n");
1931 // Duplicate the write handle to the pipe so it is not inherited.
1932 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
1933 GetCurrentProcess(), &hChildStdinWrDup,
1935 FALSE, // not inherited
1936 DUPLICATE_SAME_ACCESS);
1938 ErrorExit("DuplicateHandle failed");
1942 CloseHandle(hChildStdinWr);
1943 hChildStdinWr = INVALID_HANDLE_VALUE;
1945 // spawn program with redirected handles as appropriate
1946 bpipe->worker_pid = (pid_t)
1947 CreateChildProcess(prog, // commandline
1948 hChildStdinRd, // stdin HANDLE
1949 hChildStdoutWr, // stdout HANDLE
1950 hChildStdoutWr); // stderr HANDLE
1952 if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1956 bpipe->worker_stime = time(NULL);
1959 CloseHandle(hChildStdoutWr); // close our write side so when
1960 // process terminates we can
1962 // ugly but convert WIN32 HANDLE to FILE*
1963 int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY | O_BINARY);
1965 bpipe->rfd = _fdopen(rfd, "rb");
1969 CloseHandle(hChildStdinRd); // close our read side so as not
1970 // to interfre with child's copy
1971 // ugly but convert WIN32 HANDLE to FILE*
1972 int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY | O_BINARY);
1974 bpipe->wfd = _fdopen(wfd, "wb");
1979 bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
1986 CloseIfValid(hChildStdoutRd);
1987 CloseIfValid(hChildStdoutRdDup);
1988 CloseIfValid(hChildStdinWr);
1989 CloseIfValid(hChildStdinWrDup);
1991 free((void *) bpipe);
1992 errno = b_errno_win32; /* do GetLastError() for error code */
1998 kill(int pid, int signal)
2001 if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
2003 errno = b_errno_win32;
2005 CloseHandle((HANDLE)pid);
2011 close_bpipe(BPIPE *bpipe)
2014 int32_t remaining_wait = bpipe->wait;
2026 if (remaining_wait == 0) { /* wait indefinitely */
2027 remaining_wait = INT32_MAX;
2031 if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
2032 const char *err = errorString();
2033 rval = b_errno_win32;
2034 Dmsg1(0, "GetExitCode error %s\n", err);
2035 LocalFree((void *)err);
2038 if (exitCode == STILL_ACTIVE) {
2039 if (remaining_wait <= 0) {
2040 rval = ETIME; /* timed out */
2043 bmicrosleep(1, 0); /* wait one second */
2045 } else if (exitCode != 0) {
2046 /* Truncate exit code as it doesn't seem to be correct */
2047 rval = (exitCode & 0xFF) | b_errno_exit;
2050 break; /* Shouldn't get here */
2054 if (bpipe->timer_id) {
2055 stop_child_timer(bpipe->timer_id);
2057 if (bpipe->rfd) fclose(bpipe->rfd);
2058 if (bpipe->wfd) fclose(bpipe->wfd);
2059 free((void *)bpipe);
2064 close_wpipe(BPIPE *bpipe)
2070 if (fclose(bpipe->wfd) != 0) {
2078 #include "findlib/find.h"
2081 utime(const char *fname, struct utimbuf *times)
2086 conv_unix_to_win32_path(fname, tmpbuf, 5000);
2088 cvt_utime_to_ftime(times->actime, acc);
2089 cvt_utime_to_ftime(times->modtime, mod);
2091 HANDLE h = INVALID_HANDLE_VALUE;
2093 if (p_CreateFileW) {
2094 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2095 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
2097 h = p_CreateFileW((LPCWSTR)pwszBuf,
2098 FILE_WRITE_ATTRIBUTES,
2099 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2102 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2105 free_pool_memory(pwszBuf);
2106 } else if (p_CreateFileA) {
2107 h = p_CreateFileA(tmpbuf,
2108 FILE_WRITE_ATTRIBUTES,
2109 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2112 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2116 if (h == INVALID_HANDLE_VALUE) {
2117 const char *err = errorString();
2118 Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2119 LocalFree((void *)err);
2120 errno = b_errno_win32;
2124 int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2127 errno = b_errno_win32;
2134 file_open(const char *file, int flags, int mode)
2137 DWORD shareMode = 0;
2140 HANDLE foo = INVALID_HANDLE_VALUE;
2141 const char *remap = file;
2143 if (flags & O_WRONLY) access = GENERIC_WRITE;
2144 else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2145 else access = GENERIC_READ;
2147 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2148 create = CREATE_NEW;
2149 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2150 create = CREATE_ALWAYS;
2151 else if (flags & O_CREAT)
2152 create = OPEN_ALWAYS;
2153 else if (flags & O_TRUNC)
2154 create = TRUNCATE_EXISTING;
2156 create = OPEN_EXISTING;
2160 if (flags & O_APPEND) {
2161 printf("open...APPEND not implemented yet.");
2165 if (p_CreateFileW) {
2166 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2167 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
2169 foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
2170 free_pool_memory(pwszBuf);
2171 } else if (p_CreateFileA)
2172 foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
2174 if (INVALID_HANDLE_VALUE == foo) {
2175 errno = b_errno_win32;
2186 if (!CloseHandle((HANDLE)fd)) {
2187 errno = b_errno_win32;
2195 file_write(int fd, const void *data, ssize_t len)
2199 status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2200 if (status) return bwrite;
2201 errno = b_errno_win32;
2207 file_read(int fd, void *data, ssize_t len)
2212 status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2213 if (status) return bread;
2214 errno = b_errno_win32;
2219 file_seek(int fd, boffset_t offset, int whence)
2223 LONG offset_low = (LONG)offset;
2224 LONG offset_high = (LONG)(offset >> 32);
2228 method = FILE_BEGIN;
2231 method = FILE_CURRENT;
2242 if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
2243 errno = b_errno_win32;
2246 /* ***FIXME*** I doubt this works right */
2259 /* syslog function, added by Nicolas Boichat */
2260 void openlog(const char *ident, int option, int facility) {}