2 Bacula® - The Network Backup Solution
4 Copyright (C) 2004-2008 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;
591 FILETIME *pftLastAccessTime;
592 FILETIME *pftLastWriteTime;
593 FILETIME *pftCreationTime;
596 * Oh, cool, another exception: Microsoft doesn't let us do
597 * FindFile operations on a Drive, so simply fake root attibutes.
599 if (file[1] == ':' && file[2] == 0) {
600 time_t now = time(NULL);
601 Dmsg1(99, "faking ROOT attrs(%s).\n", file);
602 sb->st_mode = S_IFDIR;
603 sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
610 HANDLE h = INVALID_HANDLE_VALUE;
613 if (p_FindFirstFileW) {
614 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
615 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
617 h = p_FindFirstFileW((LPCWSTR)pwszBuf, &info_w);
618 free_pool_memory(pwszBuf);
620 pdwFileAttributes = &info_w.dwFileAttributes;
621 pdwReserved0 = &info_w.dwReserved0;
622 pnFileSizeHigh = &info_w.nFileSizeHigh;
623 pnFileSizeLow = &info_w.nFileSizeLow;
624 pftLastAccessTime = &info_w.ftLastAccessTime;
625 pftLastWriteTime = &info_w.ftLastWriteTime;
626 pftCreationTime = &info_w.ftCreationTime;
629 } else if (p_FindFirstFileA) {
630 h = p_FindFirstFileA(file, &info_a);
632 pdwFileAttributes = &info_a.dwFileAttributes;
633 pdwReserved0 = &info_a.dwReserved0;
634 pnFileSizeHigh = &info_a.nFileSizeHigh;
635 pnFileSizeLow = &info_a.nFileSizeLow;
636 pftLastAccessTime = &info_a.ftLastAccessTime;
637 pftLastWriteTime = &info_a.ftLastWriteTime;
638 pftCreationTime = &info_a.ftCreationTime;
641 if (h == INVALID_HANDLE_VALUE) {
642 const char *err = errorString();
643 Dmsg2(99, "FindFirstFile(%s):%s\n", file, err);
644 LocalFree((void *)err);
645 errno = b_errno_win32;
649 sb->st_mode = 0777; /* start with everything */
650 if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
651 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
652 if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
653 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
654 if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
655 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
656 sb->st_mode |= S_IFDIR;
658 /* Use st_rdev to store reparse attribute */
659 sb->st_rdev = (*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0;
660 if (sb->st_rdev == 1 && *pdwReserved0 & IO_REPARSE_TAG_MOUNT_POINT) {
661 sb->st_rdev = 2; /* mount point */
664 sb->st_size = *pnFileSizeHigh;
666 sb->st_size |= *pnFileSizeLow;
667 sb->st_blksize = 4096;
668 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
670 sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
671 sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
672 sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
679 fstat(int fd, struct stat *sb)
681 BY_HANDLE_FILE_INFORMATION info;
684 if (!GetFileInformationByHandle((HANDLE)fd, &info)) {
685 const char *err = errorString();
686 Dmsg2(99, "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
687 LocalFree((void *)err);
688 errno = b_errno_win32;
692 sb->st_dev = info.dwVolumeSerialNumber;
693 sb->st_ino = info.nFileIndexHigh;
695 sb->st_ino |= info.nFileIndexLow;
696 sb->st_nlink = (short)info.nNumberOfLinks;
697 if (sb->st_nlink > 1) {
698 Dmsg1(99, "st_nlink=%d\n", sb->st_nlink);
701 sb->st_mode = 0777; /* start with everything */
702 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
703 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
704 if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
705 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
706 if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
707 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
708 sb->st_mode |= S_IFREG;
710 /* Use st_rdev to store reparse attribute */
711 sb->st_rdev = (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0;
713 sb->st_size = info.nFileSizeHigh;
715 sb->st_size |= info.nFileSizeLow;
716 sb->st_blksize = 4096;
717 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
718 sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
719 sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
720 sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
726 stat2(const char *file, struct stat *sb)
731 conv_unix_to_win32_path(file, tmpbuf, 1024);
733 DWORD attr = (DWORD)-1;
735 if (p_GetFileAttributesW) {
736 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
737 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
739 attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
740 free_pool_memory(pwszBuf);
741 } else if (p_GetFileAttributesA) {
742 attr = p_GetFileAttributesA(tmpbuf);
745 if (attr == (DWORD)-1) {
746 const char *err = errorString();
747 Dmsg2(99, "GetFileAttributes(%s): %s\n", tmpbuf, err);
748 LocalFree((void *)err);
749 errno = b_errno_win32;
754 h = CreateFileA(tmpbuf, GENERIC_READ,
755 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
757 if (h == INVALID_HANDLE_VALUE) {
758 const char *err = errorString();
759 Dmsg2(99, "Cannot open file for stat (%s):%s\n", tmpbuf, err);
760 LocalFree((void *)err);
761 errno = b_errno_win32;
765 rval = fstat((int)h, sb);
768 if (attr & FILE_ATTRIBUTE_DIRECTORY &&
769 file[1] == ':' && file[2] != 0) {
777 stat(const char *file, struct stat *sb)
779 WIN32_FILE_ATTRIBUTE_DATA data;
783 memset(sb, 0, sizeof(*sb));
785 if (p_GetFileAttributesExW) {
786 /* dynamically allocate enough space for UCS2 filename */
787 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
788 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
790 BOOL b = p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, &data);
791 free_pool_memory(pwszBuf);
794 return stat2(file, sb);
796 } else if (p_GetFileAttributesExA) {
797 if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
798 return stat2(file, sb);
801 return stat2(file, sb);
804 sb->st_mode = 0777; /* start with everything */
805 if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
806 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
808 if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
809 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
811 if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
812 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
814 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
815 sb->st_mode |= S_IFDIR;
817 sb->st_mode |= S_IFREG;
820 /* Use st_rdev to store reparse attribute */
821 sb->st_rdev = (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0;
824 sb->st_size = data.nFileSizeHigh;
826 sb->st_size |= data.nFileSizeLow;
827 sb->st_blksize = 4096;
828 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
829 sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
830 sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
831 sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
834 * If we are not at the root, then to distinguish a reparse
835 * point from a mount point, we must call FindFirstFile() to
836 * get the WIN32_FIND_DATA, which has the bit that indicates
837 * that this directory is a mount point -- aren't Win32 APIs
838 * wonderful? (sarcasm). The code exists in the statDir
841 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
842 file[1] == ':' && file[2] != 0) {
849 * We write our own ftruncate because the one in the
850 * Microsoft library mrcrt.dll does not truncate
851 * files greater than 2GB.
854 int win32_ftruncate(int fd, int64_t length)
856 /* Set point we want to truncate file */
857 __int64 pos = _lseeki64(fd, (__int64)length, SEEK_SET);
859 if (pos != (__int64)length) {
860 errno = EACCES; /* truncation failed, get out */
865 if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0) {
866 errno = b_errno_win32;
873 int fcntl(int fd, int cmd, long arg)
896 lstat(const char *file, struct stat *sb)
898 return stat(file, sb);
914 execvp(const char *, char *[]) {
935 waitpid(int, int*, int)
942 readlink(const char *, char *, int)
951 strcasecmp(const char *s1, const char *s2)
953 register int ch1, ch2;
956 return 0; /* strings are equal if same object. */
966 } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
973 strncasecmp(const char *s1, const char *s2, int len)
975 register int ch1 = 0, ch2 = 0;
978 return 0; /* strings are equal if same object. */
989 if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
996 gettimeofday(struct timeval *tv, struct timezone *)
1001 GetSystemTime(&now);
1007 if (!SystemTimeToFileTime(&now, &tmp)) {
1008 errno = b_errno_win32;
1012 int64_t _100nsec = tmp.dwHighDateTime;
1014 _100nsec |= tmp.dwLowDateTime;
1015 _100nsec -= WIN32_FILETIME_ADJUST;
1017 tv->tv_sec = (long)(_100nsec / 10000000);
1018 tv->tv_usec = (long)((_100nsec % 10000000)/10);
1023 /* For apcupsd this is in src/lib/wincompat.c */
1024 extern "C" void syslog(int type, const char *fmt, ...)
1026 /*#ifndef HAVE_CONSOLE
1027 MessageBox(NULL, msg, "Bacula", MB_OK);
1048 // implement opendir/readdir/closedir on top of window's API
1052 WIN32_FIND_DATAA data_a; // window's file info (ansii version)
1053 WIN32_FIND_DATAW data_w; // window's file info (wchar version)
1054 const char *spec; // the directory we're traversing
1055 HANDLE dirh; // the search handle
1056 BOOL valid_a; // the info in data_a field is valid
1057 BOOL valid_w; // the info in data_w field is valid
1058 UINT32 offset; // pseudo offset for d_off
1062 opendir(const char *path)
1064 /* enough space for VSS !*/
1065 int max_len = strlen(path) + MAX_PATH;
1072 Dmsg1(100, "Opendir path=%s\n", path);
1073 rval = (_dir *)malloc(sizeof(_dir));
1074 memset (rval, 0, sizeof (_dir));
1075 if (rval == NULL) return NULL;
1076 char *tspec = (char *)malloc(max_len);
1077 if (tspec == NULL) return NULL;
1079 conv_unix_to_win32_path(path, tspec, max_len);
1080 Dmsg1(100, "win32 path=%s\n", tspec);
1082 // add backslash only if there is none yet (think of c:\)
1083 if (tspec[strlen(tspec)-1] != '\\')
1084 bstrncat(tspec, "\\*", max_len);
1086 bstrncat(tspec, "*", max_len);
1090 // convert to wchar_t
1091 if (p_FindFirstFileW) {
1092 POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
1093 make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec);
1095 rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
1097 free_pool_memory(pwcBuf);
1099 if (rval->dirh != INVALID_HANDLE_VALUE)
1101 } else if (p_FindFirstFileA) {
1102 rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
1104 if (rval->dirh != INVALID_HANDLE_VALUE)
1109 Dmsg3(99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
1110 path, rval->spec, rval->dirh);
1113 if (rval->dirh == INVALID_HANDLE_VALUE)
1116 if (rval->valid_w) {
1117 Dmsg1(99, "\tFirstFile=%s\n", rval->data_w.cFileName);
1120 if (rval->valid_a) {
1121 Dmsg1(99, "\tFirstFile=%s\n", rval->data_a.cFileName);
1127 free((void *)rval->spec);
1129 errno = b_errno_win32;
1136 _dir *dp = (_dir *)dirp;
1137 FindClose(dp->dirh);
1138 free((void *)dp->spec);
1144 typedef struct _WIN32_FIND_DATA {
1145 DWORD dwFileAttributes;
1146 FILETIME ftCreationTime;
1147 FILETIME ftLastAccessTime;
1148 FILETIME ftLastWriteTime;
1149 DWORD nFileSizeHigh;
1153 TCHAR cFileName[MAX_PATH];
1154 TCHAR cAlternateFileName[14];
1155 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1159 copyin(struct dirent &dp, const char *fname)
1163 char *cp = dp.d_name;
1173 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1175 _dir *dp = (_dir *)dirp;
1176 if (dp->valid_w || dp->valid_a) {
1177 entry->d_off = dp->offset;
1181 char szBuf[MAX_PATH_UTF8+1];
1182 wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1183 dp->offset += copyin(*entry, szBuf);
1184 } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1185 dp->offset += copyin(*entry, dp->data_a.cFileName);
1188 *result = entry; /* return entry address */
1189 Dmsg4(99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1190 dirp, entry->d_name, entry->d_reclen, entry->d_off);
1192 // Dmsg0(99, "readdir_r !valid\n");
1193 errno = b_errno_win32;
1197 // get next file, try unicode first
1198 if (p_FindNextFileW)
1199 dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1200 else if (p_FindNextFileA)
1201 dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1203 dp->valid_a = FALSE;
1204 dp->valid_w = FALSE;
1211 * Dotted IP address to network address
1217 inet_aton(const char *a, struct in_addr *inp)
1220 uint32_t acc = 0, tmp = 0;
1223 if (!isdigit(*cp)) { /* first char must be digit */
1224 return 0; /* error */
1228 tmp = (tmp * 10) + (*cp -'0');
1229 } else if (*cp == '.' || *cp == 0) {
1231 return 0; /* error */
1233 acc = (acc << 8) + tmp;
1237 return 0; /* error */
1239 } while (*cp++ != 0);
1240 if (dotc != 4) { /* want 3 .'s plus EOS */
1241 return 0; /* error */
1243 inp->s_addr = htonl(acc); /* store addr in network format */
1248 nanosleep(const struct timespec *req, struct timespec *rem)
1251 rem->tv_sec = rem->tv_nsec = 0;
1252 Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1257 init_signals(void terminate(int sig))
1263 init_stack_dump(void)
1270 pathconf(const char *path, int name)
1274 if (strncmp(path, "\\\\?\\", 4) == 0)
1286 WORD wVersionRequested = MAKEWORD( 1, 1);
1289 int err = WSAStartup(wVersionRequested, &wsaData);
1293 printf("Can not start Windows Sockets\n");
1303 win32_chdir(const char *dir)
1305 if (p_SetCurrentDirectoryW) {
1306 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1307 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1309 BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1311 free_pool_memory(pwszBuf);
1314 errno = b_errno_win32;
1318 else if (p_SetCurrentDirectoryA) {
1319 if (0 == p_SetCurrentDirectoryA(dir)) {
1320 errno = b_errno_win32;
1330 win32_mkdir(const char *dir)
1333 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1334 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1336 int n = p_wmkdir((LPCWSTR)pwszBuf);
1337 free_pool_memory(pwszBuf);
1346 win32_getcwd(char *buf, int maxlen)
1350 if (p_GetCurrentDirectoryW) {
1351 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1352 pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1354 n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1356 n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1357 free_pool_memory(pwszBuf);
1359 } else if (p_GetCurrentDirectoryA)
1360 n = p_GetCurrentDirectoryA(maxlen, buf);
1362 if (n == 0 || n > maxlen) return NULL;
1364 if (n+1 > maxlen) return NULL;
1373 win32_fputs(const char *string, FILE *stream)
1375 /* we use WriteConsoleA / WriteConsoleA
1376 so we can be sure that unicode support works on win32.
1377 with fallback if something fails
1380 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1381 if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1382 p_MultiByteToWideChar && (stream == stdout)) {
1384 POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1386 DWORD dwCharsWritten;
1389 dwChars = UTF8_2_wchar(&pwszBuf, string);
1391 /* try WriteConsoleW */
1392 if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1393 free_pool_memory(pwszBuf);
1394 return dwCharsWritten;
1397 /* convert to local codepage and try WriteConsoleA */
1398 POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1399 pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1401 dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR)pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1402 free_pool_memory(pwszBuf);
1404 if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1405 free_pool_memory(pszBuf);
1406 return dwCharsWritten;
1408 free_pool_memory(pszBuf);
1411 return fputs(string, stream);
1415 win32_cgets (char* buffer, int len)
1417 /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1418 from the win32 console and fallback if seomething fails */
1420 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1421 if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1423 wchar_t wszBuf[1024];
1426 /* nt and unicode conversion */
1427 if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1429 /* null terminate at end */
1430 if (wszBuf[dwRead-1] == L'\n') {
1431 wszBuf[dwRead-1] = L'\0';
1435 if (wszBuf[dwRead-1] == L'\r') {
1436 wszBuf[dwRead-1] = L'\0';
1440 wchar_2_UTF8(buffer, wszBuf, len);
1444 /* win 9x and unicode conversion */
1445 if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1447 /* null terminate at end */
1448 if (szBuf[dwRead-1] == L'\n') {
1449 szBuf[dwRead-1] = L'\0';
1453 if (szBuf[dwRead-1] == L'\r') {
1454 szBuf[dwRead-1] = L'\0';
1458 /* convert from ansii to wchar_t */
1459 p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1460 /* convert from wchar_t to UTF-8 */
1461 if (wchar_2_UTF8(buffer, wszBuf, len))
1467 if (fgets(buffer, len, stdin))
1474 win32_unlink(const char *filename)
1478 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1479 make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1481 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1483 /* special case if file is readonly,
1484 we retry but unset attribute before */
1485 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1486 DWORD dwAttr = p_GetFileAttributesW((LPCWSTR)pwszBuf);
1487 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1488 if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1489 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1490 /* reset to original if it didn't help */
1492 p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1496 free_pool_memory(pwszBuf);
1498 nRetCode = _unlink(filename);
1500 /* special case if file is readonly,
1501 we retry but unset attribute before */
1502 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1503 DWORD dwAttr = p_GetFileAttributesA(filename);
1504 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1505 if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1506 nRetCode = _unlink(filename);
1507 /* reset to original if it didn't help */
1509 p_SetFileAttributesA(filename, dwAttr);
1518 #include "mswinver.h"
1520 char WIN_VERSION_LONG[64];
1521 char WIN_VERSION[32];
1522 char WIN_RAWVERSION[32];
1529 static winver INIT; // cause constructor to be called before main()
1532 winver::winver(void)
1534 const char *version = "";
1535 const char *platform = "";
1536 OSVERSIONINFO osvinfo;
1537 osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1539 // Get the current OS version
1540 if (!GetVersionEx(&osvinfo)) {
1541 version = "Unknown";
1542 platform = "Unknown";
1544 const int ver = _mkversion(osvinfo.dwPlatformId,
1545 osvinfo.dwMajorVersion,
1546 osvinfo.dwMinorVersion);
1547 snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1550 case MS_WINDOWS_95: (version = "Windows 95"); break;
1551 case MS_WINDOWS_98: (version = "Windows 98"); break;
1552 case MS_WINDOWS_ME: (version = "Windows ME"); break;
1553 case MS_WINDOWS_NT4:(version = "Windows NT 4.0"); platform = "NT"; break;
1554 case MS_WINDOWS_2K: (version = "Windows 2000");platform = "NT"; break;
1555 case MS_WINDOWS_XP: (version = "Windows XP");platform = "NT"; break;
1556 case MS_WINDOWS_S2003: (version = "Windows Server 2003");platform = "NT"; break;
1557 default: version = WIN_RAWVERSION; break;
1560 bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1561 snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1562 platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1565 HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1569 BPIPE *b = open_bpipe("ls -l", 10, "r");
1571 while (!feof(b->rfd)) {
1572 fgets(buf, sizeof(buf), b->rfd);
1578 BOOL CreateChildProcess(VOID);
1579 VOID WriteToPipe(VOID);
1580 VOID ReadFromPipe(VOID);
1581 VOID ErrorExit(LPCSTR);
1582 VOID ErrMsg(LPTSTR, BOOL);
1585 * Check for a quoted path, if an absolute path name is given and it contains
1586 * spaces it will need to be quoted. i.e. "c:/Program Files/foo/bar.exe"
1587 * CreateProcess() says the best way to ensure proper results with executables
1588 * with spaces in path or filename is to quote the string.
1591 getArgv0(const char *cmdline)
1596 for (cp = cmdline; *cp; cp++)
1601 if (!inquote && isspace(*cp))
1606 int len = cp - cmdline;
1607 char *rval = (char *)malloc(len+1);
1620 * Extracts the executable or script name from the first string in
1623 * If the name contains blanks then it must be quoted with double quotes,
1624 * otherwise quotes are optional. If the name contains blanks then it
1625 * will be converted to a short name.
1627 * The optional quotes will be removed. The result is copied to a malloc'ed
1628 * buffer and returned through the pexe argument. The pargs parameter is set
1629 * to the address of the character in cmdline located after the name.
1631 * The malloc'ed buffer returned in *pexe must be freed by the caller.
1634 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1636 const char *pExeStart = NULL; /* Start of executable name in cmdline */
1637 const char *pExeEnd = NULL; /* Character after executable name (separator) */
1639 const char *pBasename = NULL; /* Character after last path separator */
1640 const char *pExtension = NULL; /* Period at start of extension */
1642 const char *current = cmdline;
1644 bool bQuoted = false;
1646 /* Skip initial whitespace */
1648 while (*current == ' ' || *current == '\t')
1653 /* Calculate start of name and determine if quoted */
1655 if (*current == '"') {
1656 pExeStart = ++current;
1659 pExeStart = current;
1667 * Scan command line looking for path separators (/ and \\) and the
1668 * terminator, either a quote or a blank. The location of the
1669 * extension is also noted.
1672 for ( ; *current != '\0'; current++)
1674 if (*current == '.') {
1675 pExtension = current;
1676 } else if (IsPathSeparator(*current) && current[1] != '\0') {
1677 pBasename = ¤t[1];
1681 /* Check for terminator, either quote or blank */
1683 if (*current != '"') {
1687 if (*current != ' ') {
1693 * Hit terminator, remember end of name (address of terminator) and
1694 * start of arguments
1698 if (bQuoted && *current == '"') {
1699 *pargs = ¤t[1];
1707 if (pBasename == NULL) {
1708 pBasename = pExeStart;
1711 if (pExeEnd == NULL) {
1720 bool bHasPathSeparators = pExeStart != pBasename;
1722 /* We have pointers to all the useful parts of the name */
1724 /* Default extensions in the order cmd.exe uses to search */
1726 static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
1727 DWORD dwBasePathLength = pExeEnd - pExeStart;
1729 DWORD dwAltNameLength = 0;
1730 char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1731 char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1733 pPathname[MAX_PATHLENGTH] = '\0';
1734 pAltPathname[MAX_PATHLENGTH] = '\0';
1736 memcpy(pPathname, pExeStart, dwBasePathLength);
1737 pPathname[dwBasePathLength] = '\0';
1739 if (pExtension == NULL) {
1740 /* Try appending extensions */
1741 for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
1743 if (!bHasPathSeparators) {
1744 /* There are no path separators, search in the standard locations */
1745 dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
1746 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1747 memcpy(pPathname, pAltPathname, dwAltNameLength);
1748 pPathname[dwAltNameLength] = '\0';
1752 bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
1753 if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) {
1756 pPathname[dwBasePathLength] = '\0';
1759 } else if (!bHasPathSeparators) {
1760 /* There are no path separators, search in the standard locations */
1761 dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
1762 if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) {
1763 memcpy(pPathname, pAltPathname, dwAltNameLength);
1764 pPathname[dwAltNameLength] = '\0';
1768 if (strchr(pPathname, ' ') != NULL) {
1769 dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH);
1771 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1772 *pexe = (char *)malloc(dwAltNameLength + 1);
1773 if (*pexe == NULL) {
1776 memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
1780 if (*pexe == NULL) {
1781 DWORD dwPathnameLength = strlen(pPathname);
1782 *pexe = (char *)malloc(dwPathnameLength + 1);
1783 if (*pexe == NULL) {
1786 memcpy(*pexe, pPathname, dwPathnameLength + 1);
1793 * OK, so it would seem CreateProcess only handles true executables:
1794 * .com or .exe files. So grab $COMSPEC value and pass command line to it.
1797 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1799 static const char *comspec = NULL;
1800 PROCESS_INFORMATION piProcInfo;
1801 STARTUPINFOA siStartInfo;
1802 BOOL bFuncRetn = FALSE;
1804 if (comspec == NULL) {
1805 comspec = getenv("COMSPEC");
1807 if (comspec == NULL) // should never happen
1808 return INVALID_HANDLE_VALUE;
1810 // Set up members of the PROCESS_INFORMATION structure.
1811 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1813 // Set up members of the STARTUPINFO structure.
1815 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1816 siStartInfo.cb = sizeof(STARTUPINFO);
1817 // setup new process to use supplied handles for stdin,stdout,stderr
1818 // if supplied handles are not used the send a copy of our STD_HANDLE
1820 siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1821 siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
1823 if (in != INVALID_HANDLE_VALUE)
1824 siStartInfo.hStdInput = in;
1826 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1828 if (out != INVALID_HANDLE_VALUE)
1829 siStartInfo.hStdOutput = out;
1831 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1832 if (err != INVALID_HANDLE_VALUE)
1833 siStartInfo.hStdError = err;
1835 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1837 // Create the child process.
1840 const char *argStart;
1842 if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
1843 return INVALID_HANDLE_VALUE;
1846 int cmdLen = strlen(comspec) + 4 + strlen(exeFile) + strlen(argStart) + 1;
1848 char *cmdLine = (char *)alloca(cmdLen);
1850 snprintf(cmdLine, cmdLen, "%s /c %s%s", comspec, exeFile, argStart);
1854 Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
1856 // try to execute program
1857 bFuncRetn = CreateProcessA(comspec,
1858 cmdLine, // command line
1859 NULL, // process security attributes
1860 NULL, // primary thread security attributes
1861 TRUE, // handles are inherited
1862 0, // creation flags
1863 NULL, // use parent's environment
1864 NULL, // use parent's current directory
1865 &siStartInfo, // STARTUPINFO pointer
1866 &piProcInfo); // receives PROCESS_INFORMATION
1868 if (bFuncRetn == 0) {
1869 ErrorExit("CreateProcess failed\n");
1870 const char *err = errorString();
1871 Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n", comspec, cmdLine, err);
1872 LocalFree((void *)err);
1873 return INVALID_HANDLE_VALUE;
1875 // we don't need a handle on the process primary thread so we close
1877 CloseHandle(piProcInfo.hThread);
1879 return piProcInfo.hProcess;
1884 ErrorExit (LPCSTR lpszMessage)
1886 Dmsg1(0, "%s", lpszMessage);
1891 typedef struct s_bpipe {
1893 time_t worker_stime;
1902 CloseIfValid(HANDLE handle)
1904 if (handle != INVALID_HANDLE_VALUE)
1905 CloseHandle(handle);
1909 open_bpipe(char *prog, int wait, const char *mode)
1911 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1912 hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1915 SECURITY_ATTRIBUTES saAttr;
1919 hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1920 hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1921 hInputFile = INVALID_HANDLE_VALUE;
1923 BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1924 memset((void *)bpipe, 0, sizeof(BPIPE));
1926 int mode_read = (mode[0] == 'r');
1927 int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1930 // Set the bInheritHandle flag so pipe handles are inherited.
1932 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1933 saAttr.bInheritHandle = TRUE;
1934 saAttr.lpSecurityDescriptor = NULL;
1938 // Create a pipe for the child process's STDOUT.
1939 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1940 ErrorExit("Stdout pipe creation failed\n");
1943 // Create noninheritable read handle and close the inheritable read
1946 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1947 GetCurrentProcess(), &hChildStdoutRdDup , 0,
1949 DUPLICATE_SAME_ACCESS);
1951 ErrorExit("DuplicateHandle failed");
1955 CloseHandle(hChildStdoutRd);
1956 hChildStdoutRd = INVALID_HANDLE_VALUE;
1961 // Create a pipe for the child process's STDIN.
1963 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1964 ErrorExit("Stdin pipe creation failed\n");
1968 // Duplicate the write handle to the pipe so it is not inherited.
1969 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
1970 GetCurrentProcess(), &hChildStdinWrDup,
1972 FALSE, // not inherited
1973 DUPLICATE_SAME_ACCESS);
1975 ErrorExit("DuplicateHandle failed");
1979 CloseHandle(hChildStdinWr);
1980 hChildStdinWr = INVALID_HANDLE_VALUE;
1982 // spawn program with redirected handles as appropriate
1983 bpipe->worker_pid = (pid_t)
1984 CreateChildProcess(prog, // commandline
1985 hChildStdinRd, // stdin HANDLE
1986 hChildStdoutWr, // stdout HANDLE
1987 hChildStdoutWr); // stderr HANDLE
1989 if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1993 bpipe->worker_stime = time(NULL);
1996 CloseHandle(hChildStdoutWr); // close our write side so when
1997 // process terminates we can
1999 // ugly but convert WIN32 HANDLE to FILE*
2000 int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY | O_BINARY);
2002 bpipe->rfd = _fdopen(rfd, "rb");
2006 CloseHandle(hChildStdinRd); // close our read side so as not
2007 // to interfre with child's copy
2008 // ugly but convert WIN32 HANDLE to FILE*
2009 int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY | O_BINARY);
2011 bpipe->wfd = _fdopen(wfd, "wb");
2016 bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
2023 CloseIfValid(hChildStdoutRd);
2024 CloseIfValid(hChildStdoutRdDup);
2025 CloseIfValid(hChildStdinWr);
2026 CloseIfValid(hChildStdinWrDup);
2028 free((void *) bpipe);
2029 errno = b_errno_win32; /* do GetLastError() for error code */
2035 kill(int pid, int signal)
2038 if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
2040 errno = b_errno_win32;
2042 CloseHandle((HANDLE)pid);
2048 close_bpipe(BPIPE *bpipe)
2051 int32_t remaining_wait = bpipe->wait;
2063 if (remaining_wait == 0) { /* wait indefinitely */
2064 remaining_wait = INT32_MAX;
2068 if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
2069 const char *err = errorString();
2070 rval = b_errno_win32;
2071 Dmsg1(0, "GetExitCode error %s\n", err);
2072 LocalFree((void *)err);
2075 if (exitCode == STILL_ACTIVE) {
2076 if (remaining_wait <= 0) {
2077 rval = ETIME; /* timed out */
2080 bmicrosleep(1, 0); /* wait one second */
2082 } else if (exitCode != 0) {
2083 /* Truncate exit code as it doesn't seem to be correct */
2084 rval = (exitCode & 0xFF) | b_errno_exit;
2087 break; /* Shouldn't get here */
2091 if (bpipe->timer_id) {
2092 stop_child_timer(bpipe->timer_id);
2094 if (bpipe->rfd) fclose(bpipe->rfd);
2095 if (bpipe->wfd) fclose(bpipe->wfd);
2096 free((void *)bpipe);
2101 close_wpipe(BPIPE *bpipe)
2107 if (fclose(bpipe->wfd) != 0) {
2115 #include "findlib/find.h"
2118 utime(const char *fname, struct utimbuf *times)
2123 conv_unix_to_win32_path(fname, tmpbuf, 5000);
2125 cvt_utime_to_ftime(times->actime, acc);
2126 cvt_utime_to_ftime(times->modtime, mod);
2128 HANDLE h = INVALID_HANDLE_VALUE;
2130 if (p_CreateFileW) {
2131 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2132 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
2134 h = p_CreateFileW((LPCWSTR)pwszBuf,
2135 FILE_WRITE_ATTRIBUTES,
2136 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2139 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2142 free_pool_memory(pwszBuf);
2143 } else if (p_CreateFileA) {
2144 h = p_CreateFileA(tmpbuf,
2145 FILE_WRITE_ATTRIBUTES,
2146 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2149 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2153 if (h == INVALID_HANDLE_VALUE) {
2154 const char *err = errorString();
2155 Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2156 LocalFree((void *)err);
2157 errno = b_errno_win32;
2161 int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2164 errno = b_errno_win32;
2171 file_open(const char *file, int flags, int mode)
2174 DWORD shareMode = 0;
2177 HANDLE foo = INVALID_HANDLE_VALUE;
2178 const char *remap = file;
2180 if (flags & O_WRONLY) access = GENERIC_WRITE;
2181 else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2182 else access = GENERIC_READ;
2184 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2185 create = CREATE_NEW;
2186 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2187 create = CREATE_ALWAYS;
2188 else if (flags & O_CREAT)
2189 create = OPEN_ALWAYS;
2190 else if (flags & O_TRUNC)
2191 create = TRUNCATE_EXISTING;
2193 create = OPEN_EXISTING;
2197 if (flags & O_APPEND) {
2198 printf("open...APPEND not implemented yet.");
2202 if (p_CreateFileW) {
2203 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2204 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
2206 foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
2207 free_pool_memory(pwszBuf);
2208 } else if (p_CreateFileA)
2209 foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
2211 if (INVALID_HANDLE_VALUE == foo) {
2212 errno = b_errno_win32;
2223 if (!CloseHandle((HANDLE)fd)) {
2224 errno = b_errno_win32;
2232 file_write(int fd, const void *data, ssize_t len)
2236 status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2237 if (status) return bwrite;
2238 errno = b_errno_win32;
2244 file_read(int fd, void *data, ssize_t len)
2249 status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2250 if (status) return bread;
2251 errno = b_errno_win32;
2256 file_seek(int fd, boffset_t offset, int whence)
2260 LONG offset_low = (LONG)offset;
2261 LONG offset_high = (LONG)(offset >> 32);
2265 method = FILE_BEGIN;
2268 method = FILE_CURRENT;
2279 if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
2280 errno = b_errno_win32;
2283 /* ***FIXME*** I doubt this works right */
2296 /* syslog function, added by Nicolas Boichat */
2297 void openlog(const char *ident, int option, int facility) {}