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