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 and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU 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;
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;
622 } else if (p_FindFirstFileA) {
623 h = p_FindFirstFileA(file, &info_a);
625 pdwFileAttributes = &info_a.dwFileAttributes;
626 pnFileSizeHigh = &info_a.nFileSizeHigh;
627 pnFileSizeLow = &info_a.nFileSizeLow;
628 pftLastAccessTime = &info_a.ftLastAccessTime;
629 pftLastWriteTime = &info_a.ftLastWriteTime;
630 pftCreationTime = &info_a.ftCreationTime;
633 if (h == INVALID_HANDLE_VALUE) {
634 const char *err = errorString();
635 Dmsg2(99, "FindFirstFile(%s):%s\n", file, err);
636 LocalFree((void *)err);
637 errno = b_errno_win32;
641 sb->st_mode = 0777; /* start with everything */
642 if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
643 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
644 if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
645 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
646 if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
647 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
648 sb->st_mode |= S_IFDIR;
650 /* Use st_rdev to store reparse attribute */
651 sb->st_rdev = (*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0;
654 sb->st_size = *pnFileSizeHigh;
656 sb->st_size |= *pnFileSizeLow;
657 sb->st_blksize = 4096;
658 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
660 sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
661 sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
662 sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
669 fstat(int fd, struct stat *sb)
671 BY_HANDLE_FILE_INFORMATION info;
674 if (!GetFileInformationByHandle((HANDLE)fd, &info)) {
675 const char *err = errorString();
676 Dmsg2(99, "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
677 LocalFree((void *)err);
678 errno = b_errno_win32;
682 sb->st_dev = info.dwVolumeSerialNumber;
683 sb->st_ino = info.nFileIndexHigh;
685 sb->st_ino |= info.nFileIndexLow;
686 sb->st_nlink = (short)info.nNumberOfLinks;
687 if (sb->st_nlink > 1) {
688 Dmsg1(99, "st_nlink=%d\n", sb->st_nlink);
691 sb->st_mode = 0777; /* start with everything */
692 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
693 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
694 if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
695 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
696 if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
697 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
698 sb->st_mode |= S_IFREG;
700 /* Use st_rdev to store reparse attribute */
701 sb->st_rdev = (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0;
703 sb->st_size = info.nFileSizeHigh;
705 sb->st_size |= info.nFileSizeLow;
706 sb->st_blksize = 4096;
707 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
708 sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
709 sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
710 sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
716 stat2(const char *file, struct stat *sb)
721 conv_unix_to_win32_path(file, tmpbuf, 1024);
723 DWORD attr = (DWORD)-1;
725 if (p_GetFileAttributesW) {
726 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
727 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
729 attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
730 free_pool_memory(pwszBuf);
731 } else if (p_GetFileAttributesA) {
732 attr = p_GetFileAttributesA(tmpbuf);
735 if (attr == (DWORD)-1) {
736 const char *err = errorString();
737 Dmsg2(99, "GetFileAttributes(%s): %s\n", tmpbuf, err);
738 LocalFree((void *)err);
739 errno = b_errno_win32;
743 if (attr & FILE_ATTRIBUTE_DIRECTORY) {
744 return statDir(tmpbuf, sb);
747 h = CreateFileA(tmpbuf, GENERIC_READ,
748 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
750 if (h == INVALID_HANDLE_VALUE) {
751 const char *err = errorString();
752 Dmsg2(99, "Cannot open file for stat (%s):%s\n", tmpbuf, err);
753 LocalFree((void *)err);
754 errno = b_errno_win32;
758 rval = fstat((int)h, sb);
765 stat(const char *file, struct stat *sb)
767 WIN32_FILE_ATTRIBUTE_DATA data;
771 memset(sb, 0, sizeof(*sb));
773 /* why not allow win 95 to use p_GetFileAttributesExA ?
774 * this function allows _some_ open files to be stat'ed
775 * if (g_platform_id == VER_PLATFORM_WIN32_WINDOWS) {
776 * return stat2(file, sb);
780 if (p_GetFileAttributesExW) {
781 /* dynamically allocate enough space for UCS2 filename */
782 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
783 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
785 BOOL b = p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, &data);
786 free_pool_memory(pwszBuf);
789 return stat2(file, sb);
791 } else if (p_GetFileAttributesExA) {
792 if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
793 return stat2(file, sb);
796 return stat2(file, sb);
799 sb->st_mode = 0777; /* start with everything */
800 if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
801 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
803 if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
804 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
806 if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
807 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
809 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
810 sb->st_mode |= S_IFDIR;
812 sb->st_mode |= S_IFREG;
815 /* Use st_rdev to store reparse attribute */
816 sb->st_rdev = (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0;
819 sb->st_size = data.nFileSizeHigh;
821 sb->st_size |= data.nFileSizeLow;
822 sb->st_blksize = 4096;
823 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
824 sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
825 sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
826 sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
831 * We write our own ftruncate because the one in the
832 * Microsoft library mrcrt.dll does not truncate
833 * files greater than 2GB.
836 int win32_ftruncate(int fd, int64_t length)
838 /* Set point we want to truncate file */
839 __int64 pos = _lseeki64(fd, (__int64)length, SEEK_SET);
841 if (pos != (__int64)length) {
842 errno = EACCES; /* truncation failed, get out */
847 if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0) {
848 errno = b_errno_win32;
855 int fcntl(int fd, int cmd, long arg)
878 lstat(const char *file, struct stat *sb)
880 return stat(file, sb);
896 execvp(const char *, char *[]) {
917 waitpid(int, int*, int)
924 readlink(const char *, char *, int)
933 strcasecmp(const char *s1, const char *s2)
935 register int ch1, ch2;
938 return 0; /* strings are equal if same object. */
948 } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
955 strncasecmp(const char *s1, const char *s2, int len)
957 register int ch1 = 0, ch2 = 0;
960 return 0; /* strings are equal if same object. */
971 if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
978 gettimeofday(struct timeval *tv, struct timezone *)
989 if (!SystemTimeToFileTime(&now, &tmp)) {
990 errno = b_errno_win32;
994 int64_t _100nsec = tmp.dwHighDateTime;
996 _100nsec |= tmp.dwLowDateTime;
997 _100nsec -= WIN32_FILETIME_ADJUST;
999 tv->tv_sec = (long)(_100nsec / 10000000);
1000 tv->tv_usec = (long)((_100nsec % 10000000)/10);
1005 /* For apcupsd this is in src/lib/wincompat.c */
1006 extern "C" void syslog(int type, const char *fmt, ...)
1008 /*#ifndef HAVE_CONSOLE
1009 MessageBox(NULL, msg, "Bacula", MB_OK);
1030 // implement opendir/readdir/closedir on top of window's API
1034 WIN32_FIND_DATAA data_a; // window's file info (ansii version)
1035 WIN32_FIND_DATAW data_w; // window's file info (wchar version)
1036 const char *spec; // the directory we're traversing
1037 HANDLE dirh; // the search handle
1038 BOOL valid_a; // the info in data_a field is valid
1039 BOOL valid_w; // the info in data_w field is valid
1040 UINT32 offset; // pseudo offset for d_off
1044 opendir(const char *path)
1046 /* enough space for VSS !*/
1047 int max_len = strlen(path) + MAX_PATH;
1054 Dmsg1(100, "Opendir path=%s\n", path);
1055 rval = (_dir *)malloc(sizeof(_dir));
1056 memset (rval, 0, sizeof (_dir));
1057 if (rval == NULL) return NULL;
1058 char *tspec = (char *)malloc(max_len);
1059 if (tspec == NULL) return NULL;
1061 conv_unix_to_win32_path(path, tspec, max_len);
1062 Dmsg1(100, "win32 path=%s\n", tspec);
1064 // add backslash only if there is none yet (think of c:\)
1065 if (tspec[strlen(tspec)-1] != '\\')
1066 bstrncat(tspec, "\\*", max_len);
1068 bstrncat(tspec, "*", max_len);
1072 // convert to wchar_t
1073 if (p_FindFirstFileW) {
1074 POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
1075 make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec);
1077 rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
1079 free_pool_memory(pwcBuf);
1081 if (rval->dirh != INVALID_HANDLE_VALUE)
1083 } else if (p_FindFirstFileA) {
1084 rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
1086 if (rval->dirh != INVALID_HANDLE_VALUE)
1091 Dmsg3(99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
1092 path, rval->spec, rval->dirh);
1095 if (rval->dirh == INVALID_HANDLE_VALUE)
1098 if (rval->valid_w) {
1099 Dmsg1(99, "\tFirstFile=%s\n", rval->data_w.cFileName);
1102 if (rval->valid_a) {
1103 Dmsg1(99, "\tFirstFile=%s\n", rval->data_a.cFileName);
1109 free((void *)rval->spec);
1111 errno = b_errno_win32;
1118 _dir *dp = (_dir *)dirp;
1119 FindClose(dp->dirh);
1120 free((void *)dp->spec);
1126 typedef struct _WIN32_FIND_DATA {
1127 DWORD dwFileAttributes;
1128 FILETIME ftCreationTime;
1129 FILETIME ftLastAccessTime;
1130 FILETIME ftLastWriteTime;
1131 DWORD nFileSizeHigh;
1135 TCHAR cFileName[MAX_PATH];
1136 TCHAR cAlternateFileName[14];
1137 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1141 copyin(struct dirent &dp, const char *fname)
1145 char *cp = dp.d_name;
1155 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1157 _dir *dp = (_dir *)dirp;
1158 if (dp->valid_w || dp->valid_a) {
1159 entry->d_off = dp->offset;
1163 char szBuf[MAX_PATH_UTF8+1];
1164 wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1165 dp->offset += copyin(*entry, szBuf);
1166 } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1167 dp->offset += copyin(*entry, dp->data_a.cFileName);
1170 *result = entry; /* return entry address */
1171 Dmsg4(99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1172 dirp, entry->d_name, entry->d_reclen, entry->d_off);
1174 // Dmsg0(99, "readdir_r !valid\n");
1175 errno = b_errno_win32;
1179 // get next file, try unicode first
1180 if (p_FindNextFileW)
1181 dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1182 else if (p_FindNextFileA)
1183 dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1185 dp->valid_a = FALSE;
1186 dp->valid_w = FALSE;
1193 * Dotted IP address to network address
1199 inet_aton(const char *a, struct in_addr *inp)
1202 uint32_t acc = 0, tmp = 0;
1205 if (!isdigit(*cp)) { /* first char must be digit */
1206 return 0; /* error */
1210 tmp = (tmp * 10) + (*cp -'0');
1211 } else if (*cp == '.' || *cp == 0) {
1213 return 0; /* error */
1215 acc = (acc << 8) + tmp;
1219 return 0; /* error */
1221 } while (*cp++ != 0);
1222 if (dotc != 4) { /* want 3 .'s plus EOS */
1223 return 0; /* error */
1225 inp->s_addr = htonl(acc); /* store addr in network format */
1230 nanosleep(const struct timespec *req, struct timespec *rem)
1233 rem->tv_sec = rem->tv_nsec = 0;
1234 Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1239 init_signals(void terminate(int sig))
1245 init_stack_dump(void)
1252 pathconf(const char *path, int name)
1256 if (strncmp(path, "\\\\?\\", 4) == 0)
1268 WORD wVersionRequested = MAKEWORD( 1, 1);
1271 int err = WSAStartup(wVersionRequested, &wsaData);
1275 printf("Can not start Windows Sockets\n");
1285 win32_chdir(const char *dir)
1287 if (p_SetCurrentDirectoryW) {
1288 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1289 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1291 BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1293 free_pool_memory(pwszBuf);
1296 errno = b_errno_win32;
1300 else if (p_SetCurrentDirectoryA) {
1301 if (0 == p_SetCurrentDirectoryA(dir)) {
1302 errno = b_errno_win32;
1312 win32_mkdir(const char *dir)
1315 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1316 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1318 int n = p_wmkdir((LPCWSTR)pwszBuf);
1319 free_pool_memory(pwszBuf);
1328 win32_getcwd(char *buf, int maxlen)
1332 if (p_GetCurrentDirectoryW) {
1333 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1334 pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1336 n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1338 n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1339 free_pool_memory(pwszBuf);
1341 } else if (p_GetCurrentDirectoryA)
1342 n = p_GetCurrentDirectoryA(maxlen, buf);
1344 if (n == 0 || n > maxlen) return NULL;
1346 if (n+1 > maxlen) return NULL;
1355 win32_fputs(const char *string, FILE *stream)
1357 /* we use WriteConsoleA / WriteConsoleA
1358 so we can be sure that unicode support works on win32.
1359 with fallback if something fails
1362 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1363 if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1364 p_MultiByteToWideChar && (stream == stdout)) {
1366 POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1368 DWORD dwCharsWritten;
1371 dwChars = UTF8_2_wchar(&pwszBuf, string);
1373 /* try WriteConsoleW */
1374 if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1375 free_pool_memory(pwszBuf);
1376 return dwCharsWritten;
1379 /* convert to local codepage and try WriteConsoleA */
1380 POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1381 pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1383 dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR)pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1384 free_pool_memory(pwszBuf);
1386 if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1387 free_pool_memory(pszBuf);
1388 return dwCharsWritten;
1390 free_pool_memory(pszBuf);
1393 return fputs(string, stream);
1397 win32_cgets (char* buffer, int len)
1399 /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1400 from the win32 console and fallback if seomething fails */
1402 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1403 if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1405 wchar_t wszBuf[1024];
1408 /* nt and unicode conversion */
1409 if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1411 /* null terminate at end */
1412 if (wszBuf[dwRead-1] == L'\n') {
1413 wszBuf[dwRead-1] = L'\0';
1417 if (wszBuf[dwRead-1] == L'\r') {
1418 wszBuf[dwRead-1] = L'\0';
1422 wchar_2_UTF8(buffer, wszBuf, len);
1426 /* win 9x and unicode conversion */
1427 if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1429 /* null terminate at end */
1430 if (szBuf[dwRead-1] == L'\n') {
1431 szBuf[dwRead-1] = L'\0';
1435 if (szBuf[dwRead-1] == L'\r') {
1436 szBuf[dwRead-1] = L'\0';
1440 /* convert from ansii to wchar_t */
1441 p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1442 /* convert from wchar_t to UTF-8 */
1443 if (wchar_2_UTF8(buffer, wszBuf, len))
1449 if (fgets(buffer, len, stdin))
1456 win32_unlink(const char *filename)
1460 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1461 make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1463 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1465 /* special case if file is readonly,
1466 we retry but unset attribute before */
1467 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1468 DWORD dwAttr = p_GetFileAttributesW((LPCWSTR)pwszBuf);
1469 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1470 if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1471 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1472 /* reset to original if it didn't help */
1474 p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1478 free_pool_memory(pwszBuf);
1480 nRetCode = _unlink(filename);
1482 /* special case if file is readonly,
1483 we retry but unset attribute before */
1484 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1485 DWORD dwAttr = p_GetFileAttributesA(filename);
1486 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1487 if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1488 nRetCode = _unlink(filename);
1489 /* reset to original if it didn't help */
1491 p_SetFileAttributesA(filename, dwAttr);
1500 #include "mswinver.h"
1502 char WIN_VERSION_LONG[64];
1503 char WIN_VERSION[32];
1504 char WIN_RAWVERSION[32];
1511 static winver INIT; // cause constructor to be called before main()
1514 winver::winver(void)
1516 const char *version = "";
1517 const char *platform = "";
1518 OSVERSIONINFO osvinfo;
1519 osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1521 // Get the current OS version
1522 if (!GetVersionEx(&osvinfo)) {
1523 version = "Unknown";
1524 platform = "Unknown";
1526 const int ver = _mkversion(osvinfo.dwPlatformId,
1527 osvinfo.dwMajorVersion,
1528 osvinfo.dwMinorVersion);
1529 snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1532 case MS_WINDOWS_95: (version = "Windows 95"); break;
1533 case MS_WINDOWS_98: (version = "Windows 98"); break;
1534 case MS_WINDOWS_ME: (version = "Windows ME"); break;
1535 case MS_WINDOWS_NT4:(version = "Windows NT 4.0"); platform = "NT"; break;
1536 case MS_WINDOWS_2K: (version = "Windows 2000");platform = "NT"; break;
1537 case MS_WINDOWS_XP: (version = "Windows XP");platform = "NT"; break;
1538 case MS_WINDOWS_S2003: (version = "Windows Server 2003");platform = "NT"; break;
1539 default: version = WIN_RAWVERSION; break;
1542 bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1543 snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1544 platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1547 HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1551 BPIPE *b = open_bpipe("ls -l", 10, "r");
1553 while (!feof(b->rfd)) {
1554 fgets(buf, sizeof(buf), b->rfd);
1560 BOOL CreateChildProcess(VOID);
1561 VOID WriteToPipe(VOID);
1562 VOID ReadFromPipe(VOID);
1563 VOID ErrorExit(LPCSTR);
1564 VOID ErrMsg(LPTSTR, BOOL);
1567 * Check for a quoted path, if an absolute path name is given and it contains
1568 * spaces it will need to be quoted. i.e. "c:/Program Files/foo/bar.exe"
1569 * CreateProcess() says the best way to ensure proper results with executables
1570 * with spaces in path or filename is to quote the string.
1573 getArgv0(const char *cmdline)
1578 for (cp = cmdline; *cp; cp++)
1583 if (!inquote && isspace(*cp))
1588 int len = cp - cmdline;
1589 char *rval = (char *)malloc(len+1);
1602 * Extracts the executable or script name from the first string in
1605 * If the name contains blanks then it must be quoted with double quotes,
1606 * otherwise quotes are optional. If the name contains blanks then it
1607 * will be converted to a short name.
1609 * The optional quotes will be removed. The result is copied to a malloc'ed
1610 * buffer and returned through the pexe argument. The pargs parameter is set
1611 * to the address of the character in cmdline located after the name.
1613 * The malloc'ed buffer returned in *pexe must be freed by the caller.
1616 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1618 const char *pExeStart = NULL; /* Start of executable name in cmdline */
1619 const char *pExeEnd = NULL; /* Character after executable name (separator) */
1621 const char *pBasename = NULL; /* Character after last path separator */
1622 const char *pExtension = NULL; /* Period at start of extension */
1624 const char *current = cmdline;
1626 bool bQuoted = false;
1628 /* Skip initial whitespace */
1630 while (*current == ' ' || *current == '\t')
1635 /* Calculate start of name and determine if quoted */
1637 if (*current == '"') {
1638 pExeStart = ++current;
1641 pExeStart = current;
1649 * Scan command line looking for path separators (/ and \\) and the
1650 * terminator, either a quote or a blank. The location of the
1651 * extension is also noted.
1654 for ( ; *current != '\0'; current++)
1656 if (*current == '.') {
1657 pExtension = current;
1658 } else if (IsPathSeparator(*current) && current[1] != '\0') {
1659 pBasename = ¤t[1];
1663 /* Check for terminator, either quote or blank */
1665 if (*current != '"') {
1669 if (*current != ' ') {
1675 * Hit terminator, remember end of name (address of terminator) and
1676 * start of arguments
1680 if (bQuoted && *current == '"') {
1681 *pargs = ¤t[1];
1689 if (pBasename == NULL) {
1690 pBasename = pExeStart;
1693 if (pExeEnd == NULL) {
1702 bool bHasPathSeparators = pExeStart != pBasename;
1704 /* We have pointers to all the useful parts of the name */
1706 /* Default extensions in the order cmd.exe uses to search */
1708 static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
1709 DWORD dwBasePathLength = pExeEnd - pExeStart;
1711 DWORD dwAltNameLength = 0;
1712 char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1713 char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1715 pPathname[MAX_PATHLENGTH] = '\0';
1716 pAltPathname[MAX_PATHLENGTH] = '\0';
1718 memcpy(pPathname, pExeStart, dwBasePathLength);
1719 pPathname[dwBasePathLength] = '\0';
1721 if (pExtension == NULL) {
1722 /* Try appending extensions */
1723 for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
1725 if (!bHasPathSeparators) {
1726 /* There are no path separators, search in the standard locations */
1727 dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
1728 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1729 memcpy(pPathname, pAltPathname, dwAltNameLength);
1730 pPathname[dwAltNameLength] = '\0';
1734 bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
1735 if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) {
1738 pPathname[dwBasePathLength] = '\0';
1741 } else if (!bHasPathSeparators) {
1742 /* There are no path separators, search in the standard locations */
1743 dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
1744 if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) {
1745 memcpy(pPathname, pAltPathname, dwAltNameLength);
1746 pPathname[dwAltNameLength] = '\0';
1750 if (strchr(pPathname, ' ') != NULL) {
1751 dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH);
1753 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1754 *pexe = (char *)malloc(dwAltNameLength + 1);
1755 if (*pexe == NULL) {
1758 memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
1762 if (*pexe == NULL) {
1763 DWORD dwPathnameLength = strlen(pPathname);
1764 *pexe = (char *)malloc(dwPathnameLength + 1);
1765 if (*pexe == NULL) {
1768 memcpy(*pexe, pPathname, dwPathnameLength + 1);
1775 * OK, so it would seem CreateProcess only handles true executables:
1776 * .com or .exe files. So grab $COMSPEC value and pass command line to it.
1779 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1781 static const char *comspec = NULL;
1782 PROCESS_INFORMATION piProcInfo;
1783 STARTUPINFOA siStartInfo;
1784 BOOL bFuncRetn = FALSE;
1786 if (comspec == NULL) {
1787 comspec = getenv("COMSPEC");
1789 if (comspec == NULL) // should never happen
1790 return INVALID_HANDLE_VALUE;
1792 // Set up members of the PROCESS_INFORMATION structure.
1793 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1795 // Set up members of the STARTUPINFO structure.
1797 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1798 siStartInfo.cb = sizeof(STARTUPINFO);
1799 // setup new process to use supplied handles for stdin,stdout,stderr
1800 // if supplied handles are not used the send a copy of our STD_HANDLE
1802 siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1803 siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
1805 if (in != INVALID_HANDLE_VALUE)
1806 siStartInfo.hStdInput = in;
1808 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1810 if (out != INVALID_HANDLE_VALUE)
1811 siStartInfo.hStdOutput = out;
1813 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1814 if (err != INVALID_HANDLE_VALUE)
1815 siStartInfo.hStdError = err;
1817 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1819 // Create the child process.
1822 const char *argStart;
1824 if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
1825 return INVALID_HANDLE_VALUE;
1828 int cmdLen = strlen(comspec) + 4 + strlen(exeFile) + strlen(argStart) + 1;
1830 char *cmdLine = (char *)alloca(cmdLen);
1832 snprintf(cmdLine, cmdLen, "%s /c %s%s", comspec, exeFile, argStart);
1836 Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
1838 // try to execute program
1839 bFuncRetn = CreateProcessA(comspec,
1840 cmdLine, // command line
1841 NULL, // process security attributes
1842 NULL, // primary thread security attributes
1843 TRUE, // handles are inherited
1844 0, // creation flags
1845 NULL, // use parent's environment
1846 NULL, // use parent's current directory
1847 &siStartInfo, // STARTUPINFO pointer
1848 &piProcInfo); // receives PROCESS_INFORMATION
1850 if (bFuncRetn == 0) {
1851 ErrorExit("CreateProcess failed\n");
1852 const char *err = errorString();
1853 Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n", comspec, cmdLine, err);
1854 LocalFree((void *)err);
1855 return INVALID_HANDLE_VALUE;
1857 // we don't need a handle on the process primary thread so we close
1859 CloseHandle(piProcInfo.hThread);
1861 return piProcInfo.hProcess;
1866 ErrorExit (LPCSTR lpszMessage)
1868 Dmsg1(0, "%s", lpszMessage);
1873 typedef struct s_bpipe {
1875 time_t worker_stime;
1884 CloseIfValid(HANDLE handle)
1886 if (handle != INVALID_HANDLE_VALUE)
1887 CloseHandle(handle);
1891 open_bpipe(char *prog, int wait, const char *mode)
1893 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1894 hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1897 SECURITY_ATTRIBUTES saAttr;
1901 hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1902 hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1903 hInputFile = INVALID_HANDLE_VALUE;
1905 BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1906 memset((void *)bpipe, 0, sizeof(BPIPE));
1908 int mode_read = (mode[0] == 'r');
1909 int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1912 // Set the bInheritHandle flag so pipe handles are inherited.
1914 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1915 saAttr.bInheritHandle = TRUE;
1916 saAttr.lpSecurityDescriptor = NULL;
1920 // Create a pipe for the child process's STDOUT.
1921 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1922 ErrorExit("Stdout pipe creation failed\n");
1925 // Create noninheritable read handle and close the inheritable read
1928 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1929 GetCurrentProcess(), &hChildStdoutRdDup , 0,
1931 DUPLICATE_SAME_ACCESS);
1933 ErrorExit("DuplicateHandle failed");
1937 CloseHandle(hChildStdoutRd);
1938 hChildStdoutRd = INVALID_HANDLE_VALUE;
1943 // Create a pipe for the child process's STDIN.
1945 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1946 ErrorExit("Stdin pipe creation failed\n");
1950 // Duplicate the write handle to the pipe so it is not inherited.
1951 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
1952 GetCurrentProcess(), &hChildStdinWrDup,
1954 FALSE, // not inherited
1955 DUPLICATE_SAME_ACCESS);
1957 ErrorExit("DuplicateHandle failed");
1961 CloseHandle(hChildStdinWr);
1962 hChildStdinWr = INVALID_HANDLE_VALUE;
1964 // spawn program with redirected handles as appropriate
1965 bpipe->worker_pid = (pid_t)
1966 CreateChildProcess(prog, // commandline
1967 hChildStdinRd, // stdin HANDLE
1968 hChildStdoutWr, // stdout HANDLE
1969 hChildStdoutWr); // stderr HANDLE
1971 if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1975 bpipe->worker_stime = time(NULL);
1978 CloseHandle(hChildStdoutWr); // close our write side so when
1979 // process terminates we can
1981 // ugly but convert WIN32 HANDLE to FILE*
1982 int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY | O_BINARY);
1984 bpipe->rfd = _fdopen(rfd, "rb");
1988 CloseHandle(hChildStdinRd); // close our read side so as not
1989 // to interfre with child's copy
1990 // ugly but convert WIN32 HANDLE to FILE*
1991 int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY | O_BINARY);
1993 bpipe->wfd = _fdopen(wfd, "wb");
1998 bpipe->timer_id = start_child_timer(NULL, bpipe->worker_pid, wait);
2005 CloseIfValid(hChildStdoutRd);
2006 CloseIfValid(hChildStdoutRdDup);
2007 CloseIfValid(hChildStdinWr);
2008 CloseIfValid(hChildStdinWrDup);
2010 free((void *) bpipe);
2011 errno = b_errno_win32; /* do GetLastError() for error code */
2017 kill(int pid, int signal)
2020 if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
2022 errno = b_errno_win32;
2024 CloseHandle((HANDLE)pid);
2030 close_bpipe(BPIPE *bpipe)
2033 int32_t remaining_wait = bpipe->wait;
2045 if (remaining_wait == 0) { /* wait indefinitely */
2046 remaining_wait = INT32_MAX;
2050 if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
2051 const char *err = errorString();
2052 rval = b_errno_win32;
2053 Dmsg1(0, "GetExitCode error %s\n", err);
2054 LocalFree((void *)err);
2057 if (exitCode == STILL_ACTIVE) {
2058 if (remaining_wait <= 0) {
2059 rval = ETIME; /* timed out */
2062 bmicrosleep(1, 0); /* wait one second */
2064 } else if (exitCode != 0) {
2065 /* Truncate exit code as it doesn't seem to be correct */
2066 rval = (exitCode & 0xFF) | b_errno_exit;
2069 break; /* Shouldn't get here */
2073 if (bpipe->timer_id) {
2074 stop_child_timer(bpipe->timer_id);
2076 if (bpipe->rfd) fclose(bpipe->rfd);
2077 if (bpipe->wfd) fclose(bpipe->wfd);
2078 free((void *)bpipe);
2083 close_wpipe(BPIPE *bpipe)
2089 if (fclose(bpipe->wfd) != 0) {
2097 #include "findlib/find.h"
2100 utime(const char *fname, struct utimbuf *times)
2105 conv_unix_to_win32_path(fname, tmpbuf, 5000);
2107 cvt_utime_to_ftime(times->actime, acc);
2108 cvt_utime_to_ftime(times->modtime, mod);
2110 HANDLE h = INVALID_HANDLE_VALUE;
2112 if (p_CreateFileW) {
2113 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2114 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
2116 h = p_CreateFileW((LPCWSTR)pwszBuf,
2117 FILE_WRITE_ATTRIBUTES,
2118 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2121 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2124 free_pool_memory(pwszBuf);
2125 } else if (p_CreateFileA) {
2126 h = p_CreateFileA(tmpbuf,
2127 FILE_WRITE_ATTRIBUTES,
2128 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2131 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2135 if (h == INVALID_HANDLE_VALUE) {
2136 const char *err = errorString();
2137 Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2138 LocalFree((void *)err);
2139 errno = b_errno_win32;
2143 int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2146 errno = b_errno_win32;
2153 file_open(const char *file, int flags, int mode)
2156 DWORD shareMode = 0;
2159 HANDLE foo = INVALID_HANDLE_VALUE;
2160 const char *remap = file;
2162 if (flags & O_WRONLY) access = GENERIC_WRITE;
2163 else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2164 else access = GENERIC_READ;
2166 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2167 create = CREATE_NEW;
2168 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2169 create = CREATE_ALWAYS;
2170 else if (flags & O_CREAT)
2171 create = OPEN_ALWAYS;
2172 else if (flags & O_TRUNC)
2173 create = TRUNCATE_EXISTING;
2175 create = OPEN_EXISTING;
2179 if (flags & O_APPEND) {
2180 printf("open...APPEND not implemented yet.");
2184 if (p_CreateFileW) {
2185 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2186 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
2188 foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
2189 free_pool_memory(pwszBuf);
2190 } else if (p_CreateFileA)
2191 foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
2193 if (INVALID_HANDLE_VALUE == foo) {
2194 errno = b_errno_win32;
2205 if (!CloseHandle((HANDLE)fd)) {
2206 errno = b_errno_win32;
2214 file_write(int fd, const void *data, ssize_t len)
2218 status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2219 if (status) return bwrite;
2220 errno = b_errno_win32;
2226 file_read(int fd, void *data, ssize_t len)
2231 status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2232 if (status) return bread;
2233 errno = b_errno_win32;
2238 file_seek(int fd, boffset_t offset, int whence)
2242 LONG offset_low = (LONG)offset;
2243 LONG offset_high = (LONG)(offset >> 32);
2247 method = FILE_BEGIN;
2250 method = FILE_CURRENT;
2261 if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
2262 errno = b_errno_win32;
2265 /* ***FIXME*** I doubt this works right */
2278 /* syslog function, added by Nicolas Boichat */
2279 void openlog(const char *ident, int option, int facility) {}