]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/attribs.c
kes Change Bacula trademark owner from John Walker to Kern Sibbald
[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   #else
230     /* Use templates to do the casting */
231     template <class T> void plug(T &st, uint64_t val)
232       { st = static_cast<T>(val); }
233   #endif
234 #endif
235
236
237 /* Decode a stat packet from base64 characters */
238 int decode_stat(char *buf, struct stat *statp, int32_t *LinkFI)
239 {
240    char *p = buf;
241    int64_t val;
242
243    p += from_base64(&val, p);
244    plug(statp->st_dev, val);
245    p++;
246    p += from_base64(&val, p);
247    plug(statp->st_ino, val);
248    p++;
249    p += from_base64(&val, p);
250    plug(statp->st_mode, val);
251    p++;
252    p += from_base64(&val, p);
253    plug(statp->st_nlink, val);
254    p++;
255    p += from_base64(&val, p);
256    plug(statp->st_uid, val);
257    p++;
258    p += from_base64(&val, p);
259    plug(statp->st_gid, val);
260    p++;
261    p += from_base64(&val, p);
262    plug(statp->st_rdev, val);
263    p++;
264    p += from_base64(&val, p);
265    plug(statp->st_size, val);
266    p++;
267 #ifndef HAVE_MINGW
268    p += from_base64(&val, p);
269    plug(statp->st_blksize, val);
270    p++;
271    p += from_base64(&val, p);
272    plug(statp->st_blocks, val);
273    p++;
274 #else
275    p += from_base64(&val, p);
276 //   plug(statp->st_blksize, val);
277    p++;
278    p += from_base64(&val, p);
279 //   plug(statp->st_blocks, val);
280    p++;
281 #endif
282    p += from_base64(&val, p);
283    plug(statp->st_atime, val);
284    p++;
285    p += from_base64(&val, p);
286    plug(statp->st_mtime, val);
287    p++;
288    p += from_base64(&val, p);
289    plug(statp->st_ctime, val);
290
291    /* Optional FileIndex of hard linked file data */
292    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
293       p++;
294       p += from_base64(&val, p);
295       *LinkFI = (uint32_t)val;
296    } else {
297       *LinkFI = 0;
298       return 0;
299    }
300
301    /* FreeBSD user flags */
302    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
303       p++;
304       p += from_base64(&val, p);
305 #ifdef HAVE_CHFLAGS
306       plug(statp->st_flags, val);
307    } else {
308       statp->st_flags  = 0;
309 #endif
310    }
311
312    /* Look for data stream id */
313    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
314       p++;
315       p += from_base64(&val, p);
316    } else {
317       val = 0;
318    }
319    return (int)val;
320 }
321
322 /* Decode a LinkFI field of encoded stat packet */
323 int32_t decode_LinkFI(char *buf, struct stat *statp)
324 {
325    char *p = buf;
326    int64_t val;
327
328    skip_nonspaces(&p);                /* st_dev */
329    p++;                               /* skip space */
330    skip_nonspaces(&p);                /* st_ino */
331    p++;
332    p += from_base64(&val, p);
333    plug(statp->st_mode, val);         /* st_mode */
334    p++;
335    skip_nonspaces(&p);                /* st_nlink */
336    p++;
337    skip_nonspaces(&p);                /* st_uid */
338    p++;
339    skip_nonspaces(&p);                /* st_gid */
340    p++;
341    skip_nonspaces(&p);                /* st_rdev */
342    p++;
343    skip_nonspaces(&p);                /* st_size */
344    p++;
345    skip_nonspaces(&p);                /* st_blksize */
346    p++;
347    skip_nonspaces(&p);                /* st_blocks */
348    p++;
349    skip_nonspaces(&p);                /* st_atime */
350    p++;
351    skip_nonspaces(&p);                /* st_mtime */
352    p++;
353    skip_nonspaces(&p);                /* st_ctime */
354
355    /* Optional FileIndex of hard linked file data */
356    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
357       p++;
358       p += from_base64(&val, p);
359       return (int32_t)val;
360    }
361    return 0;
362 }
363
364 /*
365  * Set file modes, permissions and times
366  *
367  *  fname is the original filename
368  *  ofile is the output filename (may be in a different directory)
369  *
370  * Returns:  true  on success
371  *           false on failure
372  */
373 bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
374 {
375    struct utimbuf ut;
376    mode_t old_mask;
377    bool ok = true;
378    boffset_t fsize;
379  
380    if (uid_set) {
381       my_uid = getuid();
382       my_gid = getgid();
383       uid_set = true;
384    }
385
386 #if defined(HAVE_WIN32)
387    if (attr->stream == STREAM_UNIX_ATTRIBUTES_EX &&
388        set_win32_attributes(jcr, attr, ofd)) {
389        if (is_bopen(ofd)) {
390            bclose(ofd);
391        }
392        pm_strcpy(attr->ofname, "*none*");
393        return true;
394    }
395    if (attr->data_stream == STREAM_WIN32_DATA ||
396        attr->data_stream == STREAM_WIN32_GZIP_DATA) {
397       if (is_bopen(ofd)) {
398          bclose(ofd);
399       }
400       pm_strcpy(attr->ofname, "*none*");
401       return true;
402    }
403
404
405    /*
406     * If Windows stuff failed, e.g. attempt to restore Unix file
407     *  to Windows, simply fall through and we will do it the
408     *  universal way.
409     */
410 #endif
411
412    old_mask = umask(0);
413    if (is_bopen(ofd)) {
414       char ec1[50], ec2[50];
415       fsize = blseek(ofd, 0, SEEK_END);
416       bclose(ofd);                    /* first close file */
417       if (attr->type == FT_REG && fsize > 0 && attr->statp.st_size > 0 && 
418                         fsize != (boffset_t)attr->statp.st_size) {
419          Jmsg3(jcr, M_ERROR, 0, _("File size of restored file %s not correct. Original %s, restored %s.\n"),
420             attr->ofname, edit_uint64(attr->statp.st_size, ec1),
421             edit_uint64(fsize, ec2));
422       }
423    }
424
425    /*
426     * We do not restore sockets, so skip trying to restore their
427     *   attributes.
428     */
429    if (attr->type == FT_SPEC && S_ISSOCK(attr->statp.st_mode)) {
430       goto bail_out;
431    }
432
433    ut.actime = attr->statp.st_atime;
434    ut.modtime = attr->statp.st_mtime;
435
436    /* ***FIXME**** optimize -- don't do if already correct */
437    /*
438     * For link, change owner of link using lchown, but don't
439     *   try to do a chmod as that will update the file behind it.
440     */
441    if (attr->type == FT_LNK) {
442       /* Change owner of link, not of real file */
443       if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && my_uid == 0) {
444          berrno be;
445          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
446             attr->ofname, be.bstrerror());
447          ok = false;
448       }
449    } else {
450       if (chown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && my_uid == 0) {
451          berrno be;
452          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
453             attr->ofname, be.bstrerror());
454          ok = false;
455       }
456       if (chmod(attr->ofname, attr->statp.st_mode) < 0 && my_uid == 0) {
457          berrno be;
458          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"),
459             attr->ofname, be.bstrerror());
460          ok = false;
461       }
462
463       /*
464        * Reset file times.
465        */
466       if (utime(attr->ofname, &ut) < 0 && my_uid == 0) {
467          berrno be;
468          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
469             attr->ofname, be.bstrerror());
470          ok = false;
471       }
472 #ifdef HAVE_CHFLAGS
473       /*
474        * FreeBSD user flags
475        *
476        * Note, this should really be done before the utime() above,
477        *  but if the immutable bit is set, it will make the utimes()
478        *  fail.
479        */
480       if (chflags(attr->ofname, attr->statp.st_flags) < 0 && my_uid == 0) {
481          berrno be;
482          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file flags %s: ERR=%s\n"),
483             attr->ofname, be.bstrerror());
484          ok = false;
485       }
486 #endif
487    }
488
489 bail_out:
490    pm_strcpy(attr->ofname, "*none*");
491    umask(old_mask);
492    return ok;
493 }
494
495
496 /*=============================================================*/
497 /*                                                             */
498 /*                 * * *  U n i x * * * *                      */
499 /*                                                             */
500 /*=============================================================*/
501
502 #if !defined(HAVE_WIN32)
503
504 /*
505  * It is possible to piggyback additional data e.g. ACLs on
506  *   the encode_stat() data by returning the extended attributes
507  *   here.  They must be "self-contained" (i.e. you keep track
508  *   of your own length), and they must be in ASCII string
509  *   format. Using this feature is not recommended.
510  * The code below shows how to return nothing.  See the Win32
511  *   code below for returning something in the attributes.
512  */
513 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
514 {
515 #ifdef HAVE_DARWIN_OS
516    /*
517     * We save the Mac resource fork length so that on a
518     * restore, we can be sure we put back the whole resource.
519     */
520    char *p;
521    p = attribsEx;
522    if (ff_pkt->flags & FO_HFSPLUS) {
523       p += to_base64((uint64_t)(ff_pkt->hfsinfo.rsrclength), p);
524    }
525    *p = 0;
526 #else
527    *attribsEx = 0;                    /* no extended attributes */
528 #endif
529    return STREAM_UNIX_ATTRIBUTES;
530 }
531
532 #endif
533
534
535
536 /*=============================================================*/
537 /*                                                             */
538 /*                 * * *  W i n 3 2 * * * *                    */
539 /*                                                             */
540 /*=============================================================*/
541
542 #if defined(HAVE_WIN32)
543
544 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
545 {
546    char *p = attribsEx;
547    WIN32_FILE_ATTRIBUTE_DATA atts;
548    ULARGE_INTEGER li;
549
550    attribsEx[0] = 0;                  /* no extended attributes */
551
552    unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname);
553
554    // try unicode version
555    if (p_GetFileAttributesExW)  {
556       POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);   
557       make_win32_path_UTF8_2_wchar(&pwszBuf, ff_pkt->fname);
558
559       BOOL b=p_GetFileAttributesExW((LPCWSTR) pwszBuf, GetFileExInfoStandard, (LPVOID)&atts);
560       free_pool_memory(pwszBuf);
561
562       if (!b) {
563          win_error(jcr, "GetFileAttributesExW:", ff_pkt->sys_fname);
564          return STREAM_UNIX_ATTRIBUTES;
565       }
566    }
567    else {
568       if (!p_GetFileAttributesExA)
569          return STREAM_UNIX_ATTRIBUTES;      
570
571       if (!p_GetFileAttributesExA(ff_pkt->sys_fname, GetFileExInfoStandard,
572                               (LPVOID)&atts)) {
573          win_error(jcr, "GetFileAttributesExA:", ff_pkt->sys_fname);
574          return STREAM_UNIX_ATTRIBUTES;
575       }
576    }
577
578    p += to_base64((uint64_t)atts.dwFileAttributes, p);
579    *p++ = ' ';                        /* separate fields with a space */
580    li.LowPart = atts.ftCreationTime.dwLowDateTime;
581    li.HighPart = atts.ftCreationTime.dwHighDateTime;
582    p += to_base64((uint64_t)li.QuadPart, p);
583    *p++ = ' ';
584    li.LowPart = atts.ftLastAccessTime.dwLowDateTime;
585    li.HighPart = atts.ftLastAccessTime.dwHighDateTime;
586    p += to_base64((uint64_t)li.QuadPart, p);
587    *p++ = ' ';
588    li.LowPart = atts.ftLastWriteTime.dwLowDateTime;
589    li.HighPart = atts.ftLastWriteTime.dwHighDateTime;
590    p += to_base64((uint64_t)li.QuadPart, p);
591    *p++ = ' ';
592    p += to_base64((uint64_t)atts.nFileSizeHigh, p);
593    *p++ = ' ';
594    p += to_base64((uint64_t)atts.nFileSizeLow, p);
595    *p = 0;
596    return STREAM_UNIX_ATTRIBUTES_EX;
597 }
598
599 /* Define attributes that are legal to set with SetFileAttributes() */
600 #define SET_ATTRS ( \
601          FILE_ATTRIBUTE_ARCHIVE| \
602          FILE_ATTRIBUTE_HIDDEN| \
603          FILE_ATTRIBUTE_NORMAL| \
604          FILE_ATTRIBUTE_NOT_CONTENT_INDEXED| \
605          FILE_ATTRIBUTE_OFFLINE| \
606          FILE_ATTRIBUTE_READONLY| \
607          FILE_ATTRIBUTE_SYSTEM| \
608          FILE_ATTRIBUTE_TEMPORARY)
609
610
611 /*
612  * Set Extended File Attributes for Win32
613  *
614  *  fname is the original filename
615  *  ofile is the output filename (may be in a different directory)
616  *
617  * Returns:  true  on success
618  *           false on failure
619  */
620 static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
621 {
622    char *p = attr->attrEx;
623    int64_t val;
624    WIN32_FILE_ATTRIBUTE_DATA atts;
625    ULARGE_INTEGER li;
626    POOLMEM *win32_ofile;
627
628    // if we have neither ansi nor wchar version, we leave
629    if (!(p_SetFileAttributesW || p_SetFileAttributesA)) {
630       return false;
631    }
632
633    if (!p || !*p) {                   /* we should have attributes */
634       Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", attr->ofname, ofd->fid);
635       if (is_bopen(ofd)) {
636          bclose(ofd);
637       }
638       return false;
639    } else {
640       Dmsg2(100, "Attribs %s = %s\n", attr->ofname, attr->attrEx);
641    }
642
643    p += from_base64(&val, p);
644    plug(atts.dwFileAttributes, val);
645    p++;                               /* skip space */
646    p += from_base64(&val, p);
647    li.QuadPart = val;
648    atts.ftCreationTime.dwLowDateTime = li.LowPart;
649    atts.ftCreationTime.dwHighDateTime = li.HighPart;
650    p++;                               /* skip space */
651    p += from_base64(&val, p);
652    li.QuadPart = val;
653    atts.ftLastAccessTime.dwLowDateTime = li.LowPart;
654    atts.ftLastAccessTime.dwHighDateTime = li.HighPart;
655    p++;                               /* skip space */
656    p += from_base64(&val, p);
657    li.QuadPart = val;
658    atts.ftLastWriteTime.dwLowDateTime = li.LowPart;
659    atts.ftLastWriteTime.dwHighDateTime = li.HighPart;
660    p++;
661    p += from_base64(&val, p);
662    plug(atts.nFileSizeHigh, val);
663    p++;
664    p += from_base64(&val, p);
665    plug(atts.nFileSizeLow, val);
666
667    /* Convert to Windows path format */
668    win32_ofile = get_pool_memory(PM_FNAME);
669    unix_name_to_win32(&win32_ofile, attr->ofname);
670
671    /* At this point, we have reconstructed the WIN32_FILE_ATTRIBUTE_DATA pkt */
672
673    if (!is_bopen(ofd)) {
674       Dmsg1(100, "File not open: %s\n", attr->ofname);
675       bopen(ofd, attr->ofname, O_WRONLY|O_BINARY, 0);   /* attempt to open the file */
676    }
677
678    if (is_bopen(ofd)) {
679       Dmsg1(100, "SetFileTime %s\n", attr->ofname);
680       if (!SetFileTime(bget_handle(ofd),
681                          &atts.ftCreationTime,
682                          &atts.ftLastAccessTime,
683                          &atts.ftLastWriteTime)) {
684          win_error(jcr, "SetFileTime:", win32_ofile);
685       }
686       bclose(ofd);
687    }
688
689    Dmsg1(100, "SetFileAtts %s\n", attr->ofname);
690    if (!(atts.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
691       if (p_SetFileAttributesW) {
692          POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);   
693          make_win32_path_UTF8_2_wchar(&pwszBuf, attr->ofname);
694
695          BOOL b=p_SetFileAttributesW((LPCWSTR)pwszBuf, atts.dwFileAttributes & SET_ATTRS);
696          free_pool_memory(pwszBuf);
697       
698          if (!b) 
699             win_error(jcr, "SetFileAttributesW:", win32_ofile); 
700       }
701       else {
702          if (!p_SetFileAttributesA(win32_ofile, atts.dwFileAttributes & SET_ATTRS)) {
703             win_error(jcr, "SetFileAttributesA:", win32_ofile);
704          }
705       }
706    }
707    free_pool_memory(win32_ofile);
708    return true;
709 }
710
711 void win_error(JCR *jcr, char *prefix, POOLMEM *win32_ofile)
712 {
713    DWORD lerror = GetLastError();
714    LPTSTR msg;
715    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
716                  FORMAT_MESSAGE_FROM_SYSTEM,
717                  NULL,
718                  lerror,
719                  0,
720                  (LPTSTR)&msg,
721                  0,
722                  NULL);
723    Dmsg3(100, "Error in %s on file %s: ERR=%s\n", prefix, win32_ofile, msg);
724    strip_trailing_junk(msg);
725    Jmsg(jcr, M_ERROR, 0, _("Error in %s file %s: ERR=%s\n"), prefix, win32_ofile, msg);
726    LocalFree(msg);
727 }
728
729 void win_error(JCR *jcr, char *prefix, DWORD lerror)
730 {
731    LPTSTR msg;
732    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
733                  FORMAT_MESSAGE_FROM_SYSTEM,
734                  NULL,
735                  lerror,
736                  0,
737                  (LPTSTR)&msg,
738                  0,
739                  NULL);
740    strip_trailing_junk(msg);
741    if (jcr) {
742       Jmsg2(jcr, M_ERROR, 0, _("Error in %s: ERR=%s\n"), prefix, msg);
743    } else {
744       MessageBox(NULL, msg, prefix, MB_OK);
745    }
746    LocalFree(msg);
747 }
748 #endif  /* HAVE_WIN32 */