]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/attribs.c
Apply Eric's fix for suppressing extended attributes error messages
[bacula/bacula] / bacula / src / findlib / attribs.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2009 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
524    *attribsEx = 0;                 /* no extended attributes (yet) */
525    if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) {
526       return STREAM_UNIX_ATTRIBUTES;
527    }
528    p = attribsEx;
529    if (ff_pkt->flags & FO_HFSPLUS) {
530       p += to_base64((uint64_t)(ff_pkt->hfsinfo.rsrclength), p);
531    }
532    *p = 0;
533 #else
534    *attribsEx = 0;                    /* no extended attributes */
535 #endif
536    return STREAM_UNIX_ATTRIBUTES;
537 }
538
539 #endif
540
541
542
543 /*=============================================================*/
544 /*                                                             */
545 /*                 * * *  W i n 3 2 * * * *                    */
546 /*                                                             */
547 /*=============================================================*/
548
549 #if defined(HAVE_WIN32)
550
551 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
552 {
553    char *p = attribsEx;
554    WIN32_FILE_ATTRIBUTE_DATA atts;
555    ULARGE_INTEGER li;
556
557    attribsEx[0] = 0;                  /* no extended attributes */
558
559    if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) {
560       return STREAM_UNIX_ATTRIBUTES;
561    }
562
563    unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname);
564
565    // try unicode version
566    if (p_GetFileAttributesExW)  {
567       POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);   
568       make_win32_path_UTF8_2_wchar(&pwszBuf, ff_pkt->fname);
569
570       BOOL b=p_GetFileAttributesExW((LPCWSTR)pwszBuf, GetFileExInfoStandard, 
571                                     (LPVOID)&atts);
572       free_pool_memory(pwszBuf);
573
574       if (!b) {
575          win_error(jcr, "GetFileAttributesExW:", ff_pkt->sys_fname);
576          return STREAM_UNIX_ATTRIBUTES;
577       }
578    }
579    else {
580       if (!p_GetFileAttributesExA)
581          return STREAM_UNIX_ATTRIBUTES;      
582
583       if (!p_GetFileAttributesExA(ff_pkt->sys_fname, GetFileExInfoStandard,
584                               (LPVOID)&atts)) {
585          win_error(jcr, "GetFileAttributesExA:", ff_pkt->sys_fname);
586          return STREAM_UNIX_ATTRIBUTES;
587       }
588    }
589
590    p += to_base64((uint64_t)atts.dwFileAttributes, p);
591    *p++ = ' ';                        /* separate fields with a space */
592    li.LowPart = atts.ftCreationTime.dwLowDateTime;
593    li.HighPart = atts.ftCreationTime.dwHighDateTime;
594    p += to_base64((uint64_t)li.QuadPart, p);
595    *p++ = ' ';
596    li.LowPart = atts.ftLastAccessTime.dwLowDateTime;
597    li.HighPart = atts.ftLastAccessTime.dwHighDateTime;
598    p += to_base64((uint64_t)li.QuadPart, p);
599    *p++ = ' ';
600    li.LowPart = atts.ftLastWriteTime.dwLowDateTime;
601    li.HighPart = atts.ftLastWriteTime.dwHighDateTime;
602    p += to_base64((uint64_t)li.QuadPart, p);
603    *p++ = ' ';
604    p += to_base64((uint64_t)atts.nFileSizeHigh, p);
605    *p++ = ' ';
606    p += to_base64((uint64_t)atts.nFileSizeLow, p);
607    *p = 0;
608    return STREAM_UNIX_ATTRIBUTES_EX;
609 }
610
611 /* Define attributes that are legal to set with SetFileAttributes() */
612 #define SET_ATTRS ( \
613          FILE_ATTRIBUTE_ARCHIVE| \
614          FILE_ATTRIBUTE_HIDDEN| \
615          FILE_ATTRIBUTE_NORMAL| \
616          FILE_ATTRIBUTE_NOT_CONTENT_INDEXED| \
617          FILE_ATTRIBUTE_OFFLINE| \
618          FILE_ATTRIBUTE_READONLY| \
619          FILE_ATTRIBUTE_SYSTEM| \
620          FILE_ATTRIBUTE_TEMPORARY)
621
622
623 /*
624  * Set Extended File Attributes for Win32
625  *
626  *  fname is the original filename
627  *  ofile is the output filename (may be in a different directory)
628  *
629  * Returns:  true  on success
630  *           false on failure
631  */
632 static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
633 {
634    char *p = attr->attrEx;
635    int64_t val;
636    WIN32_FILE_ATTRIBUTE_DATA atts;
637    ULARGE_INTEGER li;
638    POOLMEM *win32_ofile;
639
640    // if we have neither ansi nor wchar version, we leave
641    if (!(p_SetFileAttributesW || p_SetFileAttributesA)) {
642       return false;
643    }
644
645    if (!p || !*p) {                   /* we should have attributes */
646       Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", attr->ofname, ofd->fid);
647       if (is_bopen(ofd)) {
648          bclose(ofd);
649       }
650       return false;
651    } else {
652       Dmsg2(100, "Attribs %s = %s\n", attr->ofname, attr->attrEx);
653    }
654
655    p += from_base64(&val, p);
656    plug(atts.dwFileAttributes, val);
657    p++;                               /* skip space */
658    p += from_base64(&val, p);
659    li.QuadPart = val;
660    atts.ftCreationTime.dwLowDateTime = li.LowPart;
661    atts.ftCreationTime.dwHighDateTime = li.HighPart;
662    p++;                               /* skip space */
663    p += from_base64(&val, p);
664    li.QuadPart = val;
665    atts.ftLastAccessTime.dwLowDateTime = li.LowPart;
666    atts.ftLastAccessTime.dwHighDateTime = li.HighPart;
667    p++;                               /* skip space */
668    p += from_base64(&val, p);
669    li.QuadPart = val;
670    atts.ftLastWriteTime.dwLowDateTime = li.LowPart;
671    atts.ftLastWriteTime.dwHighDateTime = li.HighPart;
672    p++;
673    p += from_base64(&val, p);
674    plug(atts.nFileSizeHigh, val);
675    p++;
676    p += from_base64(&val, p);
677    plug(atts.nFileSizeLow, val);
678
679    /* Convert to Windows path format */
680    win32_ofile = get_pool_memory(PM_FNAME);
681    unix_name_to_win32(&win32_ofile, attr->ofname);
682
683    /* At this point, we have reconstructed the WIN32_FILE_ATTRIBUTE_DATA pkt */
684
685    if (!is_bopen(ofd)) {
686       Dmsg1(100, "File not open: %s\n", attr->ofname);
687       bopen(ofd, attr->ofname, O_WRONLY|O_BINARY, 0);   /* attempt to open the file */
688    }
689
690    if (is_bopen(ofd)) {
691       Dmsg1(100, "SetFileTime %s\n", attr->ofname);
692       if (!SetFileTime(bget_handle(ofd),
693                          &atts.ftCreationTime,
694                          &atts.ftLastAccessTime,
695                          &atts.ftLastWriteTime)) {
696          win_error(jcr, "SetFileTime:", win32_ofile);
697       }
698       bclose(ofd);
699    }
700
701    Dmsg1(100, "SetFileAtts %s\n", attr->ofname);
702    if (!(atts.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
703       if (p_SetFileAttributesW) {
704          POOLMEM* pwszBuf = get_pool_memory(PM_FNAME);   
705          make_win32_path_UTF8_2_wchar(&pwszBuf, attr->ofname);
706
707          BOOL b=p_SetFileAttributesW((LPCWSTR)pwszBuf, atts.dwFileAttributes & SET_ATTRS);
708          free_pool_memory(pwszBuf);
709       
710          if (!b) 
711             win_error(jcr, "SetFileAttributesW:", win32_ofile); 
712       }
713       else {
714          if (!p_SetFileAttributesA(win32_ofile, atts.dwFileAttributes & SET_ATTRS)) {
715             win_error(jcr, "SetFileAttributesA:", win32_ofile);
716          }
717       }
718    }
719    free_pool_memory(win32_ofile);
720    return true;
721 }
722
723 void win_error(JCR *jcr, char *prefix, POOLMEM *win32_ofile)
724 {
725    DWORD lerror = GetLastError();
726    LPTSTR msg;
727    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
728                  FORMAT_MESSAGE_FROM_SYSTEM,
729                  NULL,
730                  lerror,
731                  0,
732                  (LPTSTR)&msg,
733                  0,
734                  NULL);
735    Dmsg3(100, "Error in %s on file %s: ERR=%s\n", prefix, win32_ofile, msg);
736    strip_trailing_junk(msg);
737    Jmsg3(jcr, M_ERROR, 0, _("Error in %s file %s: ERR=%s\n"), prefix, win32_ofile, msg);
738    LocalFree(msg);
739 }
740
741 void win_error(JCR *jcr, char *prefix, DWORD lerror)
742 {
743    LPTSTR msg;
744    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
745                  FORMAT_MESSAGE_FROM_SYSTEM,
746                  NULL,
747                  lerror,
748                  0,
749                  (LPTSTR)&msg,
750                  0,
751                  NULL);
752    strip_trailing_junk(msg);
753    if (jcr) {
754       Jmsg2(jcr, M_ERROR, 0, _("Error in %s: ERR=%s\n"), prefix, msg);
755    } else {
756       MessageBox(NULL, msg, prefix, MB_OK);
757    }
758    LocalFree(msg);
759 }
760 #endif  /* HAVE_WIN32 */