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
35 #include "../../lib/winapi.h"
40 #define b_errno_win32 (1<<29)
43 /* UTF-8 to UCS2 path conversion is expensive,
44 so we cache the conversion. During backup the
45 conversion is called 3 times (lstat, attribs, open),
46 by using the cache this is reduced to 1 time */
48 static POOLMEM *g_pWin32ConvUTF8Cache = get_pool_memory (PM_FNAME);
49 static POOLMEM *g_pWin32ConvUCS2Cache = get_pool_memory (PM_FNAME);
50 static DWORD g_dwWin32ConvUTF8strlen = 0;
51 static pthread_mutex_t Win32Convmutex = PTHREAD_MUTEX_INITIALIZER;
53 void Win32ConvCleanupCache()
55 if (g_pWin32ConvUTF8Cache) {
56 free_pool_memory(g_pWin32ConvUTF8Cache);
57 g_pWin32ConvUTF8Cache = NULL;
60 if (g_pWin32ConvUCS2Cache) {
61 free_pool_memory(g_pWin32ConvUCS2Cache);
62 g_pWin32ConvUCS2Cache = NULL;
65 g_dwWin32ConvUTF8strlen = 0;
69 /* to allow the usage of the original version in this file here */
73 #define USE_WIN32_COMPAT_IO 1
74 #define USE_WIN32_32KPATHCONVERSION 1
76 extern void d_msg(const char *file, int line, int level, const char *fmt,...);
77 extern DWORD g_platform_id;
78 extern int enable_vss;
80 // from MicroSoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970
82 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL
84 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
87 #define WIN32_FILETIME_SCALE 10000000 // 100ns/second
89 void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize)
91 const char *fname = name;
92 char *tname = win32_name;
94 /* Check for Unix separator and convert to Win32 */
95 if (name[0] == '/' && name[1] == '/') { /* double slash? */
96 name++; /* yes, skip first one */
99 *win32_name++ = '\\'; /* convert char */
100 /* If Win32 separated that is "quoted", remove quote */
101 } else if (*name == '\\' && name[1] == '\\') {
102 *win32_name++ = '\\';
103 name++; /* skip first \ */
105 *win32_name++ = *name; /* copy character */
109 /* Strip any trailing slash, if we stored something */
110 /* but leave "c:\" with backslash (root directory case */
111 if (*fname != 0 && win32_name[-1] == '\\' && strlen (fname) != 3) {
118 /* here we convert to VSS specific file name which
119 can get longer because VSS will make something like
120 \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
121 from c:\bacula\uninstall.exe
123 if (g_pVSSClient && enable_vss && g_pVSSClient->IsInitialized()) {
124 POOLMEM *pszBuf = get_pool_memory (PM_FNAME);
125 pszBuf = check_pool_memory_size(pszBuf, dwSize);
126 bstrncpy(pszBuf, tname, strlen(tname)+1);
127 g_pVSSClient->GetShadowPath(pszBuf, tname, dwSize);
128 free_pool_memory(pszBuf);
134 make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/)
136 /* created 02/27/2006 Thorsten Engel
138 This function expects an UCS-encoded standard wchar_t in pszUCSPath and
139 will complete the input path to an absolue path of the form \\?\c:\path\file
141 With this trick, it is possible to have 32K characters long paths.
143 Optionally one can use pBIsRawPath to determine id pszUCSPath contains a path
144 to a raw windows partition */
147 *pBIsRawPath = FALSE;
149 if (!p_GetCurrentDirectoryW)
152 wchar_t *name = (wchar_t *) pszUCSPath;
154 /* if it has already the desired form, exit without changes */
155 if (wcslen(name) > 3 && wcsncmp(name, L"\\\\?\\", 4) == 0)
158 POOLMEM *pwszBuf = get_pool_memory(PM_FNAME);
159 POOLMEM *pwszCurDirBuf = get_pool_memory(PM_FNAME);
160 DWORD dwCurDirPathSize = 0;
162 /* get buffer with enough size (name+max 6. wchars+1 null terminator */
163 DWORD dwBufCharsNeeded = (wcslen(name)+7);
164 pwszBuf = check_pool_memory_size(pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
166 /* add \\?\ to support 32K long filepaths
167 it is important to make absolute paths, so we add drive and
168 current path if necessary */
170 BOOL bAddDrive = TRUE;
171 BOOL bAddCurrentPath = TRUE;
172 BOOL bAddPrefix = TRUE;
174 /* does path begin with drive? if yes, it is absolute */
175 if (wcslen(name) >= 3 && (iswalpha (*name) && *(name+1) == ':'
176 && (*(name+2) == '\\' || *(name+2) == '/'))) {
178 bAddCurrentPath = FALSE;
181 /* is path absolute? */
182 if (*name == '/' || *name == '\\')
183 bAddCurrentPath = FALSE;
185 /* is path relative to itself?, if yes, skip ./ */
186 if (wcslen(name) > 2 && ((wcsncmp(name, L"./", 2) == 0) || (wcsncmp(name, L".\\", 2) == 0))) {
190 /* is path of form '//./'? */
191 if (wcslen(name) > 3 && ((wcsncmp(name, L"//./", 4) == 0) || (wcsncmp(name, L"\\\\.\\", 4) == 0))) {
193 bAddCurrentPath = FALSE;
199 int nParseOffset = 0;
201 /* add 4 bytes header */
204 wcscpy ((wchar_t *) pwszBuf,L"\\\\?\\");
207 /* get current path if needed */
208 if (bAddDrive || bAddCurrentPath) {
209 dwCurDirPathSize = p_GetCurrentDirectoryW(0, NULL);
210 if (dwCurDirPathSize > 0) {
211 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
212 pwszCurDirBuf = check_pool_memory_size(pwszCurDirBuf, (dwCurDirPathSize+1)*sizeof(wchar_t));
213 p_GetCurrentDirectoryW(dwCurDirPathSize,(wchar_t *)pwszCurDirBuf);
217 /* we have no info for doing so */
219 bAddCurrentPath = FALSE;
224 /* add drive if needed */
225 if (bAddDrive && !bAddCurrentPath) {
228 if (dwCurDirPathSize > 3 && wcsncmp((LPCWSTR)pwszCurDirBuf, L"\\\\?\\", 4) == 0)
229 /* copy drive character */
230 wcsncpy((wchar_t *) szDrive, (LPCWSTR)pwszCurDirBuf+4,2);
232 /* copy drive character */
233 wcsncpy((wchar_t *) szDrive, (LPCWSTR)pwszCurDirBuf,2);
237 wcscat((wchar_t *) pwszBuf, szDrive);
241 /* add path if needed */
242 if (bAddCurrentPath) {
243 /* the 1 add. character is for the eventually added backslash */
244 dwBufCharsNeeded += dwCurDirPathSize+1;
245 pwszBuf = check_pool_memory_size(pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
246 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
248 if (dwCurDirPathSize > 3 && wcsncmp((LPCWSTR)pwszCurDirBuf, L"\\\\?\\", 4) == 0)
249 /* copy complete string */
250 wcscpy((wchar_t *) pwszBuf, (LPCWSTR)pwszCurDirBuf);
253 wcscat((wchar_t *) pwszBuf, (LPCWSTR)pwszCurDirBuf);
255 nParseOffset = wcslen ((LPCWSTR) pwszBuf);
257 /* check if path ends with backslash, if not, add one */
258 if (*((wchar_t *) pwszBuf+nParseOffset-1) != L'\\') {
259 wcscat((wchar_t *) pwszBuf, L"\\");
265 wchar_t *win32_name = (wchar_t *)pwszBuf+nParseOffset;
268 /* Check for Unix separator and convert to Win32 */
270 *win32_name++ = '\\'; /* convert char */
271 /* If Win32 separated that is "quoted", remove quote */
272 /* HELPME (Thorsten Engel): I don't understand the following part
273 and it removes a backslash from e.g. "\\.\c:" which I need for
274 RAW device access. So I took it out */
275 /* } else if (*name == '\\' && name[1] == '\\') {
276 *win32_name++ = '\\';
277 name++; */ /* skip first \ */
279 *win32_name++ = *name; /* copy character */
284 /* null terminate string */
288 /* here we convert to VSS specific file name which
289 can get longer because VSS will make something like
290 \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
291 from c:\bacula\uninstall.exe
293 if (g_pVSSClient && enable_vss && g_pVSSClient->IsInitialized()) {
294 /* is output buffer large enough? */
295 pwszBuf = check_pool_memory_size(pwszBuf, (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
296 /* create temp. buffer */
297 POOLMEM* pszBuf = get_pool_memory(PM_FNAME);
298 pszBuf = check_pool_memory_size(pszBuf, (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
303 wcsncpy((wchar_t *) pszBuf, (wchar_t *) pwszBuf+nParseOffset, wcslen((wchar_t *)pwszBuf)+1-nParseOffset);
304 g_pVSSClient->GetShadowPathW((wchar_t *)pszBuf,(wchar_t *)pwszBuf,dwBufCharsNeeded+MAX_PATH);
305 free_pool_memory(pszBuf);
309 free_pool_memory(pszUCSPath);
310 free_pool_memory(pwszCurDirBuf);
316 wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
318 /* the return value is the number of bytes written to the buffer.
319 The number includes the byte for the null terminator. */
321 if (p_WideCharToMultiByte) {
322 int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
331 UTF8_2_wchar(POOLMEM **ppszUCS, const char *pszUTF)
333 /* the return value is the number of wide characters written to the buffer. */
334 /* convert null terminated string from utf-8 to ucs2, enlarge buffer if necessary */
336 if (p_MultiByteToWideChar) {
337 /* strlen of UTF8 +1 is enough */
338 DWORD cchSize = (strlen(pszUTF)+1);
339 *ppszUCS = check_pool_memory_size(*ppszUCS, cchSize*sizeof (wchar_t));
341 int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
351 wchar_win32_path(const char *name, wchar_t *win32_name)
353 const char *fname = name;
355 /* Check for Unix separator and convert to Win32 */
357 *win32_name++ = '\\'; /* convert char */
358 /* If Win32 separated that is "quoted", remove quote */
359 } else if (*name == '\\' && name[1] == '\\') {
360 *win32_name++ = '\\';
361 name++; /* skip first \ */
363 *win32_name++ = *name; /* copy character */
367 /* Strip any trailing slash, if we stored something */
368 if (*fname != 0 && win32_name[-1] == '\\') {
376 make_win32_path_UTF8_2_wchar(POOLMEM **pszUCS, const char *pszUTF, BOOL* pBIsRawPath /*= NULL*/)
379 /* if we find the utf8 string in cache, we use the cached ucs2 version.
380 we compare the stringlength first (quick check) and then compare the content.
382 if (g_dwWin32ConvUTF8strlen == strlen(pszUTF)) {
383 if (bstrcmp(pszUTF, g_pWin32ConvUTF8Cache)) {
384 int32_t nBufSize = sizeof_pool_memory(g_pWin32ConvUCS2Cache);
385 *pszUCS = check_pool_memory_size(*pszUCS, nBufSize);
386 wcscpy((LPWSTR) *pszUCS, (LPWSTR) g_pWin32ConvUCS2Cache);
388 return nBufSize / sizeof (WCHAR);
392 /* helper to convert from utf-8 to UCS-2 and to complete a path for 32K path syntax */
393 int nRet = UTF8_2_wchar(pszUCS, pszUTF);
395 #ifdef USE_WIN32_32KPATHCONVERSION
396 /* add \\?\ to support 32K long filepaths */
397 *pszUCS = make_wchar_win32_path(*pszUCS, pBIsRawPath);
400 *pBIsRawPath = FALSE;
404 g_pWin32ConvUCS2Cache = check_pool_memory_size(g_pWin32ConvUCS2Cache, sizeof_pool_memory(*pszUCS));
405 wcscpy((LPWSTR) g_pWin32ConvUCS2Cache, (LPWSTR) *pszUCS);
407 g_dwWin32ConvUTF8strlen = strlen(pszUTF);
408 g_pWin32ConvUTF8Cache = check_pool_memory_size(g_pWin32ConvUTF8Cache, g_dwWin32ConvUTF8strlen+1);
409 bstrncpy(g_pWin32ConvUTF8Cache, pszUTF, g_dwWin32ConvUTF8strlen+1);
422 int chmod(const char *, mode_t)
427 int chown(const char *k, uid_t, gid_t)
432 int lchown(const char *k, uid_t, gid_t)
438 bool fstype(const char *fname, char *fs, int fslen)
440 return true; /* accept anything */
452 srandom(unsigned int seed)
456 // /////////////////////////////////////////////////////////////////
457 // convert from Windows concept of time to Unix concept of time
458 // /////////////////////////////////////////////////////////////////
460 cvt_utime_to_ftime(const time_t &time, FILETIME &wintime)
462 uint64_t mstime = time;
463 mstime *= WIN32_FILETIME_SCALE;
464 mstime += WIN32_FILETIME_ADJUST;
467 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL);
469 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
471 wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
475 cvt_ftime_to_utime(const FILETIME &time)
477 uint64_t mstime = time.dwHighDateTime;
479 mstime |= time.dwLowDateTime;
481 mstime -= WIN32_FILETIME_ADJUST;
482 mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
484 return (time_t) (mstime & 0xffffffff);
492 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
493 FORMAT_MESSAGE_FROM_SYSTEM |
494 FORMAT_MESSAGE_IGNORE_INSERTS,
497 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
502 /* Strip any \r or \n */
503 char *rval = (char *) lpMsgBuf;
504 char *cp = strchr(rval, '\r');
508 cp = strchr(rval, '\n');
517 statDir(const char *file, struct stat *sb)
519 WIN32_FIND_DATAW info_w; // window's file info
520 WIN32_FIND_DATAA info_a; // window's file info
522 // cache some common vars to make code more transparent
523 DWORD* pdwFileAttributes;
524 DWORD* pnFileSizeHigh;
525 DWORD* pnFileSizeLow;
526 FILETIME* pftLastAccessTime;
527 FILETIME* pftLastWriteTime;
528 FILETIME* pftCreationTime;
530 if (file[1] == ':' && file[2] == 0) {
531 d_msg(__FILE__, __LINE__, 99, "faking ROOT attrs(%s).\n", file);
532 sb->st_mode = S_IFDIR;
533 sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
540 HANDLE h = INVALID_HANDLE_VALUE;
542 // use unicode or ascii
543 if (p_FindFirstFileW) {
544 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
545 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
547 h = p_FindFirstFileW((LPCWSTR) pwszBuf, &info_w);
548 free_pool_memory(pwszBuf);
550 pdwFileAttributes = &info_w.dwFileAttributes;
551 pnFileSizeHigh = &info_w.nFileSizeHigh;
552 pnFileSizeLow = &info_w.nFileSizeLow;
553 pftLastAccessTime = &info_w.ftLastAccessTime;
554 pftLastWriteTime = &info_w.ftLastWriteTime;
555 pftCreationTime = &info_w.ftCreationTime;
557 else if (p_FindFirstFileA) {
558 h = p_FindFirstFileA(file, &info_a);
560 pdwFileAttributes = &info_a.dwFileAttributes;
561 pnFileSizeHigh = &info_a.nFileSizeHigh;
562 pnFileSizeLow = &info_a.nFileSizeLow;
563 pftLastAccessTime = &info_a.ftLastAccessTime;
564 pftLastWriteTime = &info_a.ftLastWriteTime;
565 pftCreationTime = &info_a.ftCreationTime;
568 if (h == INVALID_HANDLE_VALUE) {
569 const char *err = errorString();
570 d_msg(__FILE__, __LINE__, 99, "FindFirstFile(%s):%s\n", file, err);
571 LocalFree((void *)err);
572 errno = b_errno_win32;
576 sb->st_mode = 0777; /* start with everything */
577 if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
578 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
579 if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
580 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
581 if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
582 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
583 sb->st_mode |= S_IFDIR;
585 sb->st_size = *pnFileSizeHigh;
587 sb->st_size |= *pnFileSizeLow;
588 sb->st_blksize = 4096;
589 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
591 sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
592 sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
593 sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
600 stat2(const char *file, struct stat *sb)
602 BY_HANDLE_FILE_INFORMATION info;
606 conv_unix_to_win32_path(file, tmpbuf, 1024);
608 DWORD attr = (DWORD)-1;
610 if (p_GetFileAttributesW) {
611 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
612 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
614 attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
615 free_pool_memory(pwszBuf);
616 } else if (p_GetFileAttributesA) {
617 attr = p_GetFileAttributesA(tmpbuf);
621 const char *err = errorString();
622 d_msg(__FILE__, __LINE__, 99,
623 "GetFileAttributes(%s): %s\n", tmpbuf, err);
624 LocalFree((void *)err);
625 errno = b_errno_win32;
629 if (attr & FILE_ATTRIBUTE_DIRECTORY)
630 return statDir(tmpbuf, sb);
632 h = CreateFileA(tmpbuf, GENERIC_READ,
633 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
635 if (h == INVALID_HANDLE_VALUE) {
636 const char *err = errorString();
637 d_msg(__FILE__, __LINE__, 99,
638 "Cannot open file for stat (%s):%s\n", tmpbuf, err);
639 LocalFree((void *)err);
641 errno = b_errno_win32;
645 if (!GetFileInformationByHandle(h, &info)) {
646 const char *err = errorString();
647 d_msg(__FILE__, __LINE__, 99,
648 "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
649 LocalFree((void *)err);
651 errno = b_errno_win32;
655 sb->st_dev = info.dwVolumeSerialNumber;
656 sb->st_ino = info.nFileIndexHigh;
658 sb->st_ino |= info.nFileIndexLow;
659 sb->st_nlink = (short)info.nNumberOfLinks;
660 if (sb->st_nlink > 1) {
661 d_msg(__FILE__, __LINE__, 99, "st_nlink=%d\n", sb->st_nlink);
664 sb->st_mode = 0777; /* start with everything */
665 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
666 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
667 if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
668 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
669 if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
670 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
671 sb->st_mode |= S_IFREG;
673 sb->st_size = info.nFileSizeHigh;
675 sb->st_size |= info.nFileSizeLow;
676 sb->st_blksize = 4096;
677 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
678 sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
679 sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
680 sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
688 stat(const char *file, struct stat *sb)
690 WIN32_FILE_ATTRIBUTE_DATA data;
694 memset(sb, 0, sizeof(*sb));
696 /* why not allow win 95 to use p_GetFileAttributesExA ?
697 * this function allows _some_ open files to be stat'ed
698 * if (g_platform_id == VER_PLATFORM_WIN32_WINDOWS) {
699 * return stat2(file, sb);
703 if (p_GetFileAttributesExW) {
704 /* dynamically allocate enough space for UCS2 filename */
705 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
706 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
708 BOOL b = p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, &data);
709 free_pool_memory(pwszBuf);
712 return stat2(file, sb);
714 } else if (p_GetFileAttributesExA) {
715 if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
716 return stat2(file, sb);
719 return stat2(file, sb);
722 sb->st_mode = 0777; /* start with everything */
723 if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
724 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
726 if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
727 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
729 if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
730 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
732 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
733 sb->st_mode |= S_IFDIR;
735 sb->st_mode |= S_IFREG;
739 sb->st_size = data.nFileSizeHigh;
741 sb->st_size |= data.nFileSizeLow;
742 sb->st_blksize = 4096;
743 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
744 sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
745 sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
746 sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
751 lstat(const char *file, struct stat *sb)
753 return stat(file, sb);
769 execvp(const char *, char *[]) {
790 waitpid(int, int*, int)
797 readlink(const char *, char *, int)
806 strcasecmp(const char *s1, const char *s2)
808 register int ch1, ch2;
811 return 0; /* strings are equal if same object. */
821 } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
828 strncasecmp(const char *s1, const char *s2, int len)
830 register int ch1, ch2;
833 return 0; /* strings are equal if same object. */
843 if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
850 gettimeofday(struct timeval *tv, struct timezone *)
860 if (!SystemTimeToFileTime(&now, &tmp)) {
861 errno = b_errno_win32;
865 int64_t _100nsec = tmp.dwHighDateTime;
867 _100nsec |= tmp.dwLowDateTime;
868 _100nsec -= WIN32_FILETIME_ADJUST;
870 tv->tv_sec =(long) (_100nsec / 10000000);
871 tv->tv_usec = (long) ((_100nsec % 10000000)/10);
876 /* For apcupsd this is in src/lib/wincompat.c */
878 extern "C" void syslog(int type, const char *fmt, ...)
880 /*#ifndef HAVE_CONSOLE
881 MessageBox(NULL, msg, "Bacula", MB_OK);
898 // implement opendir/readdir/closedir on top of window's API
902 WIN32_FIND_DATAA data_a; // window's file info (ansii version)
903 WIN32_FIND_DATAW data_w; // window's file info (wchar version)
904 const char *spec; // the directory we're traversing
905 HANDLE dirh; // the search handle
906 BOOL valid_a; // the info in data_a field is valid
907 BOOL valid_w; // the info in data_w field is valid
908 UINT32 offset; // pseudo offset for d_off
912 opendir(const char *path)
914 /* enough space for VSS !*/
915 int max_len = strlen(path) + MAX_PATH;
922 rval = (_dir *)malloc(sizeof(_dir));
923 memset (rval, 0, sizeof (_dir));
924 if (rval == NULL) return NULL;
925 char *tspec = (char *)malloc(max_len);
926 if (tspec == NULL) return NULL;
928 if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS) {
930 /* will append \\?\ at front itself */
931 conv_unix_to_win32_path(path, tspec, max_len-4);
933 /* allow path to be 32767 bytes */
939 conv_unix_to_win32_path(path, tspec+4, max_len-4);
942 conv_unix_to_win32_path(path, tspec, max_len);
945 // add backslash only if there is none yet (think of c:\)
946 if (tspec[strlen(tspec)-1] != '\\')
947 bstrncat(tspec, "\\*", max_len);
949 bstrncat(tspec, "*", max_len);
953 // convert to wchar_t
954 if (p_FindFirstFileW) {
955 POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
956 make_win32_path_UTF8_2_wchar(&pwcBuf,rval->spec);
958 rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
960 free_pool_memory(pwcBuf);
962 if (rval->dirh != INVALID_HANDLE_VALUE)
964 } else if (p_FindFirstFileA) {
965 rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
967 if (rval->dirh != INVALID_HANDLE_VALUE)
972 d_msg(__FILE__, __LINE__,
973 99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
974 path, rval->spec, rval->dirh);
977 if (rval->dirh == INVALID_HANDLE_VALUE)
981 d_msg(__FILE__, __LINE__,
982 99, "\tFirstFile=%s\n", rval->data_w.cFileName);
985 d_msg(__FILE__, __LINE__,
986 99, "\tFirstFile=%s\n", rval->data_a.cFileName);
991 free((void *)rval->spec);
993 errno = b_errno_win32;
1000 _dir *dp = (_dir *)dirp;
1001 FindClose(dp->dirh);
1002 free((void *)dp->spec);
1008 typedef struct _WIN32_FIND_DATA {
1009 DWORD dwFileAttributes;
1010 FILETIME ftCreationTime;
1011 FILETIME ftLastAccessTime;
1012 FILETIME ftLastWriteTime;
1013 DWORD nFileSizeHigh;
1017 TCHAR cFileName[MAX_PATH];
1018 TCHAR cAlternateFileName[14];
1019 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
1023 copyin(struct dirent &dp, const char *fname)
1027 char *cp = dp.d_name;
1037 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
1039 _dir *dp = (_dir *)dirp;
1040 if (dp->valid_w || dp->valid_a) {
1041 entry->d_off = dp->offset;
1045 char szBuf[MAX_PATH_UTF8+1];
1046 wchar_2_UTF8(szBuf,dp->data_w.cFileName);
1047 dp->offset += copyin(*entry, szBuf);
1048 } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
1049 dp->offset += copyin(*entry, dp->data_a.cFileName);
1052 *result = entry; /* return entry address */
1053 d_msg(__FILE__, __LINE__,
1054 99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
1055 dirp, entry->d_name, entry->d_reclen, entry->d_off);
1057 // d_msg(__FILE__, __LINE__, 99, "readdir_r !valid\n");
1058 errno = b_errno_win32;
1062 // get next file, try unicode first
1063 if (p_FindNextFileW)
1064 dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1065 else if (p_FindNextFileA)
1066 dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1068 dp->valid_a = FALSE;
1069 dp->valid_w = FALSE;
1076 * Dotted IP address to network address
1082 inet_aton(const char *a, struct in_addr *inp)
1085 uint32_t acc = 0, tmp = 0;
1088 if (!isdigit(*cp)) { /* first char must be digit */
1089 return 0; /* error */
1093 tmp = (tmp * 10) + (*cp -'0');
1094 } else if (*cp == '.' || *cp == 0) {
1096 return 0; /* error */
1098 acc = (acc << 8) + tmp;
1102 return 0; /* error */
1104 } while (*cp++ != 0);
1105 if (dotc != 4) { /* want 3 .'s plus EOS */
1106 return 0; /* error */
1108 inp->s_addr = htonl(acc); /* store addr in network format */
1113 nanosleep(const struct timespec *req, struct timespec *rem)
1116 rem->tv_sec = rem->tv_nsec = 0;
1117 Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1122 init_signals(void terminate(int sig))
1128 init_stack_dump(void)
1135 pathconf(const char *path, int name)
1139 if (strncmp(path, "\\\\?\\", 4) == 0)
1151 WORD wVersionRequested = MAKEWORD( 1, 1);
1154 int err = WSAStartup(wVersionRequested, &wsaData);
1158 printf("Can not start Windows Sockets\n");
1168 win32_chdir(const char *dir)
1170 if (p_SetCurrentDirectoryW) {
1171 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1172 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1174 BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1176 free_pool_memory(pwszBuf);
1179 errno = b_errno_win32;
1183 else if (p_SetCurrentDirectoryA) {
1184 if (0 == p_SetCurrentDirectoryA(dir)) {
1185 errno = b_errno_win32;
1195 win32_mkdir(const char *dir)
1198 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1199 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1201 int n = p_wmkdir((LPCWSTR)pwszBuf);
1202 free_pool_memory(pwszBuf);
1211 win32_getcwd(char *buf, int maxlen)
1215 if (p_GetCurrentDirectoryW) {
1216 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1217 pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1219 n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1221 n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1222 free_pool_memory(pwszBuf);
1224 } else if (p_GetCurrentDirectoryA)
1225 n = p_GetCurrentDirectoryA(maxlen, buf);
1227 if (n == 0 || n > maxlen) return NULL;
1229 if (n+1 > maxlen) return NULL;
1238 win32_fputs(const char *string, FILE *stream)
1240 /* we use WriteConsoleA / WriteConsoleA
1241 so we can be sure that unicode support works on win32.
1242 with fallback if something fails
1245 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1246 if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1247 p_MultiByteToWideChar && (stream == stdout)) {
1249 POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1251 DWORD dwCharsWritten;
1254 dwChars = UTF8_2_wchar(&pwszBuf, string);
1256 /* try WriteConsoleW */
1257 if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1258 free_pool_memory(pwszBuf);
1259 return dwCharsWritten;
1262 /* convert to local codepage and try WriteConsoleA */
1263 POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1264 pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1266 dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR) pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1267 free_pool_memory(pwszBuf);
1269 if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1270 free_pool_memory(pszBuf);
1271 return dwCharsWritten;
1275 return fputs(string, stream);
1279 win32_cgets (char* buffer, int len)
1281 /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1282 from the win32 console and fallback if seomething fails */
1284 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1285 if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1287 wchar_t wszBuf[1024];
1290 /* nt and unicode conversion */
1291 if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1293 /* null terminate at end */
1294 if (wszBuf[dwRead-1] == L'\n') {
1295 wszBuf[dwRead-1] = L'\0';
1299 if (wszBuf[dwRead-1] == L'\r') {
1300 wszBuf[dwRead-1] = L'\0';
1304 wchar_2_UTF8(buffer, wszBuf, len);
1308 /* win 9x and unicode conversion */
1309 if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1311 /* null terminate at end */
1312 if (szBuf[dwRead-1] == L'\n') {
1313 szBuf[dwRead-1] = L'\0';
1317 if (szBuf[dwRead-1] == L'\r') {
1318 szBuf[dwRead-1] = L'\0';
1322 /* convert from ansii to wchar_t */
1323 p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1324 /* convert from wchar_t to UTF-8 */
1325 if (wchar_2_UTF8(buffer, wszBuf, len))
1331 if (fgets(buffer, len, stdin))
1338 win32_unlink(const char *filename)
1342 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1343 make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1345 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1347 /* special case if file is readonly,
1348 we retry but unset attribute before */
1349 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1350 DWORD dwAttr = p_GetFileAttributesW((LPCWSTR)pwszBuf);
1351 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1352 if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1353 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1354 /* reset to original if it didn't help */
1356 p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1360 free_pool_memory(pwszBuf);
1362 nRetCode = _unlink(filename);
1364 /* special case if file is readonly,
1365 we retry but unset attribute before */
1366 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1367 DWORD dwAttr = p_GetFileAttributesA(filename);
1368 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1369 if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1370 nRetCode = _unlink(filename);
1371 /* reset to original if it didn't help */
1373 p_SetFileAttributesA(filename, dwAttr);
1382 #include "mswinver.h"
1384 char WIN_VERSION_LONG[64];
1385 char WIN_VERSION[32];
1386 char WIN_RAWVERSION[32];
1393 static winver INIT; // cause constructor to be called before main()
1396 winver::winver(void)
1398 const char *version = "";
1399 const char *platform = "";
1400 OSVERSIONINFO osvinfo;
1401 osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1403 // Get the current OS version
1404 if (!GetVersionEx(&osvinfo)) {
1405 version = "Unknown";
1406 platform = "Unknown";
1408 const int ver = _mkversion(osvinfo.dwPlatformId,
1409 osvinfo.dwMajorVersion,
1410 osvinfo.dwMinorVersion);
1411 snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1414 case MS_WINDOWS_95: (version = "Windows 95"); break;
1415 case MS_WINDOWS_98: (version = "Windows 98"); break;
1416 case MS_WINDOWS_ME: (version = "Windows ME"); break;
1417 case MS_WINDOWS_NT4:(version = "Windows NT 4.0"); platform = "NT"; break;
1418 case MS_WINDOWS_2K: (version = "Windows 2000");platform = "NT"; break;
1419 case MS_WINDOWS_XP: (version = "Windows XP");platform = "NT"; break;
1420 case MS_WINDOWS_S2003: (version = "Windows Server 2003");platform = "NT"; break;
1421 default: version = WIN_RAWVERSION; break;
1424 bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1425 snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %d.%d.%d",
1426 platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1429 HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1433 BPIPE *b = open_bpipe("ls -l", 10, "r");
1435 while (!feof(b->rfd)) {
1436 fgets(buf, sizeof(buf), b->rfd);
1442 BOOL CreateChildProcess(VOID);
1443 VOID WriteToPipe(VOID);
1444 VOID ReadFromPipe(VOID);
1445 VOID ErrorExit(LPCSTR);
1446 VOID ErrMsg(LPTSTR, BOOL);
1449 * Check for a quoted path, if an absolute path name is given and it contains
1450 * spaces it will need to be quoted. i.e. "c:/Program Files/foo/bar.exe"
1451 * CreateProcess() says the best way to ensure proper results with executables
1452 * with spaces in path or filename is to quote the string.
1455 getArgv0(const char *cmdline)
1460 for (cp = cmdline; *cp; cp++)
1465 if (!inquote && isspace(*cp))
1470 int len = cp - cmdline;
1471 char *rval = (char *)malloc(len+1);
1485 * OK, so it would seem CreateProcess only handles true executables:
1486 * .com or .exe files.
1487 * So test to see whether we're getting a .bat file and if so grab
1488 * $COMSPEC value and pass batch file to it.
1491 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1493 static const char *comspec = NULL;
1494 PROCESS_INFORMATION piProcInfo;
1495 STARTUPINFOA siStartInfo;
1496 BOOL bFuncRetn = FALSE;
1498 if (comspec == NULL) {
1499 comspec = getenv("COMSPEC");
1501 if (comspec == NULL) // should never happen
1502 return INVALID_HANDLE_VALUE;
1504 // Set up members of the PROCESS_INFORMATION structure.
1505 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1507 // Set up members of the STARTUPINFO structure.
1509 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1510 siStartInfo.cb = sizeof(STARTUPINFO);
1511 // setup new process to use supplied handles for stdin,stdout,stderr
1512 // if supplied handles are not used the send a copy of our STD_HANDLE
1514 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
1516 if (in != INVALID_HANDLE_VALUE)
1517 siStartInfo.hStdInput = in;
1519 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1521 if (out != INVALID_HANDLE_VALUE)
1522 siStartInfo.hStdOutput = out;
1524 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1525 if (err != INVALID_HANDLE_VALUE)
1526 siStartInfo.hStdError = err;
1528 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1529 // Create the child process.
1532 int cmdLen = strlen(cmdline) + strlen(comspec) + 16;
1534 char *cmdLine = (char *)alloca(cmdLen);
1536 bstrncpy(exeFile, comspec, sizeof(exeFile));
1537 bstrncpy(cmdLine, comspec, cmdLen);
1538 bstrncat(cmdLine, " /c ", cmdLen);
1539 bstrncat(cmdLine, cmdline, cmdLen);
1541 // try to execute program
1542 bFuncRetn = CreateProcessA(exeFile,
1543 cmdLine, // command line
1544 NULL, // process security attributes
1545 NULL, // primary thread security attributes
1546 TRUE, // handles are inherited
1547 0, // creation flags
1548 NULL, // use parent's environment
1549 NULL, // use parent's current directory
1550 &siStartInfo, // STARTUPINFO pointer
1551 &piProcInfo); // receives PROCESS_INFORMATION
1553 if (bFuncRetn == 0) {
1554 ErrorExit("CreateProcess failed\n");
1555 const char *err = errorString();
1556 d_msg(__FILE__, __LINE__, 99,
1557 "CreateProcess(%s, %s, ...)=%s\n", exeFile, cmdLine, err);
1558 LocalFree((void *)err);
1559 return INVALID_HANDLE_VALUE;
1561 // we don't need a handle on the process primary thread so we close
1563 CloseHandle(piProcInfo.hThread);
1565 return piProcInfo.hProcess;
1570 ErrorExit (LPCSTR lpszMessage)
1572 d_msg(__FILE__, __LINE__, 0, "%s", lpszMessage);
1577 typedef struct s_bpipe {
1579 time_t worker_stime;
1588 CloseIfValid(HANDLE handle)
1590 if (handle != INVALID_HANDLE_VALUE)
1591 CloseHandle(handle);
1596 open_bpipe(char *prog, int wait, const char *mode)
1598 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1599 hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1602 SECURITY_ATTRIBUTES saAttr;
1606 hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1607 hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1608 hInputFile = INVALID_HANDLE_VALUE;
1610 BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1611 memset((void *)bpipe, 0, sizeof(BPIPE));
1613 int mode_read = (mode[0] == 'r');
1614 int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1617 // Set the bInheritHandle flag so pipe handles are inherited.
1619 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1620 saAttr.bInheritHandle = TRUE;
1621 saAttr.lpSecurityDescriptor = NULL;
1625 // Create a pipe for the child process's STDOUT.
1626 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1627 ErrorExit("Stdout pipe creation failed\n");
1630 // Create noninheritable read handle and close the inheritable read
1633 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1634 GetCurrentProcess(), &hChildStdoutRdDup , 0,
1636 DUPLICATE_SAME_ACCESS);
1638 ErrorExit("DuplicateHandle failed");
1642 CloseHandle(hChildStdoutRd);
1643 hChildStdoutRd = INVALID_HANDLE_VALUE;
1648 // Create a pipe for the child process's STDIN.
1650 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1651 ErrorExit("Stdin pipe creation failed\n");
1655 // Duplicate the write handle to the pipe so it is not inherited.
1656 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
1657 GetCurrentProcess(), &hChildStdinWrDup,
1659 FALSE, // not inherited
1660 DUPLICATE_SAME_ACCESS);
1662 ErrorExit("DuplicateHandle failed");
1666 CloseHandle(hChildStdinWr);
1667 hChildStdinWr = INVALID_HANDLE_VALUE;
1669 // spawn program with redirected handles as appropriate
1670 bpipe->worker_pid = (pid_t)
1671 CreateChildProcess(prog, // commandline
1672 hChildStdinRd, // stdin HANDLE
1673 hChildStdoutWr, // stdout HANDLE
1674 hChildStdoutWr); // stderr HANDLE
1676 if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1680 bpipe->worker_stime = time(NULL);
1683 CloseHandle(hChildStdoutWr); // close our write side so when
1684 // process terminates we can
1686 // ugly but convert WIN32 HANDLE to FILE*
1687 int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY);
1689 bpipe->rfd = _fdopen(rfd, "r");
1693 CloseHandle(hChildStdinRd); // close our read side so as not
1694 // to interfre with child's copy
1695 // ugly but convert WIN32 HANDLE to FILE*
1696 int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY);
1698 bpipe->wfd = _fdopen(wfd, "w");
1703 bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
1710 CloseIfValid(hChildStdoutRd);
1711 CloseIfValid(hChildStdoutRdDup);
1712 CloseIfValid(hChildStdinWr);
1713 CloseIfValid(hChildStdinWrDup);
1715 free((void *) bpipe);
1716 errno = b_errno_win32; /* do GetLastError() for error code */
1723 kill(int pid, int signal)
1726 if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
1728 errno = b_errno_win32;
1730 CloseHandle((HANDLE)pid);
1737 close_bpipe(BPIPE *bpipe)
1740 int32_t remaining_wait = bpipe->wait;
1742 if (remaining_wait == 0) { /* wait indefinitely */
1743 remaining_wait = INT32_MAX;
1747 if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
1748 const char *err = errorString();
1749 rval = b_errno_win32;
1750 d_msg(__FILE__, __LINE__, 0,
1751 "GetExitCode error %s\n", err);
1752 LocalFree((void *)err);
1755 if (exitCode == STILL_ACTIVE) {
1756 if (remaining_wait <= 0) {
1757 rval = ETIME; /* timed out */
1760 bmicrosleep(1, 0); /* wait one second */
1762 } else if (exitCode != 0) {
1763 /* Truncate exit code as it doesn't seem to be correct */
1764 rval = (exitCode & 0xFF) | b_errno_exit;
1767 break; /* Shouldn't get here */
1771 if (bpipe->timer_id) {
1772 stop_child_timer(bpipe->timer_id);
1774 if (bpipe->rfd) fclose(bpipe->rfd);
1775 if (bpipe->wfd) fclose(bpipe->wfd);
1776 free((void *)bpipe);
1781 close_wpipe(BPIPE *bpipe)
1787 if (fclose(bpipe->wfd) != 0) {
1795 #include "findlib/find.h"
1798 utime(const char *fname, struct utimbuf *times)
1803 conv_unix_to_win32_path(fname, tmpbuf, 5000);
1805 cvt_utime_to_ftime(times->actime, acc);
1806 cvt_utime_to_ftime(times->modtime, mod);
1808 HANDLE h = INVALID_HANDLE_VALUE;
1810 if (p_CreateFileW) {
1811 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1812 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
1814 h = p_CreateFileW((LPCWSTR)pwszBuf,
1815 FILE_WRITE_ATTRIBUTES,
1816 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
1819 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
1822 free_pool_memory(pwszBuf);
1823 } else if (p_CreateFileA) {
1824 h = p_CreateFileA(tmpbuf,
1825 FILE_WRITE_ATTRIBUTES,
1826 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
1829 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
1833 if (h == INVALID_HANDLE_VALUE) {
1834 const char *err = errorString();
1835 d_msg(__FILE__, __LINE__, 99,
1836 "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
1837 LocalFree((void *)err);
1838 errno = b_errno_win32;
1842 int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
1845 errno = b_errno_win32;
1850 #if USE_WIN32_COMPAT_IO
1853 open(const char *file, int flags, int mode)
1856 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1857 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
1859 int nRet = p_wopen((LPCWSTR) pwszBuf, flags|_O_BINARY, mode);
1860 free_pool_memory(pwszBuf);
1865 return _open(file, flags|_O_BINARY, mode);
1869 * Note, this works only for a file. If you want
1870 * to close a socket, use closesocket().
1871 * Bacula has been modified in src/lib/bnet.c
1872 * to use closesocket().
1881 #ifndef HAVE_WXCONSOLE
1883 read(int fd, void *buf, ssize_t len)
1885 return _read(fd, buf, (size_t)len);
1889 write(int fd, const void *buf, ssize_t len)
1891 return _write(fd, buf, (size_t)len);
1897 lseek(int fd, off_t offset, int whence)
1899 return (off_t)_lseeki64(fd, offset, whence);
1903 dup2(int fd1, int fd2)
1905 return _dup2(fd1, fd2);
1910 open(const char *file, int flags, int mode)
1913 DWORD shareMode = 0;
1916 HANDLE foo = INVALID_HANDLE_VALUE;
1917 const char *remap = file;
1919 if (flags & O_WRONLY) access = GENERIC_WRITE;
1920 else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
1921 else access = GENERIC_READ;
1923 if (flags & O_CREAT) create = CREATE_NEW;
1924 else create = OPEN_EXISTING;
1926 if (flags & O_TRUNC) create = TRUNCATE_EXISTING;
1928 if (!(flags & O_EXCL))
1929 shareMode = FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE;
1931 if (flags & O_APPEND) {
1932 printf("open...APPEND not implemented yet.");
1936 if (p_CreateFileW) {
1937 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1938 make_win32_path_UTF8_2_wchar(pwszBuf, file);
1940 foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
1941 free_pool_memory(pwszBuf);
1942 } else if (p_CreateFileA)
1943 foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
1945 if (INVALID_HANDLE_VALUE == foo) {
1946 errno = b_errno_win32;
1957 if (!CloseHandle((HANDLE)fd)) {
1958 errno = b_errno_win32;
1966 write(int fd, const void *data, ssize_t len)
1970 status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
1971 if (status) return bwrite;
1972 errno = b_errno_win32;
1978 read(int fd, void *data, ssize_t len)
1983 status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
1984 if (status) return bread;
1985 errno = b_errno_win32;
1990 lseek(int fd, off_t offset, int whence)
1996 method = FILE_BEGIN;
1999 method = FILE_CURRENT;
2009 if ((val=SetFilePointer((HANDLE)fd, (DWORD)offset, NULL, method)) == INVALID_SET_FILE_POINTER) {
2010 errno = b_errno_win32;
2013 /* ***FIXME*** I doubt this works right */
2030 /* syslog function, added by Nicolas Boichat */
2032 void openlog(const char *ident, int option, int facility) {}
2035 /* Temp kludges ***FIXME**** */
2037 unsigned int alarm(unsigned int seconds)