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