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