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