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