/*
Bacula® - The Network Backup Solution
- Copyright (C) 2004-2007 Free Software Foundation Europe e.V.
+ Copyright (C) 2004-2010 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
+ modify it under the terms of version three of the GNU Affero General Public
License as published by the Free Software Foundation and included
in the file LICENSE.
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
+ You should have received a copy of the GNU Affero 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 John Walker.
+ 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.
//
// 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"
+
+static const int dbglvl = 500;
#define b_errno_win32 (1<<29)
#define MAX_PATHLENGTH 1024
-/* UTF-8 to UCS2 path conversion is expensive,
+/**
+ UTF-8 to UCS2 path conversion is expensive,
so we cache the conversion. During backup the
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);
+ by using the cache this is reduced to 1 time
+ */
+static POOLMEM *g_pWin32ConvUTF8Cache = NULL;
+static POOLMEM *g_pWin32ConvUCS2Cache = NULL;
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;
g_pVSSPathConvertW = pPathConvertW;
}
+static void Win32ConvInitCache()
+{
+ if (g_pWin32ConvUTF8Cache) {
+ return;
+ }
+ g_pWin32ConvUTF8Cache = get_pool_memory(PM_FNAME);
+ g_pWin32ConvUCS2Cache = get_pool_memory(PM_FNAME);
+}
+
void Win32ConvCleanupCache()
{
+ P(Win32Convmutex);
if (g_pWin32ConvUTF8Cache) {
free_pool_memory(g_pWin32ConvUTF8Cache);
g_pWin32ConvUTF8Cache = NULL;
}
g_dwWin32ConvUTF8strlen = 0;
+ V(Win32Convmutex);
}
extern DWORD g_platform_id;
extern DWORD g_MinorVersion;
-// from MicroSoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970
+/* From Microsoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970 */
#ifdef HAVE_MINGW
#define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL
#else
#define WIN32_FILETIME_SCALE 10000000 // 100ns/second
-void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize)
+/**
+ * Convert from UTF-8 to VSS Windows path/file
+ * Used by compatibility layer for Unix system calls
+ */
+static void conv_unix_to_vss_win32_path(const char *name, char *win32_name, DWORD dwSize)
{
const char *fname = name;
char *tname = win32_name;
- Dmsg0(100, "Enter convert_unix_to_win32_path\n");
+ Dmsg0(dbglvl, "Enter convert_unix_to_win32_path\n");
if (IsPathSeparator(name[0]) &&
IsPathSeparator(name[1]) &&
}
while (*name) {
- /* Check for Unix separator and convert to Win32 */
+ /** Check for Unix separator and convert to Win32 */
if (name[0] == '/' && name[1] == '/') { /* double slash? */
name++; /* yes, skip first one */
}
}
name++;
}
- /* Strip any trailing slash, if we stored something */
- /* but leave "c:\" with backslash (root directory case */
+ /** Strip any trailing slash, if we stored something
+ * but leave "c:\" with backslash (root directory case
+ */
if (*fname != 0 && win32_name[-1] == '\\' && strlen (fname) != 3) {
win32_name[-1] = 0;
} else {
*win32_name = 0;
}
- /* here we convert to VSS specific file name which
+ /** here we convert to VSS specific file name which
can get longer because VSS will make something like
\\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\bacula\\uninstall.exe
from c:\bacula\uninstall.exe
*/
- Dmsg1(100, "path=%s\n", tname);
+ Dmsg1(dbglvl, "path=%s\n", tname);
if (g_pVSSPathConvert != NULL) {
POOLMEM *pszBuf = get_pool_memory (PM_FNAME);
pszBuf = check_pool_memory_size(pszBuf, dwSize);
free_pool_memory(pszBuf);
}
- Dmsg1(100, "Leave cvt_u_to_win32_path path=%s\n", tname);
+ Dmsg1(dbglvl, "Leave cvt_u_to_win32_path path=%s\n", tname);
}
-/* Conversion of a Unix filename to a Win32 filename */
+/** Conversion of a Unix filename to a Win32 filename */
void unix_name_to_win32(POOLMEM **win32_name, char *name)
{
/* One extra byte should suffice, but we double it */
/* add MAX_PATH bytes for VSS shadow copy name */
DWORD dwSize = 2*strlen(name)+MAX_PATH;
*win32_name = check_pool_memory_size(*win32_name, dwSize);
- conv_unix_to_win32_path(name, *win32_name, dwSize);
+ conv_unix_to_vss_win32_path(name, *win32_name, dwSize);
}
-POOLMEM*
+
+/**
+ * This function expects an UCS-encoded standard wchar_t in pszUCSPath and
+ * will complete the input path to an absolue path of the form \\?\c:\path\file
+ *
+ * With this trick, it is possible to have 32K characters long paths.
+ *
+ * Optionally one can use pBIsRawPath to determine id pszUCSPath contains a path
+ * to a raw windows partition.
+ *
+ * created 02/27/2006 Thorsten Engel
+ */
+static POOLMEM*
make_wchar_win32_path(POOLMEM *pszUCSPath, BOOL *pBIsRawPath /*= NULL*/)
{
- /* created 02/27/2006 Thorsten Engel
- *
- * This function expects an UCS-encoded standard wchar_t in pszUCSPath and
- * will complete the input path to an absolue path of the form \\?\c:\path\file
- *
- * With this trick, it is possible to have 32K characters long paths.
- *
- * Optionally one can use pBIsRawPath to determine id pszUCSPath contains a path
- * to a raw windows partition.
- */
- Dmsg0(100, "Enter wchar_win32_path\n");
+ Dmsg0(dbglvl, "Enter wchar_win32_path\n");
if (pBIsRawPath) {
*pBIsRawPath = FALSE; /* Initialize, set later */
}
if (!p_GetCurrentDirectoryW) {
- Dmsg0(100, "Leave wchar_win32_path no change \n");
+ Dmsg0(dbglvl, "Leave wchar_win32_path no change \n");
return pszUCSPath;
}
/* if it has already the desired form, exit without changes */
if (wcslen(name) > 3 && wcsncmp(name, L"\\\\?\\", 4) == 0) {
- Dmsg0(100, "Leave wchar_win32_path no change \n");
+ Dmsg0(dbglvl, "Leave wchar_win32_path no change \n");
return pszUCSPath;
}
free_pool_memory(pszUCSPath);
free_pool_memory((POOLMEM *)pwszCurDirBuf);
- Dmsg1(100, "Leave wchar_win32_path=%s\n", pwszBuf);
+ Dmsg1(dbglvl, "Leave wchar_win32_path=%s\n", pwszBuf);
return (POOLMEM *)pwszBuf;
}
int
wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
{
- /* the return value is the number of bytes written to the buffer.
- The number includes the byte for the null terminator. */
+ /**
+ * The return value is the number of bytes written to the buffer.
+ * The number includes the byte for the null terminator.
+ */
if (p_WideCharToMultiByte) {
- int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
- ASSERT (nRet > 0);
- return nRet;
- }
- else
+ int nRet = p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,pszUTF,cchChar,NULL,NULL);
+ ASSERT (nRet > 0);
+ return nRet;
+ } else {
return 0;
+ }
}
int
int nRet = p_MultiByteToWideChar(CP_UTF8, 0, pszUTF, -1, (LPWSTR) *ppszUCS,cchSize);
ASSERT (nRet > 0);
return nRet;
- }
- else
+ } else {
return 0;
+ }
}
/* if we find the utf8 string in cache, we use the cached ucs2 version.
we compare the stringlength first (quick check) and then compare the content.
*/
- if (g_dwWin32ConvUTF8strlen == strlen(pszUTF)) {
+ if (!g_pWin32ConvUTF8Cache) {
+ Win32ConvInitCache();
+ } else if (g_dwWin32ConvUTF8strlen == strlen(pszUTF)) {
if (bstrcmp(pszUTF, g_pWin32ConvUTF8Cache)) {
+ /* Return cached value */
int32_t nBufSize = sizeof_pool_memory(g_pWin32ConvUCS2Cache);
*pszUCS = check_pool_memory_size(*pszUCS, nBufSize);
- wcscpy((LPWSTR) *pszUCS, (LPWSTR) g_pWin32ConvUCS2Cache);
+ wcscpy((LPWSTR) *pszUCS, (LPWSTR)g_pWin32ConvUCS2Cache);
V(Win32Convmutex);
return nBufSize / sizeof (WCHAR);
}
wcscpy((LPWSTR) g_pWin32ConvUCS2Cache, (LPWSTR) *pszUCS);
g_dwWin32ConvUTF8strlen = strlen(pszUTF);
- g_pWin32ConvUTF8Cache = check_pool_memory_size(g_pWin32ConvUTF8Cache, g_dwWin32ConvUTF8strlen+1);
+ g_pWin32ConvUTF8Cache = check_pool_memory_size(g_pWin32ConvUTF8Cache, g_dwWin32ConvUTF8strlen+2);
bstrncpy(g_pWin32ConvUTF8Cache, pszUTF, g_dwWin32ConvUTF8strlen+1);
V(Win32Convmutex);
}
#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 */
}
-int chmod(const char *, mode_t)
+char *dlerror(void)
+{
+ static char buf[200];
+ const char *err = errorString();
+ bstrncpy(buf, (char *)err, sizeof(buf));
+ LocalFree((void *)err);
+ return buf;
+}
+
+int fcntl(int fd, int cmd)
{
return 0;
}
return (time_t) (mstime & 0xffffffff);
}
-static const char *
-errorString(void)
+static const char *errorString(void)
{
LPVOID lpMsgBuf;
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(dbglvl, "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;
POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);
make_win32_path_UTF8_2_wchar(&pwszBuf, file);
- h = p_FindFirstFileW((LPCWSTR) pwszBuf, &info_w);
+ Dmsg1(dbglvl, "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;
// use ASCII
} else if (p_FindFirstFileA) {
+ Dmsg1(dbglvl, "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(dbglvl, "No findFirstFile A or W found\n");
}
if (h == INVALID_HANDLE_VALUE) {
const char *err = errorString();
- Dmsg2(99, "FindFirstFile(%s):%s\n", file, err);
+ /*
+ * 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 */
sb->st_mode |= S_ISVTX; /* use sticky bit -> hidden */
sb->st_mode |= S_IFDIR;
- /* Use st_rdev to store reparse attribute */
- sb->st_rdev = (*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 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(dbglvl, "st_rdev=%d file=%s\n", sb->st_rdev, file);
sb->st_size = *pnFileSizeHigh;
sb->st_size <<= 32;
sb->st_size |= *pnFileSizeLow;
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);
return 0;
}
int
-fstat(int fd, struct stat *sb)
+fstat(intptr_t fd, struct stat *sb)
{
BY_HANDLE_FILE_INFORMATION info;
- char tmpbuf[1024];
- if (!GetFileInformationByHandle((HANDLE)fd, &info)) {
+ if (!GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &info)) {
const char *err = errorString();
- Dmsg2(99, "GetfileInformationByHandle(%s): %s\n", tmpbuf, err);
+ Dmsg1(2099, "GetfileInformationByHandle: %s\n", err);
LocalFree((void *)err);
errno = b_errno_win32;
return -1;
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);
+ Dmsg1(dbglvl, "st_nlink=%d\n", sb->st_nlink);
}
sb->st_mode = 0777; /* start with everything */
sb->st_mode |= S_IFREG;
/* Use st_rdev to store reparse attribute */
- sb->st_rdev = (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ? 1 : 0;
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ sb->st_rdev = WIN32_REPARSE_POINT;
+ }
+ Dmsg3(dbglvl, "st_rdev=%d sizino=%d ino=%lld\n", sb->st_rdev, sizeof(sb->st_ino),
+ (long long)sb->st_ino);
sb->st_size = info.nFileSizeHigh;
sb->st_size <<= 32;
static int
stat2(const char *file, struct stat *sb)
{
- HANDLE h;
+ HANDLE h = INVALID_HANDLE_VALUE;
int rval = 0;
- char tmpbuf[1024];
- conv_unix_to_win32_path(file, tmpbuf, 1024);
+ char tmpbuf[5000];
+ conv_unix_to_vss_win32_path(file, tmpbuf, 5000);
DWORD attr = (DWORD)-1;
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);
+ h = CreateFileA(tmpbuf, GENERIC_READ,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
}
if (attr == (DWORD)-1) {
const char *err = errorString();
- Dmsg2(99, "GetFileAttributes(%s): %s\n", tmpbuf, err);
+ Dmsg2(2099, "GetFileAttributes(%s): %s\n", tmpbuf, err);
LocalFree((void *)err);
+ if (h != INVALID_HANDLE_VALUE) {
+ CloseHandle(h);
+ }
errno = b_errno_win32;
return -1;
}
- if (attr & FILE_ATTRIBUTE_DIRECTORY) {
- return statDir(tmpbuf, sb);
- }
-
- h = CreateFileA(tmpbuf, GENERIC_READ,
- FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
-
if (h == INVALID_HANDLE_VALUE) {
const char *err = errorString();
- Dmsg2(99, "Cannot open file for stat (%s):%s\n", tmpbuf, err);
+ Dmsg2(2099, "Cannot open file for stat (%s):%s\n", tmpbuf, err);
LocalFree((void *)err);
errno = b_errno_win32;
return -1;
}
- rval = fstat((int)h, sb);
+ rval = fstat((intptr_t)h, sb);
CloseHandle(h);
+ if (attr & FILE_ATTRIBUTE_DIRECTORY &&
+ file[1] == ':' && file[2] != 0) {
+ rval = statDir(file, sb);
+ }
return rval;
}
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);
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(dbglvl, "sizino=%d ino=%lld file=%s\n", sizeof(sb->st_ino),
+ (long long)sb->st_ino, file);
return 0;
}
}
-/* For apcupsd this is in src/lib/wincompat.c */
+/*
+ * Write in Windows System log
+ */
extern "C" void syslog(int type, const char *fmt, ...)
{
-/*#ifndef HAVE_CONSOLE
- MessageBox(NULL, msg, "Bacula", MB_OK);
-#endif*/
+ va_list arg_ptr;
+ int len, maxlen;
+ POOLMEM *msg;
+
+ msg = get_pool_memory(PM_EMSG);
+
+ for (;;) {
+ maxlen = sizeof_pool_memory(msg) - 1;
+ va_start(arg_ptr, fmt);
+ len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
+ va_end(arg_ptr);
+ if (len < 0 || len >= (maxlen-5)) {
+ msg = realloc_pool_memory(msg, maxlen + maxlen/2);
+ continue;
+ }
+ break;
+ }
+ LogErrorMsg((const char *)msg);
+ free_memory(msg);
}
void
{
/* enough space for VSS !*/
int max_len = strlen(path) + MAX_PATH;
+ char *tspec = NULL;
_dir *rval = NULL;
if (path == NULL) {
errno = ENOENT;
return NULL;
}
- Dmsg1(100, "Opendir path=%s\n", path);
+ Dmsg1(dbglvl, "Opendir path=%s\n", path);
rval = (_dir *)malloc(sizeof(_dir));
+ if (!rval) {
+ goto err;
+ }
memset (rval, 0, sizeof (_dir));
- if (rval == NULL) return NULL;
- char *tspec = (char *)malloc(max_len);
- if (tspec == NULL) return NULL;
- conv_unix_to_win32_path(path, tspec, max_len);
- Dmsg1(100, "win32 path=%s\n", tspec);
+ tspec = (char *)malloc(max_len);
+ if (!tspec) {
+ goto err;
+ }
+
+ conv_unix_to_vss_win32_path(path, tspec, max_len);
+ Dmsg1(dbglvl, "win32 path=%s\n", tspec);
// add backslash only if there is none yet (think of c:\)
if (tspec[strlen(tspec)-1] != '\\')
} else goto err;
- Dmsg3(99, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
+ Dmsg3(dbglvl, "opendir(%s)\n\tspec=%s,\n\tFindFirstFile returns %d\n",
path, rval->spec, rval->dirh);
rval->offset = 0;
goto err;
if (rval->valid_w) {
- Dmsg1(99, "\tFirstFile=%s\n", rval->data_w.cFileName);
+ Dmsg1(dbglvl, "\tFirstFile=%s\n", rval->data_w.cFileName);
}
if (rval->valid_a) {
- Dmsg1(99, "\tFirstFile=%s\n", rval->data_a.cFileName);
+ Dmsg1(dbglvl, "\tFirstFile=%s\n", rval->data_a.cFileName);
}
return (DIR *)rval;
err:
- free((void *)rval->spec);
- free(rval);
+ if (rval) {
+ free(rval);
+ }
+ if (tspec) {
+ free(tspec);
+ }
errno = b_errno_win32;
return NULL;
}
}
*result = entry; /* return entry address */
- Dmsg4(99, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
+ Dmsg4(dbglvl, "readdir_r(%p, { d_name=\"%s\", d_reclen=%d, d_off=%d\n",
dirp, entry->d_name, entry->d_reclen, entry->d_off);
} else {
-// Dmsg0(99, "readdir_r !valid\n");
+// Dmsg0(dbglvl, "readdir_r !valid\n");
errno = b_errno_win32;
return -1;
}
return 0;
}
+static DWORD fill_attribute(DWORD attr, mode_t mode)
+{
+ Dmsg1(dbglvl, " before attr=%lld\n", (uint64_t) attr);
+ /* Use Bacula mappings define in stat() above */
+ if (mode & (S_IRUSR|S_IRGRP|S_IROTH)) { // If file is readable
+ attr &= ~FILE_ATTRIBUTE_READONLY; // then this is not READONLY
+ } else {
+ attr |= FILE_ATTRIBUTE_READONLY;
+ }
+ if (mode & S_ISVTX) { // The sticky bit <=> HIDDEN
+ attr |= FILE_ATTRIBUTE_HIDDEN;
+ } else {
+ attr &= ~FILE_ATTRIBUTE_HIDDEN;
+ }
+ if (mode & S_IRWXO) { // Other can read/write/execute ?
+ attr &= ~FILE_ATTRIBUTE_SYSTEM; // => Not system
+ } else {
+ attr |= FILE_ATTRIBUTE_SYSTEM;
+ }
+ Dmsg1(dbglvl, " after attr=%lld\n", (uint64_t)attr);
+ return attr;
+}
+
+int win32_chmod(const char *path, mode_t mode)
+{
+ bool ret=false;
+ DWORD attr;
+
+ Dmsg2(dbglvl, "win32_chmod(path=%s mode=%lld)\n", path, (uint64_t)mode);
+ 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 */
+ attr = fill_attribute(attr, mode);
+ ret = p_SetFileAttributesW((LPCWSTR)pwszBuf, attr);
+ }
+ free_pool_memory(pwszBuf);
+ Dmsg0(dbglvl, "Leave win32_chmod. AttributesW\n");
+ } else if (p_GetFileAttributesA) {
+ attr = p_GetFileAttributesA(path);
+ if (attr != INVALID_FILE_ATTRIBUTES) {
+ attr = fill_attribute(attr, mode);
+ ret = p_SetFileAttributesA(path, attr);
+ }
+ Dmsg0(dbglvl, "Leave win32_chmod did AttributesA\n");
+ } else {
+ Dmsg0(dbglvl, "Leave win32_chmod did nothing\n");
+ }
+
+ if (!ret) {
+ const char *err = errorString();
+ Dmsg2(dbglvl, "Get/SetFileAttributes(%s): %s\n", path, err);
+ LocalFree((void *)err);
+ errno = b_errno_win32;
+ return -1;
+ }
+ return 0;
+}
+
int
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;
}
int
win32_mkdir(const char *dir)
{
+ Dmsg1(dbglvl, "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(dbglvl, "Leave win32_mkdir did wmkdir\n");
return n;
}
+ Dmsg0(dbglvl, "Leave win32_mkdir did _mkdir\n");
return _mkdir(dir);
}
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) {
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(dbglvl, "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(dbglvl, "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.
{
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 | STARTF_USESHOWWINDOW;
- siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;
+ if (in == INVALID_HANDLE_VALUE)
+ in = GetStdHandle(STD_INPUT_HANDLE);
- if (in != INVALID_HANDLE_VALUE)
- siStartInfo.hStdInput = in;
- else
- siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ if (out == INVALID_HANDLE_VALUE)
+ out = GetStdHandle(STD_OUTPUT_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);
-
- // Create the child process.
+ if (err == INVALID_HANDLE_VALUE)
+ err = GetStdHandle(STD_ERROR_HANDLE);
char *exeFile;
const char *argStart;
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(dbglvl, "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)
{
// process terminates we can
// detect eof.
// ugly but convert WIN32 HANDLE to FILE*
- int rfd = _open_osfhandle((long)hChildStdoutRdDup, O_RDONLY | O_BINARY);
+ int rfd = _open_osfhandle((intptr_t)hChildStdoutRdDup, O_RDONLY | O_BINARY);
if (rfd >= 0) {
bpipe->rfd = _fdopen(rfd, "rb");
}
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 | O_BINARY);
+ int wfd = _open_osfhandle((intptr_t)hChildStdinWrDup, O_WRONLY | O_BINARY);
if (wfd >= 0) {
bpipe->wfd = _fdopen(wfd, "wb");
}
if (!GetExitCodeProcess((HANDLE)bpipe->worker_pid, &exitCode)) {
const char *err = errorString();
rval = b_errno_win32;
- Dmsg1(0, "GetExitCode error %s\n", err);
+ Dmsg1(dbglvl, "GetExitCode error %s\n", err);
LocalFree((void *)err);
break;
}
return result;
}
-#include "findlib/find.h"
-
+#ifndef MINGW64
int
utime(const char *fname, struct utimbuf *times)
{
FILETIME acc, mod;
char tmpbuf[5000];
- conv_unix_to_win32_path(fname, tmpbuf, 5000);
+ conv_unix_to_vss_win32_path(fname, tmpbuf, 5000);
cvt_utime_to_ftime(times->actime, acc);
cvt_utime_to_ftime(times->modtime, mod);
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,
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,
}
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(dbglvl, "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;
}
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;
}
}
#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) {}
#endif //HAVE_MINGW
+
+/* Log an error message */
+void LogErrorMsg(const char *message)
+{
+ HANDLE eventHandler;
+ const char *strings[2];
+
+ /* Use the OS event logging to log the error */
+ eventHandler = RegisterEventSource(NULL, "Bacula");
+
+ strings[0] = _("\n\nBacula ERROR: ");
+ strings[1] = message;
+
+ if (eventHandler) {
+ ReportEvent(eventHandler, EVENTLOG_ERROR_TYPE,
+ 0, /* category */
+ 0, /* ID */
+ NULL, /* SID */
+ 2, /* Number of strings */
+ 0, /* raw data size */
+ (const char **)strings, /* error strings */
+ NULL); /* raw data */
+ DeregisterEventSource(eventHandler);
+ }
+}