]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/attribs.c
kes Restore of sockets created false error messages because Bacula
[bacula/bacula] / bacula / src / findlib / attribs.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation plus additions
11    that are listed in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *  Encode and decode standard Unix attributes and
30  *   Extended attributes for Win32 and
31  *   other non-Unix systems, or Unix systems with ACLs, ...
32  *
33  *    Kern Sibbald, October MMII
34  *
35  *   Version $Id$
36  *
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    /*
414     * We do not restore sockets, so skip trying to restore their
415     *   attributes.
416     */
417    if (attr->type == FT_SPEC && S_ISSOCK(attr->statp.st_mode)) {
418       goto bail_out;
419    }
420
421    ut.actime = attr->statp.st_atime;
422    ut.modtime = attr->statp.st_mtime;
423
424    /* ***FIXME**** optimize -- don't do if already correct */
425    /*
426     * For link, change owner of link using lchown, but don't
427     *   try to do a chmod as that will update the file behind it.
428     */
429    if (attr->type == FT_LNK) {
430       /* Change owner of link, not of real file */
431       if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0) {
432          berrno be;
433          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
434             attr->ofname, be.strerror());
435          ok = false;
436       }
437    } else {
438       if (chown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0) {
439          berrno be;
440          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
441             attr->ofname, be.strerror());
442          ok = false;
443       }
444       if (chmod(attr->ofname, attr->statp.st_mode) < 0) {
445          berrno be;
446          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"),
447             attr->ofname, be.strerror());
448          ok = false;
449       }
450
451       /*
452        * Reset file times.
453        */
454       if (utime(attr->ofname, &ut) < 0) {
455          berrno be;
456          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
457             attr->ofname, be.strerror());
458          ok = false;
459       }
460 #ifdef HAVE_CHFLAGS
461       /*
462        * FreeBSD user flags
463        *
464        * Note, this should really be done before the utime() above,
465        *  but if the immutable bit is set, it will make the utimes()
466        *  fail.
467        */
468       if (chflags(attr->ofname, attr->statp.st_flags) < 0) {
469          berrno be;
470          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file flags %s: ERR=%s\n"),
471             attr->ofname, be.strerror());
472          ok = false;
473       }
474 #endif
475    }
476
477 bail_out:
478    pm_strcpy(attr->ofname, "*none*");
479    umask(old_mask);
480    return ok;
481 }
482
483
484 /*=============================================================*/
485 /*                                                             */
486 /*                 * * *  U n i x * * * *                      */
487 /*                                                             */
488 /*=============================================================*/
489
490 #if !defined(HAVE_WIN32)
491
492 /*
493  * It is possible to piggyback additional data e.g. ACLs on
494  *   the encode_stat() data by returning the extended attributes
495  *   here.  They must be "self-contained" (i.e. you keep track
496  *   of your own length), and they must be in ASCII string
497  *   format. Using this feature is not recommended.
498  * The code below shows how to return nothing.  See the Win32
499  *   code below for returning something in the attributes.
500  */
501 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
502 {
503 #ifdef HAVE_DARWIN_OS
504    /*
505     * We save the Mac resource fork length so that on a
506     * restore, we can be sure we put back the whole resource.
507     */
508    char *p;
509    p = attribsEx;
510    if (ff_pkt->flags & FO_HFSPLUS) {
511       p += to_base64((uint64_t)(ff_pkt->hfsinfo.rsrclength), p);
512    }
513    *p = 0;
514 #else
515    *attribsEx = 0;                    /* no extended attributes */
516 #endif
517    return STREAM_UNIX_ATTRIBUTES;
518 }
519
520 #endif
521
522
523
524 /*=============================================================*/
525 /*                                                             */
526 /*                 * * *  W i n 3 2 * * * *                    */
527 /*                                                             */
528 /*=============================================================*/
529
530 #if defined(HAVE_WIN32)
531
532 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
533 {
534    char *p = attribsEx;
535    WIN32_FILE_ATTRIBUTE_DATA atts;
536    ULARGE_INTEGER li;
537
538    attribsEx[0] = 0;                  /* no extended attributes */
539
540    unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname);
541
542    // try unicode version
543    if (p_GetFileAttributesExW)  {
544       POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);   
545       make_win32_path_UTF8_2_wchar(&pwszBuf, ff_pkt->fname);
546
547       BOOL b=p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, (LPVOID)&atts);
548       free_pool_memory(pwszBuf);
549
550       if (!b) {
551          win_error(jcr, "GetFileAttributesExW:", ff_pkt->sys_fname);
552          return STREAM_UNIX_ATTRIBUTES;
553       }
554    }
555    else {
556       if (!p_GetFileAttributesExA)
557          return STREAM_UNIX_ATTRIBUTES;      
558
559       if (!p_GetFileAttributesExA(ff_pkt->sys_fname, GetFileExInfoStandard,
560                               (LPVOID)&atts)) {
561          win_error(jcr, "GetFileAttributesExA:", ff_pkt->sys_fname);
562          return STREAM_UNIX_ATTRIBUTES;
563       }
564    }
565
566    p += to_base64((uint64_t)atts.dwFileAttributes, p);
567    *p++ = ' ';                        /* separate fields with a space */
568    li.LowPart = atts.ftCreationTime.dwLowDateTime;
569    li.HighPart = atts.ftCreationTime.dwHighDateTime;
570    p += to_base64((uint64_t)li.QuadPart, p);
571    *p++ = ' ';
572    li.LowPart = atts.ftLastAccessTime.dwLowDateTime;
573    li.HighPart = atts.ftLastAccessTime.dwHighDateTime;
574    p += to_base64((uint64_t)li.QuadPart, p);
575    *p++ = ' ';
576    li.LowPart = atts.ftLastWriteTime.dwLowDateTime;
577    li.HighPart = atts.ftLastWriteTime.dwHighDateTime;
578    p += to_base64((uint64_t)li.QuadPart, p);
579    *p++ = ' ';
580    p += to_base64((uint64_t)atts.nFileSizeHigh, p);
581    *p++ = ' ';
582    p += to_base64((uint64_t)atts.nFileSizeLow, p);
583    *p = 0;
584    return STREAM_UNIX_ATTRIBUTES_EX;
585 }
586
587 /* Define attributes that are legal to set with SetFileAttributes() */
588 #define SET_ATTRS ( \
589          FILE_ATTRIBUTE_ARCHIVE| \
590          FILE_ATTRIBUTE_HIDDEN| \
591          FILE_ATTRIBUTE_NORMAL| \
592          FILE_ATTRIBUTE_NOT_CONTENT_INDEXED| \
593          FILE_ATTRIBUTE_OFFLINE| \
594          FILE_ATTRIBUTE_READONLY| \
595          FILE_ATTRIBUTE_SYSTEM| \
596          FILE_ATTRIBUTE_TEMPORARY)
597
598
599 /*
600  * Set Extended File Attributes for Win32
601  *
602  *  fname is the original filename
603  *  ofile is the output filename (may be in a different directory)
604  *
605  * Returns:  true  on success
606  *           false on failure
607  */
608 static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
609 {
610    char *p = attr->attrEx;
611    int64_t val;
612    WIN32_FILE_ATTRIBUTE_DATA atts;
613    ULARGE_INTEGER li;
614    POOLMEM *win32_ofile;
615
616    // if we have neither ansi nor wchar version, we leave
617    if (!(p_SetFileAttributesW || p_SetFileAttributesA))
618       return false;
619
620    if (!p || !*p) {                   /* we should have attributes */
621       Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", attr->ofname, ofd->fid);
622       if (is_bopen(ofd)) {
623          bclose(ofd);
624       }
625       return false;
626    } else {
627       Dmsg2(100, "Attribs %s = %s\n", attr->ofname, attr->attrEx);
628    }
629
630    p += from_base64(&val, p);
631    plug(atts.dwFileAttributes, val);
632    p++;                               /* skip space */
633    p += from_base64(&val, p);
634    li.QuadPart = val;
635    atts.ftCreationTime.dwLowDateTime = li.LowPart;
636    atts.ftCreationTime.dwHighDateTime = li.HighPart;
637    p++;                               /* skip space */
638    p += from_base64(&val, p);
639    li.QuadPart = val;
640    atts.ftLastAccessTime.dwLowDateTime = li.LowPart;
641    atts.ftLastAccessTime.dwHighDateTime = li.HighPart;
642    p++;                               /* skip space */
643    p += from_base64(&val, p);
644    li.QuadPart = val;
645    atts.ftLastWriteTime.dwLowDateTime = li.LowPart;
646    atts.ftLastWriteTime.dwHighDateTime = li.HighPart;
647    p++;
648    p += from_base64(&val, p);
649    plug(atts.nFileSizeHigh, val);
650    p++;
651    p += from_base64(&val, p);
652    plug(atts.nFileSizeLow, val);
653
654    /* Convert to Windows path format */
655    win32_ofile = get_pool_memory(PM_FNAME);
656    unix_name_to_win32(&win32_ofile, attr->ofname);
657
658    /* At this point, we have reconstructed the WIN32_FILE_ATTRIBUTE_DATA pkt */
659
660    if (!is_bopen(ofd)) {
661       Dmsg1(100, "File not open: %s\n", attr->ofname);
662       bopen(ofd, attr->ofname, O_WRONLY|O_BINARY, 0);   /* attempt to open the file */
663    }
664
665    if (is_bopen(ofd)) {
666       Dmsg1(100, "SetFileTime %s\n", attr->ofname);
667       if (!SetFileTime(bget_handle(ofd),
668                          &atts.ftCreationTime,
669                          &atts.ftLastAccessTime,
670                          &atts.ftLastWriteTime)) {
671          win_error(jcr, "SetFileTime:", win32_ofile);
672       }
673       bclose(ofd);
674    }
675
676    Dmsg1(100, "SetFileAtts %s\n", attr->ofname);
677    if (!(atts.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 
678    {
679       if (p_SetFileAttributesW) {
680          POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);   
681          make_win32_path_UTF8_2_wchar(&pwszBuf, attr->ofname);
682
683          BOOL b=p_SetFileAttributesW((LPCWSTR)pwszBuf, atts.dwFileAttributes & SET_ATTRS);
684          free_pool_memory(pwszBuf);
685       
686          if (!b) 
687             win_error(jcr, "SetFileAttributesW:", win32_ofile); 
688       }
689       else {
690          if (!p_SetFileAttributesA(win32_ofile, atts.dwFileAttributes & SET_ATTRS)) {
691             win_error(jcr, "SetFileAttributesA:", win32_ofile);
692          }
693       }
694    }
695    free_pool_memory(win32_ofile);
696    return true;
697 }
698
699 void win_error(JCR *jcr, char *prefix, POOLMEM *win32_ofile)
700 {
701    DWORD lerror = GetLastError();
702    LPTSTR msg;
703    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
704                  FORMAT_MESSAGE_FROM_SYSTEM,
705                  NULL,
706                  lerror,
707                  0,
708                  (LPTSTR)&msg,
709                  0,
710                  NULL);
711    Dmsg3(100, "Error in %s on file %s: ERR=%s\n", prefix, win32_ofile, msg);
712    strip_trailing_junk(msg);
713    Jmsg(jcr, M_ERROR, 0, _("Error in %s file %s: ERR=%s\n"), prefix, win32_ofile, msg);
714    LocalFree(msg);
715 }
716
717 void win_error(JCR *jcr, char *prefix, DWORD lerror)
718 {
719    LPTSTR msg;
720    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
721                  FORMAT_MESSAGE_FROM_SYSTEM,
722                  NULL,
723                  lerror,
724                  0,
725                  (LPTSTR)&msg,
726                  0,
727                  NULL);
728    strip_trailing_junk(msg);
729    if (jcr) {
730       Jmsg2(jcr, M_ERROR, 0, _("Error in %s: ERR=%s\n"), prefix, msg);
731    } else {
732       MessageBox(NULL, msg, prefix, MB_OK);
733    }
734    LocalFree(msg);
735 }
736 #endif  /* HAVE_WIN32 */