2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Encode and decode standard Unix attributes and
21 * Extended attributes for Win32 and
22 * other non-Unix systems, or Unix systems with ACLs, ...
24 * Kern Sibbald, October MMII
28 //#define _POSIX_C_SOURCE 200809L
29 //#define _BSD_SOURCE 1
35 static uid_t my_uid = 1;
36 static gid_t my_gid = 1;
37 static bool uid_set = false;
40 /* Forward referenced Windows subroutines */
41 static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd);
42 void unix_name_to_win32(POOLMEM **win32_name, const char *name);
43 void win_error(JCR *jcr, int type, const char *prefix, POOLMEM *ofile);
44 void win_error(JCR *jcr, const char *prefix, POOLMEM *ofile);
45 HANDLE bget_handle(BFILE *bfd);
46 #endif /* HAVE_WIN32 */
49 * For old systems that don't have lchown() or lchmod()
58 /*=============================================================*/
60 /* *** A l l S y s t e m s *** */
62 /*=============================================================*/
65 * To turn off use of fchown(), fchmod(), or futimes(),
66 * uncomment one or more of the following.
73 * Print errors only if debug level defined or we are root.
74 * root should not get errors. Errors for users causes
77 #define print_error(jcr) (chk_dbglvl(100) || (my_uid == 0 && (!jcr || jcr->job_uid == 0)))
80 * Restore the owner and permissions (mode) of a Directory.
81 * See attribs.c for the equivalent for files.
83 void set_own_mod(ATTR *attr, char *path, uid_t owner, gid_t group, mode_t mode)
85 if (lchown(path, owner, group) != 0 && print_error(attr->jcr)
91 Jmsg4(attr->jcr, M_WARNING, 0, _("Cannot change owner and/or group of %s: ERR=%s %d %d\n"),
92 path, be.bstrerror(), getuid(), attr->jcr->job_uid);
94 if (lchmod(path, mode) != 0 && print_error(attr->jcr)) {
96 Jmsg2(attr->jcr, M_WARNING, 0, _("Cannot change permissions of %s: ERR=%s\n"),
97 path, be.bstrerror());
102 bool set_mod_own_time(JCR *jcr, BFILE *ofd, ATTR *attr)
107 /* Do not try to set rights with f functions when using a plugin */
108 if (is_bopen(ofd) && !ofd->cmd_plugin) { /* TODO: Look with opt_plugin */
110 * The #ifdefing is a bit ugly, but it is the only
111 * way we can ensure this works on older systems.
114 if (fchown(ofd->fid, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error(jcr)) {
116 if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error(jcr)) {
119 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
120 attr->ofname, be.bstrerror());
125 if (fchmod(ofd->fid, attr->statp.st_mode) < 0 && print_error(jcr)) {
127 if (lchmod(attr->ofname, attr->statp.st_mode) < 0 && print_error(jcr)) {
130 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"),
131 attr->ofname, be.bstrerror());
136 struct timeval times[2];
137 times[0].tv_sec = attr->statp.st_atime;
138 times[0].tv_usec = 0;
139 times[1].tv_sec = attr->statp.st_mtime;
140 times[1].tv_usec = 0;
141 if (futimes(ofd->fid, times) < 0 && print_error(jcr)) {
143 ut.actime = attr->statp.st_atime;
144 ut.modtime = attr->statp.st_mtime;
146 if (utime(attr->ofname, &ut) < 0 && print_error(jcr)) {
149 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
150 attr->ofname, be.bstrerror());
154 if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error(jcr)) {
156 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
157 attr->ofname, be.bstrerror());
160 if (lchmod(attr->ofname, attr->statp.st_mode) < 0 && print_error(jcr)) {
162 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"),
163 attr->ofname, be.bstrerror());
169 ut.actime = attr->statp.st_atime;
170 ut.modtime = attr->statp.st_mtime;
172 if (utime(attr->ofname, &ut) < 0 && print_error(jcr)) {
174 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
175 attr->ofname, be.bstrerror());
183 * Return the data stream that will be used
185 int select_data_stream(FF_PKT *ff_pkt)
189 /* This is a plugin special restore object */
190 if (ff_pkt->type == FT_RESTORE_FIRST) {
192 return STREAM_FILE_DATA;
196 * Fix all incompatible options
198 /* No sparse option for encrypted data */
199 if (ff_pkt->flags & FO_ENCRYPT) {
200 ff_pkt->flags &= ~FO_SPARSE;
203 /* Note, no sparse option for win32_data */
204 if (!is_portable_backup(&ff_pkt->bfd)) {
205 stream = STREAM_WIN32_DATA;
206 ff_pkt->flags &= ~FO_SPARSE;
207 } else if (ff_pkt->flags & FO_SPARSE) {
208 stream = STREAM_SPARSE_DATA;
210 stream = STREAM_FILE_DATA;
212 if (ff_pkt->flags & FO_OFFSETS) {
213 stream = STREAM_SPARSE_DATA;
216 /* Encryption is only supported for file data */
217 if (stream != STREAM_FILE_DATA && stream != STREAM_WIN32_DATA &&
218 stream != STREAM_MACOS_FORK_DATA) {
219 ff_pkt->flags &= ~FO_ENCRYPT;
222 /* Compression is not supported for Mac fork data */
223 if (stream == STREAM_MACOS_FORK_DATA) {
224 ff_pkt->flags &= ~FO_COMPRESS;
228 * Handle compression and encryption options
230 #if defined(HAVE_LIBZ) || defined(HAVE_LZO)
231 if (ff_pkt->flags & FO_COMPRESS) {
233 if(ff_pkt->Compress_algo == COMPRESS_GZIP) {
235 case STREAM_WIN32_DATA:
236 stream = STREAM_WIN32_GZIP_DATA;
238 case STREAM_SPARSE_DATA:
239 stream = STREAM_SPARSE_GZIP_DATA;
241 case STREAM_FILE_DATA:
242 stream = STREAM_GZIP_DATA;
246 * All stream types that do not support compression should clear out
247 * FO_COMPRESS above, and this code block should be unreachable.
249 ASSERT(!(ff_pkt->flags & FO_COMPRESS));
255 if(ff_pkt->Compress_algo == COMPRESS_LZO1X) {
257 case STREAM_WIN32_DATA:
258 stream = STREAM_WIN32_COMPRESSED_DATA;
260 case STREAM_SPARSE_DATA:
261 stream = STREAM_SPARSE_COMPRESSED_DATA;
263 case STREAM_FILE_DATA:
264 stream = STREAM_COMPRESSED_DATA;
268 * All stream types that do not support compression should clear out
269 * FO_COMPRESS above, and this code block should be unreachable.
271 ASSERT(!(ff_pkt->flags & FO_COMPRESS));
279 if (ff_pkt->flags & FO_ENCRYPT) {
281 case STREAM_WIN32_DATA:
282 stream = STREAM_ENCRYPTED_WIN32_DATA;
284 case STREAM_WIN32_GZIP_DATA:
285 stream = STREAM_ENCRYPTED_WIN32_GZIP_DATA;
287 case STREAM_WIN32_COMPRESSED_DATA:
288 stream = STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA;
290 case STREAM_FILE_DATA:
291 stream = STREAM_ENCRYPTED_FILE_DATA;
293 case STREAM_GZIP_DATA:
294 stream = STREAM_ENCRYPTED_FILE_GZIP_DATA;
296 case STREAM_COMPRESSED_DATA:
297 stream = STREAM_ENCRYPTED_FILE_COMPRESSED_DATA;
300 /* All stream types that do not support encryption should clear out
301 * FO_ENCRYPT above, and this code block should be unreachable. */
302 ASSERT(!(ff_pkt->flags & FO_ENCRYPT));
313 * Encode a stat structure into a base64 character string
314 * All systems must create such a structure.
315 * In addition, we tack on the LinkFI, which is non-zero in
316 * the case of a hard linked file that has no data. This
317 * is a File Index pointing to the link that does have the
318 * data (always the first one encountered in a save).
319 * You may piggyback attributes on this packet by encoding
320 * them in the encode_attribsEx() subroutine, but this is
323 void encode_stat(char *buf, struct stat *statp, int stat_size, int32_t LinkFI, int data_stream)
327 * We read the stat packet so make sure the caller's conception
328 * is the same as ours. They can be different if LARGEFILE is not
329 * the same when compiling this library and the calling program.
331 ASSERT(stat_size == (int)sizeof(struct stat));
334 * Encode a stat packet. I should have done this more intelligently
335 * with a length so that it could be easily expanded.
337 p += to_base64((int64_t)statp->st_dev, p);
338 *p++ = ' '; /* separate fields with a space */
339 p += to_base64((int64_t)statp->st_ino, p);
341 p += to_base64((int64_t)statp->st_mode, p);
343 p += to_base64((int64_t)statp->st_nlink, p);
345 p += to_base64((int64_t)statp->st_uid, p);
347 p += to_base64((int64_t)statp->st_gid, p);
349 p += to_base64((int64_t)statp->st_rdev, p);
351 p += to_base64((int64_t)statp->st_size, p);
354 p += to_base64((int64_t)statp->st_blksize, p);
356 p += to_base64((int64_t)statp->st_blocks, p);
359 p += to_base64((int64_t)0, p); /* output place holder */
361 p += to_base64((int64_t)0, p); /* output place holder */
364 p += to_base64((int64_t)statp->st_atime, p);
366 p += to_base64((int64_t)statp->st_mtime, p);
368 p += to_base64((int64_t)statp->st_ctime, p);
370 p += to_base64((int64_t)LinkFI, p);
374 /* FreeBSD function */
375 p += to_base64((int64_t)statp->st_flags, p); /* output st_flags */
377 p += to_base64((int64_t)0, p); /* output place holder */
380 p += to_base64((int64_t)data_stream, p);
383 p += to_base64((int64_t)statp->st_fattrs, p);
389 /* Do casting according to unknown type to keep compiler happy */
391 #define plug(st, val) st = (typeof st)val
393 #if !HAVE_GCC & HAVE_SUN_OS
394 /* Sun compiler does not handle templates correctly */
395 #define plug(st, val) st = val
397 #define plug(st, val) st = val
399 /* Use templates to do the casting */
400 template <class T> void plug(T &st, uint64_t val)
401 { st = static_cast<T>(val); }
407 * Decode a stat packet from base64 characters
408 * returns: data_stream
410 int decode_stat(char *buf, struct stat *statp, int stat_size, int32_t *LinkFI)
417 * We store into the stat packet so make sure the caller's conception
418 * is the same as ours. They can be different if LARGEFILE is not
419 * the same when compiling this library and the calling program.
421 ASSERT(stat_size == (int)sizeof(struct stat));
423 p += from_base64(&val, p);
424 plug(statp->st_dev, val);
426 p += from_base64(&val, p);
427 plug(statp->st_ino, val);
429 p += from_base64(&val, p);
430 plug(statp->st_mode, val);
432 p += from_base64(&val, p);
433 plug(statp->st_nlink, val);
435 p += from_base64(&val, p);
436 plug(statp->st_uid, val);
438 p += from_base64(&val, p);
439 plug(statp->st_gid, val);
441 p += from_base64(&val, p);
442 plug(statp->st_rdev, val);
444 p += from_base64(&val, p);
445 plug(statp->st_size, val);
448 p += from_base64(&val, p);
449 plug(statp->st_blksize, val);
451 p += from_base64(&val, p);
452 plug(statp->st_blocks, val);
455 p += from_base64(&val, p);
456 // plug(statp->st_blksize, val);
458 p += from_base64(&val, p);
459 // plug(statp->st_blocks, val);
462 p += from_base64(&val, p);
463 plug(statp->st_atime, val);
465 p += from_base64(&val, p);
466 plug(statp->st_mtime, val);
468 p += from_base64(&val, p);
469 plug(statp->st_ctime, val);
471 /* Optional FileIndex of hard linked file data */
472 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
474 p += from_base64(&val, p);
475 *LinkFI = (uint32_t)val;
481 /* FreeBSD user flags */
482 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
484 p += from_base64(&val, p);
486 plug(statp->st_flags, val);
492 /* Look for data stream id */
493 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
495 p += from_base64(&val, p);
501 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
503 p += from_base64(&val, p);
504 plug(statp->st_fattrs, val);
506 statp->st_fattrs = 0;
513 /* Decode a LinkFI field of encoded stat packet */
514 int32_t decode_LinkFI(char *buf, struct stat *statp, int stat_size)
519 * We store into the stat packet so make sure the caller's conception
520 * is the same as ours. They can be different if LARGEFILE is not
521 * the same when compiling this library and the calling program.
523 ASSERT(stat_size == (int)sizeof(struct stat));
525 skip_nonspaces(&p); /* st_dev */
526 p++; /* skip space */
527 skip_nonspaces(&p); /* st_ino */
529 p += from_base64(&val, p);
530 plug(statp->st_mode, val); /* st_mode */
532 skip_nonspaces(&p); /* st_nlink */
534 skip_nonspaces(&p); /* st_uid */
536 skip_nonspaces(&p); /* st_gid */
538 skip_nonspaces(&p); /* st_rdev */
540 skip_nonspaces(&p); /* st_size */
542 skip_nonspaces(&p); /* st_blksize */
544 skip_nonspaces(&p); /* st_blocks */
546 skip_nonspaces(&p); /* st_atime */
548 skip_nonspaces(&p); /* st_mtime */
550 skip_nonspaces(&p); /* st_ctime */
552 /* Optional FileIndex of hard linked file data */
553 if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
555 p += from_base64(&val, p);
562 * Set file modes, permissions and times
564 * fname is the original filename
565 * ofile is the output filename (may be in a different directory)
567 * Returns: true on success
570 bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
583 if (attr->stream == STREAM_UNIX_ATTRIBUTES_EX &&
584 set_win32_attributes(jcr, attr, ofd)) {
588 pm_strcpy(attr->ofname, "*none*");
591 if (attr->data_stream == STREAM_WIN32_DATA ||
592 attr->data_stream == STREAM_WIN32_GZIP_DATA ||
593 attr->data_stream == STREAM_WIN32_COMPRESSED_DATA) {
597 pm_strcpy(attr->ofname, "*none*");
602 * If Windows stuff failed, e.g. attempt to restore Unix file
603 * to Windows, simply fall through and we will do it the
606 #endif /* HAVE_WIN32 */
610 char ec1[50], ec2[50];
611 fsize = blseek(ofd, 0, SEEK_END);
612 if (attr->type == FT_REG && fsize > 0 && attr->statp.st_size > 0 &&
613 fsize != (boffset_t)attr->statp.st_size) {
614 Jmsg3(jcr, M_ERROR, 0, _("File size of restored file %s not correct. Original %s, restored %s.\n"),
615 attr->ofname, edit_uint64(attr->statp.st_size, ec1),
616 edit_uint64(fsize, ec2));
621 * We do not restore sockets, so skip trying to restore their
624 if (attr->type == FT_SPEC && S_ISSOCK(attr->statp.st_mode)) {
628 /* ***FIXME**** optimize -- don't do if already correct */
630 * For link, change owner of link using lchown, but don't
631 * try to do a chmod as that will update the file behind it.
633 if (attr->type == FT_LNK) {
635 /* Change owner of link, not of real file */
636 if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error(jcr)) {
638 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
639 attr->ofname, be.bstrerror());
644 struct timeval times[2];
645 times[0].tv_sec = attr->statp.st_atime;
646 times[0].tv_usec = 0;
647 times[1].tv_sec = attr->statp.st_mtime;
648 times[1].tv_usec = 0;
649 if (lutimes(attr->ofname, times) < 0 && print_error(jcr)) {
651 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
652 attr->ofname, be.bstrerror());
658 * At this point, we have a file that is not a LINK
660 ok = set_mod_own_time(jcr, ofd, attr);
666 * Note, this should really be done before the utime() above,
667 * but if the immutable bit is set, it will make the utimes()
670 if (chflags(attr->ofname, attr->statp.st_flags) < 0 && print_error(jcr)) {
672 Jmsg2(jcr, M_ERROR, 0, _("Unable to set file flags %s: ERR=%s\n"),
673 attr->ofname, be.bstrerror());
683 pm_strcpy(attr->ofname, "*none*");
689 /*=============================================================*/
691 /* * * * U n i x * * * * */
693 /*=============================================================*/
698 * It is possible to piggyback additional data e.g. ACLs on
699 * the encode_stat() data by returning the extended attributes
700 * here. They must be "self-contained" (i.e. you keep track
701 * of your own length), and they must be in ASCII string
702 * format. Using this feature is not recommended.
703 * The code below shows how to return nothing. See the Win32
704 * code below for returning something in the attributes.
706 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
708 #ifdef HAVE_DARWIN_OS
710 * We save the Mac resource fork length so that on a
711 * restore, we can be sure we put back the whole resource.
715 *attribsEx = 0; /* no extended attributes (yet) */
716 if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) {
717 return STREAM_UNIX_ATTRIBUTES;
720 if (ff_pkt->flags & FO_HFSPLUS) {
721 p += to_base64((uint64_t)(ff_pkt->hfsinfo.rsrclength), p);
725 *attribsEx = 0; /* no extended attributes */
727 return STREAM_UNIX_ATTRIBUTES;
734 /*=============================================================*/
736 /* * * * W i n 3 2 * * * * */
738 /*=============================================================*/
742 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
745 WIN32_FILE_ATTRIBUTE_DATA atts;
748 attribsEx[0] = 0; /* no extended attributes */
750 if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) {
751 return STREAM_UNIX_ATTRIBUTES;
754 unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname);
756 /* try unicode version */
757 if (p_GetFileAttributesExW) {
758 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
759 make_win32_path_UTF8_2_wchar(&pwszBuf, ff_pkt->fname);
761 BOOL b=p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard,
763 free_pool_memory(pwszBuf);
766 win_error(jcr, "GetFileAttributesExW:", ff_pkt->sys_fname);
767 return STREAM_UNIX_ATTRIBUTES;
771 if (!p_GetFileAttributesExA)
772 return STREAM_UNIX_ATTRIBUTES;
774 if (!p_GetFileAttributesExA(ff_pkt->sys_fname, GetFileExInfoStandard,
776 win_error(jcr, "GetFileAttributesExA:", ff_pkt->sys_fname);
777 return STREAM_UNIX_ATTRIBUTES;
781 p += to_base64((uint64_t)atts.dwFileAttributes, p);
782 *p++ = ' '; /* separate fields with a space */
783 li.LowPart = atts.ftCreationTime.dwLowDateTime;
784 li.HighPart = atts.ftCreationTime.dwHighDateTime;
785 p += to_base64((uint64_t)li.QuadPart, p);
787 li.LowPart = atts.ftLastAccessTime.dwLowDateTime;
788 li.HighPart = atts.ftLastAccessTime.dwHighDateTime;
789 p += to_base64((uint64_t)li.QuadPart, p);
791 li.LowPart = atts.ftLastWriteTime.dwLowDateTime;
792 li.HighPart = atts.ftLastWriteTime.dwHighDateTime;
793 p += to_base64((uint64_t)li.QuadPart, p);
795 p += to_base64((uint64_t)atts.nFileSizeHigh, p);
797 p += to_base64((uint64_t)atts.nFileSizeLow, p);
799 return STREAM_UNIX_ATTRIBUTES_EX;
802 /* Define attributes that are legal to set with SetFileAttributes() */
803 #define SET_ATTRS ( \
804 FILE_ATTRIBUTE_ARCHIVE| \
805 FILE_ATTRIBUTE_HIDDEN| \
806 FILE_ATTRIBUTE_NORMAL| \
807 FILE_ATTRIBUTE_NOT_CONTENT_INDEXED| \
808 FILE_ATTRIBUTE_OFFLINE| \
809 FILE_ATTRIBUTE_READONLY| \
810 FILE_ATTRIBUTE_SYSTEM| \
811 FILE_ATTRIBUTE_TEMPORARY)
814 * Set Extended File Attributes for Win32
816 * fname is the original filename
817 * ofile is the output filename (may be in a different directory)
819 * Returns: true on success
822 static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
824 char *p = attr->attrEx;
826 WIN32_FILE_ATTRIBUTE_DATA atts;
828 POOLMEM *win32_ofile;
830 /* if we have neither Win ansi nor wchar API, get out */
831 if (!(p_SetFileAttributesW || p_SetFileAttributesA)) {
835 if (!p || !*p) { /* we should have attributes */
836 Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", attr->ofname, ofd->fid);
842 Dmsg2(100, "Attribs %s = %s\n", attr->ofname, attr->attrEx);
845 p += from_base64(&val, p);
846 plug(atts.dwFileAttributes, val);
847 p++; /* skip space */
848 p += from_base64(&val, p);
850 atts.ftCreationTime.dwLowDateTime = li.LowPart;
851 atts.ftCreationTime.dwHighDateTime = li.HighPart;
852 p++; /* skip space */
853 p += from_base64(&val, p);
855 atts.ftLastAccessTime.dwLowDateTime = li.LowPart;
856 atts.ftLastAccessTime.dwHighDateTime = li.HighPart;
857 p++; /* skip space */
858 p += from_base64(&val, p);
860 atts.ftLastWriteTime.dwLowDateTime = li.LowPart;
861 atts.ftLastWriteTime.dwHighDateTime = li.HighPart;
863 p += from_base64(&val, p);
864 plug(atts.nFileSizeHigh, val);
866 p += from_base64(&val, p);
867 plug(atts.nFileSizeLow, val);
869 /* Convert to Windows path format */
870 win32_ofile = get_pool_memory(PM_FNAME);
871 unix_name_to_win32(&win32_ofile, attr->ofname);
873 /* At this point, we have reconstructed the WIN32_FILE_ATTRIBUTE_DATA pkt */
875 if (!is_bopen(ofd)) {
876 Dmsg1(100, "File not open: %s\n", attr->ofname);
877 bopen(ofd, attr->ofname, O_WRONLY|O_BINARY, 0); /* attempt to open the file */
881 Dmsg1(100, "SetFileTime %s\n", attr->ofname);
882 if (!SetFileTime(bget_handle(ofd),
883 &atts.ftCreationTime,
884 &atts.ftLastAccessTime,
885 &atts.ftLastWriteTime)) {
886 win_error(jcr, M_WARNING, "SetFileTime:", win32_ofile);
890 * Inform win32 api that the given file is a sparse file
892 if (atts.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) {
895 Dmsg1(100, "Set FILE_ATTRIBUTE_SPARSE_FILE on %s\n", attr->ofname);
896 if (!DeviceIoControl(bget_handle(ofd), FSCTL_SET_SPARSE,
897 NULL, 0, NULL, 0, &bytesReturned, NULL))
899 /* Not sure we really want to have a Warning for such attribute */
900 win_error(jcr, M_WARNING, "set SPARSE_FILE:", win32_ofile);
905 * Restore the file as compressed.
907 if (atts.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) {
908 int fmt = COMPRESSION_FORMAT_DEFAULT;
911 Dmsg1(100, "Set FILE_ATTRIBUTE_COMPRESSED on %s\n", attr->ofname);
912 if (!DeviceIoControl(bget_handle(ofd), FSCTL_SET_COMPRESSION,
913 &fmt, sizeof(fmt), NULL, 0, &bytesReturned, NULL))
915 /* Not sure we really want to have a Warning for such attribute */
916 win_error(jcr, M_WARNING, "set COMPRESSED:", win32_ofile);
923 Dmsg1(100, "SetFileAtts %s\n", attr->ofname);
924 if (!(atts.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
925 if (p_SetFileAttributesW) {
926 POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);
927 make_win32_path_UTF8_2_wchar(&pwszBuf, attr->ofname);
929 BOOL b=p_SetFileAttributesW((LPCWSTR)pwszBuf, atts.dwFileAttributes & SET_ATTRS);
930 free_pool_memory(pwszBuf);
933 win_error(jcr, M_WARNING, "SetFileAttributesW:", win32_ofile);
936 if (!p_SetFileAttributesA(win32_ofile, atts.dwFileAttributes & SET_ATTRS)) {
937 win_error(jcr, M_WARNING, "SetFileAttributesA:", win32_ofile);
941 free_pool_memory(win32_ofile);
945 void win_error(JCR *jcr, int type, const char *prefix, POOLMEM *win32_ofile)
947 DWORD lerror = GetLastError();
949 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
950 FORMAT_MESSAGE_FROM_SYSTEM,
957 Dmsg3(100, "Error in %s on file %s: ERR=%s\n", prefix, win32_ofile, msg);
958 strip_trailing_junk(msg);
959 Jmsg3(jcr, type, 0, _("Error in %s file %s: ERR=%s\n"), prefix, win32_ofile, msg);
963 void win_error(JCR *jcr, const char *prefix, POOLMEM *win32_ofile)
965 win_error(jcr, M_ERROR, prefix, win32_ofile);
968 void win_error(JCR *jcr, const char *prefix, DWORD lerror)
971 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
972 FORMAT_MESSAGE_FROM_SYSTEM,
979 strip_trailing_junk(msg);
981 Jmsg2(jcr, M_ERROR, 0, _("Error in %s: ERR=%s\n"), prefix, msg);
982 MessageBox(NULL, msg, prefix, MB_OK);
986 #endif /* HAVE_WIN32 */