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-2005 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
25 #define b_errno_win32 (1<<29)
29 #include "../../lib/winapi.h"
32 /* to allow the usage of the original version in this file here */
36 #define USE_WIN32_COMPAT_IO 1
37 #define USE_WIN32_32KPATHCONVERSION 1
39 extern void d_msg(const char *file, int line, int level, const char *fmt,...);
40 extern DWORD g_platform_id;
41 extern int enable_vss;
43 // from MicroSoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970
45 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL //Not sure it works
47 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000I64
50 #define WIN32_FILETIME_SCALE 10000000 // 100ns/second
52 void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize)
54 const char *fname = name;
55 char *tname = win32_name;
57 /* Check for Unix separator and convert to Win32 */
58 if (name[0] == '/' && name[1] == '/') { /* double slash? */
59 name++; /* yes, skip first one */
62 *win32_name++ = '\\'; /* convert char */
63 /* If Win32 separated that is "quoted", remove quote */
64 } else if (*name == '\\' && name[1] == '\\') {
66 name++; /* skip first \ */
68 *win32_name++ = *name; /* copy character */
72 /* Strip any trailing slash, if we stored something */
73 /* but leave "c:\" with backslash (root directory case */
74 if (*fname != 0 && win32_name[-1] == '\\' && strlen (fname) != 3) {
81 /* here we convert to VSS specific file name which
82 can get longer because VSS will make something like
83 \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
84 from c:\bacula\uninstall.exe
86 if (g_pVSSClient && enable_vss && g_pVSSClient->IsInitialized()) {
87 POOLMEM *pszBuf = get_pool_memory (PM_FNAME);
88 pszBuf = check_pool_memory_size(pszBuf, dwSize);
89 bstrncpy(pszBuf, tname, strlen(tname)+1);
90 g_pVSSClient->GetShadowPath(pszBuf, tname, dwSize);
91 free_pool_memory(pszBuf);
97 make_wchar_win32_path(POOLMEM* pszUCSPath, BOOL* pBIsRawPath /*= NULL*/)
99 /* created 02/27/2006 Thorsten Engel
101 This function expects an UCS-encoded standard WCHAR in pszUCSPath and
102 will complete the input path to an absolue path of the form \\?\c:\path\file
104 With this trick, it is possible to have 32K characters long paths.
106 Optionally one can use pBIsRawPath to determine id pszUCSPath contains a path
107 to a raw windows partition */
110 *pBIsRawPath = FALSE;
112 if (!p_GetCurrentDirectoryW)
115 WCHAR* name = (WCHAR*) pszUCSPath;
117 /* if it has already the desired form, exit without changes */
118 if (wcslen(name) > 3 && wcsncmp (name, L"\\\\?\\", 4) == 0)
121 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
122 POOLMEM* pwszCurDirBuf = get_pool_memory (PM_FNAME);
123 DWORD dwCurDirPathSize = 0;
125 /* get buffer with enough size (name+max 6. wchars+1 null terminator */
126 DWORD dwBufCharsNeeded = (wcslen(name)+7);
127 pwszBuf = check_pool_memory_size(pwszBuf, dwBufCharsNeeded*sizeof(WCHAR));
129 /* add \\?\ to support 32K long filepaths
130 it is important to make absolute paths, so we add drive and
131 current path if necessary */
133 BOOL bAddDrive = TRUE;
134 BOOL bAddCurrentPath = TRUE;
135 BOOL bAddPrefix = TRUE;
137 /* does path begin with drive? if yes, it is absolute */
138 if (wcslen(name) >= 3 && (iswalpha (*name) && *(name+1) == ':'
139 && (*(name+2) == '\\' || *(name+2) == '/'))) {
141 bAddCurrentPath = FALSE;
144 /* is path absolute? */
145 if (*name == '/' || *name == '\\')
146 bAddCurrentPath = FALSE;
148 /* is path relative to itself?, if yes, skip ./ */
149 if (wcslen(name) > 2 && ((wcsncmp (name, L"./", 2) == 0) || (wcsncmp (name, L".\\", 2) == 0))) {
153 /* is path of form '//./'? */
154 if (wcslen(name) > 3 && ((wcsncmp (name, L"//./", 4) == 0) || (wcsncmp (name, L"\\\\.\\", 4) == 0))) {
156 bAddCurrentPath = FALSE;
162 int nParseOffset = 0;
164 /* add 4 bytes header */
167 wcscpy ((WCHAR*) pwszBuf,L"\\\\?\\");
170 /* get current path if needed */
171 if (bAddDrive || bAddCurrentPath) {
172 dwCurDirPathSize = p_GetCurrentDirectoryW(0, NULL);
173 if (dwCurDirPathSize > 0) {
174 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
175 pwszCurDirBuf = check_pool_memory_size(pwszCurDirBuf, (dwCurDirPathSize+1)*sizeof(WCHAR));
176 p_GetCurrentDirectoryW(dwCurDirPathSize,(WCHAR*)pwszCurDirBuf);
180 /* we have no info for doing so */
182 bAddCurrentPath = FALSE;
187 /* add drive if needed */
188 if (bAddDrive && !bAddCurrentPath) {
191 if (dwCurDirPathSize > 3 && wcsncmp ((LPCWSTR)pwszCurDirBuf, L"\\\\?\\", 4) == 0)
192 /* copy drive character */
193 wcsncpy ((WCHAR*) szDrive, (LPCWSTR)pwszCurDirBuf+4,2);
195 /* copy drive character */
196 wcsncpy ((WCHAR*) szDrive, (LPCWSTR)pwszCurDirBuf,2);
200 wcscat ((WCHAR*) pwszBuf, szDrive);
204 /* add path if needed */
205 if (bAddCurrentPath) {
206 /* the 1 add. character is for the eventually added backslash */
207 dwBufCharsNeeded += dwCurDirPathSize+1;
208 pwszBuf = check_pool_memory_size(pwszBuf, dwBufCharsNeeded*sizeof(WCHAR));
209 /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */
211 if (dwCurDirPathSize > 3 && wcsncmp ((LPCWSTR)pwszCurDirBuf, L"\\\\?\\", 4) == 0)
212 /* copy complete string */
213 wcscpy ((WCHAR*) pwszBuf, (LPCWSTR)pwszCurDirBuf);
216 wcscat ((WCHAR*) pwszBuf, (LPCWSTR)pwszCurDirBuf);
218 nParseOffset = wcslen ((LPCWSTR) pwszBuf);
220 /* check if path ends with backslash, if not, add one */
221 if (*((WCHAR*) pwszBuf+nParseOffset-1) != L'\\') {
222 wcscat ((WCHAR*) pwszBuf, L"\\");
228 WCHAR* win32_name = (WCHAR*) pwszBuf+nParseOffset;
231 /* Check for Unix separator and convert to Win32 */
233 *win32_name++ = '\\'; /* convert char */
234 /* If Win32 separated that is "quoted", remove quote */
235 /* HELPME (Thorsten Engel): I don't understand the following part
236 and it removes a backslash from e.g. "\\.\c:" which I need for
237 RAW device access. So I took it out */
238 /* } else if (*name == '\\' && name[1] == '\\') {
239 *win32_name++ = '\\';
240 name++; */ /* skip first \ */
242 *win32_name++ = *name; /* copy character */
247 /* null terminate string */
251 /* here we convert to VSS specific file name which
252 can get longer because VSS will make something like
253 \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
254 from c:\bacula\uninstall.exe
256 if (g_pVSSClient && enable_vss && g_pVSSClient->IsInitialized()) {
257 /* is output buffer large enough? */
258 pwszBuf = check_pool_memory_size(pwszBuf, (dwBufCharsNeeded+MAX_PATH)*sizeof(WCHAR));
259 /* create temp. buffer */
260 POOLMEM* pszBuf = get_pool_memory (PM_FNAME);
261 pszBuf = check_pool_memory_size(pszBuf, (dwBufCharsNeeded+MAX_PATH)*sizeof(WCHAR));
266 wcsncpy ((WCHAR*) pszBuf, (WCHAR*) pwszBuf+nParseOffset, wcslen((WCHAR*)pwszBuf)+1-nParseOffset);
267 g_pVSSClient->GetShadowPathW((WCHAR*)pszBuf,(WCHAR*)pwszBuf,dwBufCharsNeeded+MAX_PATH);
268 free_pool_memory(pszBuf);
272 free_pool_memory (pszUCSPath);
273 free_pool_memory (pwszCurDirBuf);
279 wchar_2_UTF8(char *pszUTF, const WCHAR *pszUCS, int cchChar)
281 /* the return value is the number of bytes written to the buffer.
282 The number includes the byte for the null terminator. */
284 if (p_WideCharToMultiByte) {
285 int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
294 UTF8_2_wchar(POOLMEM **ppszUCS, const char *pszUTF)
296 /* the return value is the number of wide characters written to the buffer. */
297 /* convert null terminated string from utf-8 to ucs2, enlarge buffer if necessary */
299 if (p_MultiByteToWideChar) {
300 /* strlen of UTF8 +1 is enough */
301 DWORD cchSize = (strlen(pszUTF)+1);
302 *ppszUCS = check_pool_memory_size(*ppszUCS, cchSize*sizeof (WCHAR));
304 int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
314 wchar_win32_path(const char *name, WCHAR *win32_name)
316 const char *fname = name;
318 /* Check for Unix separator and convert to Win32 */
320 *win32_name++ = '\\'; /* convert char */
321 /* If Win32 separated that is "quoted", remove quote */
322 } else if (*name == '\\' && name[1] == '\\') {
323 *win32_name++ = '\\';
324 name++; /* skip first \ */
326 *win32_name++ = *name; /* copy character */
330 /* Strip any trailing slash, if we stored something */
331 if (*fname != 0 && win32_name[-1] == '\\') {
339 make_win32_path_UTF8_2_wchar(POOLMEM **pszUCS, const char *pszUTF, BOOL* pBIsRawPath /*= NULL*/)
341 /* helper to convert from utf-8 to UCS-2 and to complete a path for 32K path syntax */
342 int nRet = UTF8_2_wchar(pszUCS, pszUTF);
344 #ifdef USE_WIN32_32KPATHCONVERSION
345 /* add \\?\ to support 32K long filepaths */
346 *pszUCS = make_wchar_win32_path(*pszUCS, pBIsRawPath);
349 *pBIsRawPath = FALSE;
362 int chmod(const char *, mode_t)
367 int chown(const char *k, uid_t, gid_t)
372 int lchown(const char *k, uid_t, gid_t)
378 bool fstype(const char *fname, char *fs, int fslen)
380 return true; /* accept anything */
392 srandom(unsigned int seed)
396 // /////////////////////////////////////////////////////////////////
397 // convert from Windows concept of time to Unix concept of time
398 // /////////////////////////////////////////////////////////////////
400 cvt_utime_to_ftime(const time_t &time, FILETIME &wintime)
402 uint64_t mstime = time;
403 mstime *= WIN32_FILETIME_SCALE;
404 mstime += WIN32_FILETIME_ADJUST;
407 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL);
409 wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64);
411 wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL);
415 cvt_ftime_to_utime(const FILETIME &time)
417 uint64_t mstime = time.dwHighDateTime;
419 mstime |= time.dwLowDateTime;
421 mstime -= WIN32_FILETIME_ADJUST;
422 mstime /= WIN32_FILETIME_SCALE; // convert to seconds.
424 return (time_t) (mstime & 0xffffffff);
432 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
433 FORMAT_MESSAGE_FROM_SYSTEM |
434 FORMAT_MESSAGE_IGNORE_INSERTS,
437 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default lang
442 /* Strip any \r or \n */
443 char *rval = (char *) lpMsgBuf;
444 char *cp = strchr(rval, '\r');
448 cp = strchr(rval, '\n');
458 statDir(const char *file, struct stat *sb)
460 WIN32_FIND_DATAW info_w; // window's file info
461 WIN32_FIND_DATAA info_a; // window's file info
463 // cache some common vars to make code more transparent
464 DWORD* pdwFileAttributes;
465 DWORD* pnFileSizeHigh;
466 DWORD* pnFileSizeLow;
467 FILETIME* pftLastAccessTime;
468 FILETIME* pftLastWriteTime;
469 FILETIME* pftCreationTime;
471 if (file[1] == ':' && file[2] == 0) {
472 d_msg(__FILE__, __LINE__, 99, "faking ROOT attrs(%s).\n", file);
473 sb->st_mode = S_IFDIR;
474 sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE;
481 HANDLE h = INVALID_HANDLE_VALUE;
483 // use unicode or ascii
484 if (p_FindFirstFileW) {
485 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
486 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
488 h = p_FindFirstFileW((LPCWSTR) pwszBuf, &info_w);
489 free_pool_memory(pwszBuf);
491 pdwFileAttributes = &info_w.dwFileAttributes;
492 pnFileSizeHigh = &info_w.nFileSizeHigh;
493 pnFileSizeLow = &info_w.nFileSizeLow;
494 pftLastAccessTime = &info_w.ftLastAccessTime;
495 pftLastWriteTime = &info_w.ftLastWriteTime;
496 pftCreationTime = &info_w.ftCreationTime;
498 else if (p_FindFirstFileA) {
499 h = p_FindFirstFileA(file, &info_a);
501 pdwFileAttributes = &info_a.dwFileAttributes;
502 pnFileSizeHigh = &info_a.nFileSizeHigh;
503 pnFileSizeLow = &info_a.nFileSizeLow;
504 pftLastAccessTime = &info_a.ftLastAccessTime;
505 pftLastWriteTime = &info_a.ftLastWriteTime;
506 pftCreationTime = &info_a.ftCreationTime;
509 if (h == INVALID_HANDLE_VALUE) {
510 const char *err = errorString();
511 d_msg(__FILE__, __LINE__, 99, "FindFirstFile(%s):%s\n", file, err);
512 LocalFree((void *)err);
513 errno = b_errno_win32;
517 sb->st_mode = 0777; /* start with everything */
518 if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY)
519 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
520 if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
521 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
522 if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
523 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
524 sb->st_mode |= S_IFDIR;
526 sb->st_size = *pnFileSizeHigh;
528 sb->st_size |= *pnFileSizeLow;
529 sb->st_blksize = 4096;
530 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
532 sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime);
533 sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime);
534 sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime);
541 stat2(const char *file, struct stat *sb)
543 BY_HANDLE_FILE_INFORMATION info;
547 conv_unix_to_win32_path(file, tmpbuf, 1024);
551 if (p_GetFileAttributesW) {
552 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
553 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
555 attr = p_GetFileAttributesW((LPCWSTR) pwszBuf);
556 free_pool_memory(pwszBuf);
557 } else if (p_GetFileAttributesA) {
558 attr = p_GetFileAttributesA(tmpbuf);
562 const char *err = errorString();
563 d_msg(__FILE__, __LINE__, 99,
564 "GetFileAttributes(%s): %s\n", tmpbuf, err);
565 LocalFree((void *)err);
566 errno = b_errno_win32;
570 if (attr & FILE_ATTRIBUTE_DIRECTORY)
571 return statDir(tmpbuf, sb);
573 h = CreateFileA(tmpbuf, GENERIC_READ,
574 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
576 if (h == INVALID_HANDLE_VALUE) {
577 const char *err = errorString();
578 d_msg(__FILE__, __LINE__, 99,
579 "Cannot open file for stat (%s):%s\n", tmpbuf, err);
580 LocalFree((void *)err);
582 errno = b_errno_win32;
586 if (!GetFileInformationByHandle(h, &info)) {
587 const char *err = errorString();
588 d_msg(__FILE__, __LINE__, 99,
589 "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
590 LocalFree((void *)err);
592 errno = b_errno_win32;
596 sb->st_dev = info.dwVolumeSerialNumber;
597 sb->st_ino = info.nFileIndexHigh;
599 sb->st_ino |= info.nFileIndexLow;
600 sb->st_nlink = (short)info.nNumberOfLinks;
601 if (sb->st_nlink > 1) {
602 d_msg(__FILE__, __LINE__, 99, "st_nlink=%d\n", sb->st_nlink);
605 sb->st_mode = 0777; /* start with everything */
606 if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
607 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
608 if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
609 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
610 if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
611 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
612 sb->st_mode |= S_IFREG;
614 sb->st_size = info.nFileSizeHigh;
616 sb->st_size |= info.nFileSizeLow;
617 sb->st_blksize = 4096;
618 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
619 sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime);
620 sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime);
621 sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime);
629 stat(const char *file, struct stat *sb)
631 WIN32_FILE_ATTRIBUTE_DATA data;
635 memset(sb, 0, sizeof(*sb));
637 /* why not allow win 95 to use p_GetFileAttributesExA ?
638 * this function allows _some_ open files to be stat'ed
639 * if (g_platform_id == VER_PLATFORM_WIN32_WINDOWS) {
640 * return stat2(file, sb);
644 if (p_GetFileAttributesExW) {
645 /* dynamically allocate enough space for UCS2 filename */
646 POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
647 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
649 BOOL b = p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, &data);
650 free_pool_memory(pwszBuf);
653 return stat2(file, sb);
655 } else if (p_GetFileAttributesExA) {
656 if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) {
657 return stat2(file, sb);
660 return stat2(file, sb);
663 sb->st_mode = 0777; /* start with everything */
664 if (data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
665 sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH);
667 if (data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) {
668 sb->st_mode &= ~S_IRWXO; /* remove everything for other */
670 if (data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
671 sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
673 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
674 sb->st_mode |= S_IFDIR;
676 sb->st_mode |= S_IFREG;
680 sb->st_size = data.nFileSizeHigh;
682 sb->st_size |= data.nFileSizeLow;
683 sb->st_blksize = 4096;
684 sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096;
685 sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime);
686 sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime);
687 sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime);
694 lstat(const char *file, struct stat *sb)
696 return stat(file, sb);
712 execvp(const char *, char *[]) {
733 waitpid(int, int*, int)
740 readlink(const char *, char *, int)
749 strcasecmp(const char *s1, const char *s2)
751 register int ch1, ch2;
754 return 0; /* strings are equal if same object. */
764 } while (ch1 != 0 && tolower(ch1) == tolower(ch2));
771 strncasecmp(const char *s1, const char *s2, int len)
773 register int ch1, ch2;
776 return 0; /* strings are equal if same object. */
786 if (ch1 == 0 || tolower(ch1) != tolower(ch2)) break;
793 gettimeofday(struct timeval *tv, struct timezone *)
803 if (!SystemTimeToFileTime(&now, &tmp)) {
804 errno = b_errno_win32;
808 int64_t _100nsec = tmp.dwHighDateTime;
810 _100nsec |= tmp.dwLowDateTime;
811 _100nsec -= WIN32_FILETIME_ADJUST;
813 tv->tv_sec =(long) (_100nsec / 10000000);
814 tv->tv_usec = (long) ((_100nsec % 10000000)/10);
820 syslog(int type, const char *fmt, const char *msg)
822 /*#ifndef HAVE_CONSOLE
823 MessageBox(NULL, msg, "Bacula", MB_OK);
840 // implement opendir/readdir/closedir on top of window's API
844 WIN32_FIND_DATAA data_a; // window's file info (ansii version)
845 WIN32_FIND_DATAW data_w; // window's file info (wchar version)
846 const char *spec; // the directory we're traversing
847 HANDLE dirh; // the search handle
848 BOOL valid_a; // the info in data_a field is valid
849 BOOL valid_w; // the info in data_w field is valid
850 UINT32 offset; // pseudo offset for d_off
854 opendir(const char *path)
856 /* enough space for VSS !*/
857 int max_len = strlen(path) + MAX_PATH;
864 rval = (_dir *)malloc(sizeof(_dir));
865 memset (rval, 0, sizeof (_dir));
866 if (rval == NULL) return NULL;
867 char *tspec = (char *)malloc(max_len);
868 if (tspec == NULL) return NULL;
870 if (g_platform_id != VER_PLATFORM_WIN32_WINDOWS) {
872 /* will append \\?\ at front itself */
873 conv_unix_to_win32_path(path, tspec, max_len-4);
875 /* allow path to be 32767 bytes */
881 conv_unix_to_win32_path(path, tspec+4, max_len-4);
884 conv_unix_to_win32_path(path, tspec, max_len);
887 // add backslash only if there is none yet (think of c:\)
888 if (tspec[strlen(tspec)-1] != '\\')
889 bstrncat(tspec, "\\*", max_len);
891 bstrncat(tspec, "*", max_len);
896 if (p_FindFirstFileW) {
897 POOLMEM* pwcBuf = get_pool_memory(PM_FNAME);;
898 make_win32_path_UTF8_2_wchar(&pwcBuf,rval->spec);
900 rval->dirh = p_FindFirstFileW((LPCWSTR)pwcBuf, &rval->data_w);
902 free_pool_memory(pwcBuf);
904 if (rval->dirh != INVALID_HANDLE_VALUE)
906 } else if (p_FindFirstFileA) {
907 rval->dirh = p_FindFirstFileA(rval->spec, &rval->data_a);
909 if (rval->dirh != INVALID_HANDLE_VALUE)
914 d_msg(__FILE__, __LINE__,
915 99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
916 path, rval->spec, rval->dirh);
919 if (rval->dirh == INVALID_HANDLE_VALUE)
923 d_msg(__FILE__, __LINE__,
924 99, "\tFirstFile=%s\n", rval->data_w.cFileName);
927 d_msg(__FILE__, __LINE__,
928 99, "\tFirstFile=%s\n", rval->data_a.cFileName);
933 free((void *)rval->spec);
935 errno = b_errno_win32;
942 _dir *dp = (_dir *)dirp;
944 free((void *)dp->spec);
950 typedef struct _WIN32_FIND_DATA {
951 DWORD dwFileAttributes;
952 FILETIME ftCreationTime;
953 FILETIME ftLastAccessTime;
954 FILETIME ftLastWriteTime;
959 TCHAR cFileName[MAX_PATH];
960 TCHAR cAlternateFileName[14];
961 } WIN32_FIND_DATA, *PWIN32_FIND_DATA;
965 copyin(struct dirent &dp, const char *fname)
969 char *cp = dp.d_name;
979 readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
981 _dir *dp = (_dir *)dirp;
982 if (dp->valid_w || dp->valid_a) {
983 entry->d_off = dp->offset;
987 char szBuf[MAX_PATH_UTF8+1];
988 wchar_2_UTF8(szBuf,dp->data_w.cFileName);
989 dp->offset += copyin(*entry, szBuf);
990 } else if (dp->valid_a) { // copy ansi (only 1 will be valid)
991 dp->offset += copyin(*entry, dp->data_a.cFileName);
994 *result = entry; /* return entry address */
995 d_msg(__FILE__, __LINE__,
996 99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
997 dirp, entry->d_name, entry->d_reclen, entry->d_off);
999 // d_msg(__FILE__, __LINE__, 99, "readdir_r !valid\n");
1000 errno = b_errno_win32;
1004 // get next file, try unicode first
1005 if (p_FindNextFileW)
1006 dp->valid_w = p_FindNextFileW(dp->dirh, &dp->data_w);
1007 else if (p_FindNextFileA)
1008 dp->valid_a = p_FindNextFileA(dp->dirh, &dp->data_a);
1010 dp->valid_a = FALSE;
1011 dp->valid_w = FALSE;
1018 * Dotted IP address to network address
1024 inet_aton(const char *a, struct in_addr *inp)
1027 uint32_t acc = 0, tmp = 0;
1030 if (!isdigit(*cp)) { /* first char must be digit */
1031 return 0; /* error */
1035 tmp = (tmp * 10) + (*cp -'0');
1036 } else if (*cp == '.' || *cp == 0) {
1038 return 0; /* error */
1040 acc = (acc << 8) + tmp;
1044 return 0; /* error */
1046 } while (*cp++ != 0);
1047 if (dotc != 4) { /* want 3 .'s plus EOS */
1048 return 0; /* error */
1050 inp->s_addr = htonl(acc); /* store addr in network format */
1055 nanosleep(const struct timespec *req, struct timespec *rem)
1058 rem->tv_sec = rem->tv_nsec = 0;
1059 Sleep((req->tv_sec * 1000) + (req->tv_nsec/100000));
1064 init_signals(void terminate(int sig))
1070 init_stack_dump(void)
1077 pathconf(const char *path, int name)
1081 if (strncmp(path, "\\\\?\\", 4) == 0)
1093 WORD wVersionRequested = MAKEWORD( 1, 1);
1096 int err = WSAStartup(wVersionRequested, &wsaData);
1100 printf("Can not start Windows Sockets\n");
1110 win32_chdir(const char *dir)
1112 if (p_SetCurrentDirectoryW) {
1113 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1114 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1116 BOOL b=p_SetCurrentDirectoryW((LPCWSTR)pwszBuf);
1118 free_pool_memory(pwszBuf);
1121 errno = b_errno_win32;
1125 else if (p_SetCurrentDirectoryA) {
1126 if (0 == p_SetCurrentDirectoryA(dir)) {
1127 errno = b_errno_win32;
1137 win32_mkdir(const char *dir)
1140 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1141 make_win32_path_UTF8_2_wchar(&pwszBuf, dir);
1143 int n = p_wmkdir((LPCWSTR)pwszBuf);
1144 free_pool_memory(pwszBuf);
1153 win32_getcwd(char *buf, int maxlen)
1157 if (p_GetCurrentDirectoryW) {
1158 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1159 pwszBuf = check_pool_memory_size (pwszBuf, maxlen*sizeof(WCHAR));
1161 n = p_GetCurrentDirectoryW(maxlen, (LPWSTR) pwszBuf);
1163 n = wchar_2_UTF8 (buf, (WCHAR*)pwszBuf, maxlen)-1;
1164 free_pool_memory(pwszBuf);
1166 } else if (p_GetCurrentDirectoryA)
1167 n = p_GetCurrentDirectoryA(maxlen, buf);
1169 if (n == 0 || n > maxlen) return NULL;
1171 if (n+1 > maxlen) return NULL;
1180 win32_fputs(const char *string, FILE *stream)
1182 /* we use WriteConsoleA / WriteConsoleA
1183 so we can be sure that unicode support works on win32.
1184 with fallback if something fails
1187 HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE);
1188 if (hOut && (hOut != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte &&
1189 p_MultiByteToWideChar && (stream == stdout)) {
1191 POOLMEM* pwszBuf = get_pool_memory(PM_MESSAGE);
1193 DWORD dwCharsWritten;
1196 dwChars = UTF8_2_wchar(&pwszBuf, string);
1198 /* try WriteConsoleW */
1199 if (WriteConsoleW (hOut, pwszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1200 free_pool_memory(pwszBuf);
1201 return dwCharsWritten;
1204 /* convert to local codepage and try WriteConsoleA */
1205 POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE);
1206 pszBuf = check_pool_memory_size(pszBuf, dwChars+1);
1208 dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR) pwszBuf,-1,pszBuf,dwChars,NULL,NULL);
1209 free_pool_memory(pwszBuf);
1211 if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) {
1212 free_pool_memory(pszBuf);
1213 return dwCharsWritten;
1217 return fputs(string, stream);
1221 win32_cgets (char* buffer, int len)
1223 /* we use console ReadConsoleA / ReadConsoleW to be able to read unicode
1224 from the win32 console and fallback if seomething fails */
1226 HANDLE hIn = GetStdHandle (STD_INPUT_HANDLE);
1227 if (hIn && (hIn != INVALID_HANDLE_VALUE) && p_WideCharToMultiByte && p_MultiByteToWideChar) {
1232 /* nt and unicode conversion */
1233 if (ReadConsoleW (hIn, wszBuf, 1024, &dwRead, NULL)) {
1235 /* null terminate at end */
1236 if (wszBuf[dwRead-1] == L'\n') {
1237 wszBuf[dwRead-1] = L'\0';
1241 if (wszBuf[dwRead-1] == L'\r') {
1242 wszBuf[dwRead-1] = L'\0';
1246 wchar_2_UTF8(buffer, wszBuf, len);
1250 /* win 9x and unicode conversion */
1251 if (ReadConsoleA (hIn, szBuf, 1024, &dwRead, NULL)) {
1253 /* null terminate at end */
1254 if (szBuf[dwRead-1] == L'\n') {
1255 szBuf[dwRead-1] = L'\0';
1259 if (szBuf[dwRead-1] == L'\r') {
1260 szBuf[dwRead-1] = L'\0';
1264 /* convert from ansii to WCHAR */
1265 p_MultiByteToWideChar(GetConsoleCP(), 0, szBuf, -1, wszBuf,1024);
1266 /* convert from WCHAR to UTF-8 */
1267 if (wchar_2_UTF8(buffer, wszBuf, len))
1273 if (fgets(buffer, len, stdin))
1280 win32_unlink(const char *filename)
1284 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1285 make_win32_path_UTF8_2_wchar(&pwszBuf, filename);
1287 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1289 /* special case if file is readonly,
1290 we retry but unset attribute before */
1291 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) {
1292 DWORD dwAttr = p_GetFileAttributesW((LPCWSTR)pwszBuf);
1293 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1294 if (p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1295 nRetCode = _wunlink((LPCWSTR) pwszBuf);
1296 /* reset to original if it didn't help */
1298 p_SetFileAttributesW((LPCWSTR)pwszBuf, dwAttr);
1302 free_pool_memory(pwszBuf);
1304 nRetCode = _unlink(filename);
1306 /* special case if file is readonly,
1307 we retry but unset attribute before */
1308 if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesA && p_GetFileAttributesA) {
1309 DWORD dwAttr = p_GetFileAttributesA(filename);
1310 if (dwAttr != INVALID_FILE_ATTRIBUTES) {
1311 if (p_SetFileAttributesA(filename, dwAttr & ~FILE_ATTRIBUTE_READONLY)) {
1312 nRetCode = _unlink(filename);
1313 /* reset to original if it didn't help */
1315 p_SetFileAttributesA(filename, dwAttr);
1324 #include "mswinver.h"
1326 char WIN_VERSION_LONG[64];
1327 char WIN_VERSION[32];
1328 char WIN_RAWVERSION[32];
1335 static winver INIT; // cause constructor to be called before main()
1340 winver::winver(void)
1342 const char *version = "";
1343 const char *platform = "";
1344 OSVERSIONINFO osvinfo;
1345 osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
1347 // Get the current OS version
1348 if (!GetVersionEx(&osvinfo)) {
1349 version = "Unknown";
1350 platform = "Unknown";
1352 const int ver = _mkversion(osvinfo.dwPlatformId,
1353 osvinfo.dwMajorVersion,
1354 osvinfo.dwMinorVersion);
1355 snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver);
1358 case MS_WINDOWS_95: (version = "Windows 95"); break;
1359 case MS_WINDOWS_98: (version = "Windows 98"); break;
1360 case MS_WINDOWS_ME: (version = "Windows ME"); break;
1361 case MS_WINDOWS_NT4:(version = "Windows NT 4.0"); platform = "NT"; break;
1362 case MS_WINDOWS_2K: (version = "Windows 2000");platform = "NT"; break;
1363 case MS_WINDOWS_XP: (version = "Windows XP");platform = "NT"; break;
1364 case MS_WINDOWS_S2003: (version = "Windows Server 2003");platform = "NT"; break;
1365 default: version = WIN_RAWVERSION; break;
1368 bstrncpy(WIN_VERSION_LONG, version, sizeof(WIN_VERSION_LONG));
1369 snprintf(WIN_VERSION, sizeof(WIN_VERSION), "%s %d.%d.%d",
1370 platform, osvinfo.dwMajorVersion, osvinfo.dwMinorVersion, osvinfo.dwBuildNumber);
1373 HANDLE h = CreateFile("G:\\foobar", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
1377 BPIPE *b = open_bpipe("ls -l", 10, "r");
1379 while (!feof(b->rfd)) {
1380 fgets(buf, sizeof(buf), b->rfd);
1386 BOOL CreateChildProcess(VOID);
1387 VOID WriteToPipe(VOID);
1388 VOID ReadFromPipe(VOID);
1389 VOID ErrorExit(LPCSTR);
1390 VOID ErrMsg(LPTSTR, BOOL);
1393 * Check for a quoted path, if an absolute path name is given and it contains
1394 * spaces it will need to be quoted. i.e. "c:/Program Files/foo/bar.exe"
1395 * CreateProcess() says the best way to ensure proper results with executables
1396 * with spaces in path or filename is to quote the string.
1399 getArgv0(const char *cmdline)
1404 for (cp = cmdline; *cp; cp++)
1409 if (!inquote && isspace(*cp))
1414 int len = cp - cmdline;
1415 char *rval = (char *)malloc(len+1);
1429 * OK, so it would seem CreateProcess only handles true executables:
1430 * .com or .exe files.
1431 * So test to see whether we're getting a .bat file and if so grab
1432 * $COMSPEC value and pass batch file to it.
1435 CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err)
1437 static const char *comspec = NULL;
1438 PROCESS_INFORMATION piProcInfo;
1439 STARTUPINFOA siStartInfo;
1440 BOOL bFuncRetn = FALSE;
1442 if (comspec == NULL) {
1443 comspec = getenv("COMSPEC");
1445 if (comspec == NULL) // should never happen
1446 return INVALID_HANDLE_VALUE;
1448 // Set up members of the PROCESS_INFORMATION structure.
1449 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
1451 // Set up members of the STARTUPINFO structure.
1453 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
1454 siStartInfo.cb = sizeof(STARTUPINFO);
1455 // setup new process to use supplied handles for stdin,stdout,stderr
1456 // if supplied handles are not used the send a copy of our STD_HANDLE
1458 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
1460 if (in != INVALID_HANDLE_VALUE)
1461 siStartInfo.hStdInput = in;
1463 siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1465 if (out != INVALID_HANDLE_VALUE)
1466 siStartInfo.hStdOutput = out;
1468 siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
1469 if (err != INVALID_HANDLE_VALUE)
1470 siStartInfo.hStdError = err;
1472 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
1473 // Create the child process.
1476 int cmdLen = strlen(cmdline) + strlen(comspec) + 16;
1478 char *cmdLine = (char *)alloca(cmdLen);
1480 bstrncpy(exeFile, comspec, sizeof(exeFile));
1481 bstrncpy(cmdLine, comspec, cmdLen);
1482 bstrncat(cmdLine, " /c ", cmdLen);
1483 bstrncat(cmdLine, cmdline, cmdLen);
1485 // try to execute program
1486 bFuncRetn = CreateProcessA(exeFile,
1487 cmdLine, // command line
1488 NULL, // process security attributes
1489 NULL, // primary thread security attributes
1490 TRUE, // handles are inherited
1491 0, // creation flags
1492 NULL, // use parent's environment
1493 NULL, // use parent's current directory
1494 &siStartInfo, // STARTUPINFO pointer
1495 &piProcInfo); // receives PROCESS_INFORMATION
1497 if (bFuncRetn == 0) {
1498 ErrorExit("CreateProcess failed\n");
1499 const char *err = errorString();
1500 d_msg(__FILE__, __LINE__, 99,
1501 "CreateProcess(%s, %s, ...)=%s\n", exeFile, cmdLine, err);
1502 LocalFree((void *)err);
1503 return INVALID_HANDLE_VALUE;
1505 // we don't need a handle on the process primary thread so we close
1507 CloseHandle(piProcInfo.hThread);
1509 return piProcInfo.hProcess;
1514 ErrorExit (LPCSTR lpszMessage)
1516 d_msg(__FILE__, __LINE__, 0, "%s", lpszMessage);
1521 typedef struct s_bpipe {
1523 time_t worker_stime;
1532 CloseIfValid(HANDLE handle)
1534 if (handle != INVALID_HANDLE_VALUE)
1535 CloseHandle(handle);
1540 open_bpipe(char *prog, int wait, const char *mode)
1542 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
1543 hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
1546 SECURITY_ATTRIBUTES saAttr;
1550 hChildStdinRd = hChildStdinWr = hChildStdinWrDup =
1551 hChildStdoutRd = hChildStdoutWr = hChildStdoutRdDup =
1552 hInputFile = INVALID_HANDLE_VALUE;
1554 BPIPE *bpipe = (BPIPE *)malloc(sizeof(BPIPE));
1555 memset((void *)bpipe, 0, sizeof(BPIPE));
1557 int mode_read = (mode[0] == 'r');
1558 int mode_write = (mode[0] == 'w' || mode[1] == 'w');
1561 // Set the bInheritHandle flag so pipe handles are inherited.
1563 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
1564 saAttr.bInheritHandle = TRUE;
1565 saAttr.lpSecurityDescriptor = NULL;
1569 // Create a pipe for the child process's STDOUT.
1570 if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
1571 ErrorExit("Stdout pipe creation failed\n");
1574 // Create noninheritable read handle and close the inheritable read
1577 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
1578 GetCurrentProcess(), &hChildStdoutRdDup , 0,
1580 DUPLICATE_SAME_ACCESS);
1582 ErrorExit("DuplicateHandle failed");
1586 CloseHandle(hChildStdoutRd);
1587 hChildStdoutRd = INVALID_HANDLE_VALUE;
1592 // Create a pipe for the child process's STDIN.
1594 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
1595 ErrorExit("Stdin pipe creation failed\n");
1599 // Duplicate the write handle to the pipe so it is not inherited.
1600 fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
1601 GetCurrentProcess(), &hChildStdinWrDup,
1603 FALSE, // not inherited
1604 DUPLICATE_SAME_ACCESS);
1606 ErrorExit("DuplicateHandle failed");
1610 CloseHandle(hChildStdinWr);
1611 hChildStdinWr = INVALID_HANDLE_VALUE;
1613 // spawn program with redirected handles as appropriate
1614 bpipe->worker_pid = (pid_t)
1615 CreateChildProcess(prog, // commandline
1616 hChildStdinRd, // stdin HANDLE
1617 hChildStdoutWr, // stdout HANDLE
1618 hChildStdoutWr); // stderr HANDLE
1620 if ((HANDLE) bpipe->worker_pid == INVALID_HANDLE_VALUE)
1624 bpipe->worker_stime = time(NULL);
1627 CloseHandle(hChildStdoutWr); // close our write side so when
1628 // process terminates we can
1630 // ugly but convert WIN32 HANDLE to FILE*
1631 int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY);
1633 bpipe->rfd = _fdopen(rfd, "r");
1637 CloseHandle(hChildStdinRd); // close our read side so as not
1638 // to interfre with child's copy
1639 // ugly but convert WIN32 HANDLE to FILE*
1640 int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY);
1642 bpipe->wfd = _fdopen(wfd, "w");
1647 bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait);
1654 CloseIfValid(hChildStdoutRd);
1655 CloseIfValid(hChildStdoutRdDup);
1656 CloseIfValid(hChildStdinWr);
1657 CloseIfValid(hChildStdinWrDup);
1659 free((void *) bpipe);
1660 errno = b_errno_win32; /* do GetLastError() for error code */
1667 kill(int pid, int signal)
1670 if (!TerminateProcess((HANDLE)pid, (UINT) signal)) {
1672 errno = b_errno_win32;
1674 CloseHandle((HANDLE)pid);
1681 close_bpipe(BPIPE *bpipe)
1684 int32_t remaining_wait = bpipe->wait;
1686 if (remaining_wait == 0) { /* wait indefinitely */
1687 remaining_wait = INT32_MAX;
1691 if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
1692 const char *err = errorString();
1693 rval = b_errno_win32;
1694 d_msg(__FILE__, __LINE__, 0,
1695 "GetExitCode error %s\n", err);
1696 LocalFree((void *)err);
1699 if (exitCode == STILL_ACTIVE) {
1700 if (remaining_wait <= 0) {
1701 rval = ETIME; /* timed out */
1704 bmicrosleep(1, 0); /* wait one second */
1706 } else if (exitCode != 0) {
1707 /* Truncate exit code as it doesn't seem to be correct */
1708 rval = (exitCode & 0xFF) | b_errno_exit;
1711 break; /* Shouldn't get here */
1715 if (bpipe->timer_id) {
1716 stop_child_timer(bpipe->timer_id);
1718 if (bpipe->rfd) fclose(bpipe->rfd);
1719 if (bpipe->wfd) fclose(bpipe->wfd);
1720 free((void *)bpipe);
1725 close_wpipe(BPIPE *bpipe)
1731 if (fclose(bpipe->wfd) != 0) {
1739 #include "findlib/find.h"
1742 utime(const char *fname, struct utimbuf *times)
1747 conv_unix_to_win32_path(fname, tmpbuf, 5000);
1749 cvt_utime_to_ftime(times->actime, acc);
1750 cvt_utime_to_ftime(times->modtime, mod);
1752 HANDLE h = INVALID_HANDLE_VALUE;
1754 if (p_CreateFileW) {
1755 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1756 make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf);
1758 h = p_CreateFileW((LPCWSTR)pwszBuf,
1759 FILE_WRITE_ATTRIBUTES,
1760 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
1763 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
1766 free_pool_memory(pwszBuf);
1767 } else if (p_CreateFileA) {
1768 h = p_CreateFileA(tmpbuf,
1769 FILE_WRITE_ATTRIBUTES,
1770 FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
1773 FILE_FLAG_BACKUP_SEMANTICS, // required for directories
1777 if (h == INVALID_HANDLE_VALUE) {
1778 const char *err = errorString();
1779 d_msg(__FILE__, __LINE__, 99,
1780 "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err);
1781 LocalFree((void *)err);
1782 errno = b_errno_win32;
1786 int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1;
1789 errno = b_errno_win32;
1794 #if USE_WIN32_COMPAT_IO
1797 open(const char *file, int flags, int mode)
1800 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1801 make_win32_path_UTF8_2_wchar(&pwszBuf, file);
1803 int nRet = p_wopen((LPCWSTR) pwszBuf, flags|_O_BINARY, mode);
1804 free_pool_memory(pwszBuf);
1809 return _open(file, flags|_O_BINARY, mode);
1813 * Note, this works only for a file. If you want
1814 * to close a socket, use closesocket().
1815 * Bacula has been modified in src/lib/bnet.c
1816 * to use closesocket().
1825 #ifndef HAVE_WXCONSOLE
1827 read(int fd, void *buf, ssize_t len)
1829 return _read(fd, buf, (size_t)len);
1833 write(int fd, const void *buf, ssize_t len)
1835 return _write(fd, buf, (size_t)len);
1841 lseek(int fd, off_t offset, int whence)
1843 return (off_t)_lseeki64(fd, offset, whence);
1847 dup2(int fd1, int fd2)
1849 return _dup2(fd1, fd2);
1854 open(const char *file, int flags, int mode)
1857 DWORD shareMode = 0;
1860 HANDLE foo = INVALID_HANDLE_VALUE;
1861 const char *remap = file;
1863 if (flags & O_WRONLY) access = GENERIC_WRITE;
1864 else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE;
1865 else access = GENERIC_READ;
1867 if (flags & O_CREAT) create = CREATE_NEW;
1868 else create = OPEN_EXISTING;
1870 if (flags & O_TRUNC) create = TRUNCATE_EXISTING;
1872 if (!(flags & O_EXCL))
1873 shareMode = FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE;
1875 if (flags & O_APPEND) {
1876 printf("open...APPEND not implemented yet.");
1880 if (p_CreateFileW) {
1881 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
1882 make_win32_path_UTF8_2_wchar(pwszBuf, file);
1884 foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL);
1885 free_pool_memory(pwszBuf);
1886 } else if (p_CreateFileA)
1887 foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL);
1889 if (INVALID_HANDLE_VALUE == foo) {
1890 errno = b_errno_win32;
1901 if (!CloseHandle((HANDLE)fd)) {
1902 errno = b_errno_win32;
1910 write(int fd, const void *data, ssize_t len)
1914 status = WriteFile((HANDLE)fd, data, len, &bwrite, NULL);
1915 if (status) return bwrite;
1916 errno = b_errno_win32;
1922 read(int fd, void *data, ssize_t len)
1927 status = ReadFile((HANDLE)fd, data, len, &bread, NULL);
1928 if (status) return bread;
1929 errno = b_errno_win32;
1934 lseek(int fd, off_t offset, int whence)
1940 method = FILE_BEGIN;
1943 method = FILE_CURRENT;
1953 if ((val=SetFilePointer((HANDLE)fd, (DWORD)offset, NULL, method)) == INVALID_SET_FILE_POINTER) {
1954 errno = b_errno_win32;
1957 /* ***FIXME*** I doubt this works right */
1974 /* syslog function, added by Nicolas Boichat */