2 // compat.cpp -- compatibilty layer to make bacula-fd run
3 // natively under windows
5 // Copyright transferred from Raider Solutions, Inc to
6 // Kern Sibbald and John Walker by express permission.
8 // Copyright (C) 2004-2006 Kern Sibbald
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License
12 // version 2 as amended with additional clauses defined in the
13 // file LICENSE in the main source directory.
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // the file LICENSE for additional details.
20 // Author : Christopher S. Hull
21 // Created On : Sat Jan 31 15:55:00 2004
28 #define b_errno_win32 (1<<29)
30 #define MAX_PATHLENGTH 1024
32 /* UTF-8 to UCS2 path conversion is expensive,
33 so we cache the conversion. During backup the
34 conversion is called 3 times (lstat, attribs, open),
35 by using the cache this is reduced to 1 time */
37 static POOLMEM *g_pWin32ConvUTF8Cache = get_pool_memory (PM_FNAME);
38 static POOLMEM *g_pWin32ConvUCS2Cache = get_pool_memory (PM_FNAME);
39 static DWORD g_dwWin32ConvUTF8strlen = 0;
40 static pthread_mutex_t Win32Convmutex = PTHREAD_MUTEX_INITIALIZER;
42 static t_pVSSPathConvert g_pVSSPathConvert;
43 static t_pVSSPathConvertW g_pVSSPathConvertW;
45 void SetVSSPathConvert(t_pVSSPathConvert pPathConvert, t_pVSSPathConvertW pPathConvertW)
47 g_pVSSPathConvert = pPathConvert;
48 g_pVSSPathConvertW = pPathConvertW;
51 void Win32ConvCleanupCache()
53 if (g_pWin32ConvUTF8Cache) {
54 free_pool_memory(g_pWin32ConvUTF8Cache);
55 g_pWin32ConvUTF8Cache = NULL;
58 if (g_pWin32ConvUCS2Cache) {
59 free_pool_memory(g_pWin32ConvUCS2Cache);
60 g_pWin32ConvUCS2Cache = NULL;
63 g_dwWin32ConvUTF8strlen = 0;
67 /* to allow the usage of the original version in this file here */
71 //#define USE_WIN32_COMPAT_IO 1
72 #define USE_WIN32_32KPATHCONVERSION 1
74 extern DWORD g_platform_id;
75 extern DWORD g_MinorVersion;
77 // from MicroSoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970
79 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL
81 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
84 #define WIN32_FILETIME_SCALE 10000000 // 100ns/second
86 void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize)
88 const char *fname = name;
89 char *tname = win32_name;
91 Dmsg0(100, "Enter convert_unix_to_win32_path\n");
93 if (IsPathSeparator(name[0]) &&
94 IsPathSeparator(name[1]) &&
96 IsPathSeparator(name[3])) {
101 *win32_name++ = '\\';
104 } else if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS &&
105 g_pVSSPathConvert == NULL) {
106 /* allow path to be 32767 bytes */
107 *win32_name++ = '\\';
108 *win32_name++ = '\\';
110 *win32_name++ = '\\';
114 /* Check for Unix separator and convert to Win32 */
115 if (name[0] == '/' && name[1] == '/') { /* double slash? */
116 name++; /* yes, skip first one */
119 *win32_name++ = '\\'; /* convert char */
120 /* If Win32 separator that is "quoted", remove quote */
121 } else if (*name == '\\' && name[1] == '\\') {
122 *win32_name++ = '\\';
123 name++; /* skip first \ */
125 *win32_name++ = *name; /* copy character */
129 /* Strip any trailing slash, if we stored something */
130 /* but leave "c:\" with backslash (root directory case */
131 if (*fname != 0 && win32_name[-1] == '\\' && strlen (fname) != 3) {
137 /* here we convert to VSS specific file name which
138 can get longer because VSS will make something like
139 \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
140 from c:\bacula\uninstall.exe
142 Dmsg1(100, "path=%s\n", tname);
143 if (g_pVSSPathConvert != NULL) {
144 POOLMEM *pszBuf = get_pool_memory (PM_FNAME);
145 pszBuf = check_pool_memory_size(pszBuf, dwSize);
146 bstrncpy(pszBuf, tname, strlen(tname)+1);
147 g_pVSSPathConvert(pszBuf, tname, dwSize);
148 free_pool_memory(pszBuf);
151 Dmsg1(100, "Leave cvt_u_to_win32_path path=%s\n", tname);
154 /* Conversion of a Unix filename to a Win32 filename */
155 void unix_name_to_win32(POOLMEM **win32_name, char *name)
157 /* One extra byte should suffice, but we double it */
158 /* add MAX_PATH bytes for VSS shadow copy name */
159 DWORD dwSize = 2*strlen(name)+MAX_PATH;
160 *win32_name = check_pool_memory_size(*win32_name, dwSize);
161 conv_unix_to_win32_path(name, *win32_name, dwSize);
165 make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/)
167 /* created 02/27/2006 Thorsten Engel
169 * This function expects an UCS-encoded standard wchar_t in pszUCSPath and
170 * will complete the input path to an absolue path of the form \\?\c:\path\file
172 * With this trick, it is possible to have 32K characters long paths.
174 * Optionally one can use pBIsRawPath to determine id pszUCSPath contains a path
175 * to a raw windows partition.
178 Dmsg0(100, "Enter wchar_win32_path\n");
180 *pBIsRawPath = FALSE; /* Initialize, set later */
183 if (!p_GetCurrentDirectoryW) {
184 Dmsg0(100, "Leave wchar_win32_path no change \n");
188 wchar_t *name = (wchar_t *)pszUCSPath;
190 /* if it has already the desired form, exit without changes */
191 if (wcslen(name) > 3 && wcsncmp(name, L"\\\\?\\", 4) == 0) {
192 Dmsg0(100, "Leave wchar_win32_path no change \n");
196 wchar_t *pwszBuf = (wchar_t *)get_pool_memory(PM_FNAME);
197 wchar_t *pwszCurDirBuf = (wchar_t *)get_pool_memory(PM_FNAME);
198 DWORD dwCurDirPathSize = 0;
200 /* get buffer with enough size (name+max 6. wchars+1 null terminator */
201 DWORD dwBufCharsNeeded = (wcslen(name)+7);
202 pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
204 /* add \\?\ to support 32K long filepaths
205 it is important to make absolute paths, so we add drive and
206 current path if necessary */
208 BOOL bAddDrive = TRUE;
209 BOOL bAddCurrentPath = TRUE;
210 BOOL bAddPrefix = TRUE;
212 /* does path begin with drive? if yes, it is absolute */
213 if (iswalpha(name[0]) && name[1] == ':' && IsPathSeparator(name[2])) {
215 bAddCurrentPath = FALSE;
218 /* is path absolute? */
219 if (IsPathSeparator(name[0]))
220 bAddCurrentPath = FALSE;
222 /* is path relative to itself?, if yes, skip ./ */
223 if (name[0] == '.' && IsPathSeparator(name[1])) {
227 /* is path of form '//./'? */
228 if (IsPathSeparator(name[0]) &&
229 IsPathSeparator(name[1]) &&
231 IsPathSeparator(name[3])) {
233 bAddCurrentPath = FALSE;
240 int nParseOffset = 0;
242 /* add 4 bytes header */
245 wcscpy(pwszBuf, L"\\\\?\\");
248 /* get current path if needed */
249 if (bAddDrive || bAddCurrentPath) {
250 dwCurDirPathSize = p_GetCurrentDirectoryW(0, NULL);
251 if (dwCurDirPathSize > 0) {
252 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
253 pwszCurDirBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszCurDirBuf, (dwCurDirPathSize+1)*sizeof(wchar_t));
254 p_GetCurrentDirectoryW(dwCurDirPathSize, pwszCurDirBuf);
256 /* we have no info for doing so */
258 bAddCurrentPath = FALSE;
263 /* add drive if needed */
264 if (bAddDrive && !bAddCurrentPath) {
267 if (IsPathSeparator(pwszCurDirBuf[0]) &&
268 IsPathSeparator(pwszCurDirBuf[1]) &&
269 pwszCurDirBuf[2] == '?' &&
270 IsPathSeparator(pwszCurDirBuf[3])) {
271 /* copy drive character */
272 szDrive[0] = pwszCurDirBuf[4];
274 /* copy drive character */
275 szDrive[0] = pwszCurDirBuf[0];
281 wcscat(pwszBuf, szDrive);
285 /* add path if needed */
286 if (bAddCurrentPath) {
287 /* the 1 add. character is for the eventually added backslash */
288 dwBufCharsNeeded += dwCurDirPathSize+1;
289 pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
290 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
292 if (IsPathSeparator(pwszCurDirBuf[0]) &&
293 IsPathSeparator(pwszCurDirBuf[1]) &&
294 pwszCurDirBuf[2] == '?' &&
295 IsPathSeparator(pwszCurDirBuf[3])) {
296 /* copy complete string */
297 wcscpy(pwszBuf, pwszCurDirBuf);
300 wcscat(pwszBuf, pwszCurDirBuf);
303 nParseOffset = wcslen((LPCWSTR) pwszBuf);
305 /* check if path ends with backslash, if not, add one */
306 if (!IsPathSeparator(pwszBuf[nParseOffset-1])) {
307 wcscat(pwszBuf, L"\\");
312 wchar_t *win32_name = &pwszBuf[nParseOffset];
313 wchar_t *name_start = name;
316 /* Check for Unix separator and convert to Win32, eliminating
317 * duplicate separators.
319 if (IsPathSeparator(*name)) {
320 *win32_name++ = '\\'; /* convert char */
322 /* Eliminate consecutive slashes, but not at the start so that
325 if (name_start != name && IsPathSeparator(name[1])) {
329 *win32_name++ = *name; /* copy character */
334 /* null terminate string */
337 /* here we convert to VSS specific file name which
338 * can get longer because VSS will make something like
339 * \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
340 * from c:\bacula\uninstall.exe
342 if (g_pVSSPathConvertW != NULL) {
343 /* is output buffer large enough? */
344 pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf,
345 (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
346 /* create temp. buffer */
347 wchar_t *pszBuf = (wchar_t *)get_pool_memory(PM_FNAME);
348 pszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pszBuf,
349 (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
354 wcsncpy(pszBuf, &pwszBuf[nParseOffset], wcslen(pwszBuf)+1-nParseOffset);
355 g_pVSSPathConvertW(pszBuf, pwszBuf, dwBufCharsNeeded+MAX_PATH);
356 free_pool_memory((POOLMEM *)pszBuf);
359 free_pool_memory(pszUCSPath);
360 free_pool_memory((POOLMEM *)pwszCurDirBuf);
362 Dmsg1(100, "Leave wchar_win32_path=%s\n", pwszBuf);
363 return (POOLMEM *)pwszBuf;
367 wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
369 /* the return value is the number of bytes written to the buffer.
370 The number includes the byte for the null terminator. */
372 if (p_WideCharToMultiByte) {
373 int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
382 UTF8_2_wchar(POOLMEM **ppszUCS, const char *pszUTF)
384 /* the return value is the number of wide characters written to the buffer. */
385 /* convert null terminated string from utf-8 to ucs2, enlarge buffer if necessary */
387 if (p_MultiByteToWideChar) {
388 /* strlen of UTF8 +1 is enough */
389 DWORD cchSize = (strlen(pszUTF)+1);
390 *ppszUCS = check_pool_memory_size(*ppszUCS, cchSize*sizeof (wchar_t));
392 int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
402 wchar_win32_path(const char *name, wchar_t *win32_name)
404 const char *fname = name;
406 /* Check for Unix separator and convert to Win32 */
408 *win32_name++ = '\\'; /* convert char */
409 /* If Win32 separated that is "quoted", remove quote */
410 } else if (*name == '\\' && name[1] == '\\') {
411 *win32_name++ = '\\';
412 name++; /* skip first \ */
414 *win32_name++ = *name; /* copy character */
418 /* Strip any trailing slash, if we stored something */
419 if (*fname != 0 && win32_name[-1] == '\\') {
427 make_win32_path_UTF8_2_wchar(POOLMEM **pszUCS, const char *pszUTF, BOOL* pBIsRawPath /*= NULL*/)
430 /* if we find the utf8 string in cache, we use the cached ucs2 version.
431 we compare the stringlength first (quick check) and then compare the content.
433 if (g_dwWin32ConvUTF8strlen == strlen(pszUTF)) {
434 if (bstrcmp(pszUTF, g_pWin32ConvUTF8Cache)) {
435 int32_t nBufSize = sizeof_pool_memory(g_pWin32ConvUCS2Cache);
436 *pszUCS = check_pool_memory_size(*pszUCS, nBufSize);
437 wcscpy((LPWSTR) *pszUCS, (LPWSTR) g_pWin32ConvUCS2Cache);
439 return nBufSize / sizeof (WCHAR);
443 /* helper to convert from utf-8 to UCS-2 and to complete a path for 32K path syntax */
444 int nRet = UTF8_2_wchar(pszUCS, pszUTF);
446 #ifdef USE_WIN32_32KPATHCONVERSION
447 /* add \\?\ to support 32K long filepaths */
448 *pszUCS = make_wchar_win32_path(*pszUCS, pBIsRawPath);
451 *pBIsRawPath = FALSE;
455 g_pWin32ConvUCS2Cache = check_pool_memory_size(g_pWin32ConvUCS2Cache, sizeof_pool_memory(*pszUCS));
456 wcscpy((LPWSTR) g_pWin32ConvUCS2Cache, (LPWSTR) *pszUCS);
458 g_dwWin32ConvUTF8strlen = strlen(pszUTF);
459 g_pWin32ConvUTF8Cache = check_pool_memory_size(g_pWin32ConvUTF8Cache, g_dwWin32ConvUTF8strlen+1);
460 bstrncpy(g_pWin32ConvUTF8Cache, pszUTF, g_dwWin32ConvUTF8strlen+1);
466 #if !defined(_MSC_VER) || (_MSC_VER < 1400) // VC8+
473 int fcntl(int fd, int cmd)
478 int chmod(const char *, mode_t)
483 int chown(const char *k, uid_t, gid_t)
488 int lchown(const char *k, uid_t, gid_t)
500 srandom(unsigned int seed)
504 // /////////////////////////////////////////////////////////////////
505 // convert from Windows concept of time to Unix concept of time
506 // /////////////////////////////////////////////////////////////////
508 cvt_utime_to_ftime(const time_t &time, FILETIME &wintime)
510 uint64_t mstime = time;
511 mstime *= WIN32_FILETIME_SCALE;
512 mstime += WIN32_FILETIME_ADJUST;
514 #if defined(_MSC_VER)
515 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
517 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL);
519 wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
523 cvt_ftime_to_utime(const FILETIME &time)
525 uint64_t mstime = time.dwHighDateTime;
527 mstime |= time.dwLowDateTime;
529 mstime -= WIN32_FILETIME_ADJUST;
530 mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
532 return (time_t) (mstime & 0xffffffff);
540 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
541 FORMAT_MESSAGE_FROM_SYSTEM |
542 FORMAT_MESSAGE_IGNORE_INSERTS,
545 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
550 /* Strip any \r or \n */
551 char *rval = (char *) lpMsgBuf;
552 char *cp = strchr(rval, '\r');
556 cp = strchr(rval, '\n');
565 statDir(const char *file, struct stat *sb)
567 WIN32_FIND_DATAW info_w; // window's file info
568 WIN32_FIND_DATAA info_a; // window's file info
570 // cache some common vars to make code more transparent
571 DWORD* pdwFileAttributes;
572 DWORD* pnFileSizeHigh;
573 DWORD* pnFileSizeLow;
574 FILETIME* pftLastAccessTime;
575 FILETIME* pftLastWriteTime;
576 FILETIME* pftCreationTime;
578 if (file[1] == ':' && file[2] == 0) {
579 Dmsg1(99, "faking ROOT attrs(%s).\n", file);
580 sb->st_mode = S_IFDIR;
581 sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
588 HANDLE h = INVALID_HANDLE_VALUE;
590 // use unicode or ascii
591 if (p_FindFirstFileW) {
592 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
593 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
595 h = p_FindFirstFileW((LPCWSTR) pwszBuf, &info_w);
596 free_pool_memory(pwszBuf);
598 pdwFileAttributes = &info_w.dwFileAttributes;
599 pnFileSizeHigh = &info_w.nFileSizeHigh;
600 pnFileSizeLow = &info_w.nFileSizeLow;
601 pftLastAccessTime = &info_w.ftLastAccessTime;
602 pftLastWriteTime = &info_w.ftLastWriteTime;
603 pftCreationTime = &info_w.ftCreationTime;
605 else if (p_FindFirstFileA) {
606 h = p_FindFirstFileA(file, &info_a);
608 pdwFileAttributes = &info_a.dwFileAttributes;
609 pnFileSizeHigh = &info_a.nFileSizeHigh;
610 pnFileSizeLow = &info_a.nFileSizeLow;
611 pftLastAccessTime = &info_a.ftLastAccessTime;
612 pftLastWriteTime = &info_a.ftLastWriteTime;
613 pftCreationTime = &info_a.ftCreationTime;
616 if (h == INVALID_HANDLE_VALUE) {
617 const char *err = errorString();
618 Dmsg2(99, "FindFirstFile(%s):%s\n", file, err);
619 LocalFree((void *)err);
620 errno = b_errno_win32;
624 sb->st_mode = 0777; /* start with everything */
625 if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
626 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
627 if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
628 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
629 if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
630 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
631 sb->st_mode |= S_IFDIR;
633 sb->st_size = *pnFileSizeHigh;
635 sb->st_size |= *pnFileSizeLow;
636 sb->st_blksize = 4096;
637 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
639 sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
640 sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
641 sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
648 fstat(int fd, struct stat *sb)
650 BY_HANDLE_FILE_INFORMATION info;
653 if (!GetFileInformationByHandle((HANDLE)fd, &info)) {
654 const char *err = errorString();
655 Dmsg2(99, "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
656 LocalFree((void *)err);
657 errno = b_errno_win32;
661 sb->st_dev = info.dwVolumeSerialNumber;
662 sb->st_ino = info.nFileIndexHigh;
664 sb->st_ino |= info.nFileIndexLow;
665 sb->st_nlink = (short)info.nNumberOfLinks;
666 if (sb->st_nlink > 1) {
667 Dmsg1(99, "st_nlink=%d\n", sb->st_nlink);
670 sb->st_mode = 0777; /* start with everything */
671 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
672 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
673 if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
674 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
675 if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
676 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
677 sb->st_mode |= S_IFREG;
679 sb->st_size = info.nFileSizeHigh;
681 sb->st_size |= info.nFileSizeLow;
682 sb->st_blksize = 4096;
683 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
684 sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
685 sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
686 sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
692 stat2(const char *file, struct stat *sb)
697 conv_unix_to_win32_path(file, tmpbuf, 1024);
699 DWORD attr = (DWORD)-1;
701 if (p_GetFileAttributesW) {
702 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
703 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
705 attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
706 free_pool_memory(pwszBuf);
707 } else if (p_GetFileAttributesA) {
708 attr = p_GetFileAttributesA(tmpbuf);
711 if (attr == (DWORD)-1) {
712 const char *err = errorString();
713 Dmsg2(99, "GetFileAttributes(%s): %s\n", tmpbuf, err);
714 LocalFree((void *)err);
715 errno = b_errno_win32;
719 if (attr & FILE_ATTRIBUTE_DIRECTORY)
720 return statDir(tmpbuf, sb);
722 h = CreateFileA(tmpbuf, GENERIC_READ,
723 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
725 if (h == INVALID_HANDLE_VALUE) {
726 const char *err = errorString();
727 Dmsg2(99, "Cannot open file for stat (%s):%s\n", tmpbuf, err);
728 LocalFree((void *)err);
729 errno = b_errno_win32;
733 rval = fstat((int)h, sb);
740 stat(const char *file, struct stat *sb)
742 WIN32_FILE_ATTRIBUTE_DATA data;
746 memset(sb, 0, sizeof(*sb));
748 /* why not allow win 95 to use p_GetFileAttributesExA ?
749 * this function allows _some_ open files to be stat'ed
750 * if (g_platform_id == VER_PLATFORM_WIN32_WINDOWS) {
751 * return stat2(file, sb);
755 if (p_GetFileAttributesExW) {
756 /* dynamically allocate enough space for UCS2 filename */
757 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
758 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
760 BOOL b = p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, &data);
761 free_pool_memory(pwszBuf);
764 return stat2(file, sb);
766 } else if (p_GetFileAttributesExA) {
767 if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
768 return stat2(file, sb);
771 return stat2(file, sb);
774 sb->st_mode = 0777; /* start with everything */
775 if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
776 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
778 if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
779 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
781 if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
782 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
784 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
785 sb->st_mode |= S_IFDIR;
787 sb->st_mode |= S_IFREG;
791 sb->st_size = data.nFileSizeHigh;
793 sb->st_size |= data.nFileSizeLow;
794 sb->st_blksize = 4096;
795 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
796 sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
797 sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
798 sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
802 int fcntl(int fd, int cmd, long arg)
825 lstat(const char *file, struct stat *sb)
827 return stat(file, sb);
843 execvp(const char *, char *[]) {
864 waitpid(int, int*, int)
871 readlink(const char *, char *, int)
880 strcasecmp(const char *s1, const char *s2)
882 register int ch1, ch2;
885 return 0; /* strings are equal if same object. */
895 } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
902 strncasecmp(const char *s1, const char *s2, int len)
904 register int ch1 = 0, ch2 = 0;
907 return 0; /* strings are equal if same object. */
918 if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
925 gettimeofday(struct timeval *tv, struct timezone *)
935 if (!SystemTimeToFileTime(&now, &tmp)) {
936 errno = b_errno_win32;
940 int64_t _100nsec = tmp.dwHighDateTime;
942 _100nsec |= tmp.dwLowDateTime;
943 _100nsec -= WIN32_FILETIME_ADJUST;
945 tv->tv_sec =(long) (_100nsec / 10000000);
946 tv->tv_usec = (long) ((_100nsec % 10000000)/10);
951 /* For apcupsd this is in src/lib/wincompat.c */
952 extern "C" void syslog(int type, const char *fmt, ...)
954 /*#ifndef HAVE_CONSOLE
955 MessageBox(NULL, msg, "Bacula", MB_OK);
976 // implement opendir/readdir/closedir on top of window's API
980 WIN32_FIND_DATAA data_a; // window's file info (ansii version)
981 WIN32_FIND_DATAW data_w; // window's file info (wchar version)
982 const char *spec; // the directory we're traversing
983 HANDLE dirh; // the search handle
984 BOOL valid_a; // the info in data_a field is valid
985 BOOL valid_w; // the info in data_w field is valid
986 UINT32 offset; // pseudo offset for d_off
990 opendir(const char *path)
992 /* enough space for VSS !*/
993 int max_len = strlen(path) + MAX_PATH;
1000 Dmsg1(100, "Opendir path=%s\n", path);
1001 rval = (_dir *)malloc(sizeof(_dir));
1002 memset (rval, 0, sizeof (_dir));
1003 if (rval == NULL) return NULL;
1004 char *tspec = (char *)malloc(max_len);
1005 if (tspec == NULL) return NULL;
1007 conv_unix_to_win32_path(path, tspec, max_len);
1008 Dmsg1(100, "win32 path=%s\n", tspec);
1010 // add backslash only if there is none yet (think of c:\)
1011 if (tspec[strlen(tspec)-1] != '\\')
1012 bstrncat(tspec, "\\*", max_len);
1014 bstrncat(tspec, "*", max_len);
1018 // convert to wchar_t
1019 if (p_FindFirstFileW) {
1020 POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
1021 make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec);
1023 rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
1025 free_pool_memory(pwcBuf);
1027 if (rval->dirh != INVALID_HANDLE_VALUE)
1029 } else if (p_FindFirstFileA) {
1030 rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
1032 if (rval->dirh != INVALID_HANDLE_VALUE)
1037 Dmsg3(99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
1038 path, rval->spec, rval->dirh);
1041 if (rval->dirh == INVALID_HANDLE_VALUE)
1044 if (rval->valid_w) {
1045 Dmsg1(99, "\tFirstFile=%s\n", rval->data_w.cFileName);
1048 if (rval->valid_a) {
1049 Dmsg1(99, "\tFirstFile=%s\n", rval->data_a.cFileName);
1055 free((void *)rval->spec);
1057 errno = b_errno_win32;
1064 _dir *dp = (_dir *)dirp;
1065 FindClose(dp->dirh);
1066 free((void *)dp->spec);
1072 typedef struct _WIN32_FIND_DATA {
1073 DWORD dwFileAttributes;
1074 FILETIME ftCreationTime;
1075 FILETIME ftLastAccessTime;
1076 FILETIME ftLastWriteTime;
1077 DWORD nFileSizeHigh;
1081 TCHAR cFileName[MAX_PATH];
1082 TCHAR cAlternateFileName[14];
1083 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1087 copyin(struct dirent &dp, const char *fname)
1091 char *cp = dp.d_name;
1101 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1103 _dir *dp = (_dir *)dirp;
1104 if (dp->valid_w || dp->valid_a) {
1105 entry->d_off = dp->offset;
1109 char szBuf[MAX_PATH_UTF8+1];
1110 wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1111 dp->offset += copyin(*entry, szBuf);
1112 } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1113 dp->offset += copyin(*entry, dp->data_a.cFileName);
1116 *result = entry; /* return entry address */
1117 Dmsg4(99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1118 dirp, entry->d_name, entry->d_reclen, entry->d_off);
1120 // Dmsg0(99, "readdir_r !valid\n");
1121 errno = b_errno_win32;
1125 // get next file, try unicode first
1126 if (p_FindNextFileW)
1127 dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1128 else if (p_FindNextFileA)
1129 dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1131 dp->valid_a = FALSE;
1132 dp->valid_w = FALSE;
1139 * Dotted IP address to network address
1145 inet_aton(const char *a, struct in_addr *inp)
1148 uint32_t acc = 0, tmp = 0;
1151 if (!isdigit(*cp)) { /* first char must be digit */
1152 return 0; /* error */
1156 tmp = (tmp * 10) + (*cp -'0');
1157 } else if (*cp == '.' || *cp == 0) {
1159 return 0; /* error */
1161 acc = (acc << 8) + tmp;
1165 return 0; /* error */
1167 } while (*cp++ != 0);
1168 if (dotc != 4) { /* want 3 .'s plus EOS */
1169 return 0; /* error */
1171 inp->s_addr = htonl(acc); /* store addr in network format */
1176 nanosleep(const struct timespec *req, struct timespec *rem)
1179 rem->tv_sec = rem->tv_nsec = 0;
1180 Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1185 init_signals(void terminate(int sig))
1191 init_stack_dump(void)
1198 pathconf(const char *path, int name)
1202 if (strncmp(path, "\\\\?\\", 4) == 0)
1214 WORD wVersionRequested = MAKEWORD( 1, 1);
1217 int err = WSAStartup(wVersionRequested, &wsaData);
1221 printf("Can not start Windows Sockets\n");
1231 win32_chdir(const char *dir)
1233 if (p_SetCurrentDirectoryW) {
1234 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1235 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1237 BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1239 free_pool_memory(pwszBuf);
1242 errno = b_errno_win32;
1246 else if (p_SetCurrentDirectoryA) {
1247 if (0 == p_SetCurrentDirectoryA(dir)) {
1248 errno = b_errno_win32;
1258 win32_mkdir(const char *dir)
1261 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1262 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1264 int n = p_wmkdir((LPCWSTR)pwszBuf);
1265 free_pool_memory(pwszBuf);
1274 win32_getcwd(char *buf, int maxlen)
1278 if (p_GetCurrentDirectoryW) {
1279 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1280 pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1282 n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1284 n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1285 free_pool_memory(pwszBuf);
1287 } else if (p_GetCurrentDirectoryA)
1288 n = p_GetCurrentDirectoryA(maxlen, buf);
1290 if (n == 0 || n > maxlen) return NULL;
1292 if (n+1 > maxlen) return NULL;
1301 win32_fputs(const char *string, FILE *stream)
1303 /* we use WriteConsoleA / WriteConsoleA
1304 so we can be sure that unicode support works on win32.
1305 with fallback if something fails
1308 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1309 if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1310 p_MultiByteToWideChar && (stream == stdout)) {
1312 POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1314 DWORD dwCharsWritten;
1317 dwChars = UTF8_2_wchar(&pwszBuf, string);
1319 /* try WriteConsoleW */
1320 if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1321 free_pool_memory(pwszBuf);
1322 return dwCharsWritten;
1325 /* convert to local codepage and try WriteConsoleA */
1326 POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1327 pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1329 dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR) pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1330 free_pool_memory(pwszBuf);
1332 if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1333 free_pool_memory(pszBuf);
1334 return dwCharsWritten;
1338 return fputs(string, stream);
1342 win32_cgets (char* buffer, int len)
1344 /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1345 from the win32 console and fallback if seomething fails */
1347 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1348 if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1350 wchar_t wszBuf[1024];
1353 /* nt and unicode conversion */
1354 if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1356 /* null terminate at end */
1357 if (wszBuf[dwRead-1] == L'\n') {
1358 wszBuf[dwRead-1] = L'\0';
1362 if (wszBuf[dwRead-1] == L'\r') {
1363 wszBuf[dwRead-1] = L'\0';
1367 wchar_2_UTF8(buffer, wszBuf, len);
1371 /* win 9x and unicode conversion */
1372 if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1374 /* null terminate at end */
1375 if (szBuf[dwRead-1] == L'\n') {
1376 szBuf[dwRead-1] = L'\0';
1380 if (szBuf[dwRead-1] == L'\r') {
1381 szBuf[dwRead-1] = L'\0';
1385 /* convert from ansii to wchar_t */
1386 p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1387 /* convert from wchar_t to UTF-8 */
1388 if (wchar_2_UTF8(buffer, wszBuf, len))
1394 if (fgets(buffer, len, stdin))
1401 win32_unlink(const char *filename)
1405 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1406 make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1408 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1410 /* special case if file is readonly,
1411 we retry but unset attribute before */
1412 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1413 DWORD dwAttr = p_GetFileAttributesW((LPCWSTR)pwszBuf);
1414 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1415 if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1416 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1417 /* reset to original if it didn't help */
1419 p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1423 free_pool_memory(pwszBuf);
1425 nRetCode = _unlink(filename);
1427 /* special case if file is readonly,
1428 we retry but unset attribute before */
1429 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1430 DWORD dwAttr = p_GetFileAttributesA(filename);
1431 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1432 if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1433 nRetCode = _unlink(filename);
1434 /* reset to original if it didn't help */
1436 p_SetFileAttributesA(filename, dwAttr);
1445 #include "mswinver.h"
1447 char WIN_VERSION_LONG[64];
1448 char WIN_VERSION[32];
1449 char WIN_RAWVERSION[32];
1456 static winver INIT; // cause constructor to be called before main()
1459 winver::winver(void)
1461 const char *version = "";
1462 const char *platform = "";
1463 OSVERSIONINFO osvinfo;
1464 osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1466 // Get the current OS version
1467 if (!GetVersionEx(&osvinfo)) {
1468 version = "Unknown";
1469 platform = "Unknown";
1471 const int ver = _mkversion(osvinfo.dwPlatformId,
1472 osvinfo.dwMajorVersion,
1473 osvinfo.dwMinorVersion);
1474 snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1477 case MS_WINDOWS_95: (version = "Windows 95"); break;
1478 case MS_WINDOWS_98: (version = "Windows 98"); break;
1479 case MS_WINDOWS_ME: (version = "Windows ME"); break;
1480 case MS_WINDOWS_NT4:(version = "Windows NT 4.0"); platform = "NT"; break;
1481 case MS_WINDOWS_2K: (version = "Windows 2000");platform = "NT"; break;
1482 case MS_WINDOWS_XP: (version = "Windows XP");platform = "NT"; break;
1483 case MS_WINDOWS_S2003: (version = "Windows Server 2003");platform = "NT"; break;
1484 default: version = WIN_RAWVERSION; break;
1487 bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1488 snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1489 platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1492 HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1496 BPIPE *b = open_bpipe("ls -l", 10, "r");
1498 while (!feof(b->rfd)) {
1499 fgets(buf, sizeof(buf), b->rfd);
1505 BOOL CreateChildProcess(VOID);
1506 VOID WriteToPipe(VOID);
1507 VOID ReadFromPipe(VOID);
1508 VOID ErrorExit(LPCSTR);
1509 VOID ErrMsg(LPTSTR, BOOL);
1512 * Check for a quoted path, if an absolute path name is given and it contains
1513 * spaces it will need to be quoted. i.e. "c:/Program Files/foo/bar.exe"
1514 * CreateProcess() says the best way to ensure proper results with executables
1515 * with spaces in path or filename is to quote the string.
1518 getArgv0(const char *cmdline)
1523 for (cp = cmdline; *cp; cp++)
1528 if (!inquote && isspace(*cp))
1533 int len = cp - cmdline;
1534 char *rval = (char *)malloc(len+1);
1547 * Extracts the executable or script name from the first string in
1550 * If the name contains blanks then it must be quoted with double quotes,
1551 * otherwise quotes are optional. If the name contains blanks then it
1552 * will be converted to a short name.
1554 * The optional quotes will be removed. The result is copied to a malloc'ed
1555 * buffer and returned through the pexe argument. The pargs parameter is set
1556 * to the address of the character in cmdline located after the name.
1558 * The malloc'ed buffer returned in *pexe must be freed by the caller.
1561 GetApplicationName(const char *cmdline, char **pexe, const char **pargs)
1563 const char *pExeStart = NULL; /* Start of executable name in cmdline */
1564 const char *pExeEnd = NULL; /* Character after executable name (separator) */
1566 const char *pBasename = NULL; /* Character after last path separator */
1567 const char *pExtension = NULL; /* Period at start of extension */
1569 const char *current = cmdline;
1571 bool bQuoted = false;
1573 /* Skip initial whitespace */
1575 while (*current == ' ' || *current == '\t')
1580 /* Calculate start of name and determine if quoted */
1582 if (*current == '"') {
1583 pExeStart = ++current;
1586 pExeStart = current;
1593 * Scan command line looking for path separators (/ and \\) and the
1594 * terminator, either a quote or a blank. The location of the
1595 * extension is also noted.
1598 for ( ; *current != '\0'; current++)
1600 if (*current == '.') {
1601 pExtension = current;
1602 } else if (IsPathSeparator(*current) && current[1] != '\0') {
1603 pBasename = ¤t[1];
1607 /* Check for terminator, either quote or blank */
1609 if (*current != '"') {
1613 if (*current != ' ') {
1619 * Hit terminator, remember end of name (address of terminator) and
1620 * start of arguments
1624 if (bQuoted && *current == '"') {
1625 *pargs = ¤t[1];
1633 if (pBasename == NULL) {
1634 pBasename = pExeStart;
1637 if (pExeEnd == NULL) {
1646 bool bHasPathSeparators = pExeStart != pBasename;
1648 /* We have pointers to all the useful parts of the name */
1650 /* Default extensions in the order cmd.exe uses to search */
1652 static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" };
1653 DWORD dwBasePathLength = pExeEnd - pExeStart;
1655 DWORD dwAltNameLength = 0;
1656 char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1657 char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1);
1659 pPathname[MAX_PATHLENGTH] = '\0';
1660 pAltPathname[MAX_PATHLENGTH] = '\0';
1662 memcpy(pPathname, pExeStart, dwBasePathLength);
1663 pPathname[dwBasePathLength] = '\0';
1665 if (pExtension == NULL) {
1666 /* Try appending extensions */
1667 for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) {
1669 if (!bHasPathSeparators) {
1670 /* There are no path separators, search in the standard locations */
1671 dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL);
1672 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1673 memcpy(pPathname, pAltPathname, dwAltNameLength);
1674 pPathname[dwAltNameLength] = '\0';
1678 bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength);
1679 if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) {
1684 } else if (!bHasPathSeparators) {
1685 /* There are no path separators, search in the standard locations */
1686 dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL);
1687 if (dwAltNameLength == 0 || dwAltNameLength > MAX_PATHLENGTH) {
1691 memcpy(pPathname, pAltPathname, dwAltNameLength);
1692 pPathname[dwAltNameLength] = '\0';
1695 if (strchr(pPathname, ' ') != NULL) {
1696 dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH);
1698 if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) {
1699 *pexe = (char *)malloc(dwAltNameLength + 1);
1700 if (*pexe != NULL) {
1701 memcpy(*pexe, pAltPathname, dwAltNameLength + 1);
1709 DWORD dwPathnameLength = strlen(pPathname);
1710 *pexe = (char *)malloc(dwPathnameLength + 1);
1711 if (*pexe != NULL) {
1712 memcpy(*pexe, pPathname, dwPathnameLength + 1);
1722 * OK, so it would seem CreateProcess only handles true executables:
1723 * .com or .exe files. So grab $COMSPEC value and pass command line to it.
1726 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1728 static const char *comspec = NULL;
1729 PROCESS_INFORMATION piProcInfo;
1730 STARTUPINFOA siStartInfo;
1731 BOOL bFuncRetn = FALSE;
1733 if (comspec == NULL) {
1734 comspec = getenv("COMSPEC");
1736 if (comspec == NULL) // should never happen
1737 return INVALID_HANDLE_VALUE;
1739 // Set up members of the PROCESS_INFORMATION structure.
1740 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1742 // Set up members of the STARTUPINFO structure.
1744 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1745 siStartInfo.cb = sizeof(STARTUPINFO);
1746 // setup new process to use supplied handles for stdin,stdout,stderr
1747 // if supplied handles are not used the send a copy of our STD_HANDLE
1749 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
1751 if (in != INVALID_HANDLE_VALUE)
1752 siStartInfo.hStdInput = in;
1754 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1756 if (out != INVALID_HANDLE_VALUE)
1757 siStartInfo.hStdOutput = out;
1759 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1760 if (err != INVALID_HANDLE_VALUE)
1761 siStartInfo.hStdError = err;
1763 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1765 // Create the child process.
1768 const char *argStart;
1770 if (!GetApplicationName(cmdline, &exeFile, &argStart)) {
1771 return INVALID_HANDLE_VALUE;
1774 int cmdLen = strlen(comspec) + 4 + strlen(exeFile) + strlen(argStart) + 1;
1776 char *cmdLine = (char *)alloca(cmdLen);
1778 snprintf(cmdLine, cmdLen, "%s /c %s%s", comspec, exeFile, argStart);
1782 Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine);
1784 // try to execute program
1785 bFuncRetn = CreateProcessA(comspec,
1786 cmdLine, // command line
1787 NULL, // process security attributes
1788 NULL, // primary thread security attributes
1789 TRUE, // handles are inherited
1790 0, // creation flags
1791 NULL, // use parent's environment
1792 NULL, // use parent's current directory
1793 &siStartInfo, // STARTUPINFO pointer
1794 &piProcInfo); // receives PROCESS_INFORMATION
1796 if (bFuncRetn == 0) {
1797 ErrorExit("CreateProcess failed\n");
1798 const char *err = errorString();
1799 Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n", comspec, cmdLine, err);
1800 LocalFree((void *)err);
1801 return INVALID_HANDLE_VALUE;
1803 // we don't need a handle on the process primary thread so we close
1805 CloseHandle(piProcInfo.hThread);
1807 return piProcInfo.hProcess;
1812 ErrorExit (LPCSTR lpszMessage)
1814 Dmsg1(0, "%s", lpszMessage);
1819 typedef struct s_bpipe {
1821 time_t worker_stime;
1830 CloseIfValid(HANDLE handle)
1832 if (handle != INVALID_HANDLE_VALUE)
1833 CloseHandle(handle);
1837 open_bpipe(char *prog, int wait, const char *mode)
1839 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1840 hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1843 SECURITY_ATTRIBUTES saAttr;
1847 hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1848 hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1849 hInputFile = INVALID_HANDLE_VALUE;
1851 BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1852 memset((void *)bpipe, 0, sizeof(BPIPE));
1854 int mode_read = (mode[0] == 'r');
1855 int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1858 // Set the bInheritHandle flag so pipe handles are inherited.
1860 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1861 saAttr.bInheritHandle = TRUE;
1862 saAttr.lpSecurityDescriptor = NULL;
1866 // Create a pipe for the child process's STDOUT.
1867 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1868 ErrorExit("Stdout pipe creation failed\n");
1871 // Create noninheritable read handle and close the inheritable read
1874 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1875 GetCurrentProcess(), &hChildStdoutRdDup , 0,
1877 DUPLICATE_SAME_ACCESS);
1879 ErrorExit("DuplicateHandle failed");
1883 CloseHandle(hChildStdoutRd);
1884 hChildStdoutRd = INVALID_HANDLE_VALUE;
1889 // Create a pipe for the child process's STDIN.
1891 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1892 ErrorExit("Stdin pipe creation failed\n");
1896 // Duplicate the write handle to the pipe so it is not inherited.
1897 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
1898 GetCurrentProcess(), &hChildStdinWrDup,
1900 FALSE, // not inherited
1901 DUPLICATE_SAME_ACCESS);
1903 ErrorExit("DuplicateHandle failed");
1907 CloseHandle(hChildStdinWr);
1908 hChildStdinWr = INVALID_HANDLE_VALUE;
1910 // spawn program with redirected handles as appropriate
1911 bpipe->worker_pid = (pid_t)
1912 CreateChildProcess(prog, // commandline
1913 hChildStdinRd, // stdin HANDLE
1914 hChildStdoutWr, // stdout HANDLE
1915 hChildStdoutWr); // stderr HANDLE
1917 if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1921 bpipe->worker_stime = time(NULL);
1924 CloseHandle(hChildStdoutWr); // close our write side so when
1925 // process terminates we can
1927 // ugly but convert WIN32 HANDLE to FILE*
1928 int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY | O_BINARY);
1930 bpipe->rfd = _fdopen(rfd, "rb");
1934 CloseHandle(hChildStdinRd); // close our read side so as not
1935 // to interfre with child's copy
1936 // ugly but convert WIN32 HANDLE to FILE*
1937 int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY | O_BINARY);
1939 bpipe->wfd = _fdopen(wfd, "wb");
1944 bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
1951 CloseIfValid(hChildStdoutRd);
1952 CloseIfValid(hChildStdoutRdDup);
1953 CloseIfValid(hChildStdinWr);
1954 CloseIfValid(hChildStdinWrDup);
1956 free((void *) bpipe);
1957 errno = b_errno_win32; /* do GetLastError() for error code */
1963 kill(int pid, int signal)
1966 if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
1968 errno = b_errno_win32;
1970 CloseHandle((HANDLE)pid);
1976 close_bpipe(BPIPE *bpipe)
1979 int32_t remaining_wait = bpipe->wait;
1991 if (remaining_wait == 0) { /* wait indefinitely */
1992 remaining_wait = INT32_MAX;
1996 if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
1997 const char *err = errorString();
1998 rval = b_errno_win32;
1999 Dmsg1(0, "GetExitCode error %s\n", err);
2000 LocalFree((void *)err);
2003 if (exitCode == STILL_ACTIVE) {
2004 if (remaining_wait <= 0) {
2005 rval = ETIME; /* timed out */
2008 bmicrosleep(1, 0); /* wait one second */
2010 } else if (exitCode != 0) {
2011 /* Truncate exit code as it doesn't seem to be correct */
2012 rval = (exitCode & 0xFF) | b_errno_exit;
2015 break; /* Shouldn't get here */
2019 if (bpipe->timer_id) {
2020 stop_child_timer(bpipe->timer_id);
2022 if (bpipe->rfd) fclose(bpipe->rfd);
2023 if (bpipe->wfd) fclose(bpipe->wfd);
2024 free((void *)bpipe);
2029 close_wpipe(BPIPE *bpipe)
2035 if (fclose(bpipe->wfd) != 0) {
2043 #include "findlib/find.h"
2046 utime(const char *fname, struct utimbuf *times)
2051 conv_unix_to_win32_path(fname, tmpbuf, 5000);
2053 cvt_utime_to_ftime(times->actime, acc);
2054 cvt_utime_to_ftime(times->modtime, mod);
2056 HANDLE h = INVALID_HANDLE_VALUE;
2058 if (p_CreateFileW) {
2059 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2060 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
2062 h = p_CreateFileW((LPCWSTR)pwszBuf,
2063 FILE_WRITE_ATTRIBUTES,
2064 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2067 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2070 free_pool_memory(pwszBuf);
2071 } else if (p_CreateFileA) {
2072 h = p_CreateFileA(tmpbuf,
2073 FILE_WRITE_ATTRIBUTES,
2074 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
2077 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
2081 if (h == INVALID_HANDLE_VALUE) {
2082 const char *err = errorString();
2083 Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
2084 LocalFree((void *)err);
2085 errno = b_errno_win32;
2089 int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
2092 errno = b_errno_win32;
2099 file_open(const char *file, int flags, int mode)
2102 DWORD shareMode = 0;
2105 HANDLE foo = INVALID_HANDLE_VALUE;
2106 const char *remap = file;
2108 if (flags & O_WRONLY) access = GENERIC_WRITE;
2109 else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
2110 else access = GENERIC_READ;
2112 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
2113 create = CREATE_NEW;
2114 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
2115 create = CREATE_ALWAYS;
2116 else if (flags & O_CREAT)
2117 create = OPEN_ALWAYS;
2118 else if (flags & O_TRUNC)
2119 create = TRUNCATE_EXISTING;
2121 create = OPEN_EXISTING;
2125 if (flags & O_APPEND) {
2126 printf("open...APPEND not implemented yet.");
2130 if (p_CreateFileW) {
2131 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
2132 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
2134 foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
2135 free_pool_memory(pwszBuf);
2136 } else if (p_CreateFileA)
2137 foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
2139 if (INVALID_HANDLE_VALUE == foo) {
2140 errno = b_errno_win32;
2151 if (!CloseHandle((HANDLE)fd)) {
2152 errno = b_errno_win32;
2160 file_write(int fd, const void *data, ssize_t len)
2164 status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
2165 if (status) return bwrite;
2166 errno = b_errno_win32;
2172 file_read(int fd, void *data, ssize_t len)
2177 status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
2178 if (status) return bread;
2179 errno = b_errno_win32;
2184 file_seek(int fd, boffset_t offset, int whence)
2188 LONG offset_low = (LONG)offset;
2189 LONG offset_high = (LONG)(offset >> 32);
2193 method = FILE_BEGIN;
2196 method = FILE_CURRENT;
2207 if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) {
2208 errno = b_errno_win32;
2211 /* ***FIXME*** I doubt this works right */
2224 /* syslog function, added by Nicolas Boichat */
2225 void openlog(const char *ident, int option, int facility) {}