X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Ffindlib%2Fattribs.c;h=abd971997dd63a7ae25000b763933c970c0a81f2;hb=10cfd798ced2d27f61ead2de6fe9b1bcc8e3468d;hp=c1043308e82abf6be4097c13c067addd87010a67;hpb=c66ccc7c4feb53846ddfa3223fccf7a9ea0614e4;p=bacula%2Fbacula diff --git a/bacula/src/findlib/attribs.c b/bacula/src/findlib/attribs.c index c1043308e8..abd971997d 100644 --- a/bacula/src/findlib/attribs.c +++ b/bacula/src/findlib/attribs.c @@ -1,31 +1,22 @@ /* - Bacula® - The Network Backup Solution - - Copyright (C) 2002-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 three of the GNU Affero 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 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 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. + 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 * Extended attributes for Win32 and * other non-Unix systems, or Unix systems with ACLs, ... @@ -34,26 +25,35 @@ * */ +//#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 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 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 /*=============================================================*/ /* */ @@ -61,7 +61,125 @@ 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 */ int select_data_stream(FF_PKT *ff_pkt) @@ -74,15 +192,15 @@ int select_data_stream(FF_PKT *ff_pkt) return STREAM_FILE_DATA; } - /** + /* * Fix all incompatible options */ - /** No sparse option for encrypted data */ + /* No sparse option for encrypted data */ if (ff_pkt->flags & FO_ENCRYPT) { ff_pkt->flags &= ~FO_SPARSE; } - /** Note, no sparse option for win32_data */ + /* Note, no sparse option for win32_data */ if (!is_portable_backup(&ff_pkt->bfd)) { stream = STREAM_WIN32_DATA; ff_pkt->flags &= ~FO_SPARSE; @@ -95,40 +213,66 @@ int select_data_stream(FF_PKT *ff_pkt) stream = STREAM_SPARSE_DATA; } - /** Encryption is only supported for file data */ + /* Encryption is only supported for file data */ if (stream != STREAM_FILE_DATA && stream != STREAM_WIN32_DATA && stream != STREAM_MACOS_FORK_DATA) { ff_pkt->flags &= ~FO_ENCRYPT; } - /** Compression is not supported for Mac fork data */ + /* 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 @@ -140,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. */ @@ -159,7 +309,7 @@ int select_data_stream(FF_PKT *ff_pkt) } -/** +/* * Encode a stat structure into a base64 character string * All systems must create such a structure. * In addition, we tack on the LinkFI, which is non-zero in @@ -170,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, struct stat *statp, int32_t LinkFI, int data_stream) +void encode_stat(char *buf, struct stat *statp, int stat_size, int32_t LinkFI, int data_stream) { char *p = buf; + /* + * 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)LinkFI, p); + p += to_base64((int64_t)LinkFI, p); *p++ = ' '; #ifdef HAVE_CHFLAGS @@ -222,11 +378,14 @@ void encode_stat(char *buf, struct stat *statp, int32_t LinkFI, 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 @@ -244,11 +403,22 @@ void encode_stat(char *buf, struct stat *statp, int32_t LinkFI, 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); @@ -326,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) +/* Decode a LinkFI field of encoded stat packet */ +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 */ @@ -371,7 +558,7 @@ int32_t decode_LinkFI(char *buf, struct stat *statp) return 0; } -/** +/* * Set file modes, permissions and times * * fname is the original filename @@ -382,18 +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 (uid_set) { + + if (!uid_set) { my_uid = getuid(); my_gid = getgid(); uid_set = true; } -#if defined(HAVE_WIN32) +#ifdef HAVE_WIN32 if (attr->stream == STREAM_UNIX_ATTRIBUTES_EX && set_win32_attributes(jcr, attr, ofd)) { if (is_bopen(ofd)) { @@ -403,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); } @@ -411,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), @@ -432,7 +617,7 @@ bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) } } - /** + /* * We do not restore sockets, so skip trying to restore their * attributes. */ @@ -440,54 +625,49 @@ 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) { - /** Change owner of link, not of real file */ - if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && my_uid == 0) { +#ifdef HAVE_LCHOWN + /* Change owner of link, not of real file */ + 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 && my_uid == 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 && my_uid == 0) { - 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. - */ - if (utime(attr->ofname, &ut) < 0 && my_uid == 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 times %s: ERR=%s\n"), attr->ofname, be.bstrerror()); ok = false; } +#endif + } else { + /* + * At this point, we have a file that is not a LINK + */ + ok = set_mod_own_time(jcr, ofd, attr); + #ifdef HAVE_CHFLAGS - /** + /* * FreeBSD user flags * * Note, this should really be done before the utime() above, * but if the immutable bit is set, it will make the utimes() * fail. */ - if (chflags(attr->ofname, attr->statp.st_flags) < 0 && my_uid == 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()); @@ -497,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; @@ -509,9 +692,9 @@ bail_out: /* */ /*=============================================================*/ -#if !defined(HAVE_WIN32) +#ifndef HAVE_WIN32 -/** +/* * It is possible to piggyback additional data e.g. ACLs on * the encode_stat() data by returning the extended attributes * here. They must be "self-contained" (i.e. you keep track @@ -523,7 +706,7 @@ bail_out: int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) { #ifdef HAVE_DARWIN_OS - /** + /* * We save the Mac resource fork length so that on a * restore, we can be sure we put back the whole resource. */ @@ -554,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) { @@ -570,12 +753,12 @@ int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) 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, + BOOL b=p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, (LPVOID)&atts); free_pool_memory(pwszBuf); @@ -586,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)) { @@ -616,7 +799,7 @@ int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) return STREAM_UNIX_ATTRIBUTES_EX; } -/** Define attributes that are legal to set with SetFileAttributes() */ +/* Define attributes that are legal to set with SetFileAttributes() */ #define SET_ATTRS ( \ FILE_ATTRIBUTE_ARCHIVE| \ FILE_ATTRIBUTE_HIDDEN| \ @@ -627,8 +810,7 @@ int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) FILE_ATTRIBUTE_SYSTEM| \ FILE_ATTRIBUTE_TEMPORARY) - -/** +/* * Set Extended File Attributes for Win32 * * fname is the original filename @@ -645,7 +827,7 @@ static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) ULARGE_INTEGER li; POOLMEM *win32_ofile; - /** if we have neither Win ansi nor wchar API, get out */ + /* if we have neither Win ansi nor wchar API, get out */ if (!(p_SetFileAttributesW || p_SetFileAttributesA)) { return false; } @@ -684,11 +866,11 @@ static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) p += from_base64(&val, p); plug(atts.nFileSizeLow, val); - /** Convert to Windows path format */ + /* Convert to Windows path format */ win32_ofile = get_pool_memory(PM_FNAME); unix_name_to_win32(&win32_ofile, attr->ofname); - /** At this point, we have reconstructed the WIN32_FILE_ATTRIBUTE_DATA pkt */ + /* At this point, we have reconstructed the WIN32_FILE_ATTRIBUTE_DATA pkt */ if (!is_bopen(ofd)) { Dmsg1(100, "File not open: %s\n", attr->ofname); @@ -701,26 +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 (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); } } } @@ -728,7 +942,7 @@ static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) return true; } -void win_error(JCR *jcr, const char *prefix, POOLMEM *win32_ofile) +void win_error(JCR *jcr, int type, const char *prefix, POOLMEM *win32_ofile) { DWORD lerror = GetLastError(); LPTSTR msg; @@ -742,10 +956,15 @@ void win_error(JCR *jcr, const 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); - Jmsg3(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, 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; @@ -760,9 +979,8 @@ void win_error(JCR *jcr, const 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 */