From a83a4b5a2eeff97d5b6682d399949cb2d144817f Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Wed, 21 May 2008 11:59:00 +0000 Subject: [PATCH] kes Fix Win32 reparse points. Bacula will not recurse into any reparse point directory, including mount points, unless the directory is explicitly mentioned at the top level (same as with Unix). A file that is linked to another file will be backed up -- much as Unix does for hardlinked files. This *should* fix bug #1041. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/branches/Branch-2.2@7001 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/baconfig.h | 4 + bacula/src/findlib/find_one.c | 15 ++- bacula/src/version.h | 6 +- bacula/src/win32/compat/compat.cpp | 145 ++++++++++++++++------------- bacula/technotes-2.1 | 7 ++ 5 files changed, 106 insertions(+), 71 deletions(-) diff --git a/bacula/src/baconfig.h b/bacula/src/baconfig.h index f5b0282da7..491cf0189b 100644 --- a/bacula/src/baconfig.h +++ b/bacula/src/baconfig.h @@ -79,6 +79,10 @@ #define NPRT(x) (x)?(x):_("*None*") #if defined(HAVE_WIN32) + +#define WIN32_REPARSE_POINT 1 +#define WIN32_MOUNT_POINT 2 + void InitWinAPIWrapper(); #define OSDependentInit() InitWinAPIWrapper() diff --git a/bacula/src/findlib/find_one.c b/bacula/src/findlib/find_one.c index a1ee4dcf71..7837748ead 100644 --- a/bacula/src/findlib/find_one.c +++ b/bacula/src/findlib/find_one.c @@ -515,9 +515,11 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, * We have set st_rdev to 1 if it is a reparse point, otherwise 0, * if st_rdev is 2, it is a mount point */ - if (have_win32_api() && ff_pkt->statp.st_rdev == 1) { - ff_pkt->type = FT_REPARSE; +#if defined(HAVE_WIN32) + if (ff_pkt->statp.st_rdev == WIN32_REPARSE_POINT) { + ff_pkt->type = FT_REPARSE; } +#endif /* * Note, we return the directory to the calling program (handle_file) * when we first see the directory (FT_DIRBEGIN. @@ -555,11 +557,16 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt, * to cross, or we may be restricted by a list of permitted * file systems. */ + bool is_win32_mount_point = false; +#if defined(HAVE_WIN32) + is_win32_mount_point = ff_pkt->statp.st_rdev == WIN32_MOUNT_POINT; +#endif if (!top_level && ff_pkt->flags & FO_NO_RECURSION) { ff_pkt->type = FT_NORECURSE; recurse = false; - } else if (!top_level && parent_device != ff_pkt->statp.st_dev) { - if(!(ff_pkt->flags & FO_MULTIFS)) { + } else if (!top_level && (parent_device != ff_pkt->statp.st_dev || + is_win32_mount_point)) { + if (!(ff_pkt->flags & FO_MULTIFS)) { ff_pkt->type = FT_NOFSCHG; recurse = false; } else if (!accept_fstype(ff_pkt, NULL)) { diff --git a/bacula/src/version.h b/bacula/src/version.h index d40560bdd0..8a7426aeb2 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -3,9 +3,9 @@ */ #undef VERSION -#define VERSION "2.2.10-b3" -#define BDATE "20 May 2008" -#define LSMDATE "20May08" +#define VERSION "2.2.10-b4" +#define BDATE "21 May 2008" +#define LSMDATE "21May08" #define PROG_COPYRIGHT "Copyright (C) %d-2008 Free Software Foundation Europe e.V.\n" #define BYEAR "2008" /* year for copyright messages in progs */ diff --git a/bacula/src/win32/compat/compat.cpp b/bacula/src/win32/compat/compat.cpp index f549e26612..a3171c3c30 100644 --- a/bacula/src/win32/compat/compat.cpp +++ b/bacula/src/win32/compat/compat.cpp @@ -644,6 +644,8 @@ statDir(const char *file, struct stat *sb) LocalFree((void *)err); errno = b_errno_win32; return -1; + } else { + FindClose(h); } sb->st_mode = 0777; /* start with everything */ @@ -655,12 +657,23 @@ statDir(const char *file, struct stat *sb) 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; - if (sb->st_rdev == 1 && *pdwReserved0 & IO_REPARSE_TAG_MOUNT_POINT) { - sb->st_rdev = 2; /* mount point */ - } - + /* + * 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; @@ -670,7 +683,6 @@ statDir(const char *file, struct stat *sb) 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; } @@ -679,11 +691,10 @@ int fstat(int fd, struct stat *sb) { BY_HANDLE_FILE_INFORMATION info; - char tmpbuf[1024]; if (!GetFileInformationByHandle((HANDLE)fd, &info)) { const char *err = errorString(); - Dmsg2(99, "GetfileInformationByHandle(%s): %s\n", tmpbuf, err); + Dmsg1(99, "GetfileInformationByHandle: %s\n", err); LocalFree((void *)err); errno = b_errno_win32; return -1; @@ -708,7 +719,11 @@ fstat(int fd, struct stat *sb) 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(100, "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; @@ -727,8 +742,8 @@ stat2(const char *file, struct stat *sb) { HANDLE h; int rval = 0; - char tmpbuf[1024]; - conv_unix_to_win32_path(file, tmpbuf, 1024); + char tmpbuf[5000]; + conv_unix_to_win32_path(file, tmpbuf, 5000); DWORD attr = (DWORD)-1; @@ -779,12 +794,11 @@ stat(const char *file, struct stat *sb) WIN32_FILE_ATTRIBUTE_DATA data; errno = 0; - memset(sb, 0, sizeof(*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); @@ -793,6 +807,7 @@ stat(const char *file, struct stat *sb) if (!b) { return stat2(file, sb); } + } else if (p_GetFileAttributesExA) { if (!p_GetFileAttributesExA(file, GetFileExInfoStandard, &data)) { return stat2(file, sb); @@ -842,6 +857,8 @@ stat(const char *file, struct stat *sb) 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; } @@ -2128,10 +2145,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, @@ -2139,9 +2156,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, @@ -2151,11 +2168,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; @@ -2170,49 +2187,49 @@ utime(const char *fname, struct utimbuf *times) 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; } diff --git a/bacula/technotes-2.1 b/bacula/technotes-2.1 index ff1cf72bcd..849ec4bbfe 100644 --- a/bacula/technotes-2.1 +++ b/bacula/technotes-2.1 @@ -2,6 +2,13 @@ General: +21May08 +kes Fix Win32 reparse points. Bacula will not recurse into any + reparse point directory, including mount points, unless the + directory is explicitly mentioned at the top level (same as + with Unix). A file that is linked to another file will be + backed up -- much as Unix does for hardlinked files. + This *should* fix bug #1041. 20May08 kes Remove double quotes from ChangeLog and ReleaseNotes kes Remove StorageId test when pruning and recycling (Eric's changes). -- 2.39.5