X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Ffindlib%2Fattribs.c;h=abd971997dd63a7ae25000b763933c970c0a81f2;hb=10cfd798ced2d27f61ead2de6fe9b1bcc8e3468d;hp=bbb9117911d3a932eea261f1644cc01678bef63b;hpb=ab54e24ec150b9593621e898207605a94f135b29;p=bacula%2Fbacula diff --git a/bacula/src/findlib/attribs.c b/bacula/src/findlib/attribs.c index bbb9117911..abd971997d 100644 --- a/bacula/src/findlib/attribs.c +++ b/bacula/src/findlib/attribs.c @@ -1,29 +1,20 @@ /* - Bacula® - The Network Backup Solution - - Copyright (C) 2002-2007 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 plus additions - that are listed 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 John Walker. - The licensor of Bacula is the Free Software Foundation Europe - (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, - Switzerland, email:ftf@fsfeurope.org. + Bacula(R) - The Network Backup Solution + + Copyright (C) 2000-2017 Kern Sibbald + + The original author of Bacula is Kern Sibbald, with contributions + from many others, a complete list can be found in the file AUTHORS. + + You may use this file and others of this release according to the + license defined in the LICENSE file, which includes the Affero General + Public License, v3.0 ("AGPLv3") and some additional permissions and + terms pursuant to its AGPLv3 Section 7. + + This notice must be preserved when any source code is + conveyed and/or propagated. + + Bacula(R) is a registered trademark of Kern Sibbald. */ /* * Encode and decode standard Unix attributes and @@ -32,25 +23,37 @@ * * Kern Sibbald, October MMII * - * Version $Id$ - * */ +//#define _POSIX_C_SOURCE 200809L +//#define _BSD_SOURCE 1 + #include "bacula.h" #include "find.h" +#include "ch.h" + +static uid_t my_uid = 1; +static gid_t my_gid = 1; +static bool uid_set = false; -#if defined(HAVE_WIN32) -/* Forward referenced subroutines */ +#ifdef HAVE_WIN32 +/* Forward referenced Windows subroutines */ static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd); -void unix_name_to_win32(POOLMEM **win32_name, char *name); -void win_error(JCR *jcr, char *prefix, POOLMEM *ofile); +void unix_name_to_win32(POOLMEM **win32_name, const char *name); +void win_error(JCR *jcr, int type, const char *prefix, POOLMEM *ofile); +void win_error(JCR *jcr, const char *prefix, POOLMEM *ofile); HANDLE bget_handle(BFILE *bfd); #endif /* HAVE_WIN32 */ -/* For old systems that don't have lchown() use chown() */ +/* + * For old systems that don't have lchown() or lchmod() + */ #ifndef HAVE_LCHOWN #define lchown chown #endif +#ifndef HAVE_LCHMOD +#define lchmod chmod +#endif /*=============================================================*/ /* */ @@ -58,6 +61,124 @@ HANDLE bget_handle(BFILE *bfd); /* */ /*=============================================================*/ +/* + * To turn off use of fchown(), fchmod(), or futimes(), + * uncomment one or more of the following. + */ +//#undef HAVE_FCHOWN +//#undef HAVE_FCHMOD +//#undef HAVE_FUTIMES + +/* + * Print errors only if debug level defined or we are root. + * root should not get errors. Errors for users causes + * too much output. + */ +#define print_error(jcr) (chk_dbglvl(100) || (my_uid == 0 && (!jcr || jcr->job_uid == 0))) + +/* + * Restore the owner and permissions (mode) of a Directory. + * See attribs.c for the equivalent for files. + */ +void set_own_mod(ATTR *attr, char *path, uid_t owner, gid_t group, mode_t mode) +{ + if (lchown(path, owner, group) != 0 && print_error(attr->jcr) +#ifdef AFS + && errno != EPERM +#endif + ) { + berrno be; + Jmsg4(attr->jcr, M_WARNING, 0, _("Cannot change owner and/or group of %s: ERR=%s %d %d\n"), + path, be.bstrerror(), getuid(), attr->jcr->job_uid); + } + if (lchmod(path, mode) != 0 && print_error(attr->jcr)) { + berrno be; + Jmsg2(attr->jcr, M_WARNING, 0, _("Cannot change permissions of %s: ERR=%s\n"), + path, be.bstrerror()); + } +} + + +bool set_mod_own_time(JCR *jcr, BFILE *ofd, ATTR *attr) +{ + bool ok = true; + struct utimbuf ut; + + /* Do not try to set rights with f functions when using a plugin */ + if (is_bopen(ofd) && !ofd->cmd_plugin) { /* TODO: Look with opt_plugin */ + /* + * The #ifdefing is a bit ugly, but it is the only + * way we can ensure this works on older systems. + */ +#ifdef HAVE_FCHOWN + if (fchown(ofd->fid, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error(jcr)) { +#else + if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error(jcr)) { +#endif + berrno be; + Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"), + attr->ofname, be.bstrerror()); + ok = false; + } + +#ifdef HAVE_FCHMOD + if (fchmod(ofd->fid, attr->statp.st_mode) < 0 && print_error(jcr)) { +#else + if (lchmod(attr->ofname, attr->statp.st_mode) < 0 && print_error(jcr)) { +#endif + berrno be; + Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"), + attr->ofname, be.bstrerror()); + ok = false; + } + +#ifdef HAVE_FUTIMES + struct timeval times[2]; + times[0].tv_sec = attr->statp.st_atime; + times[0].tv_usec = 0; + times[1].tv_sec = attr->statp.st_mtime; + times[1].tv_usec = 0; + if (futimes(ofd->fid, times) < 0 && print_error(jcr)) { +#else + ut.actime = attr->statp.st_atime; + ut.modtime = attr->statp.st_mtime; + //bclose(ofd); + if (utime(attr->ofname, &ut) < 0 && print_error(jcr)) { +#endif + berrno be; + Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"), + attr->ofname, be.bstrerror()); + ok = false; + } + } else { + if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error(jcr)) { + berrno be; + Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"), + attr->ofname, be.bstrerror()); + ok = false; + } + if (lchmod(attr->ofname, attr->statp.st_mode) < 0 && print_error(jcr)) { + berrno be; + Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"), + attr->ofname, be.bstrerror()); + ok = false; + } + /* + * Reset file times. + */ + ut.actime = attr->statp.st_atime; + ut.modtime = attr->statp.st_mtime; + + if (utime(attr->ofname, &ut) < 0 && print_error(jcr)) { + berrno be; + Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"), + attr->ofname, be.bstrerror()); + ok = false; + } + } + return ok; +} + /* * Return the data stream that will be used */ @@ -65,10 +186,15 @@ int select_data_stream(FF_PKT *ff_pkt) { int stream; + /* This is a plugin special restore object */ + if (ff_pkt->type == FT_RESTORE_FIRST) { + ff_pkt->flags = 0; + return STREAM_FILE_DATA; + } + /* * Fix all incompatible options */ - /* No sparse option for encrypted data */ if (ff_pkt->flags & FO_ENCRYPT) { ff_pkt->flags &= ~FO_SPARSE; @@ -83,6 +209,9 @@ int select_data_stream(FF_PKT *ff_pkt) } else { stream = STREAM_FILE_DATA; } + if (ff_pkt->flags & FO_OFFSETS) { + stream = STREAM_SPARSE_DATA; + } /* Encryption is only supported for file data */ if (stream != STREAM_FILE_DATA && stream != STREAM_WIN32_DATA && @@ -92,30 +221,58 @@ int select_data_stream(FF_PKT *ff_pkt) /* Compression is not supported for Mac fork data */ if (stream == STREAM_MACOS_FORK_DATA) { - ff_pkt->flags &= ~FO_GZIP; + ff_pkt->flags &= ~FO_COMPRESS; } /* * Handle compression and encryption options */ -#ifdef HAVE_LIBZ - if (ff_pkt->flags & FO_GZIP) { - switch (stream) { - case STREAM_WIN32_DATA: - stream = STREAM_WIN32_GZIP_DATA; - break; - case STREAM_SPARSE_DATA: - stream = STREAM_SPARSE_GZIP_DATA; - break; - case STREAM_FILE_DATA: - stream = STREAM_GZIP_DATA; - break; - default: - /* All stream types that do not support gzip should clear out - * FO_GZIP above, and this code block should be unreachable. */ - ASSERT(!(ff_pkt->flags & FO_GZIP)); - return STREAM_NONE; - } +#if defined(HAVE_LIBZ) || defined(HAVE_LZO) + if (ff_pkt->flags & FO_COMPRESS) { + #ifdef HAVE_LIBZ + if(ff_pkt->Compress_algo == COMPRESS_GZIP) { + switch (stream) { + case STREAM_WIN32_DATA: + stream = STREAM_WIN32_GZIP_DATA; + break; + case STREAM_SPARSE_DATA: + stream = STREAM_SPARSE_GZIP_DATA; + break; + case STREAM_FILE_DATA: + stream = STREAM_GZIP_DATA; + break; + default: + /* + * All stream types that do not support compression should clear out + * FO_COMPRESS above, and this code block should be unreachable. + */ + ASSERT(!(ff_pkt->flags & FO_COMPRESS)); + return STREAM_NONE; + } + } + #endif + #ifdef HAVE_LZO + if(ff_pkt->Compress_algo == COMPRESS_LZO1X) { + switch (stream) { + case STREAM_WIN32_DATA: + stream = STREAM_WIN32_COMPRESSED_DATA; + break; + case STREAM_SPARSE_DATA: + stream = STREAM_SPARSE_COMPRESSED_DATA; + break; + case STREAM_FILE_DATA: + stream = STREAM_COMPRESSED_DATA; + break; + default: + /* + * All stream types that do not support compression should clear out + * FO_COMPRESS above, and this code block should be unreachable. + */ + ASSERT(!(ff_pkt->flags & FO_COMPRESS)); + return STREAM_NONE; + } + } + #endif } #endif #ifdef HAVE_CRYPTO @@ -127,12 +284,18 @@ int select_data_stream(FF_PKT *ff_pkt) case STREAM_WIN32_GZIP_DATA: stream = STREAM_ENCRYPTED_WIN32_GZIP_DATA; break; + case STREAM_WIN32_COMPRESSED_DATA: + stream = STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA; + break; case STREAM_FILE_DATA: stream = STREAM_ENCRYPTED_FILE_DATA; break; case STREAM_GZIP_DATA: stream = STREAM_ENCRYPTED_FILE_GZIP_DATA; break; + case STREAM_COMPRESSED_DATA: + stream = STREAM_ENCRYPTED_FILE_COMPRESSED_DATA; + break; default: /* All stream types that do not support encryption should clear out * FO_ENCRYPT above, and this code block should be unreachable. */ @@ -157,48 +320,54 @@ int select_data_stream(FF_PKT *ff_pkt) * them in the encode_attribsEx() subroutine, but this is * not recommended. */ -void encode_stat(char *buf, FF_PKT *ff_pkt, int data_stream) +void encode_stat(char *buf, struct stat *statp, int stat_size, int32_t LinkFI, int data_stream) { char *p = buf; - struct stat *statp = &ff_pkt->statp; + /* + * We read the stat packet so make sure the caller's conception + * is the same as ours. They can be different if LARGEFILE is not + * the same when compiling this library and the calling program. + */ + ASSERT(stat_size == (int)sizeof(struct stat)); + /* * Encode a stat packet. I should have done this more intelligently * with a length so that it could be easily expanded. */ - p += to_base64((int64_t)statp->st_dev, p); + p += to_base64((int64_t)statp->st_dev, p); *p++ = ' '; /* separate fields with a space */ - p += to_base64((int64_t)statp->st_ino, p); + p += to_base64((int64_t)statp->st_ino, p); *p++ = ' '; - p += to_base64((int64_t)statp->st_mode, p); + p += to_base64((int64_t)statp->st_mode, p); *p++ = ' '; - p += to_base64((int64_t)statp->st_nlink, p); + p += to_base64((int64_t)statp->st_nlink, p); *p++ = ' '; - p += to_base64((int64_t)statp->st_uid, p); + p += to_base64((int64_t)statp->st_uid, p); *p++ = ' '; - p += to_base64((int64_t)statp->st_gid, p); + p += to_base64((int64_t)statp->st_gid, p); *p++ = ' '; - p += to_base64((int64_t)statp->st_rdev, p); + p += to_base64((int64_t)statp->st_rdev, p); *p++ = ' '; - p += to_base64((int64_t)statp->st_size, p); + p += to_base64((int64_t)statp->st_size, p); *p++ = ' '; #ifndef HAVE_MINGW - p += to_base64((int64_t)statp->st_blksize, p); + p += to_base64((int64_t)statp->st_blksize, p); *p++ = ' '; - p += to_base64((int64_t)statp->st_blocks, p); + p += to_base64((int64_t)statp->st_blocks, p); *p++ = ' '; #else - p += to_base64((int64_t)0, p); /* output place holder */ + p += to_base64((int64_t)0, p); /* output place holder */ *p++ = ' '; - p += to_base64((int64_t)0, p); /* output place holder */ + p += to_base64((int64_t)0, p); /* output place holder */ *p++ = ' '; #endif - p += to_base64((int64_t)statp->st_atime, p); + p += to_base64((int64_t)statp->st_atime, p); *p++ = ' '; - p += to_base64((int64_t)statp->st_mtime, p); + p += to_base64((int64_t)statp->st_mtime, p); *p++ = ' '; p += to_base64((int64_t)statp->st_ctime, p); *p++ = ' '; - p += to_base64((int64_t)ff_pkt->LinkFI, p); + p += to_base64((int64_t)LinkFI, p); *p++ = ' '; #ifdef HAVE_CHFLAGS @@ -209,11 +378,14 @@ void encode_stat(char *buf, FF_PKT *ff_pkt, int data_stream) #endif *p++ = ' '; p += to_base64((int64_t)data_stream, p); +#ifdef HAVE_MINGW + *p++ = ' '; + p += to_base64((int64_t)statp->st_fattrs, p); +#endif *p = 0; return; } - /* Do casting according to unknown type to keep compiler happy */ #ifdef HAVE_TYPEOF #define plug(st, val) st = (typeof st)val @@ -221,6 +393,8 @@ void encode_stat(char *buf, FF_PKT *ff_pkt, int data_stream) #if !HAVE_GCC & HAVE_SUN_OS /* Sun compiler does not handle templates correctly */ #define plug(st, val) st = val + #elif __sgi + #define plug(st, val) st = val #else /* Use templates to do the casting */ template void plug(T &st, uint64_t val) @@ -229,11 +403,22 @@ void encode_stat(char *buf, FF_PKT *ff_pkt, int data_stream) #endif -/* Decode a stat packet from base64 characters */ -int decode_stat(char *buf, struct stat *statp, int32_t *LinkFI) +/* + * Decode a stat packet from base64 characters + * returns: data_stream + */ +int decode_stat(char *buf, struct stat *statp, int stat_size, int32_t *LinkFI) { char *p = buf; int64_t val; + int data_stream; + + /* + * We store into the stat packet so make sure the caller's conception + * is the same as ours. They can be different if LARGEFILE is not + * the same when compiling this library and the calling program. + */ + ASSERT(stat_size == (int)sizeof(struct stat)); p += from_base64(&val, p); plug(statp->st_dev, val); @@ -311,14 +496,31 @@ int decode_stat(char *buf, struct stat *statp, int32_t *LinkFI) } else { val = 0; } - return (int)val; + data_stream = val; +#ifdef HAVE_MINGW + if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) { + p++; + p += from_base64(&val, p); + plug(statp->st_fattrs, val); + } else { + statp->st_fattrs = 0; + val = 0; + } +#endif + return data_stream; } /* Decode a LinkFI field of encoded stat packet */ -int32_t decode_LinkFI(char *buf, struct stat *statp) +int32_t decode_LinkFI(char *buf, struct stat *statp, int stat_size) { char *p = buf; int64_t val; + /* + * We store into the stat packet so make sure the caller's conception + * is the same as ours. They can be different if LARGEFILE is not + * the same when compiling this library and the calling program. + */ + ASSERT(stat_size == (int)sizeof(struct stat)); skip_nonspaces(&p); /* st_dev */ p++; /* skip space */ @@ -367,12 +569,17 @@ int32_t decode_LinkFI(char *buf, struct stat *statp) */ bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) { - struct utimbuf ut; mode_t old_mask; bool ok = true; boffset_t fsize; -#if defined(HAVE_WIN32) + if (!uid_set) { + my_uid = getuid(); + my_gid = getgid(); + uid_set = true; + } + +#ifdef HAVE_WIN32 if (attr->stream == STREAM_UNIX_ATTRIBUTES_EX && set_win32_attributes(jcr, attr, ofd)) { if (is_bopen(ofd)) { @@ -382,7 +589,8 @@ bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) return true; } if (attr->data_stream == STREAM_WIN32_DATA || - attr->data_stream == STREAM_WIN32_GZIP_DATA) { + attr->data_stream == STREAM_WIN32_GZIP_DATA || + attr->data_stream == STREAM_WIN32_COMPRESSED_DATA) { if (is_bopen(ofd)) { bclose(ofd); } @@ -390,20 +598,18 @@ bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) return true; } - /* * If Windows stuff failed, e.g. attempt to restore Unix file * to Windows, simply fall through and we will do it the * universal way. */ -#endif +#endif /* HAVE_WIN32 */ old_mask = umask(0); if (is_bopen(ofd)) { char ec1[50], ec2[50]; fsize = blseek(ofd, 0, SEEK_END); - bclose(ofd); /* first close file */ - if (attr->type == FT_REG && fsize > 0 && attr->statp.st_size > 0 && + if (attr->type == FT_REG && fsize > 0 && attr->statp.st_size > 0 && fsize != (boffset_t)attr->statp.st_size) { Jmsg3(jcr, M_ERROR, 0, _("File size of restored file %s not correct. Original %s, restored %s.\n"), attr->ofname, edit_uint64(attr->statp.st_size, ec1), @@ -419,45 +625,40 @@ bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) goto bail_out; } - ut.actime = attr->statp.st_atime; - ut.modtime = attr->statp.st_mtime; - /* ***FIXME**** optimize -- don't do if already correct */ /* * For link, change owner of link using lchown, but don't * try to do a chmod as that will update the file behind it. */ if (attr->type == FT_LNK) { +#ifdef HAVE_LCHOWN /* Change owner of link, not of real file */ - if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0) { + if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error(jcr)) { berrno be; Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"), attr->ofname, be.bstrerror()); ok = false; } - } else { - if (chown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0) { - berrno be; - Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"), - attr->ofname, be.bstrerror()); - ok = false; - } - if (chmod(attr->ofname, attr->statp.st_mode) < 0) { +#endif +#ifdef HAVE_LUTIMES + struct timeval times[2]; + times[0].tv_sec = attr->statp.st_atime; + times[0].tv_usec = 0; + times[1].tv_sec = attr->statp.st_mtime; + times[1].tv_usec = 0; + if (lutimes(attr->ofname, times) < 0 && print_error(jcr)) { berrno be; - Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"), + Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"), attr->ofname, be.bstrerror()); ok = false; } - +#endif + } else { /* - * Reset file times. + * At this point, we have a file that is not a LINK */ - if (utime(attr->ofname, &ut) < 0) { - berrno be; - Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"), - attr->ofname, be.bstrerror()); - ok = false; - } + ok = set_mod_own_time(jcr, ofd, attr); + #ifdef HAVE_CHFLAGS /* * FreeBSD user flags @@ -466,7 +667,7 @@ bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) * but if the immutable bit is set, it will make the utimes() * fail. */ - if (chflags(attr->ofname, attr->statp.st_flags) < 0) { + if (chflags(attr->ofname, attr->statp.st_flags) < 0 && print_error(jcr)) { berrno be; Jmsg2(jcr, M_ERROR, 0, _("Unable to set file flags %s: ERR=%s\n"), attr->ofname, be.bstrerror()); @@ -476,6 +677,9 @@ bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) } bail_out: + if (is_bopen(ofd)) { + bclose(ofd); + } pm_strcpy(attr->ofname, "*none*"); umask(old_mask); return ok; @@ -488,7 +692,7 @@ bail_out: /* */ /*=============================================================*/ -#if !defined(HAVE_WIN32) +#ifndef HAVE_WIN32 /* * It is possible to piggyback additional data e.g. ACLs on @@ -507,6 +711,11 @@ int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) * restore, we can be sure we put back the whole resource. */ char *p; + + *attribsEx = 0; /* no extended attributes (yet) */ + if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) { + return STREAM_UNIX_ATTRIBUTES; + } p = attribsEx; if (ff_pkt->flags & FO_HFSPLUS) { p += to_base64((uint64_t)(ff_pkt->hfsinfo.rsrclength), p); @@ -528,7 +737,7 @@ int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) /* */ /*=============================================================*/ -#if defined(HAVE_WIN32) +#ifdef HAVE_WIN32 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) { @@ -538,14 +747,19 @@ int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) attribsEx[0] = 0; /* no extended attributes */ + if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) { + return STREAM_UNIX_ATTRIBUTES; + } + unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname); - // try unicode version + /* try unicode version */ if (p_GetFileAttributesExW) { - POOLMEM* pwszBuf = get_pool_memory (PM_FNAME); + POOLMEM* pwszBuf = get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, ff_pkt->fname); - BOOL b=p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, (LPVOID)&atts); + BOOL b=p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, + (LPVOID)&atts); free_pool_memory(pwszBuf); if (!b) { @@ -555,7 +769,7 @@ int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) } else { if (!p_GetFileAttributesExA) - return STREAM_UNIX_ATTRIBUTES; + return STREAM_UNIX_ATTRIBUTES; if (!p_GetFileAttributesExA(ff_pkt->sys_fname, GetFileExInfoStandard, (LPVOID)&atts)) { @@ -596,7 +810,6 @@ int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) FILE_ATTRIBUTE_SYSTEM| \ FILE_ATTRIBUTE_TEMPORARY) - /* * Set Extended File Attributes for Win32 * @@ -614,9 +827,10 @@ static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) ULARGE_INTEGER li; POOLMEM *win32_ofile; - // if we have neither ansi nor wchar version, we leave - if (!(p_SetFileAttributesW || p_SetFileAttributesA)) + /* if we have neither Win ansi nor wchar API, get out */ + if (!(p_SetFileAttributesW || p_SetFileAttributesA)) { return false; + } if (!p || !*p) { /* we should have attributes */ Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", attr->ofname, ofd->fid); @@ -669,27 +883,58 @@ static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) &atts.ftCreationTime, &atts.ftLastAccessTime, &atts.ftLastWriteTime)) { - win_error(jcr, "SetFileTime:", win32_ofile); + win_error(jcr, M_WARNING, "SetFileTime:", win32_ofile); } + + /* + * Inform win32 api that the given file is a sparse file + */ + if (atts.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) { + DWORD bytesReturned; + + Dmsg1(100, "Set FILE_ATTRIBUTE_SPARSE_FILE on %s\n", attr->ofname); + if (!DeviceIoControl(bget_handle(ofd), FSCTL_SET_SPARSE, + NULL, 0, NULL, 0, &bytesReturned, NULL)) + { + /* Not sure we really want to have a Warning for such attribute */ + win_error(jcr, M_WARNING, "set SPARSE_FILE:", win32_ofile); + } + } + + /* + * Restore the file as compressed. + */ + if (atts.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) { + int fmt = COMPRESSION_FORMAT_DEFAULT; + DWORD bytesReturned; + + Dmsg1(100, "Set FILE_ATTRIBUTE_COMPRESSED on %s\n", attr->ofname); + if (!DeviceIoControl(bget_handle(ofd), FSCTL_SET_COMPRESSION, + &fmt, sizeof(fmt), NULL, 0, &bytesReturned, NULL)) + { + /* Not sure we really want to have a Warning for such attribute */ + win_error(jcr, M_WARNING, "set COMPRESSED:", win32_ofile); + } + } + bclose(ofd); } Dmsg1(100, "SetFileAtts %s\n", attr->ofname); - if (!(atts.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - { + if (!(atts.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { if (p_SetFileAttributesW) { - POOLMEM* pwszBuf = get_pool_memory (PM_FNAME); + POOLMEM* pwszBuf = get_pool_memory(PM_FNAME); make_win32_path_UTF8_2_wchar(&pwszBuf, attr->ofname); BOOL b=p_SetFileAttributesW((LPCWSTR)pwszBuf, atts.dwFileAttributes & SET_ATTRS); free_pool_memory(pwszBuf); - - if (!b) - win_error(jcr, "SetFileAttributesW:", win32_ofile); + + if (!b) + win_error(jcr, M_WARNING, "SetFileAttributesW:", win32_ofile); } else { if (!p_SetFileAttributesA(win32_ofile, atts.dwFileAttributes & SET_ATTRS)) { - win_error(jcr, "SetFileAttributesA:", win32_ofile); + win_error(jcr, M_WARNING, "SetFileAttributesA:", win32_ofile); } } } @@ -697,7 +942,7 @@ static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) return true; } -void win_error(JCR *jcr, char *prefix, POOLMEM *win32_ofile) +void win_error(JCR *jcr, int type, const char *prefix, POOLMEM *win32_ofile) { DWORD lerror = GetLastError(); LPTSTR msg; @@ -711,11 +956,16 @@ void win_error(JCR *jcr, char *prefix, POOLMEM *win32_ofile) NULL); Dmsg3(100, "Error in %s on file %s: ERR=%s\n", prefix, win32_ofile, msg); strip_trailing_junk(msg); - Jmsg(jcr, M_ERROR, 0, _("Error in %s file %s: ERR=%s\n"), prefix, win32_ofile, msg); + Jmsg3(jcr, type, 0, _("Error in %s file %s: ERR=%s\n"), prefix, win32_ofile, msg); LocalFree(msg); } -void win_error(JCR *jcr, char *prefix, DWORD lerror) +void win_error(JCR *jcr, const char *prefix, POOLMEM *win32_ofile) +{ + win_error(jcr, M_ERROR, prefix, win32_ofile); +} + +void win_error(JCR *jcr, const char *prefix, DWORD lerror) { LPTSTR msg; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER| @@ -729,9 +979,8 @@ void win_error(JCR *jcr, char *prefix, DWORD lerror) strip_trailing_junk(msg); if (jcr) { Jmsg2(jcr, M_ERROR, 0, _("Error in %s: ERR=%s\n"), prefix, msg); - } else { MessageBox(NULL, msg, prefix, MB_OK); } LocalFree(msg); } -#endif /* HAVE_WIN32 */ +#endif /* HAVE_WIN32 */