X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fwin32%2Fcompat%2Fcompat.cpp;h=e93ce9c45b39d3beb4d2fc3f13f724f1892c5b7e;hb=a33d3671776f81795bb6bd649572d845a4bcea10;hp=0366cfe3ac9113b2cbeb202d203816d1781dedc3;hpb=060432347dd31b3bfee1a564d8e885746f3cc7f1;p=bacula%2Fbacula diff --git a/bacula/src/win32/compat/compat.cpp b/bacula/src/win32/compat/compat.cpp index 0366cfe3ac..e93ce9c45b 100644 --- a/bacula/src/win32/compat/compat.cpp +++ b/bacula/src/win32/compat/compat.cpp @@ -1,3 +1,30 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2004-2008 Free Software Foundation Europe e.V. + + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ // -*- Mode: C++ -*- // compat.cpp -- compatibilty layer to make bacula-fd run // natively under windows @@ -5,25 +32,15 @@ // Copyright transferred from Raider Solutions, Inc to // Kern Sibbald and John Walker by express permission. // -// Copyright (C) 2004-2006 Kern Sibbald -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// version 2 as amended with additional clauses defined in the -// file LICENSE in the main source directory. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// the file LICENSE for additional details. -// // Author : Christopher S. Hull // Created On : Sat Jan 31 15:55:00 2004 // $Id$ + #include "bacula.h" #include "compat.h" #include "jcr.h" +#include "findlib/find.h" #define b_errno_win32 (1<<29) @@ -34,14 +51,18 @@ conversion is called 3 times (lstat, attribs, open), by using the cache this is reduced to 1 time */ -static POOLMEM *g_pWin32ConvUTF8Cache = get_pool_memory (PM_FNAME); -static POOLMEM *g_pWin32ConvUCS2Cache = get_pool_memory (PM_FNAME); +static POOLMEM *g_pWin32ConvUTF8Cache = get_pool_memory(PM_FNAME); +static POOLMEM *g_pWin32ConvUCS2Cache = get_pool_memory(PM_FNAME); static DWORD g_dwWin32ConvUTF8strlen = 0; static pthread_mutex_t Win32Convmutex = PTHREAD_MUTEX_INITIALIZER; static t_pVSSPathConvert g_pVSSPathConvert; static t_pVSSPathConvertW g_pVSSPathConvertW; +/* Forward referenced functions */ +static const char *errorString(void); + + void SetVSSPathConvert(t_pVSSPathConvert pPathConvert, t_pVSSPathConvertW pPathConvertW) { g_pVSSPathConvert = pPathConvert; @@ -90,10 +111,10 @@ void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize) Dmsg0(100, "Enter convert_unix_to_win32_path\n"); - if ((name[0] == '/' || name[0] == '\\') && - (name[1] == '/' || name[1] == '\\') && - (name[2] == '.') && - (name[3] == '/' || name[3] == '\\')) { + if (IsPathSeparator(name[0]) && + IsPathSeparator(name[1]) && + name[2] == '.' && + IsPathSeparator(name[3])) { *win32_name++ = '\\'; *win32_name++ = '\\'; @@ -117,7 +138,7 @@ void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize) } if (*name == '/') { *win32_name++ = '\\'; /* convert char */ - /* If Win32 separated that is "quoted", remove quote */ + /* If Win32 separator that is "quoted", remove quote */ } else if (*name == '\\' && name[1] == '\\') { *win32_name++ = '\\'; name++; /* skip first \ */ @@ -193,13 +214,13 @@ make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/) return pszUCSPath; } - POOLMEM *pwszBuf = get_pool_memory(PM_FNAME); - POOLMEM *pwszCurDirBuf = get_pool_memory(PM_FNAME); + wchar_t *pwszBuf = (wchar_t *)get_pool_memory(PM_FNAME); + wchar_t *pwszCurDirBuf = (wchar_t *)get_pool_memory(PM_FNAME); DWORD dwCurDirPathSize = 0; /* get buffer with enough size (name+max 6. wchars+1 null terminator */ DWORD dwBufCharsNeeded = (wcslen(name)+7); - pwszBuf = check_pool_memory_size(pwszBuf, dwBufCharsNeeded*sizeof(wchar_t)); + pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t)); /* add \\?\ to support 32K long filepaths it is important to make absolute paths, so we add drive and @@ -210,23 +231,25 @@ make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/) BOOL bAddPrefix = TRUE; /* does path begin with drive? if yes, it is absolute */ - if (wcslen(name) >= 3 && (iswalpha (*name) && *(name+1) == ':' - && (*(name+2) == '\\' || *(name+2) == '/'))) { + if (iswalpha(name[0]) && name[1] == ':' && IsPathSeparator(name[2])) { bAddDrive = FALSE; bAddCurrentPath = FALSE; } /* is path absolute? */ - if (*name == '/' || *name == '\\') + if (IsPathSeparator(name[0])) bAddCurrentPath = FALSE; /* is path relative to itself?, if yes, skip ./ */ - if (wcslen(name) > 2 && ((wcsncmp(name, L"./", 2) == 0) || (wcsncmp(name, L".\\", 2) == 0))) { + if (name[0] == '.' && IsPathSeparator(name[1])) { name += 2; } - /* is path of form '//./'? */ - if (wcslen(name) > 3 && ((wcsncmp(name, L"//./", 4) == 0) || (wcsncmp(name, L"\\\\.\\", 4) == 0))) { + /* is path of form '//./'? */ + if (IsPathSeparator(name[0]) && + IsPathSeparator(name[1]) && + name[2] == '.' && + IsPathSeparator(name[3])) { bAddDrive = FALSE; bAddCurrentPath = FALSE; bAddPrefix = FALSE; @@ -240,7 +263,7 @@ make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/) /* add 4 bytes header */ if (bAddPrefix) { nParseOffset = 4; - wcscpy((wchar_t *)pwszBuf, L"\\\\?\\"); + wcscpy(pwszBuf, L"\\\\?\\"); } /* get current path if needed */ @@ -248,8 +271,8 @@ make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/) dwCurDirPathSize = p_GetCurrentDirectoryW(0, NULL); if (dwCurDirPathSize > 0) { /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */ - pwszCurDirBuf = check_pool_memory_size(pwszCurDirBuf, (dwCurDirPathSize+1)*sizeof(wchar_t)); - p_GetCurrentDirectoryW(dwCurDirPathSize,(wchar_t *)pwszCurDirBuf); + pwszCurDirBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszCurDirBuf, (dwCurDirPathSize+1)*sizeof(wchar_t)); + p_GetCurrentDirectoryW(dwCurDirPathSize, pwszCurDirBuf); } else { /* we have no info for doing so */ bAddDrive = FALSE; @@ -262,17 +285,21 @@ make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/) if (bAddDrive && !bAddCurrentPath) { wchar_t szDrive[3]; - if (dwCurDirPathSize > 3 && wcsncmp((LPCWSTR)pwszCurDirBuf, L"\\\\?\\", 4) == 0) { + if (IsPathSeparator(pwszCurDirBuf[0]) && + IsPathSeparator(pwszCurDirBuf[1]) && + pwszCurDirBuf[2] == '?' && + IsPathSeparator(pwszCurDirBuf[3])) { /* copy drive character */ - wcsncpy((wchar_t *)szDrive, (LPCWSTR)pwszCurDirBuf+4, 2); + szDrive[0] = pwszCurDirBuf[4]; } else { /* copy drive character */ - wcsncpy((wchar_t *)szDrive, (LPCWSTR)pwszCurDirBuf, 2); + szDrive[0] = pwszCurDirBuf[0]; } + szDrive[1] = ':'; szDrive[2] = 0; - - wcscat((wchar_t *)pwszBuf, szDrive); + + wcscat(pwszBuf, szDrive); nParseOffset +=2; } @@ -280,49 +307,51 @@ make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/) if (bAddCurrentPath) { /* the 1 add. character is for the eventually added backslash */ dwBufCharsNeeded += dwCurDirPathSize+1; - pwszBuf = check_pool_memory_size(pwszBuf, dwBufCharsNeeded*sizeof(wchar_t)); + pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, dwBufCharsNeeded*sizeof(wchar_t)); /* get directory into own buffer as it may either return c:\... or \\?\C:\.... */ - if (dwCurDirPathSize > 3 && wcsncmp((LPCWSTR)pwszCurDirBuf, L"\\\\?\\", 4) == 0) { + if (IsPathSeparator(pwszCurDirBuf[0]) && + IsPathSeparator(pwszCurDirBuf[1]) && + pwszCurDirBuf[2] == '?' && + IsPathSeparator(pwszCurDirBuf[3])) { /* copy complete string */ - wcscpy((wchar_t *)pwszBuf, (LPCWSTR)pwszCurDirBuf); + wcscpy(pwszBuf, pwszCurDirBuf); } else { /* append path */ - wcscat((wchar_t *)pwszBuf, (LPCWSTR)pwszCurDirBuf); + wcscat(pwszBuf, pwszCurDirBuf); } nParseOffset = wcslen((LPCWSTR) pwszBuf); /* check if path ends with backslash, if not, add one */ - if (*((wchar_t *)pwszBuf+nParseOffset-1) != L'\\') { - wcscat((wchar_t *)pwszBuf, L"\\"); + if (!IsPathSeparator(pwszBuf[nParseOffset-1])) { + wcscat(pwszBuf, L"\\"); nParseOffset++; - } + } } - - wchar_t *win32_name = (wchar_t *)pwszBuf+nParseOffset; + wchar_t *win32_name = &pwszBuf[nParseOffset]; + wchar_t *name_start = name; while (*name) { - /* Check for Unix separator and convert to Win32 */ - if (*name == '/') { + /* Check for Unix separator and convert to Win32, eliminating + * duplicate separators. + */ + if (IsPathSeparator(*name)) { *win32_name++ = '\\'; /* convert char */ - /* If Win32 separated that is "quoted", remove quote */ -/* HELPME (Thorsten Engel): I don't understand the following part - * and it removes a backslash from e.g. "\\.\c:" which I need for - * RAW device access. So I took it out. - */ -#ifdef needed - } else if (*name == '\\' && name[1] == '\\') { - *win32_name++ = '\\'; - name++; /* skip first \ */ -#endif + + /* Eliminate consecutive slashes, but not at the start so that + * \\.\ still works. + */ + if (name_start != name && IsPathSeparator(name[1])) { + name++; + } } else { *win32_name++ = *name; /* copy character */ } name++; } - + /* null terminate string */ *win32_name = 0; @@ -333,24 +362,26 @@ make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/) */ if (g_pVSSPathConvertW != NULL) { /* is output buffer large enough? */ - pwszBuf = check_pool_memory_size(pwszBuf, (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t)); + pwszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pwszBuf, + (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t)); /* create temp. buffer */ - POOLMEM* pszBuf = get_pool_memory(PM_FNAME); - pszBuf = check_pool_memory_size(pszBuf, (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t)); + wchar_t *pszBuf = (wchar_t *)get_pool_memory(PM_FNAME); + pszBuf = (wchar_t *)check_pool_memory_size((POOLMEM *)pszBuf, + (dwBufCharsNeeded+MAX_PATH)*sizeof(wchar_t)); if (bAddPrefix) nParseOffset = 4; else nParseOffset = 0; - wcsncpy((wchar_t *)pszBuf, (wchar_t *)pwszBuf+nParseOffset, wcslen((wchar_t *)pwszBuf)+1-nParseOffset); - g_pVSSPathConvertW((wchar_t *)pszBuf, (wchar_t *)pwszBuf, dwBufCharsNeeded+MAX_PATH); - free_pool_memory(pszBuf); + wcsncpy(pszBuf, &pwszBuf[nParseOffset], wcslen(pwszBuf)+1-nParseOffset); + g_pVSSPathConvertW(pszBuf, pwszBuf, dwBufCharsNeeded+MAX_PATH); + free_pool_memory((POOLMEM *)pszBuf); } free_pool_memory(pszUCSPath); - free_pool_memory(pwszCurDirBuf); + free_pool_memory((POOLMEM *)pwszCurDirBuf); Dmsg1(100, "Leave wchar_win32_path=%s\n", pwszBuf); - return pwszBuf; + return (POOLMEM *)pwszBuf; } int @@ -460,12 +491,44 @@ int umask(int) } #endif -int fcntl(int fd, int cmd) +#ifndef LOAD_WITH_ALTERED_SEARCH_PATH +#define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008 +#endif + +void *dlopen(const char *file, int mode) { - return 0; + void *handle; + + handle = LoadLibraryEx(file, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + return handle; +} + +void *dlsym(void *handle, const char *name) +{ + void *symaddr; + symaddr = (void *)GetProcAddress((HMODULE)handle, name); + return symaddr; +} + +int dlclose(void *handle) +{ + if (handle && !FreeLibrary((HMODULE)handle)) { + errno = b_errno_win32; + return 1; /* failed */ + } + return 0; /* OK */ +} + +char *dlerror(void) +{ + static char buf[200]; + const char *err = errorString(); + bstrncpy(buf, (char *)err, sizeof(buf)); + LocalFree((void *)err); + return buf; } -int chmod(const char *, mode_t) +int fcntl(int fd, int cmd) { return 0; } @@ -522,8 +585,7 @@ cvt_ftime_to_utime(const FILETIME &time) return (time_t) (mstime & 0xffffffff); } -static const char * -errorString(void) +static const char *errorString(void) { LPVOID lpMsgBuf; @@ -558,172 +620,221 @@ statDir(const char *file, struct stat *sb) WIN32_FIND_DATAA info_a; // window's file info // cache some common vars to make code more transparent - DWORD* pdwFileAttributes; - DWORD* pnFileSizeHigh; - DWORD* pnFileSizeLow; - FILETIME* pftLastAccessTime; - FILETIME* pftLastWriteTime; - FILETIME* pftCreationTime; + DWORD *pdwFileAttributes; + DWORD *pnFileSizeHigh; + DWORD *pnFileSizeLow; + DWORD *pdwReserved0; + FILETIME *pftLastAccessTime; + FILETIME *pftLastWriteTime; + FILETIME *pftCreationTime; + /* + * Oh, cool, another exception: Microsoft doesn't let us do + * FindFile operations on a Drive, so simply fake root attibutes. + */ if (file[1] == ':' && file[2] == 0) { - Dmsg1(99, "faking ROOT attrs(%s).\n", file); - sb->st_mode = S_IFDIR; - sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE; - time(&sb->st_ctime); - time(&sb->st_mtime); - time(&sb->st_atime); - return 0; + time_t now = time(NULL); + Dmsg1(99, "faking ROOT attrs(%s).\n", file); + sb->st_mode = S_IFDIR; + sb->st_mode |= S_IREAD|S_IEXEC|S_IWRITE; + sb->st_ctime = now; + sb->st_mtime = now; + sb->st_atime = now; + sb->st_rdev = 0; + return 0; } HANDLE h = INVALID_HANDLE_VALUE; - // use unicode or ascii + // use unicode if (p_FindFirstFileW) { POOLMEM* pwszBuf = get_pool_memory (PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, file); - h = p_FindFirstFileW((LPCWSTR) pwszBuf, &info_w); + Dmsg1(100, "FindFirstFileW=%s\n", file); + h = p_FindFirstFileW((LPCWSTR)pwszBuf, &info_w); free_pool_memory(pwszBuf); pdwFileAttributes = &info_w.dwFileAttributes; + pdwReserved0 = &info_w.dwReserved0; pnFileSizeHigh = &info_w.nFileSizeHigh; pnFileSizeLow = &info_w.nFileSizeLow; pftLastAccessTime = &info_w.ftLastAccessTime; pftLastWriteTime = &info_w.ftLastWriteTime; pftCreationTime = &info_w.ftCreationTime; - } - else if (p_FindFirstFileA) { + + // use ASCII + } else if (p_FindFirstFileA) { + Dmsg1(100, "FindFirstFileA=%s\n", file); h = p_FindFirstFileA(file, &info_a); pdwFileAttributes = &info_a.dwFileAttributes; + pdwReserved0 = &info_a.dwReserved0; pnFileSizeHigh = &info_a.nFileSizeHigh; pnFileSizeLow = &info_a.nFileSizeLow; pftLastAccessTime = &info_a.ftLastAccessTime; pftLastWriteTime = &info_a.ftLastWriteTime; pftCreationTime = &info_a.ftCreationTime; + } else { + Dmsg0(100, "No findFirstFile A or W found\n"); } - if (h == INVALID_HANDLE_VALUE) { - const char *err = errorString(); - Dmsg2(99, "FindFirstFile(%s):%s\n", file, err); - LocalFree((void *)err); - errno = b_errno_win32; - return -1; - } + if (h == INVALID_HANDLE_VALUE) { + const char *err = errorString(); + /* + * Note, in creating leading paths, it is normal that + * the file does not exist. + */ + Dmsg2(2099, "FindFirstFile(%s):%s\n", file, err); + LocalFree((void *)err); + errno = b_errno_win32; + return -1; + } else { + FindClose(h); + } - sb->st_mode = 0777; /* start with everything */ - if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY) - sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH); - if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM) - sb->st_mode &= ~S_IRWXO; /* remove everything for other */ - if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN) - sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */ - sb->st_mode |= S_IFDIR; - - sb->st_size = *pnFileSizeHigh; - sb->st_size <<= 32; - sb->st_size |= *pnFileSizeLow; - sb->st_blksize = 4096; - sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096; - - sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime); - sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime); - sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime); - FindClose(h); + sb->st_mode = 0777; /* start with everything */ + if (*pdwFileAttributes & FILE_ATTRIBUTE_READONLY) + sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH); + if (*pdwFileAttributes & FILE_ATTRIBUTE_SYSTEM) + sb->st_mode &= ~S_IRWXO; /* remove everything for other */ + if (*pdwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */ + sb->st_mode |= S_IFDIR; - return 0; + /* + * Store reparse/mount point info in st_rdev. Note a + * Win32 reparse point (junction point) is like a link + * though it can have many properties (directory link, + * soft link, hard link, HSM, ... + * A mount point is a reparse point where another volume + * is mounted, so it is like a Unix mount point (change of + * filesystem). + */ + if (*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + if (*pdwReserved0 & IO_REPARSE_TAG_MOUNT_POINT) { + sb->st_rdev = WIN32_MOUNT_POINT; /* mount point */ + } else { + sb->st_rdev = WIN32_REPARSE_POINT; /* reparse point */ + } + } + Dmsg2(100, "st_rdev=%d file=%s\n", sb->st_rdev, file); + sb->st_size = *pnFileSizeHigh; + sb->st_size <<= 32; + sb->st_size |= *pnFileSizeLow; + sb->st_blksize = 4096; + sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096; + + sb->st_atime = cvt_ftime_to_utime(*pftLastAccessTime); + sb->st_mtime = cvt_ftime_to_utime(*pftLastWriteTime); + sb->st_ctime = cvt_ftime_to_utime(*pftCreationTime); + + return 0; } int -fstat(int fd, struct stat *sb) +fstat(intptr_t fd, struct stat *sb) { - BY_HANDLE_FILE_INFORMATION info; - char tmpbuf[1024]; + BY_HANDLE_FILE_INFORMATION info; - if (!GetFileInformationByHandle((HANDLE)fd, &info)) { - const char *err = errorString(); - Dmsg2(99, "GetfileInformationByHandle(%s): %s\n", tmpbuf, err); - LocalFree((void *)err); - errno = b_errno_win32; - return -1; - } + if (!GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) { + const char *err = errorString(); + Dmsg1(2099, "GetfileInformationByHandle: %s\n", err); + LocalFree((void *)err); + errno = b_errno_win32; + return -1; + } - sb->st_dev = info.dwVolumeSerialNumber; - sb->st_ino = info.nFileIndexHigh; - sb->st_ino <<= 32; - sb->st_ino |= info.nFileIndexLow; - sb->st_nlink = (short)info.nNumberOfLinks; - if (sb->st_nlink > 1) { - Dmsg1(99, "st_nlink=%d\n", sb->st_nlink); - } + sb->st_dev = info.dwVolumeSerialNumber; + sb->st_ino = info.nFileIndexHigh; + sb->st_ino <<= 32; + sb->st_ino |= info.nFileIndexLow; + sb->st_nlink = (short)info.nNumberOfLinks; + if (sb->st_nlink > 1) { + Dmsg1(99, "st_nlink=%d\n", sb->st_nlink); + } - sb->st_mode = 0777; /* start with everything */ - if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) - sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH); - if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) - sb->st_mode &= ~S_IRWXO; /* remove everything for other */ - if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) - sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */ - sb->st_mode |= S_IFREG; - - sb->st_size = info.nFileSizeHigh; - sb->st_size <<= 32; - sb->st_size |= info.nFileSizeLow; - sb->st_blksize = 4096; - sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096; - sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime); - sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime); - sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime); + sb->st_mode = 0777; /* start with everything */ + if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + sb->st_mode &= ~(S_IRUSR|S_IRGRP|S_IROTH); + if (info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) + sb->st_mode &= ~S_IRWXO; /* remove everything for other */ + if (info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */ + sb->st_mode |= S_IFREG; + + /* Use st_rdev to store reparse attribute */ + if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + sb->st_rdev = WIN32_REPARSE_POINT; + } + Dmsg3(100, "st_rdev=%d sizino=%d ino=%lld\n", sb->st_rdev, sizeof(sb->st_ino), + (long long)sb->st_ino); - return 0; + sb->st_size = info.nFileSizeHigh; + sb->st_size <<= 32; + sb->st_size |= info.nFileSizeLow; + sb->st_blksize = 4096; + sb->st_blocks = (uint32_t)(sb->st_size + 4095)/4096; + sb->st_atime = cvt_ftime_to_utime(info.ftLastAccessTime); + sb->st_mtime = cvt_ftime_to_utime(info.ftLastWriteTime); + sb->st_ctime = cvt_ftime_to_utime(info.ftCreationTime); + + return 0; } static int stat2(const char *file, struct stat *sb) { - HANDLE h; - int rval = 0; - char tmpbuf[1024]; - conv_unix_to_win32_path(file, tmpbuf, 1024); + HANDLE h = INVALID_HANDLE_VALUE; + int rval = 0; + char tmpbuf[5000]; + conv_unix_to_win32_path(file, tmpbuf, 5000); - DWORD attr = (DWORD)-1; + DWORD attr = (DWORD)-1; - if (p_GetFileAttributesW) { + if (p_GetFileAttributesW) { POOLMEM* pwszBuf = get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf); attr = p_GetFileAttributesW((LPCWSTR) pwszBuf); + if (p_CreateFileW) { + h = CreateFileW((LPCWSTR)pwszBuf, GENERIC_READ, + FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + } free_pool_memory(pwszBuf); - } else if (p_GetFileAttributesA) { - attr = p_GetFileAttributesA(tmpbuf); - } - - if (attr == (DWORD)-1) { - const char *err = errorString(); - Dmsg2(99, "GetFileAttributes(%s): %s\n", tmpbuf, err); - LocalFree((void *)err); - errno = b_errno_win32; - return -1; - } + } else if (p_GetFileAttributesA) { + attr = p_GetFileAttributesA(tmpbuf); + h = CreateFileA(tmpbuf, GENERIC_READ, + FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + } - if (attr & FILE_ATTRIBUTE_DIRECTORY) - return statDir(tmpbuf, sb); + if (attr == (DWORD)-1) { + const char *err = errorString(); + Dmsg2(2099, "GetFileAttributes(%s): %s\n", tmpbuf, err); + LocalFree((void *)err); + if (h != INVALID_HANDLE_VALUE) { + CloseHandle(h); + } + errno = b_errno_win32; + return -1; + } - h = CreateFileA(tmpbuf, GENERIC_READ, - FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (h == INVALID_HANDLE_VALUE) { + const char *err = errorString(); + Dmsg2(2099, "Cannot open file for stat (%s):%s\n", tmpbuf, err); + LocalFree((void *)err); + errno = b_errno_win32; + return -1; + } - if (h == INVALID_HANDLE_VALUE) { - const char *err = errorString(); - Dmsg2(99, "Cannot open file for stat (%s):%s\n", tmpbuf, err); - LocalFree((void *)err); - errno = b_errno_win32; - return -1; - } + rval = fstat((intptr_t)h, sb); + CloseHandle(h); - rval = fstat((int)h, sb); - CloseHandle(h); - - return rval; + if (attr & FILE_ATTRIBUTE_DIRECTORY && + file[1] == ':' && file[2] != 0) { + rval = statDir(file, sb); + } + return rval; } int @@ -732,27 +843,20 @@ stat(const char *file, struct stat *sb) WIN32_FILE_ATTRIBUTE_DATA data; errno = 0; - memset(sb, 0, sizeof(*sb)); - /* why not allow win 95 to use p_GetFileAttributesExA ? - * this function allows _some_ open files to be stat'ed - * if (g_platform_id == VER_PLATFORM_WIN32_WINDOWS) { - * return stat2(file, sb); - * } - */ - if (p_GetFileAttributesExW) { /* dynamically allocate enough space for UCS2 filename */ - POOLMEM* pwszBuf = get_pool_memory (PM_FNAME); + POOLMEM *pwszBuf = get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, file); - BOOL b = p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, &data); + BOOL b = p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, &data); free_pool_memory(pwszBuf); if (!b) { return stat2(file, sb); } + } else if (p_GetFileAttributesExA) { if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) { return stat2(file, sb); @@ -777,6 +881,9 @@ stat(const char *file, struct stat *sb) sb->st_mode |= S_IFREG; } + /* Use st_rdev to store reparse attribute */ + sb->st_rdev = (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0; + sb->st_nlink = 1; sb->st_size = data.nFileSizeHigh; sb->st_size <<= 32; @@ -786,6 +893,46 @@ stat(const char *file, struct stat *sb) sb->st_atime = cvt_ftime_to_utime(data.ftLastAccessTime); sb->st_mtime = cvt_ftime_to_utime(data.ftLastWriteTime); sb->st_ctime = cvt_ftime_to_utime(data.ftCreationTime); + + /* + * If we are not at the root, then to distinguish a reparse + * point from a mount point, we must call FindFirstFile() to + * get the WIN32_FIND_DATA, which has the bit that indicates + * that this directory is a mount point -- aren't Win32 APIs + * wonderful? (sarcasm). The code exists in the statDir + * subroutine. + */ + if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && + file[1] == ':' && file[2] != 0) { + statDir(file, sb); + } + Dmsg3(100, "sizino=%d ino=%lld file=%s\n", sizeof(sb->st_ino), + (long long)sb->st_ino, file); + return 0; +} + +/* + * We write our own ftruncate because the one in the + * Microsoft library mrcrt.dll does not truncate + * files greater than 2GB. + * KES - May 2007 + */ +int win32_ftruncate(int fd, int64_t length) +{ + /* Set point we want to truncate file */ + __int64 pos = _lseeki64(fd, (__int64)length, SEEK_SET); + + if (pos != (__int64)length) { + errno = EACCES; /* truncation failed, get out */ + return -1; + } + + /* Truncate file */ + if (SetEndOfFile((HANDLE)_get_osfhandle(fd)) == 0) { + errno = b_errno_win32; + return -1; + } + errno = 0; return 0; } @@ -916,6 +1063,7 @@ gettimeofday(struct timeval *tv, struct timezone *) { SYSTEMTIME now; FILETIME tmp; + GetSystemTime(&now); if (tv == NULL) { @@ -932,8 +1080,8 @@ gettimeofday(struct timeval *tv, struct timezone *) _100nsec |= tmp.dwLowDateTime; _100nsec -= WIN32_FILETIME_ADJUST; - tv->tv_sec =(long) (_100nsec / 10000000); - tv->tv_usec = (long) ((_100nsec % 10000000)/10); + tv->tv_sec = (long)(_100nsec / 10000000); + tv->tv_usec = (long)((_100nsec % 10000000)/10); return 0; } @@ -1216,6 +1364,73 @@ WSA_Init(void) return 0; } +int win32_chmod(const char *path, mode_t mode) +{ + DWORD attr = (DWORD)-1; + + Dmsg1(100, "Enter win32_chmod. path=%s\n", path); + if (p_GetFileAttributesW) { + POOLMEM* pwszBuf = get_pool_memory(PM_FNAME); + make_win32_path_UTF8_2_wchar(&pwszBuf, path); + + attr = p_GetFileAttributesW((LPCWSTR) pwszBuf); + if (attr != INVALID_FILE_ATTRIBUTES) { + /* Use Bacula mappings define in stat() above */ + if (mode & (S_IRUSR|S_IRGRP|S_IROTH)) { + attr |= FILE_ATTRIBUTE_READONLY; + } else { + attr &= ~FILE_ATTRIBUTE_READONLY; + } + if (mode & S_ISVTX) { + attr |= FILE_ATTRIBUTE_HIDDEN; + } else { + attr &= ~FILE_ATTRIBUTE_HIDDEN; + } + if (mode & S_IRWXO) { + attr |= FILE_ATTRIBUTE_SYSTEM; + } else { + attr &= ~FILE_ATTRIBUTE_SYSTEM; + } + attr = p_SetFileAttributesW((LPCWSTR)pwszBuf, attr); + } + free_pool_memory(pwszBuf); + Dmsg0(100, "Leave win32_chmod. AttributesW\n"); + } else if (p_GetFileAttributesA) { + if (mode & (S_IRUSR|S_IRGRP|S_IROTH)) { + attr |= FILE_ATTRIBUTE_READONLY; + } else { + attr &= ~FILE_ATTRIBUTE_READONLY; + } + if (mode & S_ISVTX) { + attr |= FILE_ATTRIBUTE_HIDDEN; + } else { + attr &= ~FILE_ATTRIBUTE_HIDDEN; + } + if (mode & S_IRWXO) { + attr |= FILE_ATTRIBUTE_SYSTEM; + } else { + attr &= ~FILE_ATTRIBUTE_SYSTEM; + } + attr = p_GetFileAttributesA(path); + if (attr != INVALID_FILE_ATTRIBUTES) { + attr = p_SetFileAttributesA(path, attr); + } + Dmsg0(100, "Leave win32_chmod did AttributesA\n"); + } else { + Dmsg0(100, "Leave win32_chmod did nothing\n"); + } + + + if (attr == (DWORD)-1) { + const char *err = errorString(); + Dmsg2(99, "Get/SetFileAttributes(%s): %s\n", path, err); + LocalFree((void *)err); + errno = b_errno_win32; + return -1; + } + return 0; +} + int win32_chdir(const char *dir) @@ -1232,14 +1447,14 @@ win32_chdir(const char *dir) errno = b_errno_win32; return -1; } - } - else if (p_SetCurrentDirectoryA) { + } else if (p_SetCurrentDirectoryA) { if (0 == p_SetCurrentDirectoryA(dir)) { errno = b_errno_win32; return -1; } + } else { + return -1; } - else return -1; return 0; } @@ -1247,15 +1462,18 @@ win32_chdir(const char *dir) int win32_mkdir(const char *dir) { + Dmsg1(100, "enter win32_mkdir. dir=%s\n", dir); if (p_wmkdir){ POOLMEM* pwszBuf = get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, dir); int n = p_wmkdir((LPCWSTR)pwszBuf); free_pool_memory(pwszBuf); + Dmsg0(100, "Leave win32_mkdir did wmkdir\n"); return n; } + Dmsg0(100, "Leave win32_mkdir did _mkdir\n"); return _mkdir(dir); } @@ -1316,15 +1534,16 @@ win32_fputs(const char *string, FILE *stream) POOLMEM* pszBuf = get_pool_memory(PM_MESSAGE); pszBuf = check_pool_memory_size(pszBuf, dwChars+1); - dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR) pwszBuf,-1,pszBuf,dwChars,NULL,NULL); + dwChars = p_WideCharToMultiByte(GetConsoleOutputCP(),0,(LPCWSTR)pwszBuf,-1,pszBuf,dwChars,NULL,NULL); free_pool_memory(pwszBuf); if (WriteConsoleA (hOut, pszBuf, dwChars-1, &dwCharsWritten, NULL)) { free_pool_memory(pszBuf); return dwCharsWritten; } + free_pool_memory(pszBuf); } - + /* Fall back */ return fputs(string, stream); } @@ -1397,8 +1616,10 @@ win32_unlink(const char *filename) nRetCode = _wunlink((LPCWSTR) pwszBuf); - /* special case if file is readonly, - we retry but unset attribute before */ + /* + * special case if file is readonly, + * we retry but unset attribute before + */ if (nRetCode == -1 && errno == EACCES && p_SetFileAttributesW && p_GetFileAttributesW) { DWORD dwAttr = p_GetFileAttributesW((LPCWSTR)pwszBuf); if (dwAttr != INVALID_FILE_ATTRIBUTES) { @@ -1462,7 +1683,7 @@ winver::winver(void) osvinfo.dwMajorVersion, osvinfo.dwMinorVersion); snprintf(WIN_RAWVERSION, sizeof(WIN_RAWVERSION), "Windows %#08x", ver); - switch (ver) + switch (ver) { case MS_WINDOWS_95: (version = "Windows 95"); break; case MS_WINDOWS_98: (version = "Windows 98"); break; @@ -1558,7 +1779,6 @@ GetApplicationName(const char *cmdline, char **pexe, const char **pargs) const char *current = cmdline; - bool bHasBlanks = false; bool bQuoted = false; /* Skip initial whitespace */ @@ -1579,6 +1799,7 @@ GetApplicationName(const char *cmdline, char **pexe, const char **pargs) } *pargs = NULL; + *pexe = NULL; /* * Scan command line looking for path separators (/ and \\) and the @@ -1588,11 +1809,9 @@ GetApplicationName(const char *cmdline, char **pexe, const char **pargs) for ( ; *current != '\0'; current++) { - if (*current == ' ') { - bHasBlanks = true; - } else if (*current == '.') { + if (*current == '.') { pExtension = current; - } else if ((*current == '\\' || *current == '/') && current[1] != '\0') { + } else if (IsPathSeparator(*current) && current[1] != '\0') { pBasename = ¤t[1]; pExtension = NULL; } @@ -1631,88 +1850,173 @@ GetApplicationName(const char *cmdline, char **pexe, const char **pargs) pExeEnd = current; } - if (!bQuoted) { - bHasBlanks = false; + if (*pargs == NULL) + { + *pargs = current; } bool bHasPathSeparators = pExeStart != pBasename; - /* We have the pointers to all the useful parts of the name */ + /* We have pointers to all the useful parts of the name */ /* Default extensions in the order cmd.exe uses to search */ static const char ExtensionList[][5] = { ".com", ".exe", ".bat", ".cmd" }; DWORD dwBasePathLength = pExeEnd - pExeStart; - if (bHasBlanks) { - DWORD dwShortNameLength = 0; - char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1); - char *pShortPathname = (char *)alloca(MAX_PATHLENGTH + 1); - - pPathname[MAX_PATHLENGTH] = '\0'; - pShortPathname[MAX_PATHLENGTH] = '\0'; - - memcpy(pPathname, pExeStart, dwBasePathLength); - pPathname[dwBasePathLength] = '\0'; - - if (pExtension == NULL) { - /* Try appending extensions */ - for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) { - - if (!bHasPathSeparators) { - /* There are no path separators, search in the standard locations */ - dwShortNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pShortPathname, NULL); - if (dwShortNameLength > 0 && dwShortNameLength <= MAX_PATHLENGTH) { - memcpy(pPathname, pShortPathname, dwShortNameLength); - pPathname[dwShortNameLength] = '\0'; - break; - } - } else { - bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength); - if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) { - break; - } - } - } - } else { + DWORD dwAltNameLength = 0; + char *pPathname = (char *)alloca(MAX_PATHLENGTH + 1); + char *pAltPathname = (char *)alloca(MAX_PATHLENGTH + 1); + + pPathname[MAX_PATHLENGTH] = '\0'; + pAltPathname[MAX_PATHLENGTH] = '\0'; + + memcpy(pPathname, pExeStart, dwBasePathLength); + pPathname[dwBasePathLength] = '\0'; + + if (pExtension == NULL) { + /* Try appending extensions */ + for (int index = 0; index < (int)(sizeof(ExtensionList) / sizeof(ExtensionList[0])); index++) { + if (!bHasPathSeparators) { /* There are no path separators, search in the standard locations */ - dwShortNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pShortPathname, NULL); - if (dwShortNameLength == 0 || dwShortNameLength > MAX_PATHLENGTH) { - return false; + dwAltNameLength = SearchPath(NULL, pPathname, ExtensionList[index], MAX_PATHLENGTH, pAltPathname, NULL); + if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) { + memcpy(pPathname, pAltPathname, dwAltNameLength); + pPathname[dwAltNameLength] = '\0'; + break; } - - memcpy(pPathname, pShortPathname, dwShortNameLength); - pPathname[dwShortNameLength] = '\0'; + } else { + bstrncpy(&pPathname[dwBasePathLength], ExtensionList[index], MAX_PATHLENGTH - dwBasePathLength); + if (GetFileAttributes(pPathname) != INVALID_FILE_ATTRIBUTES) { + break; + } + pPathname[dwBasePathLength] = '\0'; } } + } else if (!bHasPathSeparators) { + /* There are no path separators, search in the standard locations */ + dwAltNameLength = SearchPath(NULL, pPathname, NULL, MAX_PATHLENGTH, pAltPathname, NULL); + if (dwAltNameLength > 0 && dwAltNameLength < MAX_PATHLENGTH) { + memcpy(pPathname, pAltPathname, dwAltNameLength); + pPathname[dwAltNameLength] = '\0'; + } + } - dwShortNameLength = GetShortPathName(pPathname, pShortPathname, MAX_PATHLENGTH); + if (strchr(pPathname, ' ') != NULL) { + dwAltNameLength = GetShortPathName(pPathname, pAltPathname, MAX_PATHLENGTH); - if (dwShortNameLength > 0 && dwShortNameLength <= MAX_PATHLENGTH) { - *pexe = (char *)malloc(dwShortNameLength + 1); - if (*pexe != NULL) { - memcpy(*pexe, pShortPathname, dwShortNameLength + 1); - } else { + if (dwAltNameLength > 0 && dwAltNameLength <= MAX_PATHLENGTH) { + *pexe = (char *)malloc(dwAltNameLength + 1); + if (*pexe == NULL) { return false; } - } else { - return false; + memcpy(*pexe, pAltPathname, dwAltNameLength + 1); } - } else { - /* There are no blanks so we don't need to munge the name */ - *pexe = (char *)malloc(dwBasePathLength + 1); - if (*pexe != NULL) { - memcpy(*pexe, pExeStart, dwBasePathLength); - (*pexe)[dwBasePathLength] = '\0'; - } else { + } + + if (*pexe == NULL) { + DWORD dwPathnameLength = strlen(pPathname); + *pexe = (char *)malloc(dwPathnameLength + 1); + if (*pexe == NULL) { return false; } + memcpy(*pexe, pPathname, dwPathnameLength + 1); } return true; } +/** + * Create the process with WCHAR API + */ +static BOOL +CreateChildProcessW(const char *comspec, const char *cmdLine, + PROCESS_INFORMATION *hProcInfo, + HANDLE in, HANDLE out, HANDLE err) +{ + STARTUPINFOW siStartInfo; + BOOL bFuncRetn = FALSE; + + // Set up members of the STARTUPINFO structure. + ZeroMemory( &siStartInfo, sizeof(siStartInfo) ); + siStartInfo.cb = sizeof(siStartInfo); + // setup new process to use supplied handles for stdin,stdout,stderr + + siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; + + siStartInfo.hStdInput = in; + siStartInfo.hStdOutput = out; + siStartInfo.hStdError = err; + + // Convert argument to WCHAR + POOLMEM *cmdLine_wchar = get_pool_memory(PM_FNAME); + POOLMEM *comspec_wchar = get_pool_memory(PM_FNAME); + + UTF8_2_wchar(&cmdLine_wchar, cmdLine); + UTF8_2_wchar(&comspec_wchar, comspec); + + // Create the child process. + Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec_wchar, cmdLine_wchar); + + // try to execute program + bFuncRetn = p_CreateProcessW((WCHAR*)comspec_wchar, + (WCHAR*)cmdLine_wchar,// command line + NULL, // process security attributes + NULL, // primary thread security attributes + TRUE, // handles are inherited + 0, // creation flags + NULL, // use parent's environment + NULL, // use parent's current directory + &siStartInfo, // STARTUPINFO pointer + hProcInfo); // receives PROCESS_INFORMATION + free_pool_memory(cmdLine_wchar); + free_pool_memory(comspec_wchar); + + return bFuncRetn; +} + + +/** + * Create the process with ANSI API + */ +static BOOL +CreateChildProcessA(const char *comspec, char *cmdLine, + PROCESS_INFORMATION *hProcInfo, + HANDLE in, HANDLE out, HANDLE err) +{ + STARTUPINFOA siStartInfo; + BOOL bFuncRetn = FALSE; + + // Set up members of the STARTUPINFO structure. + ZeroMemory( &siStartInfo, sizeof(siStartInfo) ); + siStartInfo.cb = sizeof(siStartInfo); + // setup new process to use supplied handles for stdin,stdout,stderr + siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; + + siStartInfo.hStdInput = in; + siStartInfo.hStdOutput = out; + siStartInfo.hStdError = err; + + // Create the child process. + Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine); + + // try to execute program + bFuncRetn = p_CreateProcessA(comspec, + cmdLine, // command line + NULL, // process security attributes + NULL, // primary thread security attributes + TRUE, // handles are inherited + 0, // creation flags + NULL, // use parent's environment + NULL, // use parent's current directory + &siStartInfo,// STARTUPINFO pointer + hProcInfo);// receives PROCESS_INFORMATION + return bFuncRetn; +} + /** * OK, so it would seem CreateProcess only handles true executables: * .com or .exe files. So grab $COMSPEC value and pass command line to it. @@ -1722,42 +2026,29 @@ CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err) { static const char *comspec = NULL; PROCESS_INFORMATION piProcInfo; - STARTUPINFOA siStartInfo; BOOL bFuncRetn = FALSE; - if (comspec == NULL) { + if (!p_CreateProcessA || !p_CreateProcessW) + return INVALID_HANDLE_VALUE; + + if (comspec == NULL) comspec = getenv("COMSPEC"); - } if (comspec == NULL) // should never happen return INVALID_HANDLE_VALUE; // Set up members of the PROCESS_INFORMATION structure. ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) ); - // Set up members of the STARTUPINFO structure. - - ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); - siStartInfo.cb = sizeof(STARTUPINFO); - // setup new process to use supplied handles for stdin,stdout,stderr // if supplied handles are not used the send a copy of our STD_HANDLE // as appropriate - siStartInfo.dwFlags = STARTF_USESTDHANDLES; - - if (in != INVALID_HANDLE_VALUE) - siStartInfo.hStdInput = in; - else - siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + if (in == INVALID_HANDLE_VALUE) + in = GetStdHandle(STD_INPUT_HANDLE); - if (out != INVALID_HANDLE_VALUE) - siStartInfo.hStdOutput = out; - else - siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); - if (err != INVALID_HANDLE_VALUE) - siStartInfo.hStdError = err; - else - siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + if (out == INVALID_HANDLE_VALUE) + out = GetStdHandle(STD_OUTPUT_HANDLE); - // Create the child process. + if (err == INVALID_HANDLE_VALUE) + err = GetStdHandle(STD_ERROR_HANDLE); char *exeFile; const char *argStart; @@ -1766,43 +2057,33 @@ CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err) return INVALID_HANDLE_VALUE; } - int cmdLen = strlen(comspec) + 4 + strlen(exeFile) + strlen(argStart) + 1; - - char *cmdLine = (char *)alloca(cmdLen); - - snprintf(cmdLine, cmdLen, "%s /c %s%s", comspec, exeFile, argStart); + POOL_MEM cmdLine(PM_FNAME); + Mmsg(cmdLine, "%s /c %s%s", comspec, exeFile, argStart); free(exeFile); - Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine); - - // try to execute program - bFuncRetn = CreateProcessA(comspec, - cmdLine, // command line - NULL, // process security attributes - NULL, // primary thread security attributes - TRUE, // handles are inherited - 0, // creation flags - NULL, // use parent's environment - NULL, // use parent's current directory - &siStartInfo, // STARTUPINFO pointer - &piProcInfo); // receives PROCESS_INFORMATION + // New function disabled + if (p_CreateProcessW && p_MultiByteToWideChar) { + bFuncRetn = CreateChildProcessW(comspec, cmdLine.c_str(), &piProcInfo, + in, out, err); + } else { + bFuncRetn = CreateChildProcessA(comspec, cmdLine.c_str(), &piProcInfo, + in, out, err); + } if (bFuncRetn == 0) { ErrorExit("CreateProcess failed\n"); const char *err = errorString(); - Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n", comspec, cmdLine, err); + Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n",comspec,cmdLine.c_str(),err); LocalFree((void *)err); return INVALID_HANDLE_VALUE; } // we don't need a handle on the process primary thread so we close // this now. CloseHandle(piProcInfo.hThread); - return piProcInfo.hProcess; } - void ErrorExit (LPCSTR lpszMessage) { @@ -1920,23 +2201,23 @@ open_bpipe(char *prog, int wait, const char *mode) // process terminates we can // detect eof. // ugly but convert WIN32 HANDLE to FILE* - int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY); + int rfd = _open_osfhandle((intptr_t)hChildStdoutRdDup, O_RDONLY | O_BINARY); if (rfd >= 0) { - bpipe->rfd = _fdopen(rfd, "r"); + bpipe->rfd = _fdopen(rfd, "rb"); } } if (mode_write) { CloseHandle(hChildStdinRd); // close our read side so as not // to interfre with child's copy // ugly but convert WIN32 HANDLE to FILE* - int wfd = _open_osfhandle((long)hChildStdinWrDup, O_WRONLY); + int wfd = _open_osfhandle((intptr_t)hChildStdinWrDup, O_WRONLY | O_BINARY); if (wfd >= 0) { - bpipe->wfd = _fdopen(wfd, "w"); + bpipe->wfd = _fdopen(wfd, "wb"); } } if (wait > 0) { - bpipe->timer_id = start_child_timer(bpipe->worker_pid, wait); + bpipe->timer_id = start_child_timer(NULL, bpipe->worker_pid, wait); } return bpipe; @@ -1973,6 +2254,16 @@ close_bpipe(BPIPE *bpipe) int rval = 0; int32_t remaining_wait = bpipe->wait; + /* Close pipes */ + if (bpipe->rfd) { + fclose(bpipe->rfd); + bpipe->rfd = NULL; + } + if (bpipe->wfd) { + fclose(bpipe->wfd); + bpipe->wfd = NULL; + } + if (remaining_wait == 0) { /* wait indefinitely */ remaining_wait = INT32_MAX; } @@ -2013,20 +2304,19 @@ close_bpipe(BPIPE *bpipe) int close_wpipe(BPIPE *bpipe) { - int stat = 1; + int result = 1; if (bpipe->wfd) { fflush(bpipe->wfd); if (fclose(bpipe->wfd) != 0) { - stat = 0; + result = 0; } bpipe->wfd = NULL; } - return stat; + return result; } -#include "findlib/find.h" - +#ifndef MINGW64 int utime(const char *fname, struct utimbuf *times) { @@ -2041,10 +2331,10 @@ utime(const char *fname, struct utimbuf *times) HANDLE h = INVALID_HANDLE_VALUE; if (p_CreateFileW) { - POOLMEM* pwszBuf = get_pool_memory(PM_FNAME); - make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf); + POOLMEM* pwszBuf = get_pool_memory(PM_FNAME); + make_win32_path_UTF8_2_wchar(&pwszBuf, tmpbuf); - h = p_CreateFileW((LPCWSTR)pwszBuf, + h = p_CreateFileW((LPCWSTR)pwszBuf, FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, @@ -2052,9 +2342,9 @@ utime(const char *fname, struct utimbuf *times) FILE_FLAG_BACKUP_SEMANTICS, // required for directories NULL); - free_pool_memory(pwszBuf); + free_pool_memory(pwszBuf); } else if (p_CreateFileA) { - h = p_CreateFileA(tmpbuf, + h = p_CreateFileA(tmpbuf, FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE, NULL, @@ -2064,11 +2354,11 @@ utime(const char *fname, struct utimbuf *times) } if (h == INVALID_HANDLE_VALUE) { - const char *err = errorString(); - Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err); - LocalFree((void *)err); - errno = b_errno_win32; - return -1; + const char *err = errorString(); + Dmsg2(99, "Cannot open file \"%s\" for utime(): ERR=%s", tmpbuf, err); + LocalFree((void *)err); + errno = b_errno_win32; + return -1; } int rval = SetFileTime(h, NULL, &acc, &mod) ? 0 : -1; @@ -2078,54 +2368,55 @@ utime(const char *fname, struct utimbuf *times) } return rval; } +#endif #if 0 int file_open(const char *file, int flags, int mode) { - DWORD access = 0; - DWORD shareMode = 0; - DWORD create = 0; - DWORD msflags = 0; - HANDLE foo = INVALID_HANDLE_VALUE; - const char *remap = file; - - if (flags & O_WRONLY) access = GENERIC_WRITE; - else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE; - else access = GENERIC_READ; - - if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) - create = CREATE_NEW; - else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) - create = CREATE_ALWAYS; - else if (flags & O_CREAT) - create = OPEN_ALWAYS; - else if (flags & O_TRUNC) - create = TRUNCATE_EXISTING; - else - create = OPEN_EXISTING; - - shareMode = 0; - - if (flags & O_APPEND) { - printf("open...APPEND not implemented yet."); - exit(-1); - } + DWORD access = 0; + DWORD shareMode = 0; + DWORD create = 0; + DWORD msflags = 0; + HANDLE foo = INVALID_HANDLE_VALUE; + const char *remap = file; + + if (flags & O_WRONLY) access = GENERIC_WRITE; + else if (flags & O_RDWR) access = GENERIC_READ|GENERIC_WRITE; + else access = GENERIC_READ; + + if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + create = CREATE_NEW; + else if ((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) + create = CREATE_ALWAYS; + else if (flags & O_CREAT) + create = OPEN_ALWAYS; + else if (flags & O_TRUNC) + create = TRUNCATE_EXISTING; + else + create = OPEN_EXISTING; + + shareMode = 0; + + if (flags & O_APPEND) { + printf("open...APPEND not implemented yet."); + exit(-1); + } - if (p_CreateFileW) { - POOLMEM* pwszBuf = get_pool_memory(PM_FNAME); - make_win32_path_UTF8_2_wchar(&pwszBuf, file); + if (p_CreateFileW) { + POOLMEM* pwszBuf = get_pool_memory(PM_FNAME); + make_win32_path_UTF8_2_wchar(&pwszBuf, file); - foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL); - free_pool_memory(pwszBuf); - } else if (p_CreateFileA) - foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL); + foo = p_CreateFileW((LPCWSTR) pwszBuf, access, shareMode, NULL, create, msflags, NULL); + free_pool_memory(pwszBuf); + } else if (p_CreateFileA) + foo = CreateFile(file, access, shareMode, NULL, create, msflags, NULL); - if (INVALID_HANDLE_VALUE == foo) { - errno = b_errno_win32; - return(int) -1; - } - return (int)foo; + if (INVALID_HANDLE_VALUE == foo) { + errno = b_errno_win32; + return (int)-1; + } + return (int)foo; } @@ -2165,11 +2456,14 @@ file_read(int fd, void *data, ssize_t len) return -1; } -off_t -file_seek(int fd, off_t offset, int whence) +boffset_t +file_seek(int fd, boffset_t offset, int whence) { DWORD method = 0; DWORD val; + LONG offset_low = (LONG)offset; + LONG offset_high = (LONG)(offset >> 32); + switch (whence) { case SEEK_SET : method = FILE_BEGIN; @@ -2185,7 +2479,8 @@ file_seek(int fd, off_t offset, int whence) return -1; } - if ((val=SetFilePointer((HANDLE)fd, (DWORD)offset, NULL, method)) == INVALID_SET_FILE_POINTER) { + + if ((val=SetFilePointer((HANDLE)fd, offset_low, &offset_high, method)) == INVALID_SET_FILE_POINTER) { errno = b_errno_win32; return -1; } @@ -2201,6 +2496,72 @@ file_dup2(int, int) } #endif +#ifdef xxx +/* + * Emulation of mmap and unmmap for tokyo dbm + */ +void *mmap(void *start, size_t length, int prot, int flags, + int fd, off_t offset) +{ + DWORD fm_access = 0; + DWORD mv_access = 0; + HANDLE h; + HANDLE mv; + + if (length == 0) { + return MAP_FAILED; + } + if (!fd) { + return MAP_FAILED; + } + + if (flags & PROT_WRITE) { + fm_access |= PAGE_READWRITE; + } else if (flags & PROT_READ) { + fm_access |= PAGE_READONLY; + } + + if (flags & PROT_READ) { + mv_access |= FILE_MAP_READ; + } + if (flags & PROT_WRITE) { + mv_access |= FILE_MAP_WRITE; + } + + h = CreateFileMapping((HANDLE)_get_osfhandle (fd), + NULL /* security */, + fm_access, + 0 /* MaximumSizeHigh */, + 0 /* MaximumSizeLow */, + NULL /* name of the file mapping object */); + + if (!h || h == INVALID_HANDLE_VALUE) { + return MAP_FAILED; + } + + mv = MapViewOfFile(h, mv_access, + 0 /* offset hi */, + 0 /* offset lo */, + length); + CloseHandle(h); + + if (!mv || mv == INVALID_HANDLE_VALUE) { + return MAP_FAILED; + } + + return (void *) mv; +} + +int munmap(void *start, size_t length) +{ + if (!start) { + return -1; + } + UnmapViewOfFile(start); + return 0; +} +#endif + #ifdef HAVE_MINGW /* syslog function, added by Nicolas Boichat */ void openlog(const char *ident, int option, int facility) {}