]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/attribs.c
kes Implement code that should properly set that a job was migrated,
[bacula/bacula] / bacula / src / findlib / attribs.c
1 /*
2  *  Encode and decode standard Unix attributes and
3  *   Extended attributes for Win32 and
4  *   other non-Unix systems, or Unix systems with ACLs, ...
5  *
6  *    Kern Sibbald, October MMII
7  *
8  *   Version $Id$
9  *
10  */
11 /*
12    Bacula® - The Network Backup Solution
13
14    Copyright (C) 2002-2006 Free Software Foundation Europe e.V.
15
16    The main author of Bacula is Kern Sibbald, with contributions from
17    many others, a complete list can be found in the file AUTHORS.
18    This program is Free Software; you can redistribute it and/or
19    modify it under the terms of version two of the GNU General Public
20    License as published by the Free Software Foundation plus additions
21    that are listed in the file LICENSE.
22
23    This program is distributed in the hope that it will be useful, but
24    WITHOUT ANY WARRANTY; without even the implied warranty of
25    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26    General Public License for more details.
27
28    You should have received a copy of the GNU General Public License
29    along with this program; if not, write to the Free Software
30    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31    02110-1301, USA.
32
33    Bacula® is a registered trademark of John Walker.
34    The licensor of Bacula is the Free Software Foundation Europe
35    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
36    Switzerland, email:ftf@fsfeurope.org.
37 */
38
39 #include "bacula.h"
40 #include "find.h"
41
42 #if defined(HAVE_WIN32)
43 /* Forward referenced subroutines */
44 static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd);
45 void unix_name_to_win32(POOLMEM **win32_name, char *name);
46 void win_error(JCR *jcr, char *prefix, POOLMEM *ofile);
47 HANDLE bget_handle(BFILE *bfd);
48 #endif /* HAVE_WIN32 */
49
50 /* For old systems that don't have lchown() use chown() */
51 #ifndef HAVE_LCHOWN
52 #define lchown chown
53 #endif
54
55 /*=============================================================*/
56 /*                                                             */
57 /*             ***  A l l  S y s t e m s ***                   */
58 /*                                                             */
59 /*=============================================================*/
60
61 /*
62  * Return the data stream that will be used
63  */
64 int select_data_stream(FF_PKT *ff_pkt)
65 {
66    int stream;
67
68    /*
69     *  Fix all incompatible options
70     */
71
72    /* No sparse option for encrypted data */
73    if (ff_pkt->flags & FO_ENCRYPT) {
74       ff_pkt->flags &= ~FO_SPARSE;
75    }
76
77    /* Note, no sparse option for win32_data */
78    if (!is_portable_backup(&ff_pkt->bfd)) {
79       stream = STREAM_WIN32_DATA;
80       ff_pkt->flags &= ~FO_SPARSE;
81    } else if (ff_pkt->flags & FO_SPARSE) {
82       stream = STREAM_SPARSE_DATA;
83    } else {
84       stream = STREAM_FILE_DATA;
85    }
86
87    /* Encryption is only supported for file data */
88    if (stream != STREAM_FILE_DATA && stream != STREAM_WIN32_DATA &&
89          stream != STREAM_MACOS_FORK_DATA) {
90       ff_pkt->flags &= ~FO_ENCRYPT;
91    }
92
93    /* Compression is not supported for Mac fork data */
94    if (stream == STREAM_MACOS_FORK_DATA) {
95       ff_pkt->flags &= ~FO_GZIP;
96    }
97
98    /*
99     * Handle compression and encryption options
100     */
101 #ifdef HAVE_LIBZ
102    if (ff_pkt->flags & FO_GZIP) {
103       switch (stream) {
104       case STREAM_WIN32_DATA:
105          stream = STREAM_WIN32_GZIP_DATA;
106          break;
107       case STREAM_SPARSE_DATA:
108          stream = STREAM_SPARSE_GZIP_DATA;
109          break;
110       case STREAM_FILE_DATA:
111          stream = STREAM_GZIP_DATA;
112          break;
113       default:
114          /* All stream types that do not support gzip should clear out
115           * FO_GZIP above, and this code block should be unreachable. */
116          ASSERT(!(ff_pkt->flags & FO_GZIP));
117          return STREAM_NONE;
118       }
119    }
120 #endif
121 #ifdef HAVE_CRYPTO
122    if (ff_pkt->flags & FO_ENCRYPT) {
123       switch (stream) {
124       case STREAM_WIN32_DATA:
125          stream = STREAM_ENCRYPTED_WIN32_DATA;
126          break;
127       case STREAM_WIN32_GZIP_DATA:
128          stream = STREAM_ENCRYPTED_WIN32_GZIP_DATA;
129          break;
130       case STREAM_FILE_DATA:
131          stream = STREAM_ENCRYPTED_FILE_DATA;
132          break;
133       case STREAM_GZIP_DATA:
134          stream = STREAM_ENCRYPTED_FILE_GZIP_DATA;
135          break;
136       default:
137          /* All stream types that do not support encryption should clear out
138           * FO_ENCRYPT above, and this code block should be unreachable. */
139          ASSERT(!(ff_pkt->flags & FO_ENCRYPT));
140          return STREAM_NONE;
141       }
142    }
143 #endif
144
145    return stream;
146 }
147
148
149 /*
150  * Encode a stat structure into a base64 character string
151  *   All systems must create such a structure.
152  *   In addition, we tack on the LinkFI, which is non-zero in
153  *   the case of a hard linked file that has no data.  This
154  *   is a File Index pointing to the link that does have the
155  *   data (always the first one encountered in a save).
156  * You may piggyback attributes on this packet by encoding
157  *   them in the encode_attribsEx() subroutine, but this is
158  *   not recommended.
159  */
160 void encode_stat(char *buf, FF_PKT *ff_pkt, int data_stream)
161 {
162    char *p = buf;
163    struct stat *statp = &ff_pkt->statp;
164    /*
165     *  Encode a stat packet.  I should have done this more intelligently
166     *   with a length so that it could be easily expanded.
167     */
168    p += to_base64((int64_t)statp->st_dev, p);
169    *p++ = ' ';                        /* separate fields with a space */
170    p += to_base64((int64_t)statp->st_ino, p);
171    *p++ = ' ';
172    p += to_base64((int64_t)statp->st_mode, p);
173    *p++ = ' ';
174    p += to_base64((int64_t)statp->st_nlink, p);
175    *p++ = ' ';
176    p += to_base64((int64_t)statp->st_uid, p);
177    *p++ = ' ';
178    p += to_base64((int64_t)statp->st_gid, p);
179    *p++ = ' ';
180    p += to_base64((int64_t)statp->st_rdev, p);
181    *p++ = ' ';
182    p += to_base64((int64_t)statp->st_size, p);
183    *p++ = ' ';
184 #ifndef HAVE_MINGW
185    p += to_base64((int64_t)statp->st_blksize, p);
186    *p++ = ' ';
187    p += to_base64((int64_t)statp->st_blocks, p);
188    *p++ = ' ';
189 #else
190    p += to_base64((int64_t)0, p); /* output place holder */
191    *p++ = ' ';
192    p += to_base64((int64_t)0, p); /* output place holder */
193    *p++ = ' ';
194 #endif
195    p += to_base64((int64_t)statp->st_atime, p);
196    *p++ = ' ';
197    p += to_base64((int64_t)statp->st_mtime, p);
198    *p++ = ' ';
199    p += to_base64((int64_t)statp->st_ctime, p);
200    *p++ = ' ';
201    p += to_base64((int64_t)ff_pkt->LinkFI, p);
202    *p++ = ' ';
203
204 #ifdef HAVE_CHFLAGS
205    /* FreeBSD function */
206    p += to_base64((int64_t)statp->st_flags, p);  /* output st_flags */
207 #else
208    p += to_base64((int64_t)0, p);     /* output place holder */
209 #endif
210    *p++ = ' ';
211    p += to_base64((int64_t)data_stream, p);
212    *p = 0;
213    return;
214 }
215
216
217 /* Do casting according to unknown type to keep compiler happy */
218 #ifdef HAVE_TYPEOF
219   #define plug(st, val) st = (typeof st)val
220 #else
221   #if !HAVE_GCC & HAVE_SUN_OS
222     /* Sun compiler does not handle templates correctly */
223     #define plug(st, val) st = val
224   #else
225     /* Use templates to do the casting */
226     template <class T> void plug(T &st, uint64_t val)
227       { st = static_cast<T>(val); }
228   #endif
229 #endif
230
231
232 /* Decode a stat packet from base64 characters */
233 int decode_stat(char *buf, struct stat *statp, int32_t *LinkFI)
234 {
235    char *p = buf;
236    int64_t val;
237
238    p += from_base64(&val, p);
239    plug(statp->st_dev, val);
240    p++;
241    p += from_base64(&val, p);
242    plug(statp->st_ino, val);
243    p++;
244    p += from_base64(&val, p);
245    plug(statp->st_mode, val);
246    p++;
247    p += from_base64(&val, p);
248    plug(statp->st_nlink, val);
249    p++;
250    p += from_base64(&val, p);
251    plug(statp->st_uid, val);
252    p++;
253    p += from_base64(&val, p);
254    plug(statp->st_gid, val);
255    p++;
256    p += from_base64(&val, p);
257    plug(statp->st_rdev, val);
258    p++;
259    p += from_base64(&val, p);
260    plug(statp->st_size, val);
261    p++;
262 #ifndef HAVE_MINGW
263    p += from_base64(&val, p);
264    plug(statp->st_blksize, val);
265    p++;
266    p += from_base64(&val, p);
267    plug(statp->st_blocks, val);
268    p++;
269 #else
270    p += from_base64(&val, p);
271 //   plug(statp->st_blksize, val);
272    p++;
273    p += from_base64(&val, p);
274 //   plug(statp->st_blocks, val);
275    p++;
276 #endif
277    p += from_base64(&val, p);
278    plug(statp->st_atime, val);
279    p++;
280    p += from_base64(&val, p);
281    plug(statp->st_mtime, val);
282    p++;
283    p += from_base64(&val, p);
284    plug(statp->st_ctime, val);
285
286    /* Optional FileIndex of hard linked file data */
287    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
288       p++;
289       p += from_base64(&val, p);
290       *LinkFI = (uint32_t)val;
291    } else {
292       *LinkFI = 0;
293       return 0;
294    }
295
296    /* FreeBSD user flags */
297    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
298       p++;
299       p += from_base64(&val, p);
300 #ifdef HAVE_CHFLAGS
301       plug(statp->st_flags, val);
302    } else {
303       statp->st_flags  = 0;
304 #endif
305    }
306
307    /* Look for data stream id */
308    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
309       p++;
310       p += from_base64(&val, p);
311    } else {
312       val = 0;
313    }
314    return (int)val;
315 }
316
317 /* Decode a LinkFI field of encoded stat packet */
318 int32_t decode_LinkFI(char *buf, struct stat *statp)
319 {
320    char *p = buf;
321    int64_t val;
322
323    skip_nonspaces(&p);                /* st_dev */
324    p++;                               /* skip space */
325    skip_nonspaces(&p);                /* st_ino */
326    p++;
327    p += from_base64(&val, p);
328    plug(statp->st_mode, val);         /* st_mode */
329    p++;
330    skip_nonspaces(&p);                /* st_nlink */
331    p++;
332    skip_nonspaces(&p);                /* st_uid */
333    p++;
334    skip_nonspaces(&p);                /* st_gid */
335    p++;
336    skip_nonspaces(&p);                /* st_rdev */
337    p++;
338    skip_nonspaces(&p);                /* st_size */
339    p++;
340    skip_nonspaces(&p);                /* st_blksize */
341    p++;
342    skip_nonspaces(&p);                /* st_blocks */
343    p++;
344    skip_nonspaces(&p);                /* st_atime */
345    p++;
346    skip_nonspaces(&p);                /* st_mtime */
347    p++;
348    skip_nonspaces(&p);                /* st_ctime */
349
350    /* Optional FileIndex of hard linked file data */
351    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
352       p++;
353       p += from_base64(&val, p);
354       return (int32_t)val;
355    }
356    return 0;
357 }
358
359 /*
360  * Set file modes, permissions and times
361  *
362  *  fname is the original filename
363  *  ofile is the output filename (may be in a different directory)
364  *
365  * Returns:  true  on success
366  *           false on failure
367  */
368 bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
369 {
370    struct utimbuf ut;
371    mode_t old_mask;
372    bool ok = true;
373    boffset_t fsize;
374
375 #if defined(HAVE_WIN32)
376    if (attr->stream == STREAM_UNIX_ATTRIBUTES_EX &&
377        set_win32_attributes(jcr, attr, ofd)) {
378        if (is_bopen(ofd)) {
379            bclose(ofd);
380        }
381        pm_strcpy(attr->ofname, "*none*");
382        return true;
383    }
384    if (attr->data_stream == STREAM_WIN32_DATA ||
385        attr->data_stream == STREAM_WIN32_GZIP_DATA) {
386       if (is_bopen(ofd)) {
387          bclose(ofd);
388       }
389       pm_strcpy(attr->ofname, "*none*");
390       return true;
391    }
392
393
394    /*
395     * If Windows stuff failed, e.g. attempt to restore Unix file
396     *  to Windows, simply fall through and we will do it the
397     *  universal way.
398     */
399 #endif
400
401    old_mask = umask(0);
402    if (is_bopen(ofd)) {
403       char ec1[50], ec2[50];
404       fsize = blseek(ofd, 0, SEEK_END);
405       bclose(ofd);                    /* first close file */
406       if (attr->type == FT_REG && fsize > 0 && fsize != (boffset_t)attr->statp.st_size) {
407          Jmsg3(jcr, M_ERROR, 0, _("File size of restored file %s not correct. Original %s, restored %s.\n"),
408             attr->ofname, edit_uint64(attr->statp.st_size, ec1),
409             edit_uint64(fsize, ec2));
410       }
411    }
412
413    ut.actime = attr->statp.st_atime;
414    ut.modtime = attr->statp.st_mtime;
415
416    /* ***FIXME**** optimize -- don't do if already correct */
417    /*
418     * For link, change owner of link using lchown, but don't
419     *   try to do a chmod as that will update the file behind it.
420     */
421    if (attr->type == FT_LNK) {
422       /* Change owner of link, not of real file */
423       if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0) {
424          berrno be;
425          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
426             attr->ofname, be.strerror());
427          ok = false;
428       }
429    } else {
430       if (chown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0) {
431          berrno be;
432          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
433             attr->ofname, be.strerror());
434          ok = false;
435       }
436       if (chmod(attr->ofname, attr->statp.st_mode) < 0) {
437          berrno be;
438          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"),
439             attr->ofname, be.strerror());
440          ok = false;
441       }
442
443       /*
444        * Reset file times.
445        */
446       if (utime(attr->ofname, &ut) < 0) {
447          berrno be;
448          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
449             attr->ofname, be.strerror());
450          ok = false;
451       }
452 #ifdef HAVE_CHFLAGS
453       /*
454        * FreeBSD user flags
455        *
456        * Note, this should really be done before the utime() above,
457        *  but if the immutable bit is set, it will make the utimes()
458        *  fail.
459        */
460       if (chflags(attr->ofname, attr->statp.st_flags) < 0) {
461          berrno be;
462          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file flags %s: ERR=%s\n"),
463             attr->ofname, be.strerror());
464          ok = false;
465       }
466 #endif
467    }
468    pm_strcpy(attr->ofname, "*none*");
469    umask(old_mask);
470    return ok;
471 }
472
473
474 /*=============================================================*/
475 /*                                                             */
476 /*                 * * *  U n i x * * * *                      */
477 /*                                                             */
478 /*=============================================================*/
479
480 #if !defined(HAVE_WIN32)
481
482 /*
483  * It is possible to piggyback additional data e.g. ACLs on
484  *   the encode_stat() data by returning the extended attributes
485  *   here.  They must be "self-contained" (i.e. you keep track
486  *   of your own length), and they must be in ASCII string
487  *   format. Using this feature is not recommended.
488  * The code below shows how to return nothing.  See the Win32
489  *   code below for returning something in the attributes.
490  */
491 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
492 {
493 #ifdef HAVE_DARWIN_OS
494    /*
495     * We save the Mac resource fork length so that on a
496     * restore, we can be sure we put back the whole resource.
497     */
498    char *p;
499    p = attribsEx;
500    if (ff_pkt->flags & FO_HFSPLUS) {
501       p += to_base64((uint64_t)(ff_pkt->hfsinfo.rsrclength), p);
502    }
503    *p = 0;
504 #else
505    *attribsEx = 0;                    /* no extended attributes */
506 #endif
507    return STREAM_UNIX_ATTRIBUTES;
508 }
509
510 #endif
511
512
513
514 /*=============================================================*/
515 /*                                                             */
516 /*                 * * *  W i n 3 2 * * * *                    */
517 /*                                                             */
518 /*=============================================================*/
519
520 #if defined(HAVE_WIN32)
521
522 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
523 {
524    char *p = attribsEx;
525    WIN32_FILE_ATTRIBUTE_DATA atts;
526    ULARGE_INTEGER li;
527
528    attribsEx[0] = 0;                  /* no extended attributes */
529
530    unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname);
531
532    // try unicode version
533    if (p_GetFileAttributesExW)  {
534       POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);   
535       make_win32_path_UTF8_2_wchar(&pwszBuf, ff_pkt->fname);
536
537       BOOL b=p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, (LPVOID)&atts);
538       free_pool_memory(pwszBuf);
539
540       if (!b) {
541          win_error(jcr, "GetFileAttributesExW:", ff_pkt->sys_fname);
542          return STREAM_UNIX_ATTRIBUTES;
543       }
544    }
545    else {
546       if (!p_GetFileAttributesExA)
547          return STREAM_UNIX_ATTRIBUTES;      
548
549       if (!p_GetFileAttributesExA(ff_pkt->sys_fname, GetFileExInfoStandard,
550                               (LPVOID)&atts)) {
551          win_error(jcr, "GetFileAttributesExA:", ff_pkt->sys_fname);
552          return STREAM_UNIX_ATTRIBUTES;
553       }
554    }
555
556    p += to_base64((uint64_t)atts.dwFileAttributes, p);
557    *p++ = ' ';                        /* separate fields with a space */
558    li.LowPart = atts.ftCreationTime.dwLowDateTime;
559    li.HighPart = atts.ftCreationTime.dwHighDateTime;
560    p += to_base64((uint64_t)li.QuadPart, p);
561    *p++ = ' ';
562    li.LowPart = atts.ftLastAccessTime.dwLowDateTime;
563    li.HighPart = atts.ftLastAccessTime.dwHighDateTime;
564    p += to_base64((uint64_t)li.QuadPart, p);
565    *p++ = ' ';
566    li.LowPart = atts.ftLastWriteTime.dwLowDateTime;
567    li.HighPart = atts.ftLastWriteTime.dwHighDateTime;
568    p += to_base64((uint64_t)li.QuadPart, p);
569    *p++ = ' ';
570    p += to_base64((uint64_t)atts.nFileSizeHigh, p);
571    *p++ = ' ';
572    p += to_base64((uint64_t)atts.nFileSizeLow, p);
573    *p = 0;
574    return STREAM_UNIX_ATTRIBUTES_EX;
575 }
576
577 /* Define attributes that are legal to set with SetFileAttributes() */
578 #define SET_ATTRS ( \
579          FILE_ATTRIBUTE_ARCHIVE| \
580          FILE_ATTRIBUTE_HIDDEN| \
581          FILE_ATTRIBUTE_NORMAL| \
582          FILE_ATTRIBUTE_NOT_CONTENT_INDEXED| \
583          FILE_ATTRIBUTE_OFFLINE| \
584          FILE_ATTRIBUTE_READONLY| \
585          FILE_ATTRIBUTE_SYSTEM| \
586          FILE_ATTRIBUTE_TEMPORARY)
587
588
589 /*
590  * Set Extended File Attributes for Win32
591  *
592  *  fname is the original filename
593  *  ofile is the output filename (may be in a different directory)
594  *
595  * Returns:  true  on success
596  *           false on failure
597  */
598 static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
599 {
600    char *p = attr->attrEx;
601    int64_t val;
602    WIN32_FILE_ATTRIBUTE_DATA atts;
603    ULARGE_INTEGER li;
604    POOLMEM *win32_ofile;
605
606    // if we have neither ansi nor wchar version, we leave
607    if (!(p_SetFileAttributesW || p_SetFileAttributesA))
608       return false;
609
610    if (!p || !*p) {                   /* we should have attributes */
611       Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", attr->ofname, ofd->fid);
612       if (is_bopen(ofd)) {
613          bclose(ofd);
614       }
615       return false;
616    } else {
617       Dmsg2(100, "Attribs %s = %s\n", attr->ofname, attr->attrEx);
618    }
619
620    p += from_base64(&val, p);
621    plug(atts.dwFileAttributes, val);
622    p++;                               /* skip space */
623    p += from_base64(&val, p);
624    li.QuadPart = val;
625    atts.ftCreationTime.dwLowDateTime = li.LowPart;
626    atts.ftCreationTime.dwHighDateTime = li.HighPart;
627    p++;                               /* skip space */
628    p += from_base64(&val, p);
629    li.QuadPart = val;
630    atts.ftLastAccessTime.dwLowDateTime = li.LowPart;
631    atts.ftLastAccessTime.dwHighDateTime = li.HighPart;
632    p++;                               /* skip space */
633    p += from_base64(&val, p);
634    li.QuadPart = val;
635    atts.ftLastWriteTime.dwLowDateTime = li.LowPart;
636    atts.ftLastWriteTime.dwHighDateTime = li.HighPart;
637    p++;
638    p += from_base64(&val, p);
639    plug(atts.nFileSizeHigh, val);
640    p++;
641    p += from_base64(&val, p);
642    plug(atts.nFileSizeLow, val);
643
644    /* Convert to Windows path format */
645    win32_ofile = get_pool_memory(PM_FNAME);
646    unix_name_to_win32(&win32_ofile, attr->ofname);
647
648    /* At this point, we have reconstructed the WIN32_FILE_ATTRIBUTE_DATA pkt */
649
650    if (!is_bopen(ofd)) {
651       Dmsg1(100, "File not open: %s\n", attr->ofname);
652       bopen(ofd, attr->ofname, O_WRONLY|O_BINARY, 0);   /* attempt to open the file */
653    }
654
655    if (is_bopen(ofd)) {
656       Dmsg1(100, "SetFileTime %s\n", attr->ofname);
657       if (!SetFileTime(bget_handle(ofd),
658                          &atts.ftCreationTime,
659                          &atts.ftLastAccessTime,
660                          &atts.ftLastWriteTime)) {
661          win_error(jcr, "SetFileTime:", win32_ofile);
662       }
663       bclose(ofd);
664    }
665
666    Dmsg1(100, "SetFileAtts %s\n", attr->ofname);
667    if (!(atts.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 
668    {
669       if (p_SetFileAttributesW) {
670          POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);   
671          make_win32_path_UTF8_2_wchar(&pwszBuf, attr->ofname);
672
673          BOOL b=p_SetFileAttributesW((LPCWSTR)pwszBuf, atts.dwFileAttributes & SET_ATTRS);
674          free_pool_memory(pwszBuf);
675       
676          if (!b) 
677             win_error(jcr, "SetFileAttributesW:", win32_ofile); 
678       }
679       else {
680          if (!p_SetFileAttributesA(win32_ofile, atts.dwFileAttributes & SET_ATTRS)) {
681             win_error(jcr, "SetFileAttributesA:", win32_ofile);
682          }
683       }
684    }
685    free_pool_memory(win32_ofile);
686    return true;
687 }
688
689 void win_error(JCR *jcr, char *prefix, POOLMEM *win32_ofile)
690 {
691    DWORD lerror = GetLastError();
692    LPTSTR msg;
693    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
694                  FORMAT_MESSAGE_FROM_SYSTEM,
695                  NULL,
696                  lerror,
697                  0,
698                  (LPTSTR)&msg,
699                  0,
700                  NULL);
701    Dmsg3(100, "Error in %s on file %s: ERR=%s\n", prefix, win32_ofile, msg);
702    strip_trailing_junk(msg);
703    Jmsg(jcr, M_ERROR, 0, _("Error in %s file %s: ERR=%s\n"), prefix, win32_ofile, msg);
704    LocalFree(msg);
705 }
706
707 void win_error(JCR *jcr, char *prefix, DWORD lerror)
708 {
709    LPTSTR msg;
710    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
711                  FORMAT_MESSAGE_FROM_SYSTEM,
712                  NULL,
713                  lerror,
714                  0,
715                  (LPTSTR)&msg,
716                  0,
717                  NULL);
718    strip_trailing_junk(msg);
719    if (jcr) {
720       Jmsg2(jcr, M_ERROR, 0, _("Error in %s: ERR=%s\n"), prefix, msg);
721    } else {
722       MessageBox(NULL, msg, prefix, MB_OK);
723    }
724    LocalFree(msg);
725 }
726 #endif  /* HAVE_WIN32 */