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
26 #define b_errno_win32 (1<<29)
30 #include "../../lib/winapi.h"
33 /* to allow the usage of the original version in this file here */
37 #define USE_WIN32_COMPAT_IO 1
38 #define USE_WIN32_32KPATHCONVERSION 1
40 extern void d_msg(const char *file, int line, int level, const char *fmt,...);
41 extern DWORD g_platform_id;
42 extern int enable_vss;
44 // from MicroSoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970
46 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL
48 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
51 #define WIN32_FILETIME_SCALE 10000000 // 100ns/second
53 void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize)
55 const char *fname = name;
56 char *tname = win32_name;
58 /* Check for Unix separator and convert to Win32 */
59 if (name[0] == '/' && name[1] == '/') { /* double slash? */
60 name++; /* yes, skip first one */
63 *win32_name++ = '\\'; /* convert char */
64 /* If Win32 separated that is "quoted", remove quote */
65 } else if (*name == '\\' && name[1] == '\\') {
67 name++; /* skip first \ */
69 *win32_name++ = *name; /* copy character */
73 /* Strip any trailing slash, if we stored something */
74 /* but leave "c:\" with backslash (root directory case */
75 if (*fname != 0 && win32_name[-1] == '\\' && strlen (fname) != 3) {
82 /* here we convert to VSS specific file name which
83 can get longer because VSS will make something like
84 \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
85 from c:\bacula\uninstall.exe
87 if (g_pVSSClient && enable_vss && g_pVSSClient->IsInitialized()) {
88 POOLMEM *pszBuf = get_pool_memory (PM_FNAME);
89 pszBuf = check_pool_memory_size(pszBuf, dwSize);
90 bstrncpy(pszBuf, tname, strlen(tname)+1);
91 g_pVSSClient->GetShadowPath(pszBuf, tname, dwSize);
92 free_pool_memory(pszBuf);
98 make_wchar_win32_path(POOLMEM* pszUCSPath, BOOL* pBIsRawPath /*= NULL*/)
100 /* created 02/27/2006 Thorsten Engel
102 This function expects an UCS-encoded standard wchar_t in pszUCSPath and
103 will complete the input path to an absolue path of the form \\?\c:\path\file
105 With this trick, it is possible to have 32K characters long paths.
107 Optionally one can use pBIsRawPath to determine id pszUCSPath contains a path
108 to a raw windows partition */
111 *pBIsRawPath = FALSE;
113 if (!p_GetCurrentDirectoryW)
116 wchar_t * name = (wchar_t *) pszUCSPath;
118 /* if it has already the desired form, exit without changes */
119 if (wcslen(name) > 3 && wcsncmp (name, L"\\\\?\\", 4) == 0)
122 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
123 POOLMEM* pwszCurDirBuf = get_pool_memory (PM_FNAME);
124 DWORD dwCurDirPathSize = 0;
126 /* get buffer with enough size (name+max 6. wchars+1 null terminator */
127 DWORD dwBufCharsNeeded = (wcslen(name)+7);
128 pwszBuf = check_pool_memory_size(pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
130 /* add \\?\ to support 32K long filepaths
131 it is important to make absolute paths, so we add drive and
132 current path if necessary */
134 BOOL bAddDrive = TRUE;
135 BOOL bAddCurrentPath = TRUE;
136 BOOL bAddPrefix = TRUE;
138 /* does path begin with drive? if yes, it is absolute */
139 if (wcslen(name) >= 3 && (iswalpha (*name) && *(name+1) == ':'
140 && (*(name+2) == '\\' || *(name+2) == '/'))) {
142 bAddCurrentPath = FALSE;
145 /* is path absolute? */
146 if (*name == '/' || *name == '\\')
147 bAddCurrentPath = FALSE;
149 /* is path relative to itself?, if yes, skip ./ */
150 if (wcslen(name) > 2 && ((wcsncmp (name, L"./", 2) == 0) || (wcsncmp (name, L".\\", 2) == 0))) {
154 /* is path of form '//./'? */
155 if (wcslen(name) > 3 && ((wcsncmp (name, L"//./", 4) == 0) || (wcsncmp (name, L"\\\\.\\", 4) == 0))) {
157 bAddCurrentPath = FALSE;
163 int nParseOffset = 0;
165 /* add 4 bytes header */
168 wcscpy ((wchar_t *) pwszBuf,L"\\\\?\\");
171 /* get current path if needed */
172 if (bAddDrive || bAddCurrentPath) {
173 dwCurDirPathSize = p_GetCurrentDirectoryW(0, NULL);
174 if (dwCurDirPathSize > 0) {
175 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
176 pwszCurDirBuf = check_pool_memory_size(pwszCurDirBuf, (dwCurDirPathSize+1)*sizeof(wchar_t));
177 p_GetCurrentDirectoryW(dwCurDirPathSize,(wchar_t *)pwszCurDirBuf);
181 /* we have no info for doing so */
183 bAddCurrentPath = FALSE;
188 /* add drive if needed */
189 if (bAddDrive && !bAddCurrentPath) {
192 if (dwCurDirPathSize > 3 && wcsncmp((LPCWSTR)pwszCurDirBuf, L"\\\\?\\", 4) == 0)
193 /* copy drive character */
194 wcsncpy((wchar_t *) szDrive, (LPCWSTR)pwszCurDirBuf+4,2);
196 /* copy drive character */
197 wcsncpy((wchar_t *) szDrive, (LPCWSTR)pwszCurDirBuf,2);
201 wcscat((wchar_t *) pwszBuf, szDrive);
205 /* add path if needed */
206 if (bAddCurrentPath) {
207 /* the 1 add. character is for the eventually added backslash */
208 dwBufCharsNeeded += dwCurDirPathSize+1;
209 pwszBuf = check_pool_memory_size(pwszBuf, dwBufCharsNeeded*sizeof(wchar_t));
210 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
212 if (dwCurDirPathSize > 3 && wcsncmp ((LPCWSTR)pwszCurDirBuf, L"\\\\?\\", 4) == 0)
213 /* copy complete string */
214 wcscpy((wchar_t *) pwszBuf, (LPCWSTR)pwszCurDirBuf);
217 wcscat((wchar_t *) pwszBuf, (LPCWSTR)pwszCurDirBuf);
219 nParseOffset = wcslen ((LPCWSTR) pwszBuf);
221 /* check if path ends with backslash, if not, add one */
222 if (*((wchar_t *) pwszBuf+nParseOffset-1) != L'\\') {
223 wcscat((wchar_t *) pwszBuf, L"\\");
229 wchar_t * win32_name = (wchar_t *)pwszBuf+nParseOffset;
232 /* Check for Unix separator and convert to Win32 */
234 *win32_name++ = '\\'; /* convert char */
235 /* If Win32 separated that is "quoted", remove quote */
236 /* HELPME (Thorsten Engel): I don't understand the following part
237 and it removes a backslash from e.g. "\\.\c:" which I need for
238 RAW device access. So I took it out */
239 /* } else if (*name == '\\' && name[1] == '\\') {
240 *win32_name++ = '\\';
241 name++; */ /* skip first \ */
243 *win32_name++ = *name; /* copy character */
248 /* null terminate string */
252 /* here we convert to VSS specific file name which
253 can get longer because VSS will make something like
254 \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
255 from c:\bacula\uninstall.exe
257 if (g_pVSSClient && enable_vss && g_pVSSClient->IsInitialized()) {
258 /* is output buffer large enough? */
259 pwszBuf = check_pool_memory_size(pwszBuf, (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
260 /* create temp. buffer */
261 POOLMEM* pszBuf = get_pool_memory(PM_FNAME);
262 pszBuf = check_pool_memory_size(pszBuf, (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t));
267 wcsncpy((wchar_t *) pszBuf, (wchar_t *) pwszBuf+nParseOffset, wcslen((wchar_t *)pwszBuf)+1-nParseOffset);
268 g_pVSSClient->GetShadowPathW((wchar_t *)pszBuf,(wchar_t *)pwszBuf,dwBufCharsNeeded+MAX_PATH);
269 free_pool_memory(pszBuf);
273 free_pool_memory (pszUCSPath);
274 free_pool_memory (pwszCurDirBuf);
280 wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
282 /* the return value is the number of bytes written to the buffer.
283 The number includes the byte for the null terminator. */
285 if (p_WideCharToMultiByte) {
286 int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
295 UTF8_2_wchar(POOLMEM **ppszUCS, const char *pszUTF)
297 /* the return value is the number of wide characters written to the buffer. */
298 /* convert null terminated string from utf-8 to ucs2, enlarge buffer if necessary */
300 if (p_MultiByteToWideChar) {
301 /* strlen of UTF8 +1 is enough */
302 DWORD cchSize = (strlen(pszUTF)+1);
303 *ppszUCS = check_pool_memory_size(*ppszUCS, cchSize*sizeof (wchar_t));
305 int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
315 wchar_win32_path(const char *name, wchar_t *win32_name)
317 const char *fname = name;
319 /* Check for Unix separator and convert to Win32 */
321 *win32_name++ = '\\'; /* convert char */
322 /* If Win32 separated that is "quoted", remove quote */
323 } else if (*name == '\\' && name[1] == '\\') {
324 *win32_name++ = '\\';
325 name++; /* skip first \ */
327 *win32_name++ = *name; /* copy character */
331 /* Strip any trailing slash, if we stored something */
332 if (*fname != 0 && win32_name[-1] == '\\') {
340 make_win32_path_UTF8_2_wchar(POOLMEM **pszUCS, const char *pszUTF, BOOL* pBIsRawPath /*= NULL*/)
342 /* helper to convert from utf-8 to UCS-2 and to complete a path for 32K path syntax */
343 int nRet = UTF8_2_wchar(pszUCS, pszUTF);
345 #ifdef USE_WIN32_32KPATHCONVERSION
346 /* add \\?\ to support 32K long filepaths */
347 *pszUCS = make_wchar_win32_path(*pszUCS, pBIsRawPath);
350 *pBIsRawPath = FALSE;
363 int chmod(const char *, mode_t)
368 int chown(const char *k, uid_t, gid_t)
373 int lchown(const char *k, uid_t, gid_t)
379 bool fstype(const char *fname, char *fs, int fslen)
381 return true; /* accept anything */
393 srandom(unsigned int seed)
397 // /////////////////////////////////////////////////////////////////
398 // convert from Windows concept of time to Unix concept of time
399 // /////////////////////////////////////////////////////////////////
401 cvt_utime_to_ftime(const time_t &time, FILETIME &wintime)
403 uint64_t mstime = time;
404 mstime *= WIN32_FILETIME_SCALE;
405 mstime += WIN32_FILETIME_ADJUST;
408 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL);
410 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
412 wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
416 cvt_ftime_to_utime(const FILETIME &time)
418 uint64_t mstime = time.dwHighDateTime;
420 mstime |= time.dwLowDateTime;
422 mstime -= WIN32_FILETIME_ADJUST;
423 mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
425 return (time_t) (mstime & 0xffffffff);
433 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
434 FORMAT_MESSAGE_FROM_SYSTEM |
435 FORMAT_MESSAGE_IGNORE_INSERTS,
438 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
443 /* Strip any \r or \n */
444 char *rval = (char *) lpMsgBuf;
445 char *cp = strchr(rval, '\r');
449 cp = strchr(rval, '\n');
459 statDir(const char *file, struct stat *sb)
461 WIN32_FIND_DATAW info_w; // window's file info
462 WIN32_FIND_DATAA info_a; // window's file info
464 // cache some common vars to make code more transparent
465 DWORD* pdwFileAttributes;
466 DWORD* pnFileSizeHigh;
467 DWORD* pnFileSizeLow;
468 FILETIME* pftLastAccessTime;
469 FILETIME* pftLastWriteTime;
470 FILETIME* pftCreationTime;
472 if (file[1] == ':' && file[2] == 0) {
473 d_msg(__FILE__, __LINE__, 99, "faking ROOT attrs(%s).\n", file);
474 sb->st_mode = S_IFDIR;
475 sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
482 HANDLE h = INVALID_HANDLE_VALUE;
484 // use unicode or ascii
485 if (p_FindFirstFileW) {
486 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
487 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
489 h = p_FindFirstFileW((LPCWSTR) pwszBuf, &info_w);
490 free_pool_memory(pwszBuf);
492 pdwFileAttributes = &info_w.dwFileAttributes;
493 pnFileSizeHigh = &info_w.nFileSizeHigh;
494 pnFileSizeLow = &info_w.nFileSizeLow;
495 pftLastAccessTime = &info_w.ftLastAccessTime;
496 pftLastWriteTime = &info_w.ftLastWriteTime;
497 pftCreationTime = &info_w.ftCreationTime;
499 else if (p_FindFirstFileA) {
500 h = p_FindFirstFileA(file, &info_a);
502 pdwFileAttributes = &info_a.dwFileAttributes;
503 pnFileSizeHigh = &info_a.nFileSizeHigh;
504 pnFileSizeLow = &info_a.nFileSizeLow;
505 pftLastAccessTime = &info_a.ftLastAccessTime;
506 pftLastWriteTime = &info_a.ftLastWriteTime;
507 pftCreationTime = &info_a.ftCreationTime;
510 if (h == INVALID_HANDLE_VALUE) {
511 const char *err = errorString();
512 d_msg(__FILE__, __LINE__, 99, "FindFirstFile(%s):%s\n", file, err);
513 LocalFree((void *)err);
514 errno = b_errno_win32;
518 sb->st_mode = 0777; /* start with everything */
519 if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
520 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
521 if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
522 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
523 if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
524 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
525 sb->st_mode |= S_IFDIR;
527 sb->st_size = *pnFileSizeHigh;
529 sb->st_size |= *pnFileSizeLow;
530 sb->st_blksize = 4096;
531 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
533 sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
534 sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
535 sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
542 stat2(const char *file, struct stat *sb)
544 BY_HANDLE_FILE_INFORMATION info;
548 conv_unix_to_win32_path(file, tmpbuf, 1024);
552 if (p_GetFileAttributesW) {
553 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
554 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
556 attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
557 free_pool_memory(pwszBuf);
558 } else if (p_GetFileAttributesA) {
559 attr = p_GetFileAttributesA(tmpbuf);
563 const char *err = errorString();
564 d_msg(__FILE__, __LINE__, 99,
565 "GetFileAttributes(%s): %s\n", tmpbuf, err);
566 LocalFree((void *)err);
567 errno = b_errno_win32;
571 if (attr & FILE_ATTRIBUTE_DIRECTORY)
572 return statDir(tmpbuf, sb);
574 h = CreateFileA(tmpbuf, GENERIC_READ,
575 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
577 if (h == INVALID_HANDLE_VALUE) {
578 const char *err = errorString();
579 d_msg(__FILE__, __LINE__, 99,
580 "Cannot open file for stat (%s):%s\n", tmpbuf, err);
581 LocalFree((void *)err);
583 errno = b_errno_win32;
587 if (!GetFileInformationByHandle(h, &info)) {
588 const char *err = errorString();
589 d_msg(__FILE__, __LINE__, 99,
590 "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
591 LocalFree((void *)err);
593 errno = b_errno_win32;
597 sb->st_dev = info.dwVolumeSerialNumber;
598 sb->st_ino = info.nFileIndexHigh;
600 sb->st_ino |= info.nFileIndexLow;
601 sb->st_nlink = (short)info.nNumberOfLinks;
602 if (sb->st_nlink > 1) {
603 d_msg(__FILE__, __LINE__, 99, "st_nlink=%d\n", sb->st_nlink);
606 sb->st_mode = 0777; /* start with everything */
607 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
608 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
609 if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
610 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
611 if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
612 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
613 sb->st_mode |= S_IFREG;
615 sb->st_size = info.nFileSizeHigh;
617 sb->st_size |= info.nFileSizeLow;
618 sb->st_blksize = 4096;
619 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
620 sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
621 sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
622 sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
630 stat(const char *file, struct stat *sb)
632 WIN32_FILE_ATTRIBUTE_DATA data;
636 memset(sb, 0, sizeof(*sb));
638 /* why not allow win 95 to use p_GetFileAttributesExA ?
639 * this function allows _some_ open files to be stat'ed
640 * if (g_platform_id == VER_PLATFORM_WIN32_WINDOWS) {
641 * return stat2(file, sb);
645 if (p_GetFileAttributesExW) {
646 /* dynamically allocate enough space for UCS2 filename */
647 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
648 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
650 BOOL b = p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, &data);
651 free_pool_memory(pwszBuf);
654 return stat2(file, sb);
656 } else if (p_GetFileAttributesExA) {
657 if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
658 return stat2(file, sb);
661 return stat2(file, sb);
664 sb->st_mode = 0777; /* start with everything */
665 if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
666 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
668 if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
669 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
671 if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
672 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
674 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
675 sb->st_mode |= S_IFDIR;
677 sb->st_mode |= S_IFREG;
681 sb->st_size = data.nFileSizeHigh;
683 sb->st_size |= data.nFileSizeLow;
684 sb->st_blksize = 4096;
685 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
686 sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
687 sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
688 sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
695 lstat(const char *file, struct stat *sb)
697 return stat(file, sb);
713 execvp(const char *, char *[]) {
734 waitpid(int, int*, int)
741 readlink(const char *, char *, int)
750 strcasecmp(const char *s1, const char *s2)
752 register int ch1, ch2;
755 return 0; /* strings are equal if same object. */
765 } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
772 strncasecmp(const char *s1, const char *s2, int len)
774 register int ch1, ch2;
777 return 0; /* strings are equal if same object. */
787 if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
794 gettimeofday(struct timeval *tv, struct timezone *)
804 if (!SystemTimeToFileTime(&now, &tmp)) {
805 errno = b_errno_win32;
809 int64_t _100nsec = tmp.dwHighDateTime;
811 _100nsec |= tmp.dwLowDateTime;
812 _100nsec -= WIN32_FILETIME_ADJUST;
814 tv->tv_sec =(long) (_100nsec / 10000000);
815 tv->tv_usec = (long) ((_100nsec % 10000000)/10);
821 syslog(int type, const char *fmt, const char *msg)
823 /*#ifndef HAVE_CONSOLE
824 MessageBox(NULL, msg, "Bacula", MB_OK);
841 // implement opendir/readdir/closedir on top of window's API
845 WIN32_FIND_DATAA data_a; // window's file info (ansii version)
846 WIN32_FIND_DATAW data_w; // window's file info (wchar version)
847 const char *spec; // the directory we're traversing
848 HANDLE dirh; // the search handle
849 BOOL valid_a; // the info in data_a field is valid
850 BOOL valid_w; // the info in data_w field is valid
851 UINT32 offset; // pseudo offset for d_off
855 opendir(const char *path)
857 /* enough space for VSS !*/
858 int max_len = strlen(path) + MAX_PATH;
865 rval = (_dir *)malloc(sizeof(_dir));
866 memset (rval, 0, sizeof (_dir));
867 if (rval == NULL) return NULL;
868 char *tspec = (char *)malloc(max_len);
869 if (tspec == NULL) return NULL;
871 if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS) {
873 /* will append \\?\ at front itself */
874 conv_unix_to_win32_path(path, tspec, max_len-4);
876 /* allow path to be 32767 bytes */
882 conv_unix_to_win32_path(path, tspec+4, max_len-4);
885 conv_unix_to_win32_path(path, tspec, max_len);
888 // add backslash only if there is none yet (think of c:\)
889 if (tspec[strlen(tspec)-1] != '\\')
890 bstrncat(tspec, "\\*", max_len);
892 bstrncat(tspec, "*", max_len);
896 // convert to wchar_t
897 if (p_FindFirstFileW) {
898 POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
899 make_win32_path_UTF8_2_wchar(&pwcBuf,rval->spec);
901 rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
903 free_pool_memory(pwcBuf);
905 if (rval->dirh != INVALID_HANDLE_VALUE)
907 } else if (p_FindFirstFileA) {
908 rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
910 if (rval->dirh != INVALID_HANDLE_VALUE)
915 d_msg(__FILE__, __LINE__,
916 99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
917 path, rval->spec, rval->dirh);
920 if (rval->dirh == INVALID_HANDLE_VALUE)
924 d_msg(__FILE__, __LINE__,
925 99, "\tFirstFile=%s\n", rval->data_w.cFileName);
928 d_msg(__FILE__, __LINE__,
929 99, "\tFirstFile=%s\n", rval->data_a.cFileName);
934 free((void *)rval->spec);
936 errno = b_errno_win32;
943 _dir *dp = (_dir *)dirp;
945 free((void *)dp->spec);
951 typedef struct _WIN32_FIND_DATA {
952 DWORD dwFileAttributes;
953 FILETIME ftCreationTime;
954 FILETIME ftLastAccessTime;
955 FILETIME ftLastWriteTime;
960 TCHAR cFileName[MAX_PATH];
961 TCHAR cAlternateFileName[14];
962 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
966 copyin(struct dirent &dp, const char *fname)
970 char *cp = dp.d_name;
980 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
982 _dir *dp = (_dir *)dirp;
983 if (dp->valid_w || dp->valid_a) {
984 entry->d_off = dp->offset;
988 char szBuf[MAX_PATH_UTF8+1];
989 wchar_2_UTF8(szBuf,dp->data_w.cFileName);
990 dp->offset += copyin(*entry, szBuf);
991 } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
992 dp->offset += copyin(*entry, dp->data_a.cFileName);
995 *result = entry; /* return entry address */
996 d_msg(__FILE__, __LINE__,
997 99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
998 dirp, entry->d_name, entry->d_reclen, entry->d_off);
1000 // d_msg(__FILE__, __LINE__, 99, "readdir_r !valid\n");
1001 errno = b_errno_win32;
1005 // get next file, try unicode first
1006 if (p_FindNextFileW)
1007 dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1008 else if (p_FindNextFileA)
1009 dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1011 dp->valid_a = FALSE;
1012 dp->valid_w = FALSE;
1019 * Dotted IP address to network address
1025 inet_aton(const char *a, struct in_addr *inp)
1028 uint32_t acc = 0, tmp = 0;
1031 if (!isdigit(*cp)) { /* first char must be digit */
1032 return 0; /* error */
1036 tmp = (tmp * 10) + (*cp -'0');
1037 } else if (*cp == '.' || *cp == 0) {
1039 return 0; /* error */
1041 acc = (acc << 8) + tmp;
1045 return 0; /* error */
1047 } while (*cp++ != 0);
1048 if (dotc != 4) { /* want 3 .'s plus EOS */
1049 return 0; /* error */
1051 inp->s_addr = htonl(acc); /* store addr in network format */
1056 nanosleep(const struct timespec *req, struct timespec *rem)
1059 rem->tv_sec = rem->tv_nsec = 0;
1060 Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1065 init_signals(void terminate(int sig))
1071 init_stack_dump(void)
1078 pathconf(const char *path, int name)
1082 if (strncmp(path, "\\\\?\\", 4) == 0)
1094 WORD wVersionRequested = MAKEWORD( 1, 1);
1097 int err = WSAStartup(wVersionRequested, &wsaData);
1101 printf("Can not start Windows Sockets\n");
1111 win32_chdir(const char *dir)
1113 if (p_SetCurrentDirectoryW) {
1114 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1115 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1117 BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1119 free_pool_memory(pwszBuf);
1122 errno = b_errno_win32;
1126 else if (p_SetCurrentDirectoryA) {
1127 if (0 == p_SetCurrentDirectoryA(dir)) {
1128 errno = b_errno_win32;
1138 win32_mkdir(const char *dir)
1141 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1142 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1144 int n = p_wmkdir((LPCWSTR)pwszBuf);
1145 free_pool_memory(pwszBuf);
1154 win32_getcwd(char *buf, int maxlen)
1158 if (p_GetCurrentDirectoryW) {
1159 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1160 pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(wchar_t));
1162 n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1164 n = wchar_2_UTF8 (buf, (wchar_t *)pwszBuf, maxlen)-1;
1165 free_pool_memory(pwszBuf);
1167 } else if (p_GetCurrentDirectoryA)
1168 n = p_GetCurrentDirectoryA(maxlen, buf);
1170 if (n == 0 || n > maxlen) return NULL;
1172 if (n+1 > maxlen) return NULL;
1181 win32_fputs(const char *string, FILE *stream)
1183 /* we use WriteConsoleA / WriteConsoleA
1184 so we can be sure that unicode support works on win32.
1185 with fallback if something fails
1188 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1189 if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1190 p_MultiByteToWideChar && (stream == stdout)) {
1192 POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1194 DWORD dwCharsWritten;
1197 dwChars = UTF8_2_wchar(&pwszBuf, string);
1199 /* try WriteConsoleW */
1200 if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1201 free_pool_memory(pwszBuf);
1202 return dwCharsWritten;
1205 /* convert to local codepage and try WriteConsoleA */
1206 POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1207 pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1209 dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR) pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1210 free_pool_memory(pwszBuf);
1212 if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1213 free_pool_memory(pszBuf);
1214 return dwCharsWritten;
1218 return fputs(string, stream);
1222 win32_cgets (char* buffer, int len)
1224 /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1225 from the win32 console and fallback if seomething fails */
1227 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1228 if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1230 wchar_t wszBuf[1024];
1233 /* nt and unicode conversion */
1234 if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1236 /* null terminate at end */
1237 if (wszBuf[dwRead-1] == L'\n') {
1238 wszBuf[dwRead-1] = L'\0';
1242 if (wszBuf[dwRead-1] == L'\r') {
1243 wszBuf[dwRead-1] = L'\0';
1247 wchar_2_UTF8(buffer, wszBuf, len);
1251 /* win 9x and unicode conversion */
1252 if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1254 /* null terminate at end */
1255 if (szBuf[dwRead-1] == L'\n') {
1256 szBuf[dwRead-1] = L'\0';
1260 if (szBuf[dwRead-1] == L'\r') {
1261 szBuf[dwRead-1] = L'\0';
1265 /* convert from ansii to wchar_t */
1266 p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1267 /* convert from wchar_t to UTF-8 */
1268 if (wchar_2_UTF8(buffer, wszBuf, len))
1274 if (fgets(buffer, len, stdin))
1281 win32_unlink(const char *filename)
1285 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1286 make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1288 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1290 /* special case if file is readonly,
1291 we retry but unset attribute before */
1292 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1293 DWORD dwAttr = p_GetFileAttributesW((LPCWSTR)pwszBuf);
1294 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1295 if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1296 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1297 /* reset to original if it didn't help */
1299 p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1303 free_pool_memory(pwszBuf);
1305 nRetCode = _unlink(filename);
1307 /* special case if file is readonly,
1308 we retry but unset attribute before */
1309 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1310 DWORD dwAttr = p_GetFileAttributesA(filename);
1311 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1312 if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1313 nRetCode = _unlink(filename);
1314 /* reset to original if it didn't help */
1316 p_SetFileAttributesA(filename, dwAttr);
1325 #include "mswinver.h"
1327 char WIN_VERSION_LONG[64];
1328 char WIN_VERSION[32];
1329 char WIN_RAWVERSION[32];
1336 static winver INIT; // cause constructor to be called before main()
1341 winver::winver(void)
1343 const char *version = "";
1344 const char *platform = "";
1345 OSVERSIONINFO osvinfo;
1346 osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1348 // Get the current OS version
1349 if (!GetVersionEx(&osvinfo)) {
1350 version = "Unknown";
1351 platform = "Unknown";
1353 const int ver = _mkversion(osvinfo.dwPlatformId,
1354 osvinfo.dwMajorVersion,
1355 osvinfo.dwMinorVersion);
1356 snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1359 case MS_WINDOWS_95: (version = "Windows 95"); break;
1360 case MS_WINDOWS_98: (version = "Windows 98"); break;
1361 case MS_WINDOWS_ME: (version = "Windows ME"); break;
1362 case MS_WINDOWS_NT4:(version = "Windows NT 4.0"); platform = "NT"; break;
1363 case MS_WINDOWS_2K: (version = "Windows 2000");platform = "NT"; break;
1364 case MS_WINDOWS_XP: (version = "Windows XP");platform = "NT"; break;
1365 case MS_WINDOWS_S2003: (version = "Windows Server 2003");platform = "NT"; break;
1366 default: version = WIN_RAWVERSION; break;
1369 bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1370 snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %d.%d.%d",
1371 platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1374 HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1378 BPIPE *b = open_bpipe("ls -l", 10, "r");
1380 while (!feof(b->rfd)) {
1381 fgets(buf, sizeof(buf), b->rfd);
1387 BOOL CreateChildProcess(VOID);
1388 VOID WriteToPipe(VOID);
1389 VOID ReadFromPipe(VOID);
1390 VOID ErrorExit(LPCSTR);
1391 VOID ErrMsg(LPTSTR, BOOL);
1394 * Check for a quoted path, if an absolute path name is given and it contains
1395 * spaces it will need to be quoted. i.e. "c:/Program Files/foo/bar.exe"
1396 * CreateProcess() says the best way to ensure proper results with executables
1397 * with spaces in path or filename is to quote the string.
1400 getArgv0(const char *cmdline)
1405 for (cp = cmdline; *cp; cp++)
1410 if (!inquote && isspace(*cp))
1415 int len = cp - cmdline;
1416 char *rval = (char *)malloc(len+1);
1430 * OK, so it would seem CreateProcess only handles true executables:
1431 * .com or .exe files.
1432 * So test to see whether we're getting a .bat file and if so grab
1433 * $COMSPEC value and pass batch file to it.
1436 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1438 static const char *comspec = NULL;
1439 PROCESS_INFORMATION piProcInfo;
1440 STARTUPINFOA siStartInfo;
1441 BOOL bFuncRetn = FALSE;
1443 if (comspec == NULL) {
1444 comspec = getenv("COMSPEC");
1446 if (comspec == NULL) // should never happen
1447 return INVALID_HANDLE_VALUE;
1449 // Set up members of the PROCESS_INFORMATION structure.
1450 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1452 // Set up members of the STARTUPINFO structure.
1454 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1455 siStartInfo.cb = sizeof(STARTUPINFO);
1456 // setup new process to use supplied handles for stdin,stdout,stderr
1457 // if supplied handles are not used the send a copy of our STD_HANDLE
1459 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
1461 if (in != INVALID_HANDLE_VALUE)
1462 siStartInfo.hStdInput = in;
1464 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1466 if (out != INVALID_HANDLE_VALUE)
1467 siStartInfo.hStdOutput = out;
1469 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1470 if (err != INVALID_HANDLE_VALUE)
1471 siStartInfo.hStdError = err;
1473 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1474 // Create the child process.
1477 int cmdLen = strlen(cmdline) + strlen(comspec) + 16;
1479 char *cmdLine = (char *)alloca(cmdLen);
1481 bstrncpy(exeFile, comspec, sizeof(exeFile));
1482 bstrncpy(cmdLine, comspec, cmdLen);
1483 bstrncat(cmdLine, " /c ", cmdLen);
1484 bstrncat(cmdLine, cmdline, cmdLen);
1486 // try to execute program
1487 bFuncRetn = CreateProcessA(exeFile,
1488 cmdLine, // command line
1489 NULL, // process security attributes
1490 NULL, // primary thread security attributes
1491 TRUE, // handles are inherited
1492 0, // creation flags
1493 NULL, // use parent's environment
1494 NULL, // use parent's current directory
1495 &siStartInfo, // STARTUPINFO pointer
1496 &piProcInfo); // receives PROCESS_INFORMATION
1498 if (bFuncRetn == 0) {
1499 ErrorExit("CreateProcess failed\n");
1500 const char *err = errorString();
1501 d_msg(__FILE__, __LINE__, 99,
1502 "CreateProcess(%s, %s, ...)=%s\n", exeFile, cmdLine, err);
1503 LocalFree((void *)err);
1504 return INVALID_HANDLE_VALUE;
1506 // we don't need a handle on the process primary thread so we close
1508 CloseHandle(piProcInfo.hThread);
1510 return piProcInfo.hProcess;
1515 ErrorExit (LPCSTR lpszMessage)
1517 d_msg(__FILE__, __LINE__, 0, "%s", lpszMessage);
1522 typedef struct s_bpipe {
1524 time_t worker_stime;
1533 CloseIfValid(HANDLE handle)
1535 if (handle != INVALID_HANDLE_VALUE)
1536 CloseHandle(handle);
1541 open_bpipe(char *prog, int wait, const char *mode)
1543 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1544 hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1547 SECURITY_ATTRIBUTES saAttr;
1551 hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1552 hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1553 hInputFile = INVALID_HANDLE_VALUE;
1555 BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1556 memset((void *)bpipe, 0, sizeof(BPIPE));
1558 int mode_read = (mode[0] == 'r');
1559 int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1562 // Set the bInheritHandle flag so pipe handles are inherited.
1564 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1565 saAttr.bInheritHandle = TRUE;
1566 saAttr.lpSecurityDescriptor = NULL;
1570 // Create a pipe for the child process's STDOUT.
1571 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1572 ErrorExit("Stdout pipe creation failed\n");
1575 // Create noninheritable read handle and close the inheritable read
1578 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1579 GetCurrentProcess(), &hChildStdoutRdDup , 0,
1581 DUPLICATE_SAME_ACCESS);
1583 ErrorExit("DuplicateHandle failed");
1587 CloseHandle(hChildStdoutRd);
1588 hChildStdoutRd = INVALID_HANDLE_VALUE;
1593 // Create a pipe for the child process's STDIN.
1595 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1596 ErrorExit("Stdin pipe creation failed\n");
1600 // Duplicate the write handle to the pipe so it is not inherited.
1601 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
1602 GetCurrentProcess(), &hChildStdinWrDup,
1604 FALSE, // not inherited
1605 DUPLICATE_SAME_ACCESS);
1607 ErrorExit("DuplicateHandle failed");
1611 CloseHandle(hChildStdinWr);
1612 hChildStdinWr = INVALID_HANDLE_VALUE;
1614 // spawn program with redirected handles as appropriate
1615 bpipe->worker_pid = (pid_t)
1616 CreateChildProcess(prog, // commandline
1617 hChildStdinRd, // stdin HANDLE
1618 hChildStdoutWr, // stdout HANDLE
1619 hChildStdoutWr); // stderr HANDLE
1621 if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1625 bpipe->worker_stime = time(NULL);
1628 CloseHandle(hChildStdoutWr); // close our write side so when
1629 // process terminates we can
1631 // ugly but convert WIN32 HANDLE to FILE*
1632 int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY);
1634 bpipe->rfd = _fdopen(rfd, "r");
1638 CloseHandle(hChildStdinRd); // close our read side so as not
1639 // to interfre with child's copy
1640 // ugly but convert WIN32 HANDLE to FILE*
1641 int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY);
1643 bpipe->wfd = _fdopen(wfd, "w");
1648 bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
1655 CloseIfValid(hChildStdoutRd);
1656 CloseIfValid(hChildStdoutRdDup);
1657 CloseIfValid(hChildStdinWr);
1658 CloseIfValid(hChildStdinWrDup);
1660 free((void *) bpipe);
1661 errno = b_errno_win32; /* do GetLastError() for error code */
1668 kill(int pid, int signal)
1671 if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
1673 errno = b_errno_win32;
1675 CloseHandle((HANDLE)pid);
1682 close_bpipe(BPIPE *bpipe)
1685 int32_t remaining_wait = bpipe->wait;
1687 if (remaining_wait == 0) { /* wait indefinitely */
1688 remaining_wait = INT32_MAX;
1692 if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
1693 const char *err = errorString();
1694 rval = b_errno_win32;
1695 d_msg(__FILE__, __LINE__, 0,
1696 "GetExitCode error %s\n", err);
1697 LocalFree((void *)err);
1700 if (exitCode == STILL_ACTIVE) {
1701 if (remaining_wait <= 0) {
1702 rval = ETIME; /* timed out */
1705 bmicrosleep(1, 0); /* wait one second */
1707 } else if (exitCode != 0) {
1708 /* Truncate exit code as it doesn't seem to be correct */
1709 rval = (exitCode & 0xFF) | b_errno_exit;
1712 break; /* Shouldn't get here */
1716 if (bpipe->timer_id) {
1717 stop_child_timer(bpipe->timer_id);
1719 if (bpipe->rfd) fclose(bpipe->rfd);
1720 if (bpipe->wfd) fclose(bpipe->wfd);
1721 free((void *)bpipe);
1726 close_wpipe(BPIPE *bpipe)
1732 if (fclose(bpipe->wfd) != 0) {
1740 #include "findlib/find.h"
1743 utime(const char *fname, struct utimbuf *times)
1748 conv_unix_to_win32_path(fname, tmpbuf, 5000);
1750 cvt_utime_to_ftime(times->actime, acc);
1751 cvt_utime_to_ftime(times->modtime, mod);
1753 HANDLE h = INVALID_HANDLE_VALUE;
1755 if (p_CreateFileW) {
1756 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1757 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
1759 h = p_CreateFileW((LPCWSTR)pwszBuf,
1760 FILE_WRITE_ATTRIBUTES,
1761 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
1764 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
1767 free_pool_memory(pwszBuf);
1768 } else if (p_CreateFileA) {
1769 h = p_CreateFileA(tmpbuf,
1770 FILE_WRITE_ATTRIBUTES,
1771 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
1774 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
1778 if (h == INVALID_HANDLE_VALUE) {
1779 const char *err = errorString();
1780 d_msg(__FILE__, __LINE__, 99,
1781 "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
1782 LocalFree((void *)err);
1783 errno = b_errno_win32;
1787 int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
1790 errno = b_errno_win32;
1795 #if USE_WIN32_COMPAT_IO
1798 open(const char *file, int flags, int mode)
1801 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1802 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
1804 int nRet = p_wopen((LPCWSTR) pwszBuf, flags|_O_BINARY, mode);
1805 free_pool_memory(pwszBuf);
1810 return _open(file, flags|_O_BINARY, mode);
1814 * Note, this works only for a file. If you want
1815 * to close a socket, use closesocket().
1816 * Bacula has been modified in src/lib/bnet.c
1817 * to use closesocket().
1826 #ifndef HAVE_WXCONSOLE
1828 read(int fd, void *buf, ssize_t len)
1830 return _read(fd, buf, (size_t)len);
1834 write(int fd, const void *buf, ssize_t len)
1836 return _write(fd, buf, (size_t)len);
1842 lseek(int fd, off_t offset, int whence)
1844 return (off_t)_lseeki64(fd, offset, whence);
1848 dup2(int fd1, int fd2)
1850 return _dup2(fd1, fd2);
1855 open(const char *file, int flags, int mode)
1858 DWORD shareMode = 0;
1861 HANDLE foo = INVALID_HANDLE_VALUE;
1862 const char *remap = file;
1864 if (flags & O_WRONLY) access = GENERIC_WRITE;
1865 else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
1866 else access = GENERIC_READ;
1868 if (flags & O_CREAT) create = CREATE_NEW;
1869 else create = OPEN_EXISTING;
1871 if (flags & O_TRUNC) create = TRUNCATE_EXISTING;
1873 if (!(flags & O_EXCL))
1874 shareMode = FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE;
1876 if (flags & O_APPEND) {
1877 printf("open...APPEND not implemented yet.");
1881 if (p_CreateFileW) {
1882 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1883 make_win32_path_UTF8_2_wchar(pwszBuf, file);
1885 foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
1886 free_pool_memory(pwszBuf);
1887 } else if (p_CreateFileA)
1888 foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
1890 if (INVALID_HANDLE_VALUE == foo) {
1891 errno = b_errno_win32;
1902 if (!CloseHandle((HANDLE)fd)) {
1903 errno = b_errno_win32;
1911 write(int fd, const void *data, ssize_t len)
1915 status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
1916 if (status) return bwrite;
1917 errno = b_errno_win32;
1923 read(int fd, void *data, ssize_t len)
1928 status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
1929 if (status) return bread;
1930 errno = b_errno_win32;
1935 lseek(int fd, off_t offset, int whence)
1941 method = FILE_BEGIN;
1944 method = FILE_CURRENT;
1954 if ((val=SetFilePointer((HANDLE)fd, (DWORD)offset, NULL, method)) == INVALID_SET_FILE_POINTER) {
1955 errno = b_errno_win32;
1958 /* ***FIXME*** I doubt this works right */
1975 /* syslog function, added by Nicolas Boichat */