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)
31 /* UTF-8 to UCS2 path conversion is expensive,
32 so we cache the conversion. During backup the
33 conversion is called 3 times (lstat, attribs, open),
34 by using the cache this is reduced to 1 time */
36 static POOLMEM *g_pWin32ConvUTF8Cache = get_pool_memory (PM_FNAME);
37 static POOLMEM *g_pWin32ConvUCS2Cache = get_pool_memory (PM_FNAME);
38 static DWORD g_dwWin32ConvUTF8strlen = 0;
39 static pthread_mutex_t Win32Convmutex = PTHREAD_MUTEX_INITIALIZER;
41 static t_pVSSPathConvert g_pVSSPathConvert;
42 static t_pVSSPathConvertW g_pVSSPathConvertW;
44 void SetVSSPathConvert(t_pVSSPathConvert pPathConvert, t_pVSSPathConvertW pPathConvertW)
46 g_pVSSPathConvert = pPathConvert;
47 g_pVSSPathConvertW = pPathConvertW;
50 void Win32ConvCleanupCache()
52 if (g_pWin32ConvUTF8Cache) {
53 free_pool_memory(g_pWin32ConvUTF8Cache);
54 g_pWin32ConvUTF8Cache = NULL;
57 if (g_pWin32ConvUCS2Cache) {
58 free_pool_memory(g_pWin32ConvUCS2Cache);
59 g_pWin32ConvUCS2Cache = NULL;
62 g_dwWin32ConvUTF8strlen = 0;
66 /* to allow the usage of the original version in this file here */
70 //#define USE_WIN32_COMPAT_IO 1
71 #define USE_WIN32_32KPATHCONVERSION 1
73 extern DWORD g_platform_id;
74 extern DWORD g_MinorVersion;
76 // from MicroSoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970
78 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL
80 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
83 #define WIN32_FILETIME_SCALE 10000000 // 100ns/second
85 void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize)
87 const char *fname = name;
88 char *tname = win32_name;
90 Dmsg0(100, "Enter convert_unix_to_win32_path\n");
92 if ((name[0] == '/' || name[0] == '\\') &&
93 (name[1] == '/' || name[1] == '\\') &&
95 (name[3] == '/' || name[3] == '\\')) {
100 *win32_name++ = '\\';
106 /* Check for Unix separator and convert to Win32 */
107 if (name[0] == '/' && name[1] == '/') { /* double slash? */
108 name++; /* yes, skip first one */
111 *win32_name++ = '\\'; /* convert char */
112 /* If Win32 separated that is "quoted", remove quote */
113 } else if (*name == '\\' && name[1] == '\\') {
114 *win32_name++ = '\\';
115 name++; /* skip first \ */
117 *win32_name++ = *name; /* copy character */
121 /* Strip any trailing slash, if we stored something */
122 /* but leave "c:\" with backslash (root directory case */
123 if (*fname != 0 && win32_name[-1] == '\\' && strlen (fname) != 3) {
129 /* here we convert to VSS specific file name which
130 can get longer because VSS will make something like
131 \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
132 from c:\bacula\uninstall.exe
134 Dmsg1(100, "path=%s\n", tname);
135 if (g_pVSSPathConvert != NULL) {
136 POOLMEM *pszBuf = get_pool_memory (PM_FNAME);
137 pszBuf = check_pool_memory_size(pszBuf, dwSize);
138 bstrncpy(pszBuf, tname, strlen(tname)+1);
139 g_pVSSPathConvert(pszBuf, tname, dwSize);
140 free_pool_memory(pszBuf);
142 Dmsg1(100, "Leave cvt_u_to_win32_path path=%s\n", tname);
145 /* Conversion of a Unix filename to a Win32 filename */
146 void unix_name_to_win32(POOLMEM **win32_name, char *name)
148 /* One extra byte should suffice, but we double it */
149 /* add MAX_PATH bytes for VSS shadow copy name */
150 DWORD dwSize = 2*strlen(name)+MAX_PATH;
151 *win32_name = check_pool_memory_size(*win32_name, dwSize);
152 conv_unix_to_win32_path(name, *win32_name, dwSize);
156 make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/)
158 /* created 02/27/2006 Thorsten Engel
160 * This function expects an UCS-encoded standard wchar_t in pszUCSPath and
161 * will complete the input path to an absolue path of the form \\?\c:\path\file
163 * With this trick, it is possible to have 32K characters long paths.
165 * Optionally one can use pBIsRawPath to determine id pszUCSPath contains a path
166 * to a raw windows partition.
169 Dmsg0(100, "Enter wchar_win32_path\n");
171 *pBIsRawPath = FALSE; /* Initialize, set later */
174 if (!p_GetCurrentDirectoryW) {
175 Dmsg0(100, "Leave wchar_win32_path no change \n");
179 wchar_t *name = (wchar_t *)pszUCSPath;
181 /* if it has already the desired form, exit without changes */
182 if (wcslen(name) > 3 && wcsncmp(name, L"\\\\?\\", 4) == 0) {
183 Dmsg0(100, "Leave wchar_win32_path no change \n");
187 POOLMEM *pwszBuf = get_pool_memory(PM_FNAME);
188 POOLMEM *pwszCurDirBuf = get_pool_memory(PM_FNAME);
189 DWORD dwCurDirPathSize = 0;
191 /* get buffer with enough size (name+max 6. wchars+1 null terminator */
192 DWORD dwBufCharsNeeded = (wcslen(name)+7);
193 pwszBuf = check_pool_memory_size(pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
195 /* add \\?\ to support 32K long filepaths
196 it is important to make absolute paths, so we add drive and
197 current path if necessary */
199 BOOL bAddDrive = TRUE;
200 BOOL bAddCurrentPath = TRUE;
201 BOOL bAddPrefix = TRUE;
203 /* does path begin with drive? if yes, it is absolute */
204 if (wcslen(name) >= 3 && (iswalpha (*name) && *(name+1) == ':'
205 && (*(name+2) == '\\' || *(name+2) == '/'))) {
207 bAddCurrentPath = FALSE;
210 /* is path absolute? */
211 if (*name == '/' || *name == '\\')
212 bAddCurrentPath = FALSE;
214 /* is path relative to itself?, if yes, skip ./ */
215 if (wcslen(name) > 2 && ((wcsncmp(name, L"./", 2) == 0) || (wcsncmp(name, L".\\", 2) == 0))) {
219 /* is path of form '//./'? */
220 if (wcslen(name) > 3 && ((wcsncmp(name, L"//./", 4) == 0) || (wcsncmp(name, L"\\\\.\\", 4) == 0))) {
222 bAddCurrentPath = FALSE;
229 int nParseOffset = 0;
231 /* add 4 bytes header */
234 wcscpy((wchar_t *)pwszBuf, L"\\\\?\\");
237 /* get current path if needed */
238 if (bAddDrive || bAddCurrentPath) {
239 dwCurDirPathSize = p_GetCurrentDirectoryW(0, NULL);
240 if (dwCurDirPathSize > 0) {
241 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
242 pwszCurDirBuf = check_pool_memory_size(pwszCurDirBuf, (dwCurDirPathSize+1)*sizeof(wchar_t));
243 p_GetCurrentDirectoryW(dwCurDirPathSize,(wchar_t *)pwszCurDirBuf);
245 /* we have no info for doing so */
247 bAddCurrentPath = FALSE;
252 /* add drive if needed */
253 if (bAddDrive && !bAddCurrentPath) {
256 if (dwCurDirPathSize > 3 && wcsncmp((LPCWSTR)pwszCurDirBuf, L"\\\\?\\", 4) == 0) {
257 /* copy drive character */
258 wcsncpy((wchar_t *)szDrive, (LPCWSTR)pwszCurDirBuf+4, 2);
260 /* copy drive character */
261 wcsncpy((wchar_t *)szDrive, (LPCWSTR)pwszCurDirBuf, 2);
266 wcscat((wchar_t *)pwszBuf, szDrive);
270 /* add path if needed */
271 if (bAddCurrentPath) {
272 /* the 1 add. character is for the eventually added backslash */
273 dwBufCharsNeeded += dwCurDirPathSize+1;
274 pwszBuf = check_pool_memory_size(pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
275 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
277 if (dwCurDirPathSize > 3 && wcsncmp((LPCWSTR)pwszCurDirBuf, L"\\\\?\\", 4) == 0) {
278 /* copy complete string */
279 wcscpy((wchar_t *)pwszBuf, (LPCWSTR)pwszCurDirBuf);
282 wcscat((wchar_t *)pwszBuf, (LPCWSTR)pwszCurDirBuf);
285 nParseOffset = wcslen((LPCWSTR) pwszBuf);
287 /* check if path ends with backslash, if not, add one */
288 if (*((wchar_t *)pwszBuf+nParseOffset-1) != L'\\') {
289 wcscat((wchar_t *)pwszBuf, L"\\");
295 wchar_t *win32_name = (wchar_t *)pwszBuf+nParseOffset;
298 /* Check for Unix separator and convert to Win32 */
300 *win32_name++ = '\\'; /* convert char */
301 /* If Win32 separated that is "quoted", remove quote */
302 /* HELPME (Thorsten Engel): I don't understand the following part
303 * and it removes a backslash from e.g. "\\.\c:" which I need for
304 * RAW device access. So I took it out.
307 } else if (*name == '\\' && name[1] == '\\') {
308 *win32_name++ = '\\';
309 name++; /* skip first \ */
312 *win32_name++ = *name; /* copy character */
317 /* null terminate string */
320 /* here we convert to VSS specific file name which
321 * can get longer because VSS will make something like
322 * \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
323 * from c:\bacula\uninstall.exe
325 if (g_pVSSPathConvertW != NULL) {
326 /* is output buffer large enough? */
327 pwszBuf = check_pool_memory_size(pwszBuf, (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
328 /* create temp. buffer */
329 POOLMEM* pszBuf = get_pool_memory(PM_FNAME);
330 pszBuf = check_pool_memory_size(pszBuf, (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
335 wcsncpy((wchar_t *)pszBuf, (wchar_t *)pwszBuf+nParseOffset, wcslen((wchar_t *)pwszBuf)+1-nParseOffset);
336 g_pVSSPathConvertW((wchar_t *)pszBuf, (wchar_t *)pwszBuf, dwBufCharsNeeded+MAX_PATH);
337 free_pool_memory(pszBuf);
340 free_pool_memory(pszUCSPath);
341 free_pool_memory(pwszCurDirBuf);
343 Dmsg1(100, "Leave wchar_win32_path=%s\n", pwszBuf);
348 wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
350 /* the return value is the number of bytes written to the buffer.
351 The number includes the byte for the null terminator. */
353 if (p_WideCharToMultiByte) {
354 int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
363 UTF8_2_wchar(POOLMEM **ppszUCS, const char *pszUTF)
365 /* the return value is the number of wide characters written to the buffer. */
366 /* convert null terminated string from utf-8 to ucs2, enlarge buffer if necessary */
368 if (p_MultiByteToWideChar) {
369 /* strlen of UTF8 +1 is enough */
370 DWORD cchSize = (strlen(pszUTF)+1);
371 *ppszUCS = check_pool_memory_size(*ppszUCS, cchSize*sizeof (wchar_t));
373 int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
383 wchar_win32_path(const char *name, wchar_t *win32_name)
385 const char *fname = name;
387 /* Check for Unix separator and convert to Win32 */
389 *win32_name++ = '\\'; /* convert char */
390 /* If Win32 separated that is "quoted", remove quote */
391 } else if (*name == '\\' && name[1] == '\\') {
392 *win32_name++ = '\\';
393 name++; /* skip first \ */
395 *win32_name++ = *name; /* copy character */
399 /* Strip any trailing slash, if we stored something */
400 if (*fname != 0 && win32_name[-1] == '\\') {
408 make_win32_path_UTF8_2_wchar(POOLMEM **pszUCS, const char *pszUTF, BOOL* pBIsRawPath /*= NULL*/)
411 /* if we find the utf8 string in cache, we use the cached ucs2 version.
412 we compare the stringlength first (quick check) and then compare the content.
414 if (g_dwWin32ConvUTF8strlen == strlen(pszUTF)) {
415 if (bstrcmp(pszUTF, g_pWin32ConvUTF8Cache)) {
416 int32_t nBufSize = sizeof_pool_memory(g_pWin32ConvUCS2Cache);
417 *pszUCS = check_pool_memory_size(*pszUCS, nBufSize);
418 wcscpy((LPWSTR) *pszUCS, (LPWSTR) g_pWin32ConvUCS2Cache);
420 return nBufSize / sizeof (WCHAR);
424 /* helper to convert from utf-8 to UCS-2 and to complete a path for 32K path syntax */
425 int nRet = UTF8_2_wchar(pszUCS, pszUTF);
427 #ifdef USE_WIN32_32KPATHCONVERSION
428 /* add \\?\ to support 32K long filepaths */
429 *pszUCS = make_wchar_win32_path(*pszUCS, pBIsRawPath);
432 *pBIsRawPath = FALSE;
436 g_pWin32ConvUCS2Cache = check_pool_memory_size(g_pWin32ConvUCS2Cache, sizeof_pool_memory(*pszUCS));
437 wcscpy((LPWSTR) g_pWin32ConvUCS2Cache, (LPWSTR) *pszUCS);
439 g_dwWin32ConvUTF8strlen = strlen(pszUTF);
440 g_pWin32ConvUTF8Cache = check_pool_memory_size(g_pWin32ConvUTF8Cache, g_dwWin32ConvUTF8strlen+1);
441 bstrncpy(g_pWin32ConvUTF8Cache, pszUTF, g_dwWin32ConvUTF8strlen+1);
447 #if !defined(_MSC_VER) || (_MSC_VER < 1400) // VC8+
454 int fcntl(int fd, int cmd)
459 int chmod(const char *, mode_t)
464 int chown(const char *k, uid_t, gid_t)
469 int lchown(const char *k, uid_t, gid_t)
481 srandom(unsigned int seed)
485 // /////////////////////////////////////////////////////////////////
486 // convert from Windows concept of time to Unix concept of time
487 // /////////////////////////////////////////////////////////////////
489 cvt_utime_to_ftime(const time_t &time, FILETIME &wintime)
491 uint64_t mstime = time;
492 mstime *= WIN32_FILETIME_SCALE;
493 mstime += WIN32_FILETIME_ADJUST;
495 #if defined(_MSC_VER)
496 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
498 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL);
500 wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
504 cvt_ftime_to_utime(const FILETIME &time)
506 uint64_t mstime = time.dwHighDateTime;
508 mstime |= time.dwLowDateTime;
510 mstime -= WIN32_FILETIME_ADJUST;
511 mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
513 return (time_t) (mstime & 0xffffffff);
521 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
522 FORMAT_MESSAGE_FROM_SYSTEM |
523 FORMAT_MESSAGE_IGNORE_INSERTS,
526 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
531 /* Strip any \r or \n */
532 char *rval = (char *) lpMsgBuf;
533 char *cp = strchr(rval, '\r');
537 cp = strchr(rval, '\n');
546 statDir(const char *file, struct stat *sb)
548 WIN32_FIND_DATAW info_w; // window's file info
549 WIN32_FIND_DATAA info_a; // window's file info
551 // cache some common vars to make code more transparent
552 DWORD* pdwFileAttributes;
553 DWORD* pnFileSizeHigh;
554 DWORD* pnFileSizeLow;
555 FILETIME* pftLastAccessTime;
556 FILETIME* pftLastWriteTime;
557 FILETIME* pftCreationTime;
559 if (file[1] == ':' && file[2] == 0) {
560 Dmsg1(99, "faking ROOT attrs(%s).\n", file);
561 sb->st_mode = S_IFDIR;
562 sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
569 HANDLE h = INVALID_HANDLE_VALUE;
571 // use unicode or ascii
572 if (p_FindFirstFileW) {
573 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
574 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
576 h = p_FindFirstFileW((LPCWSTR) pwszBuf, &info_w);
577 free_pool_memory(pwszBuf);
579 pdwFileAttributes = &info_w.dwFileAttributes;
580 pnFileSizeHigh = &info_w.nFileSizeHigh;
581 pnFileSizeLow = &info_w.nFileSizeLow;
582 pftLastAccessTime = &info_w.ftLastAccessTime;
583 pftLastWriteTime = &info_w.ftLastWriteTime;
584 pftCreationTime = &info_w.ftCreationTime;
586 else if (p_FindFirstFileA) {
587 h = p_FindFirstFileA(file, &info_a);
589 pdwFileAttributes = &info_a.dwFileAttributes;
590 pnFileSizeHigh = &info_a.nFileSizeHigh;
591 pnFileSizeLow = &info_a.nFileSizeLow;
592 pftLastAccessTime = &info_a.ftLastAccessTime;
593 pftLastWriteTime = &info_a.ftLastWriteTime;
594 pftCreationTime = &info_a.ftCreationTime;
597 if (h == INVALID_HANDLE_VALUE) {
598 const char *err = errorString();
599 Dmsg2(99, "FindFirstFile(%s):%s\n", file, err);
600 LocalFree((void *)err);
601 errno = b_errno_win32;
605 sb->st_mode = 0777; /* start with everything */
606 if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
607 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
608 if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
609 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
610 if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
611 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
612 sb->st_mode |= S_IFDIR;
614 sb->st_size = *pnFileSizeHigh;
616 sb->st_size |= *pnFileSizeLow;
617 sb->st_blksize = 4096;
618 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
620 sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
621 sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
622 sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
629 fstat(int fd, struct stat *sb)
631 BY_HANDLE_FILE_INFORMATION info;
634 if (!GetFileInformationByHandle((HANDLE)fd, &info)) {
635 const char *err = errorString();
636 Dmsg2(99, "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
637 LocalFree((void *)err);
638 errno = b_errno_win32;
642 sb->st_dev = info.dwVolumeSerialNumber;
643 sb->st_ino = info.nFileIndexHigh;
645 sb->st_ino |= info.nFileIndexLow;
646 sb->st_nlink = (short)info.nNumberOfLinks;
647 if (sb->st_nlink > 1) {
648 Dmsg1(99, "st_nlink=%d\n", sb->st_nlink);
651 sb->st_mode = 0777; /* start with everything */
652 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
653 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
654 if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
655 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
656 if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
657 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
658 sb->st_mode |= S_IFREG;
660 sb->st_size = info.nFileSizeHigh;
662 sb->st_size |= info.nFileSizeLow;
663 sb->st_blksize = 4096;
664 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
665 sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
666 sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
667 sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
673 stat2(const char *file, struct stat *sb)
678 conv_unix_to_win32_path(file, tmpbuf, 1024);
680 DWORD attr = (DWORD)-1;
682 if (p_GetFileAttributesW) {
683 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
684 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
686 attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
687 free_pool_memory(pwszBuf);
688 } else if (p_GetFileAttributesA) {
689 attr = p_GetFileAttributesA(tmpbuf);
692 if (attr == (DWORD)-1) {
693 const char *err = errorString();
694 Dmsg2(99, "GetFileAttributes(%s): %s\n", tmpbuf, err);
695 LocalFree((void *)err);
696 errno = b_errno_win32;
700 if (attr & FILE_ATTRIBUTE_DIRECTORY)
701 return statDir(tmpbuf, sb);
703 h = CreateFileA(tmpbuf, GENERIC_READ,
704 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
706 if (h == INVALID_HANDLE_VALUE) {
707 const char *err = errorString();
708 Dmsg2(99, "Cannot open file for stat (%s):%s\n", tmpbuf, err);
709 LocalFree((void *)err);
710 errno = b_errno_win32;
714 rval = fstat((int)h, sb);
721 stat(const char *file, struct stat *sb)
723 WIN32_FILE_ATTRIBUTE_DATA data;
727 memset(sb, 0, sizeof(*sb));
729 /* why not allow win 95 to use p_GetFileAttributesExA ?
730 * this function allows _some_ open files to be stat'ed
731 * if (g_platform_id == VER_PLATFORM_WIN32_WINDOWS) {
732 * return stat2(file, sb);
736 if (p_GetFileAttributesExW) {
737 /* dynamically allocate enough space for UCS2 filename */
738 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
739 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
741 BOOL b = p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, &data);
742 free_pool_memory(pwszBuf);
745 return stat2(file, sb);
747 } else if (p_GetFileAttributesExA) {
748 if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
749 return stat2(file, sb);
752 return stat2(file, sb);
755 sb->st_mode = 0777; /* start with everything */
756 if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
757 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
759 if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
760 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
762 if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
763 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
765 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
766 sb->st_mode |= S_IFDIR;
768 sb->st_mode |= S_IFREG;
772 sb->st_size = data.nFileSizeHigh;
774 sb->st_size |= data.nFileSizeLow;
775 sb->st_blksize = 4096;
776 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
777 sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
778 sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
779 sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
783 int fcntl(int fd, int cmd, long arg)
806 lstat(const char *file, struct stat *sb)
808 return stat(file, sb);
824 execvp(const char *, char *[]) {
845 waitpid(int, int*, int)
852 readlink(const char *, char *, int)
861 strcasecmp(const char *s1, const char *s2)
863 register int ch1, ch2;
866 return 0; /* strings are equal if same object. */
876 } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
883 strncasecmp(const char *s1, const char *s2, int len)
885 register int ch1 = 0, ch2 = 0;
888 return 0; /* strings are equal if same object. */
899 if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
906 gettimeofday(struct timeval *tv, struct timezone *)
916 if (!SystemTimeToFileTime(&now, &tmp)) {
917 errno = b_errno_win32;
921 int64_t _100nsec = tmp.dwHighDateTime;
923 _100nsec |= tmp.dwLowDateTime;
924 _100nsec -= WIN32_FILETIME_ADJUST;
926 tv->tv_sec =(long) (_100nsec / 10000000);
927 tv->tv_usec = (long) ((_100nsec % 10000000)/10);
932 /* For apcupsd this is in src/lib/wincompat.c */
933 extern "C" void syslog(int type, const char *fmt, ...)
935 /*#ifndef HAVE_CONSOLE
936 MessageBox(NULL, msg, "Bacula", MB_OK);
957 // implement opendir/readdir/closedir on top of window's API
961 WIN32_FIND_DATAA data_a; // window's file info (ansii version)
962 WIN32_FIND_DATAW data_w; // window's file info (wchar version)
963 const char *spec; // the directory we're traversing
964 HANDLE dirh; // the search handle
965 BOOL valid_a; // the info in data_a field is valid
966 BOOL valid_w; // the info in data_w field is valid
967 UINT32 offset; // pseudo offset for d_off
971 opendir(const char *path)
973 /* enough space for VSS !*/
974 int max_len = strlen(path) + MAX_PATH;
981 Dmsg1(100, "Opendir path=%s\n", path);
982 rval = (_dir *)malloc(sizeof(_dir));
983 memset (rval, 0, sizeof (_dir));
984 if (rval == NULL) return NULL;
985 char *tspec = (char *)malloc(max_len);
986 if (tspec == NULL) return NULL;
988 if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS) {
990 /* will append \\?\ at front itself */
991 conv_unix_to_win32_path(path, tspec, max_len-4);
992 Dmsg1(100, "win32 path=%s\n", tspec);
994 /* allow path to be 32767 bytes */
1000 conv_unix_to_win32_path(path, tspec+4, max_len-4);
1001 Dmsg1(100, "win32 path=%s\n", tspec);
1004 conv_unix_to_win32_path(path, tspec, max_len);
1005 Dmsg1(100, "win32 path=%s\n", tspec);
1008 // add backslash only if there is none yet (think of c:\)
1009 if (tspec[strlen(tspec)-1] != '\\')
1010 bstrncat(tspec, "\\*", max_len);
1012 bstrncat(tspec, "*", max_len);
1016 // convert to wchar_t
1017 if (p_FindFirstFileW) {
1018 POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
1019 make_win32_path_UTF8_2_wchar(&pwcBuf, rval->spec);
1021 rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
1023 free_pool_memory(pwcBuf);
1025 if (rval->dirh != INVALID_HANDLE_VALUE)
1027 } else if (p_FindFirstFileA) {
1028 rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
1030 if (rval->dirh != INVALID_HANDLE_VALUE)
1035 Dmsg3(99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
1036 path, rval->spec, rval->dirh);
1039 if (rval->dirh == INVALID_HANDLE_VALUE)
1042 if (rval->valid_w) {
1043 Dmsg1(99, "\tFirstFile=%s\n", rval->data_w.cFileName);
1046 if (rval->valid_a) {
1047 Dmsg1(99, "\tFirstFile=%s\n", rval->data_a.cFileName);
1053 free((void *)rval->spec);
1055 errno = b_errno_win32;
1062 _dir *dp = (_dir *)dirp;
1063 FindClose(dp->dirh);
1064 free((void *)dp->spec);
1070 typedef struct _WIN32_FIND_DATA {
1071 DWORD dwFileAttributes;
1072 FILETIME ftCreationTime;
1073 FILETIME ftLastAccessTime;
1074 FILETIME ftLastWriteTime;
1075 DWORD nFileSizeHigh;
1079 TCHAR cFileName[MAX_PATH];
1080 TCHAR cAlternateFileName[14];
1081 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1085 copyin(struct dirent &dp, const char *fname)
1089 char *cp = dp.d_name;
1099 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1101 _dir *dp = (_dir *)dirp;
1102 if (dp->valid_w || dp->valid_a) {
1103 entry->d_off = dp->offset;
1107 char szBuf[MAX_PATH_UTF8+1];
1108 wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1109 dp->offset += copyin(*entry, szBuf);
1110 } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1111 dp->offset += copyin(*entry, dp->data_a.cFileName);
1114 *result = entry; /* return entry address */
1115 Dmsg4(99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1116 dirp, entry->d_name, entry->d_reclen, entry->d_off);
1118 // Dmsg0(99, "readdir_r !valid\n");
1119 errno = b_errno_win32;
1123 // get next file, try unicode first
1124 if (p_FindNextFileW)
1125 dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1126 else if (p_FindNextFileA)
1127 dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1129 dp->valid_a = FALSE;
1130 dp->valid_w = FALSE;
1137 * Dotted IP address to network address
1143 inet_aton(const char *a, struct in_addr *inp)
1146 uint32_t acc = 0, tmp = 0;
1149 if (!isdigit(*cp)) { /* first char must be digit */
1150 return 0; /* error */
1154 tmp = (tmp * 10) + (*cp -'0');
1155 } else if (*cp == '.' || *cp == 0) {
1157 return 0; /* error */
1159 acc = (acc << 8) + tmp;
1163 return 0; /* error */
1165 } while (*cp++ != 0);
1166 if (dotc != 4) { /* want 3 .'s plus EOS */
1167 return 0; /* error */
1169 inp->s_addr = htonl(acc); /* store addr in network format */
1174 nanosleep(const struct timespec *req, struct timespec *rem)
1177 rem->tv_sec = rem->tv_nsec = 0;
1178 Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1183 init_signals(void terminate(int sig))
1189 init_stack_dump(void)
1196 pathconf(const char *path, int name)
1200 if (strncmp(path, "\\\\?\\", 4) == 0)
1212 WORD wVersionRequested = MAKEWORD( 1, 1);
1215 int err = WSAStartup(wVersionRequested, &wsaData);
1219 printf("Can not start Windows Sockets\n");
1229 win32_chdir(const char *dir)
1231 if (p_SetCurrentDirectoryW) {
1232 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1233 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1235 BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1237 free_pool_memory(pwszBuf);
1240 errno = b_errno_win32;
1244 else if (p_SetCurrentDirectoryA) {
1245 if (0 == p_SetCurrentDirectoryA(dir)) {
1246 errno = b_errno_win32;
1256 win32_mkdir(const char *dir)
1259 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1260 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1262 int n = p_wmkdir((LPCWSTR)pwszBuf);
1263 free_pool_memory(pwszBuf);
1272 win32_getcwd(char *buf, int maxlen)
1276 if (p_GetCurrentDirectoryW) {
1277 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1278 pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1280 n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1282 n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1283 free_pool_memory(pwszBuf);
1285 } else if (p_GetCurrentDirectoryA)
1286 n = p_GetCurrentDirectoryA(maxlen, buf);
1288 if (n == 0 || n > maxlen) return NULL;
1290 if (n+1 > maxlen) return NULL;
1299 win32_fputs(const char *string, FILE *stream)
1301 /* we use WriteConsoleA / WriteConsoleA
1302 so we can be sure that unicode support works on win32.
1303 with fallback if something fails
1306 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1307 if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1308 p_MultiByteToWideChar && (stream == stdout)) {
1310 POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1312 DWORD dwCharsWritten;
1315 dwChars = UTF8_2_wchar(&pwszBuf, string);
1317 /* try WriteConsoleW */
1318 if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1319 free_pool_memory(pwszBuf);
1320 return dwCharsWritten;
1323 /* convert to local codepage and try WriteConsoleA */
1324 POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1325 pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1327 dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR) pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1328 free_pool_memory(pwszBuf);
1330 if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1331 free_pool_memory(pszBuf);
1332 return dwCharsWritten;
1336 return fputs(string, stream);
1340 win32_cgets (char* buffer, int len)
1342 /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1343 from the win32 console and fallback if seomething fails */
1345 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1346 if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1348 wchar_t wszBuf[1024];
1351 /* nt and unicode conversion */
1352 if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1354 /* null terminate at end */
1355 if (wszBuf[dwRead-1] == L'\n') {
1356 wszBuf[dwRead-1] = L'\0';
1360 if (wszBuf[dwRead-1] == L'\r') {
1361 wszBuf[dwRead-1] = L'\0';
1365 wchar_2_UTF8(buffer, wszBuf, len);
1369 /* win 9x and unicode conversion */
1370 if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1372 /* null terminate at end */
1373 if (szBuf[dwRead-1] == L'\n') {
1374 szBuf[dwRead-1] = L'\0';
1378 if (szBuf[dwRead-1] == L'\r') {
1379 szBuf[dwRead-1] = L'\0';
1383 /* convert from ansii to wchar_t */
1384 p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1385 /* convert from wchar_t to UTF-8 */
1386 if (wchar_2_UTF8(buffer, wszBuf, len))
1392 if (fgets(buffer, len, stdin))
1399 win32_unlink(const char *filename)
1403 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1404 make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1406 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1408 /* special case if file is readonly,
1409 we retry but unset attribute before */
1410 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1411 DWORD dwAttr = p_GetFileAttributesW((LPCWSTR)pwszBuf);
1412 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1413 if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1414 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1415 /* reset to original if it didn't help */
1417 p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1421 free_pool_memory(pwszBuf);
1423 nRetCode = _unlink(filename);
1425 /* special case if file is readonly,
1426 we retry but unset attribute before */
1427 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1428 DWORD dwAttr = p_GetFileAttributesA(filename);
1429 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1430 if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1431 nRetCode = _unlink(filename);
1432 /* reset to original if it didn't help */
1434 p_SetFileAttributesA(filename, dwAttr);
1443 #include "mswinver.h"
1445 char WIN_VERSION_LONG[64];
1446 char WIN_VERSION[32];
1447 char WIN_RAWVERSION[32];
1454 static winver INIT; // cause constructor to be called before main()
1457 winver::winver(void)
1459 const char *version = "";
1460 const char *platform = "";
1461 OSVERSIONINFO osvinfo;
1462 osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1464 // Get the current OS version
1465 if (!GetVersionEx(&osvinfo)) {
1466 version = "Unknown";
1467 platform = "Unknown";
1469 const int ver = _mkversion(osvinfo.dwPlatformId,
1470 osvinfo.dwMajorVersion,
1471 osvinfo.dwMinorVersion);
1472 snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1475 case MS_WINDOWS_95: (version = "Windows 95"); break;
1476 case MS_WINDOWS_98: (version = "Windows 98"); break;
1477 case MS_WINDOWS_ME: (version = "Windows ME"); break;
1478 case MS_WINDOWS_NT4:(version = "Windows NT 4.0"); platform = "NT"; break;
1479 case MS_WINDOWS_2K: (version = "Windows 2000");platform = "NT"; break;
1480 case MS_WINDOWS_XP: (version = "Windows XP");platform = "NT"; break;
1481 case MS_WINDOWS_S2003: (version = "Windows Server 2003");platform = "NT"; break;
1482 default: version = WIN_RAWVERSION; break;
1485 bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1486 snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %lu.%lu.%lu",
1487 platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1490 HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1494 BPIPE *b = open_bpipe("ls -l", 10, "r");
1496 while (!feof(b->rfd)) {
1497 fgets(buf, sizeof(buf), b->rfd);
1503 BOOL CreateChildProcess(VOID);
1504 VOID WriteToPipe(VOID);
1505 VOID ReadFromPipe(VOID);
1506 VOID ErrorExit(LPCSTR);
1507 VOID ErrMsg(LPTSTR, BOOL);
1510 * Check for a quoted path, if an absolute path name is given and it contains
1511 * spaces it will need to be quoted. i.e. "c:/Program Files/foo/bar.exe"
1512 * CreateProcess() says the best way to ensure proper results with executables
1513 * with spaces in path or filename is to quote the string.
1516 getArgv0(const char *cmdline)
1521 for (cp = cmdline; *cp; cp++)
1526 if (!inquote && isspace(*cp))
1531 int len = cp - cmdline;
1532 char *rval = (char *)malloc(len+1);
1546 * OK, so it would seem CreateProcess only handles true executables:
1547 * .com or .exe files.
1548 * So test to see whether we're getting a .bat file and if so grab
1549 * $COMSPEC value and pass batch file to it.
1552 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1554 static const char *comspec = NULL;
1555 PROCESS_INFORMATION piProcInfo;
1556 STARTUPINFOA siStartInfo;
1557 BOOL bFuncRetn = FALSE;
1559 if (comspec == NULL) {
1560 comspec = getenv("COMSPEC");
1562 if (comspec == NULL) // should never happen
1563 return INVALID_HANDLE_VALUE;
1565 // Set up members of the PROCESS_INFORMATION structure.
1566 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1568 // Set up members of the STARTUPINFO structure.
1570 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1571 siStartInfo.cb = sizeof(STARTUPINFO);
1572 // setup new process to use supplied handles for stdin,stdout,stderr
1573 // if supplied handles are not used the send a copy of our STD_HANDLE
1575 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
1577 if (in != INVALID_HANDLE_VALUE)
1578 siStartInfo.hStdInput = in;
1580 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1582 if (out != INVALID_HANDLE_VALUE)
1583 siStartInfo.hStdOutput = out;
1585 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1586 if (err != INVALID_HANDLE_VALUE)
1587 siStartInfo.hStdError = err;
1589 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1590 // Create the child process.
1593 int cmdLen = strlen(cmdline) + strlen(comspec) + 16;
1595 char *cmdLine = (char *)alloca(cmdLen);
1597 bstrncpy(exeFile, comspec, sizeof(exeFile));
1598 bstrncpy(cmdLine, comspec, cmdLen);
1599 bstrncat(cmdLine, " /c ", cmdLen);
1600 bstrncat(cmdLine, cmdline, cmdLen);
1602 // try to execute program
1603 bFuncRetn = CreateProcessA(exeFile,
1604 cmdLine, // command line
1605 NULL, // process security attributes
1606 NULL, // primary thread security attributes
1607 TRUE, // handles are inherited
1608 0, // creation flags
1609 NULL, // use parent's environment
1610 NULL, // use parent's current directory
1611 &siStartInfo, // STARTUPINFO pointer
1612 &piProcInfo); // receives PROCESS_INFORMATION
1614 if (bFuncRetn == 0) {
1615 ErrorExit("CreateProcess failed\n");
1616 const char *err = errorString();
1617 Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n", exeFile, cmdLine, err);
1618 LocalFree((void *)err);
1619 return INVALID_HANDLE_VALUE;
1621 // we don't need a handle on the process primary thread so we close
1623 CloseHandle(piProcInfo.hThread);
1625 return piProcInfo.hProcess;
1630 ErrorExit (LPCSTR lpszMessage)
1632 Dmsg1(0, "%s", lpszMessage);
1637 typedef struct s_bpipe {
1639 time_t worker_stime;
1648 CloseIfValid(HANDLE handle)
1650 if (handle != INVALID_HANDLE_VALUE)
1651 CloseHandle(handle);
1655 open_bpipe(char *prog, int wait, const char *mode)
1657 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1658 hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1661 SECURITY_ATTRIBUTES saAttr;
1665 hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1666 hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1667 hInputFile = INVALID_HANDLE_VALUE;
1669 BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1670 memset((void *)bpipe, 0, sizeof(BPIPE));
1672 int mode_read = (mode[0] == 'r');
1673 int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1676 // Set the bInheritHandle flag so pipe handles are inherited.
1678 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1679 saAttr.bInheritHandle = TRUE;
1680 saAttr.lpSecurityDescriptor = NULL;
1684 // Create a pipe for the child process's STDOUT.
1685 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1686 ErrorExit("Stdout pipe creation failed\n");
1689 // Create noninheritable read handle and close the inheritable read
1692 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1693 GetCurrentProcess(), &hChildStdoutRdDup , 0,
1695 DUPLICATE_SAME_ACCESS);
1697 ErrorExit("DuplicateHandle failed");
1701 CloseHandle(hChildStdoutRd);
1702 hChildStdoutRd = INVALID_HANDLE_VALUE;
1707 // Create a pipe for the child process's STDIN.
1709 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1710 ErrorExit("Stdin pipe creation failed\n");
1714 // Duplicate the write handle to the pipe so it is not inherited.
1715 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
1716 GetCurrentProcess(), &hChildStdinWrDup,
1718 FALSE, // not inherited
1719 DUPLICATE_SAME_ACCESS);
1721 ErrorExit("DuplicateHandle failed");
1725 CloseHandle(hChildStdinWr);
1726 hChildStdinWr = INVALID_HANDLE_VALUE;
1728 // spawn program with redirected handles as appropriate
1729 bpipe->worker_pid = (pid_t)
1730 CreateChildProcess(prog, // commandline
1731 hChildStdinRd, // stdin HANDLE
1732 hChildStdoutWr, // stdout HANDLE
1733 hChildStdoutWr); // stderr HANDLE
1735 if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1739 bpipe->worker_stime = time(NULL);
1742 CloseHandle(hChildStdoutWr); // close our write side so when
1743 // process terminates we can
1745 // ugly but convert WIN32 HANDLE to FILE*
1746 int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY);
1748 bpipe->rfd = _fdopen(rfd, "r");
1752 CloseHandle(hChildStdinRd); // close our read side so as not
1753 // to interfre with child's copy
1754 // ugly but convert WIN32 HANDLE to FILE*
1755 int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY);
1757 bpipe->wfd = _fdopen(wfd, "w");
1762 bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
1769 CloseIfValid(hChildStdoutRd);
1770 CloseIfValid(hChildStdoutRdDup);
1771 CloseIfValid(hChildStdinWr);
1772 CloseIfValid(hChildStdinWrDup);
1774 free((void *) bpipe);
1775 errno = b_errno_win32; /* do GetLastError() for error code */
1781 kill(int pid, int signal)
1784 if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
1786 errno = b_errno_win32;
1788 CloseHandle((HANDLE)pid);
1794 close_bpipe(BPIPE *bpipe)
1797 int32_t remaining_wait = bpipe->wait;
1799 if (remaining_wait == 0) { /* wait indefinitely */
1800 remaining_wait = INT32_MAX;
1804 if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
1805 const char *err = errorString();
1806 rval = b_errno_win32;
1807 Dmsg1(0, "GetExitCode error %s\n", err);
1808 LocalFree((void *)err);
1811 if (exitCode == STILL_ACTIVE) {
1812 if (remaining_wait <= 0) {
1813 rval = ETIME; /* timed out */
1816 bmicrosleep(1, 0); /* wait one second */
1818 } else if (exitCode != 0) {
1819 /* Truncate exit code as it doesn't seem to be correct */
1820 rval = (exitCode & 0xFF) | b_errno_exit;
1823 break; /* Shouldn't get here */
1827 if (bpipe->timer_id) {
1828 stop_child_timer(bpipe->timer_id);
1830 if (bpipe->rfd) fclose(bpipe->rfd);
1831 if (bpipe->wfd) fclose(bpipe->wfd);
1832 free((void *)bpipe);
1837 close_wpipe(BPIPE *bpipe)
1843 if (fclose(bpipe->wfd) != 0) {
1851 #include "findlib/find.h"
1854 utime(const char *fname, struct utimbuf *times)
1859 conv_unix_to_win32_path(fname, tmpbuf, 5000);
1861 cvt_utime_to_ftime(times->actime, acc);
1862 cvt_utime_to_ftime(times->modtime, mod);
1864 HANDLE h = INVALID_HANDLE_VALUE;
1866 if (p_CreateFileW) {
1867 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1868 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
1870 h = p_CreateFileW((LPCWSTR)pwszBuf,
1871 FILE_WRITE_ATTRIBUTES,
1872 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
1875 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
1878 free_pool_memory(pwszBuf);
1879 } else if (p_CreateFileA) {
1880 h = p_CreateFileA(tmpbuf,
1881 FILE_WRITE_ATTRIBUTES,
1882 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
1885 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
1889 if (h == INVALID_HANDLE_VALUE) {
1890 const char *err = errorString();
1891 Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
1892 LocalFree((void *)err);
1893 errno = b_errno_win32;
1897 int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
1900 errno = b_errno_win32;
1907 file_open(const char *file, int flags, int mode)
1910 DWORD shareMode = 0;
1913 HANDLE foo = INVALID_HANDLE_VALUE;
1914 const char *remap = file;
1916 if (flags & O_WRONLY) access = GENERIC_WRITE;
1917 else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
1918 else access = GENERIC_READ;
1920 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
1921 create = CREATE_NEW;
1922 else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
1923 create = CREATE_ALWAYS;
1924 else if (flags & O_CREAT)
1925 create = OPEN_ALWAYS;
1926 else if (flags & O_TRUNC)
1927 create = TRUNCATE_EXISTING;
1929 create = OPEN_EXISTING;
1933 if (flags & O_APPEND) {
1934 printf("open...APPEND not implemented yet.");
1938 if (p_CreateFileW) {
1939 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1940 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
1942 foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
1943 free_pool_memory(pwszBuf);
1944 } else if (p_CreateFileA)
1945 foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
1947 if (INVALID_HANDLE_VALUE == foo) {
1948 errno = b_errno_win32;
1959 if (!CloseHandle((HANDLE)fd)) {
1960 errno = b_errno_win32;
1968 file_write(int fd, const void *data, ssize_t len)
1972 status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
1973 if (status) return bwrite;
1974 errno = b_errno_win32;
1980 file_read(int fd, void *data, ssize_t len)
1985 status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
1986 if (status) return bread;
1987 errno = b_errno_win32;
1992 file_seek(int fd, off_t offset, int whence)
1998 method = FILE_BEGIN;
2001 method = FILE_CURRENT;
2011 if ((val=SetFilePointer((HANDLE)fd, (DWORD)offset, NULL, method)) == INVALID_SET_FILE_POINTER) {
2012 errno = b_errno_win32;
2015 /* ***FIXME*** I doubt this works right */
2028 /* syslog function, added by Nicolas Boichat */
2029 void openlog(const char *ident, int option, int facility) {}