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