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