]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/attribs.c
take out 260char limit for win NT/XP, etc. paths can become 32K characters long now.
[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    unix_name_to_win32(&ff_pkt->sys_fname, ff_pkt->fname);
516
517    // try unicode version
518    if (p_GetFileAttributesExW)  {
519       POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);   
520       make_win32_path_UTF8_2_wchar(&pwszBuf, ff_pkt->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       if (!p_GetFileAttributesExA(ff_pkt->sys_fname, GetFileExInfoStandard,
535                               (LPVOID)&atts)) {
536          win_error(jcr, "GetFileAttributesExA:", ff_pkt->sys_fname);
537          return STREAM_UNIX_ATTRIBUTES;
538       }
539    }
540
541    p += to_base64((uint64_t)atts.dwFileAttributes, p);
542    *p++ = ' ';                        /* separate fields with a space */
543    li.LowPart = atts.ftCreationTime.dwLowDateTime;
544    li.HighPart = atts.ftCreationTime.dwHighDateTime;
545    p += to_base64((uint64_t)li.QuadPart, p);
546    *p++ = ' ';
547    li.LowPart = atts.ftLastAccessTime.dwLowDateTime;
548    li.HighPart = atts.ftLastAccessTime.dwHighDateTime;
549    p += to_base64((uint64_t)li.QuadPart, p);
550    *p++ = ' ';
551    li.LowPart = atts.ftLastWriteTime.dwLowDateTime;
552    li.HighPart = atts.ftLastWriteTime.dwHighDateTime;
553    p += to_base64((uint64_t)li.QuadPart, p);
554    *p++ = ' ';
555    p += to_base64((uint64_t)atts.nFileSizeHigh, p);
556    *p++ = ' ';
557    p += to_base64((uint64_t)atts.nFileSizeLow, p);
558    *p = 0;
559    return STREAM_UNIX_ATTRIBUTES_EX;
560 }
561
562 /* Define attributes that are legal to set with SetFileAttributes() */
563 #define SET_ATTRS ( \
564          FILE_ATTRIBUTE_ARCHIVE| \
565          FILE_ATTRIBUTE_HIDDEN| \
566          FILE_ATTRIBUTE_NORMAL| \
567          FILE_ATTRIBUTE_NOT_CONTENT_INDEXED| \
568          FILE_ATTRIBUTE_OFFLINE| \
569          FILE_ATTRIBUTE_READONLY| \
570          FILE_ATTRIBUTE_SYSTEM| \
571          FILE_ATTRIBUTE_TEMPORARY)
572
573
574 /*
575  * Set Extended File Attributes for Win32
576  *
577  *  fname is the original filename
578  *  ofile is the output filename (may be in a different directory)
579  *
580  * Returns:  true  on success
581  *           false on failure
582  */
583 static bool set_win32_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
584 {
585    char *p = attr->attrEx;
586    int64_t val;
587    WIN32_FILE_ATTRIBUTE_DATA atts;
588    ULARGE_INTEGER li;
589    POOLMEM *win32_ofile;
590
591    // if we have neither ansi nor wchar version, we leave
592    if (!(p_SetFileAttributesW || p_SetFileAttributesA))
593       return false;
594
595    if (!p || !*p) {                   /* we should have attributes */
596       Dmsg2(100, "Attributes missing. of=%s ofd=%d\n", attr->ofname, ofd->fid);
597       if (is_bopen(ofd)) {
598          bclose(ofd);
599       }
600       return false;
601    } else {
602       Dmsg2(100, "Attribs %s = %s\n", attr->ofname, attr->attrEx);
603    }
604
605    p += from_base64(&val, p);
606    plug(atts.dwFileAttributes, val);
607    p++;                               /* skip space */
608    p += from_base64(&val, p);
609    li.QuadPart = val;
610    atts.ftCreationTime.dwLowDateTime = li.LowPart;
611    atts.ftCreationTime.dwHighDateTime = li.HighPart;
612    p++;                               /* skip space */
613    p += from_base64(&val, p);
614    li.QuadPart = val;
615    atts.ftLastAccessTime.dwLowDateTime = li.LowPart;
616    atts.ftLastAccessTime.dwHighDateTime = li.HighPart;
617    p++;                               /* skip space */
618    p += from_base64(&val, p);
619    li.QuadPart = val;
620    atts.ftLastWriteTime.dwLowDateTime = li.LowPart;
621    atts.ftLastWriteTime.dwHighDateTime = li.HighPart;
622    p++;
623    p += from_base64(&val, p);
624    plug(atts.nFileSizeHigh, val);
625    p++;
626    p += from_base64(&val, p);
627    plug(atts.nFileSizeLow, val);
628
629    /* Convert to Windows path format */
630    win32_ofile = get_pool_memory(PM_FNAME);
631    unix_name_to_win32(&win32_ofile, attr->ofname);
632
633    /* At this point, we have reconstructed the WIN32_FILE_ATTRIBUTE_DATA pkt */
634
635    if (!is_bopen(ofd)) {
636       Dmsg1(100, "File not open: %s\n", attr->ofname);
637       bopen(ofd, attr->ofname, O_WRONLY|O_BINARY, 0);   /* attempt to open the file */
638    }
639
640    if (is_bopen(ofd)) {
641       Dmsg1(100, "SetFileTime %s\n", attr->ofname);
642       if (!SetFileTime(bget_handle(ofd),
643                          &atts.ftCreationTime,
644                          &atts.ftLastAccessTime,
645                          &atts.ftLastWriteTime)) {
646          win_error(jcr, "SetFileTime:", win32_ofile);
647       }
648       bclose(ofd);
649    }
650
651    Dmsg1(100, "SetFileAtts %s\n", attr->ofname);
652    if (!(atts.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 
653    {
654       if (p_SetFileAttributesW) {
655          POOLMEM* pwszBuf = get_pool_memory (PM_FNAME);   
656          make_win32_path_UTF8_2_wchar(&pwszBuf, attr->ofname);
657
658          BOOL b=p_SetFileAttributesW((LPCWSTR)pwszBuf, atts.dwFileAttributes & SET_ATTRS);
659          free_pool_memory(pwszBuf);
660       
661          if (!b) 
662             win_error(jcr, "SetFileAttributesW:", win32_ofile); 
663       }
664       else {
665          if (!p_SetFileAttributesA(win32_ofile, atts.dwFileAttributes & SET_ATTRS)) {
666             win_error(jcr, "SetFileAttributesA:", win32_ofile);
667          }
668       }
669    }
670    free_pool_memory(win32_ofile);
671    return true;
672 }
673
674 void win_error(JCR *jcr, char *prefix, POOLMEM *win32_ofile)
675 {
676    DWORD lerror = GetLastError();
677    LPTSTR msg;
678    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
679                  FORMAT_MESSAGE_FROM_SYSTEM,
680                  NULL,
681                  lerror,
682                  0,
683                  (LPTSTR)&msg,
684                  0,
685                  NULL);
686    Dmsg3(100, "Error in %s on file %s: ERR=%s\n", prefix, win32_ofile, msg);
687    strip_trailing_junk(msg);
688    Jmsg(jcr, M_ERROR, 0, _("Error in %s file %s: ERR=%s\n"), prefix, win32_ofile, msg);
689    LocalFree(msg);
690 }
691
692 void win_error(JCR *jcr, char *prefix, DWORD lerror)
693 {
694    LPTSTR msg;
695    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
696                  FORMAT_MESSAGE_FROM_SYSTEM,
697                  NULL,
698                  lerror,
699                  0,
700                  (LPTSTR)&msg,
701                  0,
702                  NULL);
703    strip_trailing_junk(msg);
704    if (jcr) {
705       Jmsg2(jcr, M_ERROR, 0, _("Error in %s: ERR=%s\n"), prefix, msg);
706    } else {
707       MessageBox(NULL, msg, prefix, MB_OK);
708    }
709    LocalFree(msg);
710 }
711
712
713 /* Conversion of a Unix filename to a Win32 filename */
714 extern void conv_unix_to_win32_path(const char *path, char *win32_path, DWORD dwSize);
715 void unix_name_to_win32(POOLMEM **win32_name, char *name)
716 {
717    /* One extra byte should suffice, but we double it */
718    /* add MAX_PATH bytes for VSS shadow copy name */
719    DWORD dwSize = 2*strlen(name)+MAX_PATH;
720    *win32_name = check_pool_memory_size(*win32_name, dwSize);
721    conv_unix_to_win32_path(name, *win32_name, dwSize);
722 }
723
724 #endif  /* HAVE_CYGWIN */