case FT_NOFSCHG:
/* Suppress message for /dev filesystems */
if (!is_in_fileset(ff_pkt)) {
-#ifdef HAVE_WIN32
- Jmsg(jcr, M_INFO, 1, _(" %s is a junction point or a different filesystem. Will not descend from %s into it.\n"),
- ff_pkt->fname, ff_pkt->top_fname);
-#else
Jmsg(jcr, M_INFO, 1, _(" %s is a different filesystem. Will not descend from %s into it.\n"),
ff_pkt->fname, ff_pkt->top_fname);
-#endif
}
ff_pkt->type = FT_DIREND; /* Backup only the directory entry */
break;
ff_pkt->fname);
break;
case FT_REPARSE:
+ case FT_JUNCTION:
case FT_DIREND:
Dmsg1(130, "FT_DIREND: %s\n", ff_pkt->link);
break;
do_read = ff_pkt->statp.st_size > 0;
#endif
} else if (ff_pkt->type == FT_RAW || ff_pkt->type == FT_FIFO ||
- ff_pkt->type == FT_REPARSE ||
+ ff_pkt->type == FT_REPARSE || ff_pkt->type == FT_JUNCTION ||
(!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) {
do_read = true;
}
tid = NULL;
}
int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
- ff_pkt->bfd.reparse_point = ff_pkt->type == FT_REPARSE;
+ ff_pkt->bfd.reparse_point = (ff_pkt->type == FT_REPARSE ||
+ ff_pkt->type == FT_JUNCTION);
if (bopen(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0) < 0) {
ff_pkt->ff_errno = errno;
berrno be;
break;
case FT_DIREND:
case FT_REPARSE:
+ case FT_JUNCTION:
/* Here link is the canonical filename (i.e. with trailing slash) */
stat = sd->fsend("%ld %d %s%c%s%c%c%s%c%u%c", jcr->JobFiles,
ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0,
ff_pkt->object_name = (char *)"job_metadata.xml";
ff_pkt->object = (char *)metadata;
ff_pkt->object_len = (wcslen(metadata) + 1) * sizeof(WCHAR);
+ ff_pkt->object_index = (int)time(NULL);
save_file(jcr, ff_pkt, true);
}
}
* if st_rdev is 2, it is a mount point
*/
#if defined(HAVE_WIN32)
+ /*
+ * A reparse point (WIN32_REPARSE_POINT)
+ * is something special like one of the following:
+ * IO_REPARSE_TAG_DFS 0x8000000A
+ * IO_REPARSE_TAG_DFSR 0x80000012
+ * IO_REPARSE_TAG_HSM 0xC0000004
+ * IO_REPARSE_TAG_HSM2 0x80000006
+ * IO_REPARSE_TAG_SIS 0x80000007
+ * IO_REPARSE_TAG_SYMLINK 0xA000000C
+ *
+ * A junction point is a:
+ * IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
+ * which can be either a link to a Volume (WIN32_MOUNT_POINT)
+ * or a link to a directory (WIN32_JUNCTION_POINT)
+ *
+ * Ignore WIN32_REPARSE_POINT and WIN32_JUNCTION_POINT
+ */
if (ff_pkt->statp.st_rdev == WIN32_REPARSE_POINT) {
ff_pkt->type = FT_REPARSE;
+ } else if (ff_pkt->statp.st_rdev == WIN32_JUNCTION_POINT) {
+ ff_pkt->type = FT_JUNCTION;
}
#endif
/*
* in the directory is seen (i.e. the FT_DIREND).
*/
rtn_stat = handle_file(jcr, ff_pkt, top_level);
- if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE) { /* ignore or error status */
+ if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE ||
+ ff_pkt->type == FT_JUNCTION) { /* ignore or error status */
free(link);
return rtn_stat;
}
#include "jcr.h"
#include "findlib/find.h"
+/* Note, if you want to see what Windows variables and structures
+ * are defined, bacula.h includes <windows.h>, which is found in:
+ *
+ * cross-tools/mingw32/mingw32/include
+ * or
+ * cross-tools/mingw-w64/x86_64-pc-mingw32/include
+ *
+ * depending on whether we are building the 32 bit version or
+ * the 64 bit version.
+ */
+
static const int dbglvl = 500;
#define b_errno_win32 (1<<29)
return (POOLMEM *)pwszBuf;
}
+/*
+ * Convert from WCHAR (UCS) to UTF-8
+ */
+int
+wchar_2_UTF8(POOLMEM **pszUTF, const wchar_t *pszUCS)
+{
+ /**
+ * 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,NULL,0,NULL,NULL);
+ *pszUTF = check_pool_memory_size(*pszUTF, nRet);
+ return p_WideCharToMultiByte(CP_UTF8,0,pszUCS,-1,*pszUTF,nRet,NULL,NULL);
+
+ } else {
+ return 0;
+ }
+}
+
+/*
+ * Convert from WCHAR (UCS) to UTF-8
+ */
int
wchar_2_UTF8(char *pszUTF, const wchar_t *pszUCS, int cchChar)
{
}
+/*
+ * This is only called for directories, and is used to get the directory
+ * attributes and find out if we have a junction point or a mount point
+ * or other kind of "funny" directory.
+ */
static int
statDir(const char *file, struct stat *sb)
{
FILETIME *pftLastAccessTime;
FILETIME *pftLastWriteTime;
FILETIME *pftCreationTime;
+ HANDLE h = INVALID_HANDLE_VALUE;
/*
* Oh, cool, another exception: Microsoft doesn't let us do
return 0;
}
- HANDLE h = INVALID_HANDLE_VALUE;
// use unicode
if (p_FindFirstFileW) {
* filesystem).
*/
if (*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
- if (*pdwReserved0 & IO_REPARSE_TAG_MOUNT_POINT) {
- sb->st_rdev = WIN32_MOUNT_POINT; /* mount point */
+ sb->st_rdev = WIN32_MOUNT_POINT;
+ } else {
+ sb->st_rdev = 0;
+ }
+ if ((*pdwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
+ (*pdwReserved0 & IO_REPARSE_TAG_MOUNT_POINT)) {
+ sb->st_rdev = WIN32_MOUNT_POINT; /* mount point */
+ /*
+ * Now to find out if the directory is a mount point or
+ * a reparse point, we must do a song and a dance.
+ * Explicitly open the file to read the reparse point, then
+ * call DeviceIoControl to find out if it points to a Volume
+ * or to a directory.
+ */
+ h = INVALID_HANDLE_VALUE;
+ if (p_GetFileAttributesW) {
+ POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
+ make_win32_path_UTF8_2_wchar(&pwszBuf, file);
+ if (p_CreateFileW) {
+ h = CreateFileW((LPCWSTR)pwszBuf, GENERIC_READ,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+ NULL);
+ }
+ free_pool_memory(pwszBuf);
+ } else if (p_GetFileAttributesA) {
+ h = CreateFileA(file, GENERIC_READ,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+ NULL);
+ }
+ if (h != INVALID_HANDLE_VALUE) {
+ char dummy[1000];
+ REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)dummy;
+ rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ DWORD bytes;
+ bool ok;
+ ok = DeviceIoControl(h, FSCTL_GET_REPARSE_POINT,
+ NULL, 0, /* in buffer, bytes */
+ (LPVOID)rdb, (DWORD)sizeof(dummy), /* out buffer, btyes */
+ (LPDWORD)&bytes, (LPOVERLAPPED)0);
+ if (ok) {
+ POOLMEM *utf8 = get_pool_memory(PM_NAME);
+ wchar_2_UTF8(&utf8, (wchar_t *)rdb->SymbolicLinkReparseBuffer.PathBuffer);
+ Dmsg2(dbglvl, "Junction %s points to: %s\n", file, utf8);
+ if (strncasecmp(utf8, "\\??\\volume{", 11) == 0) {
+ sb->st_rdev = WIN32_MOUNT_POINT;
+ } else {
+ /* It points to a directory so we ignore it. */
+ sb->st_rdev = WIN32_JUNCTION_POINT;
+ }
+ free_pool_memory(utf8);
+ }
+ CloseHandle(h);
} else {
- sb->st_rdev = WIN32_REPARSE_POINT; /* reparse point */
+ Dmsg1(dbglvl, "Invalid handle from CreateFile(%s)\n", file);
}
}
Dmsg2(dbglvl, "st_rdev=%d file=%s\n", sb->st_rdev, file);
// copy unicode
if (dp->valid_w) {
- char szBuf[MAX_PATH_UTF8+1];
- wchar_2_UTF8(szBuf,dp->data_w.cFileName);
+ POOLMEM *szBuf = get_pool_memory(PM_NAME);
+ wchar_2_UTF8(&szBuf, dp->data_w.cFileName);
dp->offset += copyin(*entry, szBuf);
+ free_pool_memory(szBuf);
} else if (dp->valid_a) { // copy ansi (only 1 will be valid)
dp->offset += copyin(*entry, dp->data_a.cFileName);
}
} else if (p_GetCurrentDirectoryA)
n = p_GetCurrentDirectoryA(maxlen, buf);
- if (n == 0 || n > maxlen) return NULL;
+ if (n <= 0 || n > maxlen) return NULL;
if (n+1 > maxlen) return NULL;
if (n != 3) {
*/
static void
-CloseIfValid(HANDLE handle)
+CloseHandleIfValid(HANDLE handle)
{
- if (handle != INVALID_HANDLE_VALUE)
+ if (handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle);
+ }
}
BPIPE *
cleanup:
- CloseIfValid(hChildStdoutRd);
- CloseIfValid(hChildStdoutRdDup);
- CloseIfValid(hChildStdinWr);
- CloseIfValid(hChildStdinWrDup);
+ CloseHandleIfValid(hChildStdoutRd);
+ CloseHandleIfValid(hChildStdoutRdDup);
+ CloseHandleIfValid(hChildStdinWr);
+ CloseHandleIfValid(hChildStdinWrDup);
- free((void *) bpipe);
+ free((void *)bpipe);
errno = b_errno_win32; /* do GetLastError() for error code */
return NULL;
}
/*
Bacula® - The Network Backup Solution
- Copyright (C) 2004-2009 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.
/*
* Author : Christopher S. Hull
* Created On : Fri Jan 30 13:00:51 2004
- * Last Modified By: Thorsten Engel
- * Last Modified On: Fri Apr 22 19:30:00 2004
- * Update Count : 218
- * $Id$
*/
#ifdef MINGW64
#include <direct.h>
#define _declspec __declspec
+
+/* Missing in 64 bit mingw */
+typedef struct _REPARSE_DATA_BUFFER {
+ DWORD ReparseTag;
+ WORD ReparseDataLength;
+ WORD Reserved;
+ union {
+ struct {
+ WORD SubstituteNameOffset;
+ WORD SubstituteNameLength;
+ WORD PrintNameOffset;
+ WORD PrintNameLength;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ WORD SubstituteNameOffset;
+ WORD SubstituteNameLength;
+ WORD PrintNameOffset;
+ WORD PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct {
+ BYTE DataBuffer[1];
+ } GenericReparseBuffer;
+ } DUMMYUNIONNAME;
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+
#endif
+#include <winioctl.h>
+
#ifdef _WIN64
# define GWL_USERDATA GWLP_USERDATA
#endif
void openlog(const char *ident, int option, int facility);
#endif //HAVE_MINGW
-void LogErrorMsg(const char *message);
-
/* Don't let OS go to sleep (usually a Laptop) while we are backing up */
void prevent_os_suspensions();
void allow_os_suspensions();
typedef DWORD EXECUTION_STATE;
#ifndef ES_CONTINUOUS
#define ES_CONTINUOUS 0x80000000
+#endif
+#ifndef ES_SYSTEM_REQUIRED
#define ES_SYSTEM_REQUIRED 0x00000001
+#endif
+#ifndef ES_DISPLAY_REQUIRED
#define ES_DISPLAY_REQUIRED 0x00000002
#endif
#ifndef ES_USER_PRESENT
WINBASEAPI EXECUTION_STATE WINAPI SetThreadExecutionState(EXECUTION_STATE esFlags);
+extern void LogErrorMsg(const char *message);
+
#if !defined(INVALID_FILE_ATTRIBUTES)
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif