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 /* Forward referenced functions */
62 static const char *errorString(void);
65 void SetVSSPathConvert(t_pVSSPathConvert pPathConvert, t_pVSSPathConvertW pPathConvertW)
67 g_pVSSPathConvert = pPathConvert;
68 g_pVSSPathConvertW = pPathConvertW;
71 void Win32ConvCleanupCache()
73 if (g_pWin32ConvUTF8Cache) {
74 free_pool_memory(g_pWin32ConvUTF8Cache);
75 g_pWin32ConvUTF8Cache = NULL;
78 if (g_pWin32ConvUCS2Cache) {
79 free_pool_memory(g_pWin32ConvUCS2Cache);
80 g_pWin32ConvUCS2Cache = NULL;
83 g_dwWin32ConvUTF8strlen = 0;
87 /* to allow the usage of the original version in this file here */
91 //#define USE_WIN32_COMPAT_IO 1
92 #define USE_WIN32_32KPATHCONVERSION 1
94 extern DWORD g_platform_id;
95 extern DWORD g_MinorVersion;
97 // from MicroSoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970
99 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL
101 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
104 #define WIN32_FILETIME_SCALE 10000000 // 100ns/second
106 void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize)
108 const char *fname = name;
109 char *tname = win32_name;
111 Dmsg0(100, "Enter convert_unix_to_win32_path\n");
113 if (IsPathSeparator(name[0]) &&
114 IsPathSeparator(name[1]) &&
116 IsPathSeparator(name[3])) {
118 *win32_name++ = '\\';
119 *win32_name++ = '\\';
121 *win32_name++ = '\\';
124 } else if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS &&
125 g_pVSSPathConvert == NULL) {
126 /* allow path to be 32767 bytes */
127 *win32_name++ = '\\';
128 *win32_name++ = '\\';
130 *win32_name++ = '\\';
134 /* Check for Unix separator and convert to Win32 */
135 if (name[0] == '/' && name[1] == '/') { /* double slash? */
136 name++; /* yes, skip first one */
139 *win32_name++ = '\\'; /* convert char */
140 /* If Win32 separator that is "quoted", remove quote */
141 } else if (*name == '\\' && name[1] == '\\') {
142 *win32_name++ = '\\';
143 name++; /* skip first \ */
145 *win32_name++ = *name; /* copy character */
149 /* Strip any trailing slash, if we stored something */
150 /* but leave "c:\" with backslash (root directory case */
151 if (*fname != 0 && win32_name[-1] == '\\' && strlen (fname) != 3) {
157 /* here we convert to VSS specific file name which
158 can get longer because VSS will make something like
159 \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
160 from c:\bacula\uninstall.exe
162 Dmsg1(100, "path=%s\n", tname);
163 if (g_pVSSPathConvert != NULL) {
164 POOLMEM *pszBuf = get_pool_memory (PM_FNAME);
165 pszBuf = check_pool_memory_size(pszBuf, dwSize);
166 bstrncpy(pszBuf, tname, strlen(tname)+1);
167 g_pVSSPathConvert(pszBuf, tname, dwSize);
168 free_pool_memory(pszBuf);
171 Dmsg1(100, "Leave cvt_u_to_win32_path path=%s\n", tname);
174 /* Conversion of a Unix filename to a Win32 filename */
175 void unix_name_to_win32(POOLMEM **win32_name, char *name)
177 /* One extra byte should suffice, but we double it */
178 /* add MAX_PATH bytes for VSS shadow copy name */
179 DWORD dwSize = 2*strlen(name)+MAX_PATH;
180 *win32_name = check_pool_memory_size(*win32_name, dwSize);
181 conv_unix_to_win32_path(name, *win32_name, dwSize);
185 make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/)
187 /* created 02/27/2006 Thorsten Engel
189 * This function expects an UCS-encoded standard wchar_t in pszUCSPath and
190 * will complete the input path to an absolue path of the form \\?\c:\path\file
192 * With this trick, it is possible to have 32K characters long paths.
194 * Optionally one can use pBIsRawPath to determine id pszUCSPath contains a path
195 * to a raw windows partition.
198 Dmsg0(100, "Enter wchar_win32_path\n");
200 *pBIsRawPath = FALSE; /* Initialize, set later */
203 if (!p_GetCurrentDirectoryW) {
204 Dmsg0(100, "Leave wchar_win32_path no change \n");
208 wchar_t *name = (wchar_t *)pszUCSPath;
210 /* if it has already the desired form, exit without changes */
211 if (wcslen(name) > 3 && wcsncmp(name, L"\\\\?\\", 4) == 0) {
212 Dmsg0(100, "Leave wchar_win32_path no change \n");
216 wchar_t *pwszBuf = (wchar_t *)get_pool_memory(PM_FNAME);
217 wchar_t *pwszCurDirBuf = (wchar_t *)get_pool_memory(PM_FNAME);
218 DWORD dwCurDirPathSize = 0;
220 /* get buffer with enough size (name+max 6. wchars+1 null terminator */
221 DWORD dwBufCharsNeeded = (wcslen(name)+7);
222 pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
224 /* add \\?\ to support 32K long filepaths
225 it is important to make absolute paths, so we add drive and
226 current path if necessary */
228 BOOL bAddDrive = TRUE;
229 BOOL bAddCurrentPath = TRUE;
230 BOOL bAddPrefix = TRUE;
232 /* does path begin with drive? if yes, it is absolute */
233 if (iswalpha(name[0]) && name[1] == ':' && IsPathSeparator(name[2])) {
235 bAddCurrentPath = FALSE;
238 /* is path absolute? */
239 if (IsPathSeparator(name[0]))
240 bAddCurrentPath = FALSE;
242 /* is path relative to itself?, if yes, skip ./ */
243 if (name[0] == '.' && IsPathSeparator(name[1])) {
247 /* is path of form '//./'? */
248 if (IsPathSeparator(name[0]) &&
249 IsPathSeparator(name[1]) &&
251 IsPathSeparator(name[3])) {
253 bAddCurrentPath = FALSE;
260 int nParseOffset = 0;
262 /* add 4 bytes header */
265 wcscpy(pwszBuf, L"\\\\?\\");
268 /* get current path if needed */
269 if (bAddDrive || bAddCurrentPath) {
270 dwCurDirPathSize = p_GetCurrentDirectoryW(0, NULL);
271 if (dwCurDirPathSize > 0) {
272 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
273 pwszCurDirBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszCurDirBuf, (dwCurDirPathSize+1)*sizeof(wchar_t));
274 p_GetCurrentDirectoryW(dwCurDirPathSize, pwszCurDirBuf);
276 /* we have no info for doing so */
278 bAddCurrentPath = FALSE;
283 /* add drive if needed */
284 if (bAddDrive && !bAddCurrentPath) {
287 if (IsPathSeparator(pwszCurDirBuf[0]) &&
288 IsPathSeparator(pwszCurDirBuf[1]) &&
289 pwszCurDirBuf[2] == '?' &&
290 IsPathSeparator(pwszCurDirBuf[3])) {
291 /* copy drive character */
292 szDrive[0] = pwszCurDirBuf[4];
294 /* copy drive character */
295 szDrive[0] = pwszCurDirBuf[0];
301 wcscat(pwszBuf, szDrive);
305 /* add path if needed */
306 if (bAddCurrentPath) {
307 /* the 1 add. character is for the eventually added backslash */
308 dwBufCharsNeeded += dwCurDirPathSize+1;
309 pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
310 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
312 if (IsPathSeparator(pwszCurDirBuf[0]) &&
313 IsPathSeparator(pwszCurDirBuf[1]) &&
314 pwszCurDirBuf[2] == '?' &&
315 IsPathSeparator(pwszCurDirBuf[3])) {
316 /* copy complete string */
317 wcscpy(pwszBuf, pwszCurDirBuf);
320 wcscat(pwszBuf, pwszCurDirBuf);
323 nParseOffset = wcslen((LPCWSTR) pwszBuf);
325 /* check if path ends with backslash, if not, add one */
326 if (!IsPathSeparator(pwszBuf[nParseOffset-1])) {
327 wcscat(pwszBuf, L"\\");
332 wchar_t *win32_name = &pwszBuf[nParseOffset];
333 wchar_t *name_start = name;
336 /* Check for Unix separator and convert to Win32, eliminating
337 * duplicate separators.
339 if (IsPathSeparator(*name)) {
340 *win32_name++ = '\\'; /* convert char */
342 /* Eliminate consecutive slashes, but not at the start so that
345 if (name_start != name && IsPathSeparator(name[1])) {
349 *win32_name++ = *name; /* copy character */
354 /* null terminate string */
357 /* here we convert to VSS specific file name which
358 * can get longer because VSS will make something like
359 * \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
360 * from c:\bacula\uninstall.exe
362 if (g_pVSSPathConvertW != NULL) {
363 /* is output buffer large enough? */
364 pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf,
365 (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
366 /* create temp. buffer */
367 wchar_t *pszBuf = (wchar_t *)get_pool_memory(PM_FNAME);
368 pszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pszBuf,
369 (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
374 wcsncpy(pszBuf, &pwszBuf[nParseOffset], wcslen(pwszBuf)+1-nParseOffset);
375 g_pVSSPathConvertW(pszBuf, pwszBuf, dwBufCharsNeeded+MAX_PATH);
376 free_pool_memory((POOLMEM *)pszBuf);
379 free_pool_memory(pszUCSPath);
380 free_pool_memory((POOLMEM *)pwszCurDirBuf);
382 Dmsg1(100, "Leave wchar_win32_path=%s\n", pwszBuf);
383 return (POOLMEM *)pwszBuf;
387 wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
389 /* the return value is the number of bytes written to the buffer.
390 The number includes the byte for the null terminator. */
392 if (p_WideCharToMultiByte) {
393 int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
402 UTF8_2_wchar(POOLMEM **ppszUCS, const char *pszUTF)
404 /* the return value is the number of wide characters written to the buffer. */
405 /* convert null terminated string from utf-8 to ucs2, enlarge buffer if necessary */
407 if (p_MultiByteToWideChar) {
408 /* strlen of UTF8 +1 is enough */
409 DWORD cchSize = (strlen(pszUTF)+1);
410 *ppszUCS = check_pool_memory_size(*ppszUCS, cchSize*sizeof (wchar_t));
412 int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
422 wchar_win32_path(const char *name, wchar_t *win32_name)
424 const char *fname = name;
426 /* Check for Unix separator and convert to Win32 */
428 *win32_name++ = '\\'; /* convert char */
429 /* If Win32 separated that is "quoted", remove quote */
430 } else if (*name == '\\' && name[1] == '\\') {
431 *win32_name++ = '\\';
432 name++; /* skip first \ */
434 *win32_name++ = *name; /* copy character */
438 /* Strip any trailing slash, if we stored something */
439 if (*fname != 0 && win32_name[-1] == '\\') {
447 make_win32_path_UTF8_2_wchar(POOLMEM **pszUCS, const char *pszUTF, BOOL* pBIsRawPath /*= NULL*/)
450 /* if we find the utf8 string in cache, we use the cached ucs2 version.
451 we compare the stringlength first (quick check) and then compare the content.
453 if (g_dwWin32ConvUTF8strlen == strlen(pszUTF)) {
454 if (bstrcmp(pszUTF, g_pWin32ConvUTF8Cache)) {
455 int32_t nBufSize = sizeof_pool_memory(g_pWin32ConvUCS2Cache);
456 *pszUCS = check_pool_memory_size(*pszUCS, nBufSize);
457 wcscpy((LPWSTR) *pszUCS, (LPWSTR) g_pWin32ConvUCS2Cache);
459 return nBufSize / sizeof (WCHAR);
463 /* helper to convert from utf-8 to UCS-2 and to complete a path for 32K path syntax */
464 int nRet = UTF8_2_wchar(pszUCS, pszUTF);
466 #ifdef USE_WIN32_32KPATHCONVERSION
467 /* add \\?\ to support 32K long filepaths */
468 *pszUCS = make_wchar_win32_path(*pszUCS, pBIsRawPath);
471 *pBIsRawPath = FALSE;
475 g_pWin32ConvUCS2Cache = check_pool_memory_size(g_pWin32ConvUCS2Cache, sizeof_pool_memory(*pszUCS));
476 wcscpy((LPWSTR) g_pWin32ConvUCS2Cache, (LPWSTR) *pszUCS);
478 g_dwWin32ConvUTF8strlen = strlen(pszUTF);
479 g_pWin32ConvUTF8Cache = check_pool_memory_size(g_pWin32ConvUTF8Cache, g_dwWin32ConvUTF8strlen+1);
480 bstrncpy(g_pWin32ConvUTF8Cache, pszUTF, g_dwWin32ConvUTF8strlen+1);
486 #if !defined(_MSC_VER) || (_MSC_VER < 1400) // VC8+
493 #ifndef LOAD_WITH_ALTERED_SEARCH_PATH
494 #define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008
497 void *dlopen(const char *file, int mode)
501 handle = LoadLibraryEx(file, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
505 void *dlsym(void *handle, const char *name)
508 symaddr = (void *)GetProcAddress((HMODULE)handle, name);
512 int dlclose(void *handle)
514 if (handle && !FreeLibrary((HMODULE)handle)) {
515 errno = b_errno_win32;
516 return 1; /* failed */
523 static char buf[200];
524 const char *err = errorString();
525 bstrncpy(buf, (char *)err, sizeof(buf));
526 LocalFree((void *)err);
530 int fcntl(int fd, int cmd)
535 int chmod(const char *, mode_t)
540 int chown(const char *k, uid_t, gid_t)
545 int lchown(const char *k, uid_t, gid_t)
557 srandom(unsigned int seed)
561 // /////////////////////////////////////////////////////////////////
562 // convert from Windows concept of time to Unix concept of time
563 // /////////////////////////////////////////////////////////////////
565 cvt_utime_to_ftime(const time_t &time, FILETIME &wintime)
567 uint64_t mstime = time;
568 mstime *= WIN32_FILETIME_SCALE;
569 mstime += WIN32_FILETIME_ADJUST;
571 #if defined(_MSC_VER)
572 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
574 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL);
576 wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
580 cvt_ftime_to_utime(const FILETIME &time)
582 uint64_t mstime = time.dwHighDateTime;
584 mstime |= time.dwLowDateTime;
586 mstime -= WIN32_FILETIME_ADJUST;
587 mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
589 return (time_t) (mstime & 0xffffffff);
592 static const char *errorString(void)
596 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
597 FORMAT_MESSAGE_FROM_SYSTEM |
598 FORMAT_MESSAGE_IGNORE_INSERTS,
601 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
606 /* Strip any \r or \n */
607 char *rval = (char *) lpMsgBuf;
608 char *cp = strchr(rval, '\r');
612 cp = strchr(rval, '\n');
621 statDir(const char *file, struct stat *sb)
623 WIN32_FIND_DATAW info_w; // window's file info
624 WIN32_FIND_DATAA info_a; // window's file info
626 // cache some common vars to make code more transparent
627 DWORD *pdwFileAttributes;
628 DWORD *pnFileSizeHigh;
629 DWORD *pnFileSizeLow;
631 FILETIME *pftLastAccessTime;
632 FILETIME *pftLastWriteTime;
633 FILETIME *pftCreationTime;
636 * Oh, cool, another exception: Microsoft doesn't let us do
637 * FindFile operations on a Drive, so simply fake root attibutes.
639 if (file[1] == ':' && file[2] == 0) {
640 time_t now = time(NULL);
641 Dmsg1(99, "faking ROOT attrs(%s).\n", file);
642 sb->st_mode = S_IFDIR;
643 sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
650 HANDLE h = INVALID_HANDLE_VALUE;
653 if (p_FindFirstFileW) {
654 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
655 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
657 h = p_FindFirstFileW((LPCWSTR)pwszBuf, &info_w);
658 free_pool_memory(pwszBuf);
660 pdwFileAttributes = &info_w.dwFileAttributes;
661 pdwReserved0 = &info_w.dwReserved0;
662 pnFileSizeHigh = &info_w.nFileSizeHigh;
663 pnFileSizeLow = &info_w.nFileSizeLow;
664 pftLastAccessTime = &info_w.ftLastAccessTime;
665 pftLastWriteTime = &info_w.ftLastWriteTime;
666 pftCreationTime = &info_w.ftCreationTime;
669 } else if (p_FindFirstFileA) {
670 h = p_FindFirstFileA(file, &info_a);
672 pdwFileAttributes = &info_a.dwFileAttributes;
673 pdwReserved0 = &info_a.dwReserved0;
674 pnFileSizeHigh = &info_a.nFileSizeHigh;
675 pnFileSizeLow = &info_a.nFileSizeLow;
676 pftLastAccessTime = &info_a.ftLastAccessTime;
677 pftLastWriteTime = &info_a.ftLastWriteTime;
678 pftCreationTime = &info_a.ftCreationTime;
681 if (h == INVALID_HANDLE_VALUE) {
682 const char *err = errorString();
683 Dmsg2(99, "FindFirstFile(%s):%s\n", file, err);
684 LocalFree((void *)err);
685 errno = b_errno_win32;
689 sb->st_mode = 0777; /* start with everything */
690 if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
691 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
692 if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
693 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
694 if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
695 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
696 sb->st_mode |= S_IFDIR;
698 /* Use st_rdev to store reparse attribute */
699 sb->st_rdev = (*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0;
700 if (sb->st_rdev == 1 && *pdwReserved0 & IO_REPARSE_TAG_MOUNT_POINT) {
701 sb->st_rdev = 2; /* mount point */
704 sb->st_size = *pnFileSizeHigh;
706 sb->st_size |= *pnFileSizeLow;
707 sb->st_blksize = 4096;
708 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
710 sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
711 sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
712 sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
719 fstat(int fd, struct stat *sb)
721 BY_HANDLE_FILE_INFORMATION info;
724 if (!GetFileInformationByHandle((HANDLE)fd, &info)) {
725 const char *err = errorString();
726 Dmsg2(99, "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
727 LocalFree((void *)err);
728 errno = b_errno_win32;
732 sb->st_dev = info.dwVolumeSerialNumber;
733 sb->st_ino = info.nFileIndexHigh;
735 sb->st_ino |= info.nFileIndexLow;
736 sb->st_nlink = (short)info.nNumberOfLinks;
737 if (sb->st_nlink > 1) {
738 Dmsg1(99, "st_nlink=%d\n", sb->st_nlink);
741 sb->st_mode = 0777; /* start with everything */
742 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
743 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
744 if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
745 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
746 if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
747 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
748 sb->st_mode |= S_IFREG;
750 /* Use st_rdev to store reparse attribute */
751 sb->st_rdev = (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0;
753 sb->st_size = info.nFileSizeHigh;
755 sb->st_size |= info.nFileSizeLow;
756 sb->st_blksize = 4096;
757 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
758 sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
759 sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
760 sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
766 stat2(const char *file, struct stat *sb)
771 conv_unix_to_win32_path(file, tmpbuf, 1024);
773 DWORD attr = (DWORD)-1;
775 if (p_GetFileAttributesW) {
776 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
777 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
779 attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
780 free_pool_memory(pwszBuf);
781 } else if (p_GetFileAttributesA) {
782 attr = p_GetFileAttributesA(tmpbuf);
785 if (attr == (DWORD)-1) {
786 const char *err = errorString();
787 Dmsg2(99, "GetFileAttributes(%s): %s\n", tmpbuf, err);
788 LocalFree((void *)err);
789 errno = b_errno_win32;
793 h = CreateFileA(tmpbuf, GENERIC_READ,
794 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
796 if (h == INVALID_HANDLE_VALUE) {
797 const char *err = errorString();
798 Dmsg2(99, "Cannot open file for stat (%s):%s\n", tmpbuf, err);
799 LocalFree((void *)err);
800 errno = b_errno_win32;
804 rval = fstat((int)h, sb);
807 if (attr & FILE_ATTRIBUTE_DIRECTORY &&
808 file[1] == ':' && file[2] != 0) {
816 stat(const char *file, struct stat *sb)
818 WIN32_FILE_ATTRIBUTE_DATA data;
822 memset(sb, 0, sizeof(*sb));
824 if (p_GetFileAttributesExW) {
825 /* dynamically allocate enough space for UCS2 filename */
826 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
827 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
829 BOOL b = p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, &data);
830 free_pool_memory(pwszBuf);
833 return stat2(file, sb);
835 } else if (p_GetFileAttributesExA) {
836 if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
837 return stat2(file, sb);
840 return stat2(file, sb);
843 sb->st_mode = 0777; /* start with everything */
844 if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
845 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
847 if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
848 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
850 if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
851 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
853 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
854 sb->st_mode |= S_IFDIR;
856 sb->st_mode |= S_IFREG;
859 /* Use st_rdev to store reparse attribute */
860 sb->st_rdev = (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0;
863 sb->st_size = data.nFileSizeHigh;
865 sb->st_size |= data.nFileSizeLow;
866 sb->st_blksize = 4096;
867 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
868 sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
869 sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
870 sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
873 * If we are not at the root, then to distinguish a reparse
874 * point from a mount point, we must call FindFirstFile() to
875 * get the WIN32_FIND_DATA, which has the bit that indicates
876 * that this directory is a mount point -- aren't Win32 APIs
877 * wonderful? (sarcasm). The code exists in the statDir
880 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
881 file[1] == ':' && file[2] != 0) {
888 * We write our own ftruncate because the one in the
889 * Microsoft library mrcrt.dll does not truncate
890 * files greater than 2GB.
893 int win32_ftruncate(int fd, int64_t length)
895 /* Set point we want to truncate file */
896 __int64 pos = _lseeki64(fd, (__int64)length, SEEK_SET);
898 if (pos != (__int64)length) {
899 errno = EACCES; /* truncation failed, get out */
904 if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0) {
905 errno = b_errno_win32;
912 int fcntl(int fd, int cmd, long arg)
935 lstat(const char *file, struct stat *sb)
937 return stat(file, sb);
953 execvp(const char *, char *[]) {
974 waitpid(int, int*, int)
981 readlink(const char *, char *, int)
990 strcasecmp(const char *s1, const char *s2)
992 register int ch1, ch2;
995 return 0; /* strings are equal if same object. */
1005 } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
1012 strncasecmp(const char *s1, const char *s2, int len)
1014 register int ch1 = 0, ch2 = 0;
1017 return 0; /* strings are equal if same object. */
1028 if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
1035 gettimeofday(struct timeval *tv, struct timezone *)
1040 GetSystemTime(&now);
1046 if (!SystemTimeToFileTime(&now, &tmp)) {
1047 errno = b_errno_win32;
1051 int64_t _100nsec = tmp.dwHighDateTime;
1053 _100nsec |= tmp.dwLowDateTime;
1054 _100nsec -= WIN32_FILETIME_ADJUST;
1056 tv->tv_sec = (long)(_100nsec / 10000000);
1057 tv->tv_usec = (long)((_100nsec % 10000000)/10);
1062 /* For apcupsd this is in src/lib/wincompat.c */
1063 extern "C" void syslog(int type, const char *fmt, ...)
1065 /*#ifndef HAVE_CONSOLE
1066 MessageBox(NULL, msg, "Bacula", MB_OK);
1087 // implement opendir/readdir/closedir on top of window's API
1091 WIN32_FIND_DATAA data_a; // window's file info (ansii version)
1092 WIN32_FIND_DATAW data_w; // window's file info (wchar version)
1093 const char *spec; // the directory we're traversing
1094 HANDLE dirh; // the search handle
1095 BOOL valid_a; // the info in data_a field is valid
1096 BOOL valid_w; // the info in data_w field is valid
1097 UINT32 offset; // pseudo offset for d_off
1101 opendir(const char *path)
1103 /* enough space for VSS !*/
1104 int max_len = strlen(path) + MAX_PATH;
1111 Dmsg1(100, "Opendir path=%s\n", path);
1112 rval = (_dir *)malloc(sizeof(_dir));
1113 memset (rval, 0, sizeof (_dir));
1114 if (rval == NULL) return NULL;
1115 char *tspec = (char *)malloc(max_len);
1116 if (tspec == NULL) return NULL;
1118 conv_unix_to_win32_path(path, tspec, max_len);
1119 Dmsg1(100, "win32 path=%s\n", tspec);
1121 // add backslash only if there is none yet (think of c:\)
1122 if (tspec[strlen(tspec)-1] != '\\')
1123 bstrncat(tspec, "\\*", max_len);
1125 bstrncat(tspec, "*", max_len);
1129 // convert to wchar_t
1130 if (p_FindFirstFileW) {
1131 POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
1132 make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec);
1134 rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
1136 free_pool_memory(pwcBuf);
1138 if (rval->dirh != INVALID_HANDLE_VALUE)
1140 } else if (p_FindFirstFileA) {
1141 rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
1143 if (rval->dirh != INVALID_HANDLE_VALUE)
1148 Dmsg3(99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
1149 path, rval->spec, rval->dirh);
1152 if (rval->dirh == INVALID_HANDLE_VALUE)
1155 if (rval->valid_w) {
1156 Dmsg1(99, "\tFirstFile=%s\n", rval->data_w.cFileName);
1159 if (rval->valid_a) {
1160 Dmsg1(99, "\tFirstFile=%s\n", rval->data_a.cFileName);
1166 free((void *)rval->spec);
1168 errno = b_errno_win32;
1175 _dir *dp = (_dir *)dirp;
1176 FindClose(dp->dirh);
1177 free((void *)dp->spec);
1183 typedef struct _WIN32_FIND_DATA {
1184 DWORD dwFileAttributes;
1185 FILETIME ftCreationTime;
1186 FILETIME ftLastAccessTime;
1187 FILETIME ftLastWriteTime;
1188 DWORD nFileSizeHigh;
1192 TCHAR cFileName[MAX_PATH];
1193 TCHAR cAlternateFileName[14];
1194 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1198 copyin(struct dirent &dp, const char *fname)
1202 char *cp = dp.d_name;
1212 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1214 _dir *dp = (_dir *)dirp;
1215 if (dp->valid_w || dp->valid_a) {
1216 entry->d_off = dp->offset;
1220 char szBuf[MAX_PATH_UTF8+1];
1221 wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1222 dp->offset += copyin(*entry, szBuf);
1223 } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1224 dp->offset += copyin(*entry, dp->data_a.cFileName);
1227 *result = entry; /* return entry address */
1228 Dmsg4(99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1229 dirp, entry->d_name, entry->d_reclen, entry->d_off);
1231 // Dmsg0(99, "readdir_r !valid\n");
1232 errno = b_errno_win32;
1236 // get next file, try unicode first
1237 if (p_FindNextFileW)
1238 dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1239 else if (p_FindNextFileA)
1240 dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1242 dp->valid_a = FALSE;
1243 dp->valid_w = FALSE;
1250 * Dotted IP address to network address
1256 inet_aton(const char *a, struct in_addr *inp)
1259 uint32_t acc = 0, tmp = 0;
1262 if (!isdigit(*cp)) { /* first char must be digit */
1263 return 0; /* error */
1267 tmp = (tmp * 10) + (*cp -'0');
1268 } else if (*cp == '.' || *cp == 0) {
1270 return 0; /* error */
1272 acc = (acc << 8) + tmp;
1276 return 0; /* error */
1278 } while (*cp++ != 0);
1279 if (dotc != 4) { /* want 3 .'s plus EOS */
1280 return 0; /* error */
1282 inp->s_addr = htonl(acc); /* store addr in network format */
1287 nanosleep(const struct timespec *req, struct timespec *rem)
1290 rem->tv_sec = rem->tv_nsec = 0;
1291 Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1296 init_signals(void terminate(int sig))
1302 init_stack_dump(void)
1309 pathconf(const char *path, int name)
1313 if (strncmp(path, "\\\\?\\", 4) == 0)
1325 WORD wVersionRequested = MAKEWORD( 1, 1);
1328 int err = WSAStartup(wVersionRequested, &wsaData);
1332 printf("Can not start Windows Sockets\n");
1342 win32_chdir(const char *dir)
1344 if (p_SetCurrentDirectoryW) {
1345 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1346 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1348 BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1350 free_pool_memory(pwszBuf);
1353 errno = b_errno_win32;
1357 else if (p_SetCurrentDirectoryA) {
1358 if (0 == p_SetCurrentDirectoryA(dir)) {
1359 errno = b_errno_win32;
1369 win32_mkdir(const char *dir)
1372 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1373 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1375 int n = p_wmkdir((LPCWSTR)pwszBuf);
1376 free_pool_memory(pwszBuf);
1385 win32_getcwd(char *buf, int maxlen)
1389 if (p_GetCurrentDirectoryW) {
1390 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1391 pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1393 n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1395 n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1396 free_pool_memory(pwszBuf);
1398 } else if (p_GetCurrentDirectoryA)
1399 n = p_GetCurrentDirectoryA(maxlen, buf);
1401 if (n == 0 || n > maxlen) return NULL;
1403 if (n+1 > maxlen) return NULL;
1412 win32_fputs(const char *string, FILE *stream)
1414 /* we use WriteConsoleA / WriteConsoleA
1415 so we can be sure that unicode support works on win32.
1416 with fallback if something fails
1419 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1420 if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1421 p_MultiByteToWideChar && (stream == stdout)) {
1423 POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1425 DWORD dwCharsWritten;
1428 dwChars = UTF8_2_wchar(&pwszBuf, string);
1430 /* try WriteConsoleW */
1431 if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1432 free_pool_memory(pwszBuf);
1433 return dwCharsWritten;
1436 /* convert to local codepage and try WriteConsoleA */
1437 POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1438 pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1440 dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR)pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1441 free_pool_memory(pwszBuf);
1443 if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1444 free_pool_memory(pszBuf);
1445 return dwCharsWritten;
1447 free_pool_memory(pszBuf);
1450 return fputs(string, stream);
1454 win32_cgets (char* buffer, int len)
1456 /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1457 from the win32 console and fallback if seomething fails */
1459 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1460 if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1462 wchar_t wszBuf[1024];
1465 /* nt and unicode conversion */
1466 if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1468 /* null terminate at end */
1469 if (wszBuf[dwRead-1] == L'\n') {
1470 wszBuf[dwRead-1] = L'\0';
1474 if (wszBuf[dwRead-1] == L'\r') {
1475 wszBuf[dwRead-1] = L'\0';
1479 wchar_2_UTF8(buffer, wszBuf, len);
1483 /* win 9x and unicode conversion */
1484 if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1486 /* null terminate at end */
1487 if (szBuf[dwRead-1] == L'\n') {
1488 szBuf[dwRead-1] = L'\0';
1492 if (szBuf[dwRead-1] == L'\r') {
1493 szBuf[dwRead-1] = L'\0';
1497 /* convert from ansii to wchar_t */
1498 p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1499 /* convert from wchar_t to UTF-8 */
1500 if (wchar_2_UTF8(buffer, wszBuf, len))
1506 if (fgets(buffer, len, stdin))
1513 win32_unlink(const char *filename)
1517 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1518 make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1520 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1522 /* special case if file is readonly,
1523 we retry but unset attribute before */
1524 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1525 DWORD dwAttr = p_GetFileAttributesW((LPCWSTR)pwszBuf);
1526 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1527 if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1528 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1529 /* reset to original if it didn't help */
1531 p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1535 free_pool_memory(pwszBuf);
1537 nRetCode = _unlink(filename);
1539 /* special case if file is readonly,
1540 we retry but unset attribute before */
1541 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1542 DWORD dwAttr = p_GetFileAttributesA(filename);
1543 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1544 if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1545 nRetCode = _unlink(filename);
1546 /* reset to original if it didn't help */
1548 p_SetFileAttributesA(filename, dwAttr);
1557 #include "mswinver.h"
1559 char WIN_VERSION_LONG[64];
1560 char WIN_VERSION[32];
1561 char WIN_RAWVERSION[32];
1568 static winver INIT; // cause constructor to be called before main()
1571 winver::winver(void)
1573 const char *version = "";
1574 const char *platform = "";
1575 OSVERSIONINFO osvinfo;
1576 osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1578 // Get the current OS version
1579 if (!GetVersionEx(&osvinfo)) {
1580 version = "Unknown";
1581 platform = "Unknown";
1583 const int ver = _mkversion(osvinfo.dwPlatformId,
1584 osvinfo.dwMajorVersion,
1585 osvinfo.dwMinorVersion);
1586 snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1589 case MS_WINDOWS_95: (version = "Windows 95"); break;
1590 case MS_WINDOWS_98: (version = "Windows 98"); break;
1591 case MS_WINDOWS_ME: (version = "Windows ME"); break;
1592 case MS_WINDOWS_NT4:(version = "Windows NT 4.0"); platform = "NT"; break;
1593 case MS_WINDOWS_2K: (version = "Windows 2000");platform = "NT"; break;
1594 case MS_WINDOWS_XP: (version = "Windows XP");platform = "NT"; break;
1595 case MS_WINDOWS_S2003: (version = "Windows Server 2003");platform = "NT"; break;
1596 default: version = WIN_RAWVERSION; break;
1599 bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1600 snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1601 platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1604 HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1608 BPIPE *b = open_bpipe("ls -l", 10, "r");
1610 while (!feof(b->rfd)) {
1611 fgets(buf, sizeof(buf), b->rfd);
1617 BOOL CreateChildProcess(VOID);
1618 VOID WriteToPipe(VOID);
1619 VOID ReadFromPipe(VOID);
1620 VOID ErrorExit(LPCSTR);
1621 VOID ErrMsg(LPTSTR, BOOL);
1624 * Check for a quoted path, if an absolute path name is given and it contains
1625 * spaces it will need to be quoted. i.e. "c:/Program Files/foo/bar.exe"
1626 * CreateProcess() says the best way to ensure proper results with executables
1627 * with spaces in path or filename is to quote the string.
1630 getArgv0(const char *cmdline)
1635 for (cp = cmdline; *cp; cp++)
1640 if (!inquote && isspace(*cp))
1645 int len = cp - cmdline;
1646 char *rval = (char *)malloc(len+1);
1659 * Extracts the executable or script name from the first string in
1662 * If the name contains blanks then it must be quoted with double quotes,
1663 * otherwise quotes are optional. If the name contains blanks then it
1664 * will be converted to a short name.
1666 * The optional quotes will be removed. The result is copied to a malloc'ed
1667 * buffer and returned through the pexe argument. The pargs parameter is set
1668 * to the address of the character in cmdline located after the name.
1670 * The malloc'ed buffer returned in *pexe must be freed by the caller.
1673 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1675 const char *pExeStart = NULL; /* Start of executable name in cmdline */
1676 const char *pExeEnd = NULL; /* Character after executable name (separator) */
1678 const char *pBasename = NULL; /* Character after last path separator */
1679 const char *pExtension = NULL; /* Period at start of extension */
1681 const char *current = cmdline;
1683 bool bQuoted = false;
1685 /* Skip initial whitespace */
1687 while (*current == ' ' || *current == '\t')
1692 /* Calculate start of name and determine if quoted */
1694 if (*current == '"') {
1695 pExeStart = ++current;
1698 pExeStart = current;
1706 * Scan command line looking for path separators (/ and \\) and the
1707 * terminator, either a quote or a blank. The location of the
1708 * extension is also noted.
1711 for ( ; *current != '\0'; current++)
1713 if (*current == '.') {
1714 pExtension = current;
1715 } else if (IsPathSeparator(*current) && current[1] != '\0') {
1716 pBasename = ¤t[1];
1720 /* Check for terminator, either quote or blank */
1722 if (*current != '"') {
1726 if (*current != ' ') {
1732 * Hit terminator, remember end of name (address of terminator) and
1733 * start of arguments
1737 if (bQuoted && *current == '"') {
1738 *pargs = ¤t[1];
1746 if (pBasename == NULL) {
1747 pBasename = pExeStart;
1750 if (pExeEnd == NULL) {
1759 bool bHasPathSeparators = pExeStart != pBasename;
1761 /* We have pointers to all the useful parts of the name */
1763 /* Default extensions in the order cmd.exe uses to search */
1765 static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
1766 DWORD dwBasePathLength = pExeEnd - pExeStart;
1768 DWORD dwAltNameLength = 0;
1769 char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1770 char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1772 pPathname[MAX_PATHLENGTH] = '\0';
1773 pAltPathname[MAX_PATHLENGTH] = '\0';
1775 memcpy(pPathname, pExeStart, dwBasePathLength);
1776 pPathname[dwBasePathLength] = '\0';
1778 if (pExtension == NULL) {
1779 /* Try appending extensions */
1780 for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
1782 if (!bHasPathSeparators) {
1783 /* There are no path separators, search in the standard locations */
1784 dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
1785 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1786 memcpy(pPathname, pAltPathname, dwAltNameLength);
1787 pPathname[dwAltNameLength] = '\0';
1791 bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
1792 if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) {
1795 pPathname[dwBasePathLength] = '\0';
1798 } else if (!bHasPathSeparators) {
1799 /* There are no path separators, search in the standard locations */
1800 dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
1801 if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) {
1802 memcpy(pPathname, pAltPathname, dwAltNameLength);
1803 pPathname[dwAltNameLength] = '\0';
1807 if (strchr(pPathname, ' ') != NULL) {
1808 dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH);
1810 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1811 *pexe = (char *)malloc(dwAltNameLength + 1);
1812 if (*pexe == NULL) {
1815 memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
1819 if (*pexe == NULL) {
1820 DWORD dwPathnameLength = strlen(pPathname);
1821 *pexe = (char *)malloc(dwPathnameLength + 1);
1822 if (*pexe == NULL) {
1825 memcpy(*pexe, pPathname, dwPathnameLength + 1);
1832 * OK, so it would seem CreateProcess only handles true executables:
1833 * .com or .exe files. So grab $COMSPEC value and pass command line to it.
1836 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1838 static const char *comspec = NULL;
1839 PROCESS_INFORMATION piProcInfo;
1840 STARTUPINFOA siStartInfo;
1841 BOOL bFuncRetn = FALSE;
1843 if (comspec == NULL) {
1844 comspec = getenv("COMSPEC");
1846 if (comspec == NULL) // should never happen
1847 return INVALID_HANDLE_VALUE;
1849 // Set up members of the PROCESS_INFORMATION structure.
1850 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1852 // Set up members of the STARTUPINFO structure.
1854 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1855 siStartInfo.cb = sizeof(STARTUPINFO);
1856 // setup new process to use supplied handles for stdin,stdout,stderr
1857 // if supplied handles are not used the send a copy of our STD_HANDLE
1859 siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1860 siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
1862 if (in != INVALID_HANDLE_VALUE)
1863 siStartInfo.hStdInput = in;
1865 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1867 if (out != INVALID_HANDLE_VALUE)
1868 siStartInfo.hStdOutput = out;
1870 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1871 if (err != INVALID_HANDLE_VALUE)
1872 siStartInfo.hStdError = err;
1874 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1876 // Create the child process.
1879 const char *argStart;
1881 if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
1882 return INVALID_HANDLE_VALUE;
1885 int cmdLen = strlen(comspec) + 4 + strlen(exeFile) + strlen(argStart) + 1;
1887 char *cmdLine = (char *)alloca(cmdLen);
1889 snprintf(cmdLine, cmdLen, "%s /c %s%s", comspec, exeFile, argStart);
1893 Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
1895 // try to execute program
1896 bFuncRetn = CreateProcessA(comspec,
1897 cmdLine, // command line
1898 NULL, // process security attributes
1899 NULL, // primary thread security attributes
1900 TRUE, // handles are inherited
1901 0, // creation flags
1902 NULL, // use parent's environment
1903 NULL, // use parent's current directory
1904 &siStartInfo, // STARTUPINFO pointer
1905 &piProcInfo); // receives PROCESS_INFORMATION
1907 if (bFuncRetn == 0) {
1908 ErrorExit("CreateProcess failed\n");
1909 const char *err = errorString();
1910 Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n", comspec, cmdLine, err);
1911 LocalFree((void *)err);
1912 return INVALID_HANDLE_VALUE;
1914 // we don't need a handle on the process primary thread so we close
1916 CloseHandle(piProcInfo.hThread);
1918 return piProcInfo.hProcess;
1923 ErrorExit (LPCSTR lpszMessage)
1925 Dmsg1(0, "%s", lpszMessage);
1930 typedef struct s_bpipe {
1932 time_t worker_stime;
1941 CloseIfValid(HANDLE handle)
1943 if (handle != INVALID_HANDLE_VALUE)
1944 CloseHandle(handle);
1948 open_bpipe(char *prog, int wait, const char *mode)
1950 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1951 hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1954 SECURITY_ATTRIBUTES saAttr;
1958 hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1959 hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1960 hInputFile = INVALID_HANDLE_VALUE;
1962 BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1963 memset((void *)bpipe, 0, sizeof(BPIPE));
1965 int mode_read = (mode[0] == 'r');
1966 int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1969 // Set the bInheritHandle flag so pipe handles are inherited.
1971 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1972 saAttr.bInheritHandle = TRUE;
1973 saAttr.lpSecurityDescriptor = NULL;
1977 // Create a pipe for the child process's STDOUT.
1978 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1979 ErrorExit("Stdout pipe creation failed\n");
1982 // Create noninheritable read handle and close the inheritable read
1985 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1986 GetCurrentProcess(), &hChildStdoutRdDup , 0,
1988 DUPLICATE_SAME_ACCESS);
1990 ErrorExit("DuplicateHandle failed");
1994 CloseHandle(hChildStdoutRd);
1995 hChildStdoutRd = INVALID_HANDLE_VALUE;
2000 // Create a pipe for the child process's STDIN.
2002 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
2003 ErrorExit("Stdin pipe creation failed\n");
2007 // Duplicate the write handle to the pipe so it is not inherited.
2008 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
2009 GetCurrentProcess(), &hChildStdinWrDup,
2011 FALSE, // not inherited
2012 DUPLICATE_SAME_ACCESS);
2014 ErrorExit("DuplicateHandle failed");
2018 CloseHandle(hChildStdinWr);
2019 hChildStdinWr = INVALID_HANDLE_VALUE;
2021 // spawn program with redirected handles as appropriate
2022 bpipe->worker_pid = (pid_t)
2023 CreateChildProcess(prog, // commandline
2024 hChildStdinRd, // stdin HANDLE
2025 hChildStdoutWr, // stdout HANDLE
2026 hChildStdoutWr); // stderr HANDLE
2028 if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
2032 bpipe->worker_stime = time(NULL);
2035 CloseHandle(hChildStdoutWr); // close our write side so when
2036 // process terminates we can
2038 // ugly but convert WIN32 HANDLE to FILE*
2039 int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY | O_BINARY);
2041 bpipe->rfd = _fdopen(rfd, "rb");
2045 CloseHandle(hChildStdinRd); // close our read side so as not
2046 // to interfre with child's copy
2047 // ugly but convert WIN32 HANDLE to FILE*
2048 int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY | O_BINARY);
2050 bpipe->wfd = _fdopen(wfd, "wb");
2055 bpipe->timer_id = start_child_timer(NULL, bpipe->worker_pid, wait);
2062 CloseIfValid(hChildStdoutRd);
2063 CloseIfValid(hChildStdoutRdDup);
2064 CloseIfValid(hChildStdinWr);
2065 CloseIfValid(hChildStdinWrDup);
2067 free((void *) bpipe);
2068 errno = b_errno_win32; /* do GetLastError() for error code */
2074 kill(int pid, int signal)
2077 if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
2079 errno = b_errno_win32;
2081 CloseHandle((HANDLE)pid);
2087 close_bpipe(BPIPE *bpipe)
2090 int32_t remaining_wait = bpipe->wait;
2102 if (remaining_wait == 0) { /* wait indefinitely */
2103 remaining_wait = INT32_MAX;
2107 if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
2108 const char *err = errorString();
2109 rval = b_errno_win32;
2110 Dmsg1(0, "GetExitCode error %s\n", err);
2111 LocalFree((void *)err);
2114 if (exitCode == STILL_ACTIVE) {
2115 if (remaining_wait <= 0) {
2116 rval = ETIME; /* timed out */
2119 bmicrosleep(1, 0); /* wait one second */
2121 } else if (exitCode != 0) {
2122 /* Truncate exit code as it doesn't seem to be correct */
2123 rval = (exitCode & 0xFF) | b_errno_exit;
2126 break; /* Shouldn't get here */
2130 if (bpipe->timer_id) {
2131 stop_child_timer(bpipe->timer_id);
2133 if (bpipe->rfd) fclose(bpipe->rfd);
2134 if (bpipe->wfd) fclose(bpipe->wfd);
2135 free((void *)bpipe);
2140 close_wpipe(BPIPE *bpipe)
2146 if (fclose(bpipe->wfd) != 0) {
2154 #include "findlib/find.h"
2157 utime(const char *fname, struct utimbuf *times)
2162 conv_unix_to_win32_path(fname, tmpbuf, 5000);
2164 cvt_utime_to_ftime(times->actime, acc);
2165 cvt_utime_to_ftime(times->modtime, mod);
2167 HANDLE h = INVALID_HANDLE_VALUE;
2169 if (p_CreateFileW) {
2170 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2171 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
2173 h = p_CreateFileW((LPCWSTR)pwszBuf,
2174 FILE_WRITE_ATTRIBUTES,
2175 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2178 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2181 free_pool_memory(pwszBuf);
2182 } else if (p_CreateFileA) {
2183 h = p_CreateFileA(tmpbuf,
2184 FILE_WRITE_ATTRIBUTES,
2185 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2188 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2192 if (h == INVALID_HANDLE_VALUE) {
2193 const char *err = errorString();
2194 Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2195 LocalFree((void *)err);
2196 errno = b_errno_win32;
2200 int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2203 errno = b_errno_win32;
2210 file_open(const char *file, int flags, int mode)
2213 DWORD shareMode = 0;
2216 HANDLE foo = INVALID_HANDLE_VALUE;
2217 const char *remap = file;
2219 if (flags & O_WRONLY) access = GENERIC_WRITE;
2220 else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2221 else access = GENERIC_READ;
2223 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2224 create = CREATE_NEW;
2225 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2226 create = CREATE_ALWAYS;
2227 else if (flags & O_CREAT)
2228 create = OPEN_ALWAYS;
2229 else if (flags & O_TRUNC)
2230 create = TRUNCATE_EXISTING;
2232 create = OPEN_EXISTING;
2236 if (flags & O_APPEND) {
2237 printf("open...APPEND not implemented yet.");
2241 if (p_CreateFileW) {
2242 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2243 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
2245 foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
2246 free_pool_memory(pwszBuf);
2247 } else if (p_CreateFileA)
2248 foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
2250 if (INVALID_HANDLE_VALUE == foo) {
2251 errno = b_errno_win32;
2262 if (!CloseHandle((HANDLE)fd)) {
2263 errno = b_errno_win32;
2271 file_write(int fd, const void *data, ssize_t len)
2275 status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2276 if (status) return bwrite;
2277 errno = b_errno_win32;
2283 file_read(int fd, void *data, ssize_t len)
2288 status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2289 if (status) return bread;
2290 errno = b_errno_win32;
2295 file_seek(int fd, boffset_t offset, int whence)
2299 LONG offset_low = (LONG)offset;
2300 LONG offset_high = (LONG)(offset >> 32);
2304 method = FILE_BEGIN;
2307 method = FILE_CURRENT;
2318 if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
2319 errno = b_errno_win32;
2322 /* ***FIXME*** I doubt this works right */
2335 /* syslog function, added by Nicolas Boichat */
2336 void openlog(const char *ident, int option, int facility) {}