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 return statDir(file, sb);
776 stat(const char *file, struct stat *sb)
778 WIN32_FILE_ATTRIBUTE_DATA data;
782 memset(sb, 0, sizeof(*sb));
784 if (p_GetFileAttributesExW) {
785 /* dynamically allocate enough space for UCS2 filename */
786 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
787 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
789 BOOL b = p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, &data);
790 free_pool_memory(pwszBuf);
793 return stat2(file, sb);
795 } else if (p_GetFileAttributesExA) {
796 if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
797 return stat2(file, sb);
800 return stat2(file, sb);
803 sb->st_mode = 0777; /* start with everything */
804 if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
805 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
807 if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
808 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
810 if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
811 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
813 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
814 sb->st_mode |= S_IFDIR;
816 sb->st_mode |= S_IFREG;
819 /* Use st_rdev to store reparse attribute */
820 sb->st_rdev = (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0;
823 sb->st_size = data.nFileSizeHigh;
825 sb->st_size |= data.nFileSizeLow;
826 sb->st_blksize = 4096;
827 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
828 sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
829 sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
830 sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
833 * If we are not at the root, then to distinguish a reparse
834 * point from a mount point, we must call FindFirstFile() to
835 * get the WIN32_FIND_DATA, which has the bit that indicates
836 * that this directory is a mount point -- aren't Win32 APIs
837 * wonderful? (sarcasm). The code exists in the statDir
840 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
841 file[1] == ':' && file[2] != 0) {
842 return statDir(file, sb);
848 * We write our own ftruncate because the one in the
849 * Microsoft library mrcrt.dll does not truncate
850 * files greater than 2GB.
853 int win32_ftruncate(int fd, int64_t length)
855 /* Set point we want to truncate file */
856 __int64 pos = _lseeki64(fd, (__int64)length, SEEK_SET);
858 if (pos != (__int64)length) {
859 errno = EACCES; /* truncation failed, get out */
864 if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0) {
865 errno = b_errno_win32;
872 int fcntl(int fd, int cmd, long arg)
895 lstat(const char *file, struct stat *sb)
897 return stat(file, sb);
913 execvp(const char *, char *[]) {
934 waitpid(int, int*, int)
941 readlink(const char *, char *, int)
950 strcasecmp(const char *s1, const char *s2)
952 register int ch1, ch2;
955 return 0; /* strings are equal if same object. */
965 } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
972 strncasecmp(const char *s1, const char *s2, int len)
974 register int ch1 = 0, ch2 = 0;
977 return 0; /* strings are equal if same object. */
988 if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
995 gettimeofday(struct timeval *tv, struct timezone *)
1000 GetSystemTime(&now);
1006 if (!SystemTimeToFileTime(&now, &tmp)) {
1007 errno = b_errno_win32;
1011 int64_t _100nsec = tmp.dwHighDateTime;
1013 _100nsec |= tmp.dwLowDateTime;
1014 _100nsec -= WIN32_FILETIME_ADJUST;
1016 tv->tv_sec = (long)(_100nsec / 10000000);
1017 tv->tv_usec = (long)((_100nsec % 10000000)/10);
1022 /* For apcupsd this is in src/lib/wincompat.c */
1023 extern "C" void syslog(int type, const char *fmt, ...)
1025 /*#ifndef HAVE_CONSOLE
1026 MessageBox(NULL, msg, "Bacula", MB_OK);
1047 // implement opendir/readdir/closedir on top of window's API
1051 WIN32_FIND_DATAA data_a; // window's file info (ansii version)
1052 WIN32_FIND_DATAW data_w; // window's file info (wchar version)
1053 const char *spec; // the directory we're traversing
1054 HANDLE dirh; // the search handle
1055 BOOL valid_a; // the info in data_a field is valid
1056 BOOL valid_w; // the info in data_w field is valid
1057 UINT32 offset; // pseudo offset for d_off
1061 opendir(const char *path)
1063 /* enough space for VSS !*/
1064 int max_len = strlen(path) + MAX_PATH;
1071 Dmsg1(100, "Opendir path=%s\n", path);
1072 rval = (_dir *)malloc(sizeof(_dir));
1073 memset (rval, 0, sizeof (_dir));
1074 if (rval == NULL) return NULL;
1075 char *tspec = (char *)malloc(max_len);
1076 if (tspec == NULL) return NULL;
1078 conv_unix_to_win32_path(path, tspec, max_len);
1079 Dmsg1(100, "win32 path=%s\n", tspec);
1081 // add backslash only if there is none yet (think of c:\)
1082 if (tspec[strlen(tspec)-1] != '\\')
1083 bstrncat(tspec, "\\*", max_len);
1085 bstrncat(tspec, "*", max_len);
1089 // convert to wchar_t
1090 if (p_FindFirstFileW) {
1091 POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
1092 make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec);
1094 rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
1096 free_pool_memory(pwcBuf);
1098 if (rval->dirh != INVALID_HANDLE_VALUE)
1100 } else if (p_FindFirstFileA) {
1101 rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
1103 if (rval->dirh != INVALID_HANDLE_VALUE)
1108 Dmsg3(99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
1109 path, rval->spec, rval->dirh);
1112 if (rval->dirh == INVALID_HANDLE_VALUE)
1115 if (rval->valid_w) {
1116 Dmsg1(99, "\tFirstFile=%s\n", rval->data_w.cFileName);
1119 if (rval->valid_a) {
1120 Dmsg1(99, "\tFirstFile=%s\n", rval->data_a.cFileName);
1126 free((void *)rval->spec);
1128 errno = b_errno_win32;
1135 _dir *dp = (_dir *)dirp;
1136 FindClose(dp->dirh);
1137 free((void *)dp->spec);
1143 typedef struct _WIN32_FIND_DATA {
1144 DWORD dwFileAttributes;
1145 FILETIME ftCreationTime;
1146 FILETIME ftLastAccessTime;
1147 FILETIME ftLastWriteTime;
1148 DWORD nFileSizeHigh;
1152 TCHAR cFileName[MAX_PATH];
1153 TCHAR cAlternateFileName[14];
1154 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1158 copyin(struct dirent &dp, const char *fname)
1162 char *cp = dp.d_name;
1172 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1174 _dir *dp = (_dir *)dirp;
1175 if (dp->valid_w || dp->valid_a) {
1176 entry->d_off = dp->offset;
1180 char szBuf[MAX_PATH_UTF8+1];
1181 wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1182 dp->offset += copyin(*entry, szBuf);
1183 } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1184 dp->offset += copyin(*entry, dp->data_a.cFileName);
1187 *result = entry; /* return entry address */
1188 Dmsg4(99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1189 dirp, entry->d_name, entry->d_reclen, entry->d_off);
1191 // Dmsg0(99, "readdir_r !valid\n");
1192 errno = b_errno_win32;
1196 // get next file, try unicode first
1197 if (p_FindNextFileW)
1198 dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1199 else if (p_FindNextFileA)
1200 dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1202 dp->valid_a = FALSE;
1203 dp->valid_w = FALSE;
1210 * Dotted IP address to network address
1216 inet_aton(const char *a, struct in_addr *inp)
1219 uint32_t acc = 0, tmp = 0;
1222 if (!isdigit(*cp)) { /* first char must be digit */
1223 return 0; /* error */
1227 tmp = (tmp * 10) + (*cp -'0');
1228 } else if (*cp == '.' || *cp == 0) {
1230 return 0; /* error */
1232 acc = (acc << 8) + tmp;
1236 return 0; /* error */
1238 } while (*cp++ != 0);
1239 if (dotc != 4) { /* want 3 .'s plus EOS */
1240 return 0; /* error */
1242 inp->s_addr = htonl(acc); /* store addr in network format */
1247 nanosleep(const struct timespec *req, struct timespec *rem)
1250 rem->tv_sec = rem->tv_nsec = 0;
1251 Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1256 init_signals(void terminate(int sig))
1262 init_stack_dump(void)
1269 pathconf(const char *path, int name)
1273 if (strncmp(path, "\\\\?\\", 4) == 0)
1285 WORD wVersionRequested = MAKEWORD( 1, 1);
1288 int err = WSAStartup(wVersionRequested, &wsaData);
1292 printf("Can not start Windows Sockets\n");
1302 win32_chdir(const char *dir)
1304 if (p_SetCurrentDirectoryW) {
1305 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1306 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1308 BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1310 free_pool_memory(pwszBuf);
1313 errno = b_errno_win32;
1317 else if (p_SetCurrentDirectoryA) {
1318 if (0 == p_SetCurrentDirectoryA(dir)) {
1319 errno = b_errno_win32;
1329 win32_mkdir(const char *dir)
1332 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1333 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1335 int n = p_wmkdir((LPCWSTR)pwszBuf);
1336 free_pool_memory(pwszBuf);
1345 win32_getcwd(char *buf, int maxlen)
1349 if (p_GetCurrentDirectoryW) {
1350 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1351 pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1353 n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1355 n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1356 free_pool_memory(pwszBuf);
1358 } else if (p_GetCurrentDirectoryA)
1359 n = p_GetCurrentDirectoryA(maxlen, buf);
1361 if (n == 0 || n > maxlen) return NULL;
1363 if (n+1 > maxlen) return NULL;
1372 win32_fputs(const char *string, FILE *stream)
1374 /* we use WriteConsoleA / WriteConsoleA
1375 so we can be sure that unicode support works on win32.
1376 with fallback if something fails
1379 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1380 if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1381 p_MultiByteToWideChar && (stream == stdout)) {
1383 POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1385 DWORD dwCharsWritten;
1388 dwChars = UTF8_2_wchar(&pwszBuf, string);
1390 /* try WriteConsoleW */
1391 if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1392 free_pool_memory(pwszBuf);
1393 return dwCharsWritten;
1396 /* convert to local codepage and try WriteConsoleA */
1397 POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1398 pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1400 dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR)pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1401 free_pool_memory(pwszBuf);
1403 if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1404 free_pool_memory(pszBuf);
1405 return dwCharsWritten;
1407 free_pool_memory(pszBuf);
1410 return fputs(string, stream);
1414 win32_cgets (char* buffer, int len)
1416 /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1417 from the win32 console and fallback if seomething fails */
1419 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1420 if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1422 wchar_t wszBuf[1024];
1425 /* nt and unicode conversion */
1426 if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1428 /* null terminate at end */
1429 if (wszBuf[dwRead-1] == L'\n') {
1430 wszBuf[dwRead-1] = L'\0';
1434 if (wszBuf[dwRead-1] == L'\r') {
1435 wszBuf[dwRead-1] = L'\0';
1439 wchar_2_UTF8(buffer, wszBuf, len);
1443 /* win 9x and unicode conversion */
1444 if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1446 /* null terminate at end */
1447 if (szBuf[dwRead-1] == L'\n') {
1448 szBuf[dwRead-1] = L'\0';
1452 if (szBuf[dwRead-1] == L'\r') {
1453 szBuf[dwRead-1] = L'\0';
1457 /* convert from ansii to wchar_t */
1458 p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1459 /* convert from wchar_t to UTF-8 */
1460 if (wchar_2_UTF8(buffer, wszBuf, len))
1466 if (fgets(buffer, len, stdin))
1473 win32_unlink(const char *filename)
1477 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1478 make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1480 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1482 /* special case if file is readonly,
1483 we retry but unset attribute before */
1484 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1485 DWORD dwAttr = p_GetFileAttributesW((LPCWSTR)pwszBuf);
1486 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1487 if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1488 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1489 /* reset to original if it didn't help */
1491 p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1495 free_pool_memory(pwszBuf);
1497 nRetCode = _unlink(filename);
1499 /* special case if file is readonly,
1500 we retry but unset attribute before */
1501 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1502 DWORD dwAttr = p_GetFileAttributesA(filename);
1503 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1504 if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1505 nRetCode = _unlink(filename);
1506 /* reset to original if it didn't help */
1508 p_SetFileAttributesA(filename, dwAttr);
1517 #include "mswinver.h"
1519 char WIN_VERSION_LONG[64];
1520 char WIN_VERSION[32];
1521 char WIN_RAWVERSION[32];
1528 static winver INIT; // cause constructor to be called before main()
1531 winver::winver(void)
1533 const char *version = "";
1534 const char *platform = "";
1535 OSVERSIONINFO osvinfo;
1536 osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1538 // Get the current OS version
1539 if (!GetVersionEx(&osvinfo)) {
1540 version = "Unknown";
1541 platform = "Unknown";
1543 const int ver = _mkversion(osvinfo.dwPlatformId,
1544 osvinfo.dwMajorVersion,
1545 osvinfo.dwMinorVersion);
1546 snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1549 case MS_WINDOWS_95: (version = "Windows 95"); break;
1550 case MS_WINDOWS_98: (version = "Windows 98"); break;
1551 case MS_WINDOWS_ME: (version = "Windows ME"); break;
1552 case MS_WINDOWS_NT4:(version = "Windows NT 4.0"); platform = "NT"; break;
1553 case MS_WINDOWS_2K: (version = "Windows 2000");platform = "NT"; break;
1554 case MS_WINDOWS_XP: (version = "Windows XP");platform = "NT"; break;
1555 case MS_WINDOWS_S2003: (version = "Windows Server 2003");platform = "NT"; break;
1556 default: version = WIN_RAWVERSION; break;
1559 bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1560 snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1561 platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1564 HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1568 BPIPE *b = open_bpipe("ls -l", 10, "r");
1570 while (!feof(b->rfd)) {
1571 fgets(buf, sizeof(buf), b->rfd);
1577 BOOL CreateChildProcess(VOID);
1578 VOID WriteToPipe(VOID);
1579 VOID ReadFromPipe(VOID);
1580 VOID ErrorExit(LPCSTR);
1581 VOID ErrMsg(LPTSTR, BOOL);
1584 * Check for a quoted path, if an absolute path name is given and it contains
1585 * spaces it will need to be quoted. i.e. "c:/Program Files/foo/bar.exe"
1586 * CreateProcess() says the best way to ensure proper results with executables
1587 * with spaces in path or filename is to quote the string.
1590 getArgv0(const char *cmdline)
1595 for (cp = cmdline; *cp; cp++)
1600 if (!inquote && isspace(*cp))
1605 int len = cp - cmdline;
1606 char *rval = (char *)malloc(len+1);
1619 * Extracts the executable or script name from the first string in
1622 * If the name contains blanks then it must be quoted with double quotes,
1623 * otherwise quotes are optional. If the name contains blanks then it
1624 * will be converted to a short name.
1626 * The optional quotes will be removed. The result is copied to a malloc'ed
1627 * buffer and returned through the pexe argument. The pargs parameter is set
1628 * to the address of the character in cmdline located after the name.
1630 * The malloc'ed buffer returned in *pexe must be freed by the caller.
1633 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1635 const char *pExeStart = NULL; /* Start of executable name in cmdline */
1636 const char *pExeEnd = NULL; /* Character after executable name (separator) */
1638 const char *pBasename = NULL; /* Character after last path separator */
1639 const char *pExtension = NULL; /* Period at start of extension */
1641 const char *current = cmdline;
1643 bool bQuoted = false;
1645 /* Skip initial whitespace */
1647 while (*current == ' ' || *current == '\t')
1652 /* Calculate start of name and determine if quoted */
1654 if (*current == '"') {
1655 pExeStart = ++current;
1658 pExeStart = current;
1666 * Scan command line looking for path separators (/ and \\) and the
1667 * terminator, either a quote or a blank. The location of the
1668 * extension is also noted.
1671 for ( ; *current != '\0'; current++)
1673 if (*current == '.') {
1674 pExtension = current;
1675 } else if (IsPathSeparator(*current) && current[1] != '\0') {
1676 pBasename = ¤t[1];
1680 /* Check for terminator, either quote or blank */
1682 if (*current != '"') {
1686 if (*current != ' ') {
1692 * Hit terminator, remember end of name (address of terminator) and
1693 * start of arguments
1697 if (bQuoted && *current == '"') {
1698 *pargs = ¤t[1];
1706 if (pBasename == NULL) {
1707 pBasename = pExeStart;
1710 if (pExeEnd == NULL) {
1719 bool bHasPathSeparators = pExeStart != pBasename;
1721 /* We have pointers to all the useful parts of the name */
1723 /* Default extensions in the order cmd.exe uses to search */
1725 static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
1726 DWORD dwBasePathLength = pExeEnd - pExeStart;
1728 DWORD dwAltNameLength = 0;
1729 char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1730 char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1732 pPathname[MAX_PATHLENGTH] = '\0';
1733 pAltPathname[MAX_PATHLENGTH] = '\0';
1735 memcpy(pPathname, pExeStart, dwBasePathLength);
1736 pPathname[dwBasePathLength] = '\0';
1738 if (pExtension == NULL) {
1739 /* Try appending extensions */
1740 for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
1742 if (!bHasPathSeparators) {
1743 /* There are no path separators, search in the standard locations */
1744 dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
1745 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1746 memcpy(pPathname, pAltPathname, dwAltNameLength);
1747 pPathname[dwAltNameLength] = '\0';
1751 bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
1752 if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) {
1755 pPathname[dwBasePathLength] = '\0';
1758 } else if (!bHasPathSeparators) {
1759 /* There are no path separators, search in the standard locations */
1760 dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
1761 if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) {
1762 memcpy(pPathname, pAltPathname, dwAltNameLength);
1763 pPathname[dwAltNameLength] = '\0';
1767 if (strchr(pPathname, ' ') != NULL) {
1768 dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH);
1770 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1771 *pexe = (char *)malloc(dwAltNameLength + 1);
1772 if (*pexe == NULL) {
1775 memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
1779 if (*pexe == NULL) {
1780 DWORD dwPathnameLength = strlen(pPathname);
1781 *pexe = (char *)malloc(dwPathnameLength + 1);
1782 if (*pexe == NULL) {
1785 memcpy(*pexe, pPathname, dwPathnameLength + 1);
1792 * OK, so it would seem CreateProcess only handles true executables:
1793 * .com or .exe files. So grab $COMSPEC value and pass command line to it.
1796 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1798 static const char *comspec = NULL;
1799 PROCESS_INFORMATION piProcInfo;
1800 STARTUPINFOA siStartInfo;
1801 BOOL bFuncRetn = FALSE;
1803 if (comspec == NULL) {
1804 comspec = getenv("COMSPEC");
1806 if (comspec == NULL) // should never happen
1807 return INVALID_HANDLE_VALUE;
1809 // Set up members of the PROCESS_INFORMATION structure.
1810 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1812 // Set up members of the STARTUPINFO structure.
1814 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1815 siStartInfo.cb = sizeof(STARTUPINFO);
1816 // setup new process to use supplied handles for stdin,stdout,stderr
1817 // if supplied handles are not used the send a copy of our STD_HANDLE
1819 siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1820 siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
1822 if (in != INVALID_HANDLE_VALUE)
1823 siStartInfo.hStdInput = in;
1825 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1827 if (out != INVALID_HANDLE_VALUE)
1828 siStartInfo.hStdOutput = out;
1830 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1831 if (err != INVALID_HANDLE_VALUE)
1832 siStartInfo.hStdError = err;
1834 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1836 // Create the child process.
1839 const char *argStart;
1841 if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
1842 return INVALID_HANDLE_VALUE;
1845 int cmdLen = strlen(comspec) + 4 + strlen(exeFile) + strlen(argStart) + 1;
1847 char *cmdLine = (char *)alloca(cmdLen);
1849 snprintf(cmdLine, cmdLen, "%s /c %s%s", comspec, exeFile, argStart);
1853 Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
1855 // try to execute program
1856 bFuncRetn = CreateProcessA(comspec,
1857 cmdLine, // command line
1858 NULL, // process security attributes
1859 NULL, // primary thread security attributes
1860 TRUE, // handles are inherited
1861 0, // creation flags
1862 NULL, // use parent's environment
1863 NULL, // use parent's current directory
1864 &siStartInfo, // STARTUPINFO pointer
1865 &piProcInfo); // receives PROCESS_INFORMATION
1867 if (bFuncRetn == 0) {
1868 ErrorExit("CreateProcess failed\n");
1869 const char *err = errorString();
1870 Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n", comspec, cmdLine, err);
1871 LocalFree((void *)err);
1872 return INVALID_HANDLE_VALUE;
1874 // we don't need a handle on the process primary thread so we close
1876 CloseHandle(piProcInfo.hThread);
1878 return piProcInfo.hProcess;
1883 ErrorExit (LPCSTR lpszMessage)
1885 Dmsg1(0, "%s", lpszMessage);
1890 typedef struct s_bpipe {
1892 time_t worker_stime;
1901 CloseIfValid(HANDLE handle)
1903 if (handle != INVALID_HANDLE_VALUE)
1904 CloseHandle(handle);
1908 open_bpipe(char *prog, int wait, const char *mode)
1910 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1911 hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1914 SECURITY_ATTRIBUTES saAttr;
1918 hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1919 hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1920 hInputFile = INVALID_HANDLE_VALUE;
1922 BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1923 memset((void *)bpipe, 0, sizeof(BPIPE));
1925 int mode_read = (mode[0] == 'r');
1926 int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1929 // Set the bInheritHandle flag so pipe handles are inherited.
1931 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1932 saAttr.bInheritHandle = TRUE;
1933 saAttr.lpSecurityDescriptor = NULL;
1937 // Create a pipe for the child process's STDOUT.
1938 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1939 ErrorExit("Stdout pipe creation failed\n");
1942 // Create noninheritable read handle and close the inheritable read
1945 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1946 GetCurrentProcess(), &hChildStdoutRdDup , 0,
1948 DUPLICATE_SAME_ACCESS);
1950 ErrorExit("DuplicateHandle failed");
1954 CloseHandle(hChildStdoutRd);
1955 hChildStdoutRd = INVALID_HANDLE_VALUE;
1960 // Create a pipe for the child process's STDIN.
1962 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1963 ErrorExit("Stdin pipe creation failed\n");
1967 // Duplicate the write handle to the pipe so it is not inherited.
1968 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
1969 GetCurrentProcess(), &hChildStdinWrDup,
1971 FALSE, // not inherited
1972 DUPLICATE_SAME_ACCESS);
1974 ErrorExit("DuplicateHandle failed");
1978 CloseHandle(hChildStdinWr);
1979 hChildStdinWr = INVALID_HANDLE_VALUE;
1981 // spawn program with redirected handles as appropriate
1982 bpipe->worker_pid = (pid_t)
1983 CreateChildProcess(prog, // commandline
1984 hChildStdinRd, // stdin HANDLE
1985 hChildStdoutWr, // stdout HANDLE
1986 hChildStdoutWr); // stderr HANDLE
1988 if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1992 bpipe->worker_stime = time(NULL);
1995 CloseHandle(hChildStdoutWr); // close our write side so when
1996 // process terminates we can
1998 // ugly but convert WIN32 HANDLE to FILE*
1999 int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY | O_BINARY);
2001 bpipe->rfd = _fdopen(rfd, "rb");
2005 CloseHandle(hChildStdinRd); // close our read side so as not
2006 // to interfre with child's copy
2007 // ugly but convert WIN32 HANDLE to FILE*
2008 int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY | O_BINARY);
2010 bpipe->wfd = _fdopen(wfd, "wb");
2015 bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
2022 CloseIfValid(hChildStdoutRd);
2023 CloseIfValid(hChildStdoutRdDup);
2024 CloseIfValid(hChildStdinWr);
2025 CloseIfValid(hChildStdinWrDup);
2027 free((void *) bpipe);
2028 errno = b_errno_win32; /* do GetLastError() for error code */
2034 kill(int pid, int signal)
2037 if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
2039 errno = b_errno_win32;
2041 CloseHandle((HANDLE)pid);
2047 close_bpipe(BPIPE *bpipe)
2050 int32_t remaining_wait = bpipe->wait;
2062 if (remaining_wait == 0) { /* wait indefinitely */
2063 remaining_wait = INT32_MAX;
2067 if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
2068 const char *err = errorString();
2069 rval = b_errno_win32;
2070 Dmsg1(0, "GetExitCode error %s\n", err);
2071 LocalFree((void *)err);
2074 if (exitCode == STILL_ACTIVE) {
2075 if (remaining_wait <= 0) {
2076 rval = ETIME; /* timed out */
2079 bmicrosleep(1, 0); /* wait one second */
2081 } else if (exitCode != 0) {
2082 /* Truncate exit code as it doesn't seem to be correct */
2083 rval = (exitCode & 0xFF) | b_errno_exit;
2086 break; /* Shouldn't get here */
2090 if (bpipe->timer_id) {
2091 stop_child_timer(bpipe->timer_id);
2093 if (bpipe->rfd) fclose(bpipe->rfd);
2094 if (bpipe->wfd) fclose(bpipe->wfd);
2095 free((void *)bpipe);
2100 close_wpipe(BPIPE *bpipe)
2106 if (fclose(bpipe->wfd) != 0) {
2114 #include "findlib/find.h"
2117 utime(const char *fname, struct utimbuf *times)
2122 conv_unix_to_win32_path(fname, tmpbuf, 5000);
2124 cvt_utime_to_ftime(times->actime, acc);
2125 cvt_utime_to_ftime(times->modtime, mod);
2127 HANDLE h = INVALID_HANDLE_VALUE;
2129 if (p_CreateFileW) {
2130 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2131 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
2133 h = p_CreateFileW((LPCWSTR)pwszBuf,
2134 FILE_WRITE_ATTRIBUTES,
2135 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2138 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2141 free_pool_memory(pwszBuf);
2142 } else if (p_CreateFileA) {
2143 h = p_CreateFileA(tmpbuf,
2144 FILE_WRITE_ATTRIBUTES,
2145 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2148 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2152 if (h == INVALID_HANDLE_VALUE) {
2153 const char *err = errorString();
2154 Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2155 LocalFree((void *)err);
2156 errno = b_errno_win32;
2160 int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2163 errno = b_errno_win32;
2170 file_open(const char *file, int flags, int mode)
2173 DWORD shareMode = 0;
2176 HANDLE foo = INVALID_HANDLE_VALUE;
2177 const char *remap = file;
2179 if (flags & O_WRONLY) access = GENERIC_WRITE;
2180 else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2181 else access = GENERIC_READ;
2183 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2184 create = CREATE_NEW;
2185 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2186 create = CREATE_ALWAYS;
2187 else if (flags & O_CREAT)
2188 create = OPEN_ALWAYS;
2189 else if (flags & O_TRUNC)
2190 create = TRUNCATE_EXISTING;
2192 create = OPEN_EXISTING;
2196 if (flags & O_APPEND) {
2197 printf("open...APPEND not implemented yet.");
2201 if (p_CreateFileW) {
2202 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2203 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
2205 foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
2206 free_pool_memory(pwszBuf);
2207 } else if (p_CreateFileA)
2208 foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
2210 if (INVALID_HANDLE_VALUE == foo) {
2211 errno = b_errno_win32;
2222 if (!CloseHandle((HANDLE)fd)) {
2223 errno = b_errno_win32;
2231 file_write(int fd, const void *data, ssize_t len)
2235 status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2236 if (status) return bwrite;
2237 errno = b_errno_win32;
2243 file_read(int fd, void *data, ssize_t len)
2248 status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2249 if (status) return bread;
2250 errno = b_errno_win32;
2255 file_seek(int fd, boffset_t offset, int whence)
2259 LONG offset_low = (LONG)offset;
2260 LONG offset_high = (LONG)(offset >> 32);
2264 method = FILE_BEGIN;
2267 method = FILE_CURRENT;
2278 if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
2279 errno = b_errno_win32;
2282 /* ***FIXME*** I doubt this works right */
2295 /* syslog function, added by Nicolas Boichat */
2296 void openlog(const char *ident, int option, int facility) {}