1 /* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
2 
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6 
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation.  The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License, version 2.0, for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 /*
24   The purpose of this file is to provide implementation of file IO routines on
25   Windows that can be thought as drop-in replacement for corresponding C runtime
26   functionality.
27 
28   Compared to Windows CRT, this one
29   - does not have the same file descriptor
30   limitation (default is 16384 and can  be increased further, whereas CRT poses
31   a hard limit of 2048 file descriptors)
32   - the file operations are not serialized
33   - positional IO pread/pwrite is ported here.
34   - no text mode for files, all IO is "binary"
35 
36   Naming convention:
37   All routines are prefixed with my_win_, e.g Posix open() is implemented with
38   my_win_open()
39 
40   Implemented are
41   - POSIX routines(e.g open, read, lseek ...)
42   - Some ANSI C stream routines (fopen, fdopen, fileno, fclose)
43   - Windows CRT equvalients (my_get_osfhandle, open_osfhandle)
44 
45   Worth to note:
46   - File descriptors used here are located in a range that is not compatible
47   with CRT on purpose. Attempt to use a file descriptor from Windows CRT library
48   range in my_win_* function will be punished with DBUG_ASSERT()
49 
50   - File streams (FILE *) are actually from the C runtime. The routines provided
51   here are useful only in scernarios that use low-level IO with my_win_fileno()
52 */
53 
54 #ifdef _WIN32
55 
56 #include "mysys_priv.h"
57 #include <share.h>
58 #include <sys/stat.h>
59 
60 /* Associates a file descriptor with an existing operating-system file handle.*/
my_open_osfhandle(HANDLE handle,int oflag)61 File my_open_osfhandle(HANDLE handle, int oflag)
62 {
63   int offset= -1;
64   uint i;
65   DBUG_ENTER("my_open_osfhandle");
66 
67   mysql_mutex_lock(&THR_LOCK_open);
68   for(i= MY_FILE_MIN; i < my_file_limit;i++)
69   {
70     if(my_file_info[i].fhandle == 0)
71     {
72       struct st_my_file_info *finfo= &(my_file_info[i]);
73       finfo->type=    FILE_BY_OPEN;
74       finfo->fhandle= handle;
75       finfo->oflag=   oflag;
76       offset= i;
77       break;
78     }
79   }
80   mysql_mutex_unlock(&THR_LOCK_open);
81   if(offset == -1)
82     errno= EMFILE; /* to many file handles open */
83   DBUG_RETURN(offset);
84 }
85 
86 
invalidate_fd(File fd)87 static void invalidate_fd(File fd)
88 {
89   DBUG_ENTER("invalidate_fd");
90   DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit);
91   my_file_info[fd].fhandle= 0;
92   DBUG_VOID_RETURN;
93 }
94 
95 
96 /* Get Windows handle for a file descriptor */
my_get_osfhandle(File fd)97 HANDLE my_get_osfhandle(File fd)
98 {
99   DBUG_ENTER("my_get_osfhandle");
100   DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit);
101   DBUG_RETURN(my_file_info[fd].fhandle);
102 }
103 
104 
my_get_open_flags(File fd)105 static int my_get_open_flags(File fd)
106 {
107   DBUG_ENTER("my_get_open_flags");
108   DBUG_ASSERT(fd >= MY_FILE_MIN && fd < (int)my_file_limit);
109   DBUG_RETURN(my_file_info[fd].oflag);
110 }
111 
112 
113 /*
114   Open a file with sharing. Similar to _sopen() from libc, but allows managing
115   share delete on win32
116 
117   SYNOPSIS
118   my_win_sopen()
119   path    file name
120   oflag   operation flags
121   shflag  share flag
122   pmode   permission flags
123 
124   RETURN VALUE
125   File descriptor of opened file if success
126   -1 and sets errno if fails.
127 */
128 
my_win_sopen(const char * path,int oflag,int shflag,int pmode)129 File my_win_sopen(const char *path, int oflag, int shflag, int pmode)
130 {
131   int  fh;                                /* handle of opened file */
132   int mask;
133   HANDLE osfh;                            /* OS handle of opened file */
134   DWORD fileaccess;                       /* OS file access (requested) */
135   DWORD fileshare;                        /* OS file sharing mode */
136   DWORD filecreate;                       /* OS method of opening/creating */
137   DWORD fileattrib;                       /* OS file attribute flags */
138   SECURITY_ATTRIBUTES SecurityAttributes;
139 
140   DBUG_ENTER("my_win_sopen");
141 
142   if (check_if_legal_filename(path))
143   {
144     errno= EACCES;
145     DBUG_RETURN(-1);
146   }
147   SecurityAttributes.nLength= sizeof(SecurityAttributes);
148   SecurityAttributes.lpSecurityDescriptor= NULL;
149   SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT);
150 
151   /* decode the access flags  */
152   switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
153     case _O_RDONLY:         /* read access */
154       fileaccess= GENERIC_READ;
155       break;
156     case _O_WRONLY:         /* write access */
157       fileaccess= GENERIC_WRITE;
158       break;
159     case _O_RDWR:           /* read and write access */
160       fileaccess= GENERIC_READ | GENERIC_WRITE;
161       break;
162     default:                /* error, bad oflag */
163       errno= EINVAL;
164       DBUG_RETURN(-1);
165   }
166 
167   /* decode sharing flags */
168   switch (shflag) {
169     case _SH_DENYRW:        /* exclusive access except delete */
170       fileshare= FILE_SHARE_DELETE;
171       break;
172     case _SH_DENYWR:        /* share read and delete access */
173       fileshare= FILE_SHARE_READ | FILE_SHARE_DELETE;
174       break;
175     case _SH_DENYRD:        /* share write and delete access */
176       fileshare= FILE_SHARE_WRITE | FILE_SHARE_DELETE;
177       break;
178     case _SH_DENYNO:        /* share read, write and delete access */
179       fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
180       break;
181     case _SH_DENYRWD:       /* exclusive access */
182       fileshare= 0L;
183       break;
184     case _SH_DENYWRD:       /* share read access */
185       fileshare= FILE_SHARE_READ;
186       break;
187     case _SH_DENYRDD:       /* share write access */
188       fileshare= FILE_SHARE_WRITE;
189       break;
190     case _SH_DENYDEL:       /* share read and write access */
191       fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE;
192       break;
193     default:                /* error, bad shflag */
194       errno= EINVAL;
195       DBUG_RETURN(-1);
196   }
197 
198   /* decode open/create method flags  */
199   switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
200     case 0:
201     case _O_EXCL:                   /* ignore EXCL w/o CREAT */
202       filecreate= OPEN_EXISTING;
203       break;
204 
205     case _O_CREAT:
206       filecreate= OPEN_ALWAYS;
207       break;
208 
209     case _O_CREAT | _O_EXCL:
210     case _O_CREAT | _O_TRUNC | _O_EXCL:
211       filecreate= CREATE_NEW;
212       break;
213 
214     case _O_TRUNC:
215     case _O_TRUNC | _O_EXCL:        /* ignore EXCL w/o CREAT */
216       filecreate= TRUNCATE_EXISTING;
217       break;
218 
219     case _O_CREAT | _O_TRUNC:
220       filecreate= CREATE_ALWAYS;
221       break;
222 
223     default:
224       /* this can't happen ... all cases are covered */
225       errno= EINVAL;
226       DBUG_RETURN(-1);
227   }
228 
229   /* decode file attribute flags if _O_CREAT was specified */
230   fileattrib= FILE_ATTRIBUTE_NORMAL;     /* default */
231   if (oflag & _O_CREAT)
232   {
233     _umask((mask= _umask(0)));
234 
235     if (!((pmode & ~mask) & _S_IWRITE))
236       fileattrib= FILE_ATTRIBUTE_READONLY;
237   }
238 
239   /* Set temporary file (delete-on-close) attribute if requested. */
240   if (oflag & _O_TEMPORARY)
241   {
242     fileattrib|= FILE_FLAG_DELETE_ON_CLOSE;
243     fileaccess|= DELETE;
244   }
245 
246   /* Set temporary file (delay-flush-to-disk) attribute if requested.*/
247   if (oflag & _O_SHORT_LIVED)
248     fileattrib|= FILE_ATTRIBUTE_TEMPORARY;
249 
250   /* Set sequential or random access attribute if requested. */
251   if (oflag & _O_SEQUENTIAL)
252     fileattrib|= FILE_FLAG_SEQUENTIAL_SCAN;
253   else if (oflag & _O_RANDOM)
254     fileattrib|= FILE_FLAG_RANDOM_ACCESS;
255 
256   /* try to open/create the file  */
257   if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes,
258     filecreate, fileattrib, NULL)) == INVALID_HANDLE_VALUE)
259   {
260     /*
261        OS call to open/create file failed! map the error, release
262        the lock, and return -1. note that it's not necessary to
263        call _free_osfhnd (it hasn't been used yet).
264     */
265     my_osmaperr(GetLastError());     /* map error */
266     DBUG_RETURN(-1);                 /* return error to caller */
267   }
268 
269   if ((fh= my_open_osfhandle(osfh,
270     oflag & (_O_APPEND | _O_RDONLY | _O_TEXT))) == -1)
271   {
272     CloseHandle(osfh);
273   }
274 
275   DBUG_RETURN(fh);                   /* return handle */
276 }
277 
278 
my_win_open(const char * path,int flags)279 File my_win_open(const char *path, int flags)
280 {
281   DBUG_ENTER("my_win_open");
282   DBUG_RETURN(my_win_sopen((char *) path, flags | _O_BINARY, _SH_DENYNO,
283     _S_IREAD | S_IWRITE));
284 }
285 
286 
my_win_close(File fd)287 int my_win_close(File fd)
288 {
289   DBUG_ENTER("my_win_close");
290   if(CloseHandle(my_get_osfhandle(fd)))
291   {
292     invalidate_fd(fd);
293     DBUG_RETURN(0);
294   }
295   my_osmaperr(GetLastError());
296   DBUG_RETURN(-1);
297 }
298 
299 
my_win_pread(File Filedes,uchar * Buffer,size_t Count,my_off_t offset)300 size_t my_win_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset)
301 {
302   DWORD         nBytesRead;
303   HANDLE        hFile;
304   OVERLAPPED    ov= {0};
305   LARGE_INTEGER li;
306 
307   DBUG_ENTER("my_win_pread");
308 
309   if(!Count)
310     DBUG_RETURN(0);
311 #ifdef _WIN64
312   if(Count > UINT_MAX)
313     Count= UINT_MAX;
314 #endif
315 
316   hFile=         (HANDLE)my_get_osfhandle(Filedes);
317   li.QuadPart=   offset;
318   ov.Offset=     li.LowPart;
319   ov.OffsetHigh= li.HighPart;
320 
321   if(!ReadFile(hFile, Buffer, (DWORD)Count, &nBytesRead, &ov))
322   {
323     DWORD lastError= GetLastError();
324     /*
325       ERROR_BROKEN_PIPE is returned when no more data coming
326       through e.g. a command pipe in windows : see MSDN on ReadFile.
327     */
328     if(lastError == ERROR_HANDLE_EOF || lastError == ERROR_BROKEN_PIPE)
329       DBUG_RETURN(0); /*return 0 at EOF*/
330     my_osmaperr(lastError);
331     DBUG_RETURN((size_t)-1);
332   }
333   DBUG_RETURN(nBytesRead);
334 }
335 
336 
my_win_read(File Filedes,uchar * Buffer,size_t Count)337 size_t my_win_read(File Filedes, uchar *Buffer, size_t Count)
338 {
339   DWORD         nBytesRead;
340   HANDLE        hFile;
341 
342   DBUG_ENTER("my_win_read");
343   if(!Count)
344     DBUG_RETURN(0);
345 #ifdef _WIN64
346   if(Count > UINT_MAX)
347     Count= UINT_MAX;
348 #endif
349 
350   hFile= (HANDLE)my_get_osfhandle(Filedes);
351 
352   if(!ReadFile(hFile, Buffer, (DWORD)Count, &nBytesRead, NULL))
353   {
354     DWORD lastError= GetLastError();
355     /*
356       ERROR_BROKEN_PIPE is returned when no more data coming
357       through e.g. a command pipe in windows : see MSDN on ReadFile.
358     */
359     if(lastError == ERROR_HANDLE_EOF || lastError == ERROR_BROKEN_PIPE)
360       DBUG_RETURN(0); /*return 0 at EOF*/
361     my_osmaperr(lastError);
362     DBUG_RETURN((size_t)-1);
363   }
364   DBUG_RETURN(nBytesRead);
365 }
366 
367 
my_win_pwrite(File Filedes,const uchar * Buffer,size_t Count,my_off_t offset)368 size_t my_win_pwrite(File Filedes, const uchar *Buffer, size_t Count,
369                      my_off_t offset)
370 {
371   DWORD         nBytesWritten;
372   HANDLE        hFile;
373   OVERLAPPED    ov= {0};
374   LARGE_INTEGER li;
375 
376   DBUG_ENTER("my_win_pwrite");
377   DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count: %llu, offset: %llu",
378     Filedes, Buffer, (ulonglong)Count, (ulonglong)offset));
379 
380   if(!Count)
381     DBUG_RETURN(0);
382 
383 #ifdef _WIN64
384   if(Count > UINT_MAX)
385     Count= UINT_MAX;
386 #endif
387 
388   hFile=         (HANDLE)my_get_osfhandle(Filedes);
389   li.QuadPart=   offset;
390   ov.Offset=     li.LowPart;
391   ov.OffsetHigh= li.HighPart;
392 
393   if(!WriteFile(hFile, Buffer, (DWORD)Count, &nBytesWritten, &ov))
394   {
395     my_osmaperr(GetLastError());
396     DBUG_RETURN((size_t)-1);
397   }
398   else
399     DBUG_RETURN(nBytesWritten);
400 }
401 
402 
my_win_lseek(File fd,my_off_t pos,int whence)403 my_off_t my_win_lseek(File fd, my_off_t pos, int whence)
404 {
405   LARGE_INTEGER offset;
406   LARGE_INTEGER newpos;
407 
408   DBUG_ENTER("my_win_lseek");
409 
410   /* Check compatibility of Windows and Posix seek constants */
411   compile_time_assert(FILE_BEGIN == SEEK_SET && FILE_CURRENT == SEEK_CUR
412     && FILE_END == SEEK_END);
413 
414   offset.QuadPart= pos;
415   if(!SetFilePointerEx(my_get_osfhandle(fd), offset, &newpos, whence))
416   {
417     my_osmaperr(GetLastError());
418     newpos.QuadPart= -1;
419   }
420   DBUG_RETURN(newpos.QuadPart);
421 }
422 
423 
424 #ifndef FILE_WRITE_TO_END_OF_FILE
425 #define FILE_WRITE_TO_END_OF_FILE       0xffffffff
426 #endif
my_win_write(File fd,const uchar * Buffer,size_t Count)427 size_t my_win_write(File fd, const uchar *Buffer, size_t Count)
428 {
429   DWORD nWritten;
430   OVERLAPPED ov;
431   OVERLAPPED *pov= NULL;
432   HANDLE hFile;
433 
434   DBUG_ENTER("my_win_write");
435   DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count %llu", fd, Buffer,
436       (ulonglong)Count));
437 
438   if(!Count)
439     DBUG_RETURN(0);
440 
441 #ifdef _WIN64
442   if(Count > UINT_MAX)
443     Count= UINT_MAX;
444 #endif
445 
446   if(my_get_open_flags(fd) & _O_APPEND)
447   {
448     /*
449        Atomic append to the end of file is is done by special initialization of
450        the OVERLAPPED structure. See MSDN WriteFile documentation for more info.
451     */
452     memset(&ov, 0, sizeof(ov));
453     ov.Offset= FILE_WRITE_TO_END_OF_FILE;
454     ov.OffsetHigh= -1;
455     pov= &ov;
456   }
457 
458   hFile= my_get_osfhandle(fd);
459   if(!WriteFile(hFile, Buffer, (DWORD)Count, &nWritten, pov))
460   {
461     my_osmaperr(GetLastError());
462     DBUG_RETURN((size_t)-1);
463   }
464   DBUG_RETURN(nWritten);
465 }
466 
467 
my_win_chsize(File fd,my_off_t newlength)468 int my_win_chsize(File fd,  my_off_t newlength)
469 {
470   HANDLE hFile;
471   LARGE_INTEGER length;
472   DBUG_ENTER("my_win_chsize");
473 
474   hFile= (HANDLE) my_get_osfhandle(fd);
475   length.QuadPart= newlength;
476   if (!SetFilePointerEx(hFile, length , NULL , FILE_BEGIN))
477     goto err;
478   if (!SetEndOfFile(hFile))
479     goto err;
480   DBUG_RETURN(0);
481 err:
482   my_osmaperr(GetLastError());
483   my_errno= errno;
484   DBUG_RETURN(-1);
485 }
486 
487 
488 /* Get the file descriptor for stdin,stdout or stderr */
my_get_stdfile_descriptor(FILE * stream)489 static File my_get_stdfile_descriptor(FILE *stream)
490 {
491   HANDLE hFile;
492   DWORD nStdHandle;
493   DBUG_ENTER("my_get_stdfile_descriptor");
494 
495   if(stream == stdin)
496     nStdHandle= STD_INPUT_HANDLE;
497   else if(stream == stdout)
498     nStdHandle= STD_OUTPUT_HANDLE;
499   else if(stream == stderr)
500     nStdHandle= STD_ERROR_HANDLE;
501   else
502     DBUG_RETURN(-1);
503 
504   hFile= GetStdHandle(nStdHandle);
505   if(hFile != INVALID_HANDLE_VALUE)
506     DBUG_RETURN(my_open_osfhandle(hFile, 0));
507   DBUG_RETURN(-1);
508 }
509 
510 
my_win_fileno(FILE * file)511 File my_win_fileno(FILE *file)
512 {
513   HANDLE hFile= (HANDLE)_get_osfhandle(fileno(file));
514   int retval= -1;
515   uint i;
516 
517   DBUG_ENTER("my_win_fileno");
518 
519   for(i= MY_FILE_MIN; i < my_file_limit; i++)
520   {
521     if(my_file_info[i].fhandle == hFile)
522     {
523       retval= i;
524       break;
525     }
526   }
527   if(retval == -1)
528     /* try std stream */
529     DBUG_RETURN(my_get_stdfile_descriptor(file));
530   DBUG_RETURN(retval);
531 }
532 
533 
my_win_fopen(const char * filename,const char * type)534 FILE *my_win_fopen(const char *filename, const char *type)
535 {
536   FILE *file;
537   int flags= 0;
538   DBUG_ENTER("my_win_open");
539 
540   /*
541     If we are not creating, then we need to use my_access to make sure
542     the file exists since Windows doesn't handle files like "com1.sym"
543     very  well
544   */
545   if (check_if_legal_filename(filename))
546   {
547     errno= EACCES;
548     DBUG_RETURN(NULL);
549   }
550 
551   file= fopen(filename, type);
552   if(!file)
553     DBUG_RETURN(NULL);
554 
555   if(strchr(type,'a') != NULL)
556     flags= O_APPEND;
557 
558   /*
559      Register file handle in my_table_info.
560      Necessary for my_fileno()
561    */
562   if(my_open_osfhandle((HANDLE)_get_osfhandle(fileno(file)), flags) < 0)
563   {
564     fclose(file);
565     DBUG_RETURN(NULL);
566   }
567   DBUG_RETURN(file);
568 }
569 
570 
my_win_fdopen(File fd,const char * type)571 FILE * my_win_fdopen(File fd, const char *type)
572 {
573   FILE *file;
574   int crt_fd;
575   int flags= 0;
576 
577   DBUG_ENTER("my_win_fdopen");
578 
579   if(strchr(type,'a') != NULL)
580     flags= O_APPEND;
581   /* Convert OS file handle to CRT file descriptor and then call fdopen*/
582   crt_fd= _open_osfhandle((intptr_t)my_get_osfhandle(fd), flags);
583   if(crt_fd < 0)
584     file= NULL;
585   else
586     file= fdopen(crt_fd, type);
587   DBUG_RETURN(file);
588 }
589 
590 
my_win_fclose(FILE * file)591 int my_win_fclose(FILE *file)
592 {
593   File fd;
594 
595   DBUG_ENTER("my_win_close");
596   fd= my_fileno(file);
597   if(fd < 0)
598     DBUG_RETURN(-1);
599   if(fclose(file) < 0)
600     DBUG_RETURN(-1);
601   invalidate_fd(fd);
602   DBUG_RETURN(0);
603 }
604 
605 
606 
607 /*
608   Quick and dirty my_fstat() implementation for Windows.
609   Use CRT fstat on temporarily allocated file descriptor.
610   Patch file size, because size that fstat returns is not
611   reliable (may be outdated)
612 */
my_win_fstat(File fd,struct _stati64 * buf)613 int my_win_fstat(File fd, struct _stati64 *buf)
614 {
615   int crt_fd;
616   int retval;
617   HANDLE hFile, hDup;
618 
619   DBUG_ENTER("my_win_fstat");
620 
621   hFile= my_get_osfhandle(fd);
622   if(!DuplicateHandle( GetCurrentProcess(), hFile, GetCurrentProcess(),
623     &hDup ,0,FALSE,DUPLICATE_SAME_ACCESS))
624   {
625     my_osmaperr(GetLastError());
626     DBUG_RETURN(-1);
627   }
628   if ((crt_fd= _open_osfhandle((intptr_t)hDup,0)) < 0)
629     DBUG_RETURN(-1);
630 
631   retval= _fstati64(crt_fd, buf);
632   if(retval == 0)
633   {
634     /* File size returned by stat is not accurate (may be outdated), fix it*/
635     GetFileSizeEx(hDup, (PLARGE_INTEGER) (&(buf->st_size)));
636   }
637   _close(crt_fd);
638   DBUG_RETURN(retval);
639 }
640 
641 
642 
my_win_stat(const char * path,struct _stati64 * buf)643 int my_win_stat( const char *path, struct _stati64 *buf)
644 {
645   DBUG_ENTER("my_win_stat");
646   if(_stati64( path, buf) == 0)
647   {
648     /* File size returned by stat is not accurate (may be outdated), fix it*/
649     WIN32_FILE_ATTRIBUTE_DATA data;
650     if (GetFileAttributesEx(path, GetFileExInfoStandard, &data))
651     {
652       LARGE_INTEGER li;
653       li.LowPart=    data.nFileSizeLow;
654       li.HighPart=   data.nFileSizeHigh;
655       buf->st_size= li.QuadPart;
656     }
657     DBUG_RETURN(0);
658   }
659   DBUG_RETURN(-1);
660 }
661 
662 
663 
my_win_fsync(File fd)664 int my_win_fsync(File fd)
665 {
666   DBUG_ENTER("my_win_fsync");
667   if(FlushFileBuffers(my_get_osfhandle(fd)))
668     DBUG_RETURN(0);
669   my_osmaperr(GetLastError());
670   DBUG_RETURN(-1);
671 }
672 
673 
674 
my_win_dup(File fd)675 int my_win_dup(File fd)
676 {
677   HANDLE hDup;
678   DBUG_ENTER("my_win_dup");
679   if (DuplicateHandle(GetCurrentProcess(), my_get_osfhandle(fd),
680        GetCurrentProcess(), &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS))
681   {
682      DBUG_RETURN(my_open_osfhandle(hDup, my_get_open_flags(fd)));
683   }
684   my_osmaperr(GetLastError());
685   DBUG_RETURN(-1);
686 }
687 
688 #endif /*_WIN32*/
689