X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Ffindlib%2Fattribs.c;h=abd971997dd63a7ae25000b763933c970c0a81f2;hb=10cfd798ced2d27f61ead2de6fe9b1bcc8e3468d;hp=cc5e20f000a2bc059eb97846f60b96465b4e6a8a;hpb=fc38f5f8fd46fc30f7518db365758d20abd8de21;p=bacula%2Fbacula diff --git a/bacula/src/findlib/attribs.c b/bacula/src/findlib/attribs.c old mode 100755 new mode 100644 index cc5e20f000..abd971997d --- a/bacula/src/findlib/attribs.c +++ b/bacula/src/findlib/attribs.c @@ -1,3 +1,21 @@ +/* + 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 @@ -5,48 +23,37 @@ * * Kern Sibbald, October MMII * - * Version $Id$ - * */ -/* - Copyright (C) 2002-2005 Kern Sibbald - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - 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., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. - - */ +//#define _POSIX_C_SOURCE 200809L +//#define _BSD_SOURCE 1 #include "bacula.h" #include "find.h" +#include "ch.h" -#if defined(HAVE_CYGWIN) || defined(HAVE_WIN32) +static uid_t my_uid = 1; +static gid_t my_gid = 1; +static bool uid_set = false; -#include "../lib/winapi.h" - - -/* 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 +#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 /*=============================================================*/ /* */ @@ -54,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 */ @@ -61,6 +186,20 @@ 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; + } + /* Note, no sparse option for win32_data */ if (!is_portable_backup(&ff_pkt->bfd)) { stream = STREAM_WIN32_DATA; @@ -70,17 +209,102 @@ int select_data_stream(FF_PKT *ff_pkt) } else { stream = STREAM_FILE_DATA; } -#ifdef HAVE_LIBZ - if (ff_pkt->flags & FO_GZIP) { - if (stream == STREAM_WIN32_DATA) { - stream = STREAM_WIN32_GZIP_DATA; - } else if (stream == STREAM_FILE_DATA) { - stream = STREAM_GZIP_DATA; - } else { - stream = STREAM_SPARSE_GZIP_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 && + stream != STREAM_MACOS_FORK_DATA) { + ff_pkt->flags &= ~FO_ENCRYPT; + } + + /* Compression is not supported for Mac fork data */ + if (stream == STREAM_MACOS_FORK_DATA) { + ff_pkt->flags &= ~FO_COMPRESS; + } + + /* + * Handle compression and encryption options + */ +#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 + if (ff_pkt->flags & FO_ENCRYPT) { + switch (stream) { + case STREAM_WIN32_DATA: + stream = STREAM_ENCRYPTED_WIN32_DATA; + break; + 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. */ + ASSERT(!(ff_pkt->flags & FO_ENCRYPT)); + return STREAM_NONE; } } #endif + return stream; } @@ -96,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 @@ -148,25 +378,47 @@ 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 */ -#if !HAVE_GCC & HAVE_SUN_OS -#define plug(st, val) st = val /* brain damaged compiler */ +#ifdef HAVE_TYPEOF + #define plug(st, val) st = (typeof st)val #else -template void plug(T &st, uint64_t val) - { st = static_cast(val); } + #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) + { st = static_cast(val); } + #endif #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); @@ -244,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 */ @@ -300,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; - off_t fsize; + boffset_t fsize; + + if (!uid_set) { + my_uid = getuid(); + my_gid = getgid(); + uid_set = true; + } -#if defined(HAVE_CYGWIN) || defined(HAVE_WIN32) +#ifdef HAVE_WIN32 if (attr->stream == STREAM_UNIX_ATTRIBUTES_EX && set_win32_attributes(jcr, attr, ofd)) { if (is_bopen(ofd)) { @@ -315,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); } @@ -323,28 +598,32 @@ 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 (fsize > 0 && fsize != (off_t)attr->statp.st_size) { + 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), edit_uint64(fsize, ec2)); } } - ut.actime = attr->statp.st_atime; - ut.modtime = attr->statp.st_mtime; + /* + * We do not restore sockets, so skip trying to restore their + * attributes. + */ + if (attr->type == FT_SPEC && S_ISSOCK(attr->statp.st_mode)) { + goto bail_out; + } /* ***FIXME**** optimize -- don't do if already correct */ /* @@ -352,36 +631,34 @@ bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) * 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.strerror()); + 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.strerror()); - 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"), - attr->ofname, be.strerror()); + 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.strerror()); - ok = false; - } + ok = set_mod_own_time(jcr, ofd, attr); + #ifdef HAVE_CHFLAGS /* * FreeBSD user flags @@ -390,14 +667,19 @@ 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.strerror()); + attr->ofname, be.bstrerror()); ok = false; } #endif } + +bail_out: + if (is_bopen(ofd)) { + bclose(ofd); + } pm_strcpy(attr->ofname, "*none*"); umask(old_mask); return ok; @@ -410,7 +692,7 @@ bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) /* */ /*=============================================================*/ -#if !defined(HAVE_CYGWIN) && !defined(HAVE_WIN32) +#ifndef HAVE_WIN32 /* * It is possible to piggyback additional data e.g. ACLs on @@ -429,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); @@ -450,7 +737,7 @@ int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) /* */ /*=============================================================*/ -#if defined(HAVE_CYGWIN) || defined(HAVE_WIN32) +#ifdef HAVE_WIN32 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) { @@ -460,14 +747,19 @@ int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) attribsEx[0] = 0; /* no extended attributes */ - // try unicode version - if (p_GetFileAttributesExW) { - unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname); + if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) { + return STREAM_UNIX_ATTRIBUTES; + } - POOLMEM* pwszBuf = get_pool_memory (PM_FNAME); - UTF8_2_wchar(&pwszBuf, ff_pkt->sys_fname); + unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname); - BOOL b=p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, (LPVOID)&atts); + /* try unicode version */ + if (p_GetFileAttributesExW) { + 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); free_pool_memory(pwszBuf); if (!b) { @@ -479,8 +771,6 @@ int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt) if (!p_GetFileAttributesExA) return STREAM_UNIX_ATTRIBUTES; - unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname); - if (!p_GetFileAttributesExA(ff_pkt->sys_fname, GetFileExInfoStandard, (LPVOID)&atts)) { win_error(jcr, "GetFileAttributesExA:", ff_pkt->sys_fname); @@ -520,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 * @@ -538,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); @@ -580,8 +870,6 @@ static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd) 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 */ if (!is_bopen(ofd)) { @@ -595,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); - UTF8_2_wchar(&pwszBuf, win32_ofile); + POOLMEM* pwszBuf = get_pool_memory(PM_FNAME); + make_win32_path_UTF8_2_wchar(&pwszBuf, attr->ofname); - BOOL b=SetFileAttributesW((LPCWSTR)pwszBuf, atts.dwFileAttributes & SET_ATTRS); + 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 (!SetFileAttributes(win32_ofile, atts.dwFileAttributes & SET_ATTRS)) { - win_error(jcr, "SetFileAttributesA:", win32_ofile); + if (!p_SetFileAttributesA(win32_ofile, atts.dwFileAttributes & SET_ATTRS)) { + win_error(jcr, M_WARNING, "SetFileAttributesA:", win32_ofile); } } } @@ -623,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; @@ -637,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| @@ -655,22 +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); } - - -/* Conversion of a Unix filename to a Win32 filename */ -extern void conv_unix_to_win32_path(const char *path, char *win32_path, DWORD dwSize); -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); -} - -#endif /* HAVE_CYGWIN */ +#endif /* HAVE_WIN32 */