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