size_t my_win_read(File Filedes, uchar *Buffer, size_t Count) { DWORD nBytesRead; HANDLE hFile; DBUG_ENTER("my_win_read"); if(!Count) DBUG_RETURN(0); #ifdef _WIN64 if(Count > UINT_MAX) Count= UINT_MAX; #endif hFile= (HANDLE)my_get_osfhandle(Filedes); if(!ReadFile(hFile, Buffer, (DWORD)Count, &nBytesRead, NULL)) { DWORD lastError= GetLastError(); /* ERROR_BROKEN_PIPE is returned when no more data coming through e.g. a command pipe in windows : see MSDN on ReadFile. */ if(lastError == ERROR_HANDLE_EOF || lastError == ERROR_BROKEN_PIPE) DBUG_RETURN(0); /*return 0 at EOF*/ my_osmaperr(lastError); DBUG_RETURN((size_t)-1); } DBUG_RETURN(nBytesRead); }
/* Quick and dirty my_fstat() implementation for Windows. Use CRT fstat on temporarily allocated file descriptor. Patch file size, because size that fstat returns is not reliable (may be outdated) */ int my_win_fstat(File fd, struct _stati64 *buf) { int crt_fd; int retval; HANDLE hFile, hDup; DBUG_ENTER("my_win_fstat"); hFile= my_get_osfhandle(fd); if(!DuplicateHandle( GetCurrentProcess(), hFile, GetCurrentProcess(), &hDup ,0,FALSE,DUPLICATE_SAME_ACCESS)) { my_osmaperr(GetLastError()); DBUG_RETURN(-1); } if ((crt_fd= _open_osfhandle((intptr_t)hDup,0)) < 0) DBUG_RETURN(-1); retval= _fstati64(crt_fd, buf); if(retval == 0) { /* File size returned by stat is not accurate (may be outdated), fix it*/ GetFileSizeEx(hDup, (PLARGE_INTEGER) (&(buf->st_size))); } _close(crt_fd); DBUG_RETURN(retval); }
size_t my_win_pwrite(File Filedes, const uchar *Buffer, size_t Count, my_off_t offset) { DWORD nBytesWritten; HANDLE hFile; OVERLAPPED ov= {0}; LARGE_INTEGER li; DBUG_ENTER("my_win_pwrite"); DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count: %llu, offset: %llu", Filedes, Buffer, (ulonglong)Count, (ulonglong)offset)); if(!Count) DBUG_RETURN(0); #ifdef _WIN64 if(Count > UINT_MAX) Count= UINT_MAX; #endif hFile= (HANDLE)my_get_osfhandle(Filedes); li.QuadPart= offset; ov.Offset= li.LowPart; ov.OffsetHigh= li.HighPart; if(!WriteFile(hFile, Buffer, (DWORD)Count, &nBytesWritten, &ov)) { my_osmaperr(GetLastError()); DBUG_RETURN((size_t)-1); } else DBUG_RETURN(nBytesWritten); }
size_t my_win_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset) { DWORD nBytesRead; HANDLE hFile; OVERLAPPED ov= {0}; LARGE_INTEGER li; DBUG_ENTER("my_win_pread"); if(!Count) DBUG_RETURN(0); #ifdef _WIN64 if(Count > UINT_MAX) Count= UINT_MAX; #endif hFile= (HANDLE)my_get_osfhandle(Filedes); li.QuadPart= offset; ov.Offset= li.LowPart; ov.OffsetHigh= li.HighPart; if(!ReadFile(hFile, Buffer, (DWORD)Count, &nBytesRead, &ov)) { DWORD lastError= GetLastError(); /* ERROR_BROKEN_PIPE is returned when no more data coming through e.g. a command pipe in windows : see MSDN on ReadFile. */ if(lastError == ERROR_HANDLE_EOF || lastError == ERROR_BROKEN_PIPE) DBUG_RETURN(0); /*return 0 at EOF*/ my_osmaperr(lastError); DBUG_RETURN((size_t)-1); } DBUG_RETURN(nBytesRead); }
void *my_mmap(void *addr, size_t len, int prot, int flags, File fd, my_off_t offset) { HANDLE hFileMap; LPVOID ptr; HANDLE hFile= (HANDLE)my_get_osfhandle(fd); if (hFile == INVALID_HANDLE_VALUE) return MAP_FAILED; hFileMap=CreateFileMapping(hFile, &mmap_security_attributes, PAGE_READWRITE, 0, (DWORD) len, NULL); if (hFileMap == 0) return MAP_FAILED; ptr=MapViewOfFile(hFileMap, prot & PROT_WRITE ? FILE_MAP_WRITE : FILE_MAP_READ, (DWORD)(offset >> 32), (DWORD)offset, len); /* MSDN explicitly states that it's possible to close File Mapping Object even when a view is not unmapped - then the object will be held open implicitly until unmap, as every view stores internally a handler of a corresponding File Mapping Object */ CloseHandle(hFileMap); if (ptr) return ptr; return MAP_FAILED; }
size_t my_win_write(File fd, const uchar *Buffer, size_t Count) { DWORD nWritten; OVERLAPPED ov; OVERLAPPED *pov= NULL; HANDLE hFile; DBUG_ENTER("my_win_write"); DBUG_PRINT("my",("Filedes: %d, Buffer: %p, Count %zd", fd, Buffer, Count)); if(my_get_open_flags(fd) & _O_APPEND) { /* Atomic append to the end of file is is done by special initialization of the OVERLAPPED structure. See MSDN WriteFile documentation for more info. */ memset(&ov, 0, sizeof(ov)); ov.Offset= FILE_WRITE_TO_END_OF_FILE; ov.OffsetHigh= -1; pov= &ov; } hFile= my_get_osfhandle(fd); if(!WriteFile(hFile, Buffer, (DWORD)Count, &nWritten, pov)) { nWritten= (size_t)-1; my_osmaperr(GetLastError()); } DBUG_RETURN((size_t)nWritten); }
size_t my_win_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset) { DWORD nBytesRead; HANDLE hFile; OVERLAPPED ov= {0}; LARGE_INTEGER li; DBUG_ENTER("my_win_pread"); if(!Count) DBUG_RETURN(0); #ifdef _WIN64 if(Count > UINT_MAX) Count= UINT_MAX; #endif hFile= (HANDLE)my_get_osfhandle(Filedes); li.QuadPart= offset; ov.Offset= li.LowPart; ov.OffsetHigh= li.HighPart; if(!ReadFile(hFile, Buffer, (DWORD)Count, &nBytesRead, &ov)) { DWORD lastError= GetLastError(); if(lastError == ERROR_HANDLE_EOF) DBUG_RETURN(0); /*return 0 at EOF*/ my_osmaperr(lastError); DBUG_RETURN(-1); } DBUG_RETURN(nBytesRead); }
int my_win_fsync(File fd) { DBUG_ENTER("my_win_fsync"); if(FlushFileBuffers(my_get_osfhandle(fd))) DBUG_RETURN(0); my_osmaperr(GetLastError()); DBUG_RETURN(-1); }
int my_win_close(File fd) { DBUG_ENTER("my_win_close"); if(CloseHandle(my_get_osfhandle(fd))) { invalidate_fd(fd); DBUG_RETURN(0); } my_osmaperr(GetLastError()); DBUG_RETURN(-1); }
int my_win_dup(File fd) { HANDLE hDup; DBUG_ENTER("my_win_dup"); if (DuplicateHandle(GetCurrentProcess(), my_get_osfhandle(fd), GetCurrentProcess(), &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS)) { DBUG_RETURN(my_open_osfhandle(hDup, my_get_open_flags(fd))); } my_osmaperr(GetLastError()); DBUG_RETURN(-1); }
FILE * my_win_fdopen(File fd, const char *type) { FILE *file; int crt_fd; int flags= 0; DBUG_ENTER("my_win_fdopen"); if(strchr(type,'a') != NULL) flags= O_APPEND; /* Convert OS file handle to CRT file descriptor and then call fdopen*/ crt_fd= _open_osfhandle((intptr_t)my_get_osfhandle(fd), flags); if(crt_fd < 0) file= NULL; else file= fdopen(crt_fd, type); DBUG_RETURN(file); }
int my_win_chsize(File fd, my_off_t newlength) { HANDLE hFile; LARGE_INTEGER length; DBUG_ENTER("my_win_chsize"); hFile= (HANDLE) my_get_osfhandle(fd); length.QuadPart= newlength; if (!SetFilePointerEx(hFile, length , NULL , FILE_BEGIN)) goto err; if (!SetEndOfFile(hFile)) goto err; DBUG_RETURN(0); err: my_osmaperr(GetLastError()); my_errno= errno; DBUG_RETURN(-1); }
my_off_t my_win_lseek(File fd, my_off_t pos, int whence) { LARGE_INTEGER offset; LARGE_INTEGER newpos; DBUG_ENTER("my_win_lseek"); /* Check compatibility of Windows and Posix seek constants */ compile_time_assert(FILE_BEGIN == SEEK_SET && FILE_CURRENT == SEEK_CUR && FILE_END == SEEK_END); offset.QuadPart= pos; if(!SetFilePointerEx(my_get_osfhandle(fd), offset, &newpos, whence)) { my_osmaperr(GetLastError()); newpos.QuadPart= -1; } DBUG_RETURN(newpos.QuadPart); }
static int win_lock(File fd, int locktype, my_off_t start, my_off_t length, int timeout_sec) { LARGE_INTEGER liOffset,liLength; DWORD dwFlags; OVERLAPPED ov= {0}; HANDLE hFile= (HANDLE)my_get_osfhandle(fd); DWORD lastError= 0; int i; int timeout_millis= timeout_sec * 1000; DBUG_ENTER("win_lock"); liOffset.QuadPart= start; liLength.QuadPart= length; ov.Offset= liOffset.LowPart; ov.OffsetHigh= liOffset.HighPart; if (locktype == F_UNLCK) { if (UnlockFileEx(hFile, 0, liLength.LowPart, liLength.HighPart, &ov)) DBUG_RETURN(0); /* For compatibility with fcntl implementation, ignore error, if region was not locked */ if (GetLastError() == ERROR_NOT_LOCKED) { SetLastError(0); DBUG_RETURN(0); } goto error; } else if (locktype == F_RDLCK) /* read lock is mapped to a shared lock. */ dwFlags= 0; else /* write lock is mapped to an exclusive lock. */ dwFlags= LOCKFILE_EXCLUSIVE_LOCK; /* Drop old lock first to avoid double locking. During analyze of Bug#38133 (Myisamlog test fails on Windows) I met the situation that the program myisamlog locked the file exclusively, then additionally shared, then did one unlock, and then blocked on an attempt to lock it exclusively again. Unlocking before every lock fixed the problem. Note that this introduces a race condition. When the application wants to convert an exclusive lock into a shared one, it will now first unlock the file and then lock it shared. A waiting exclusive lock could step in here. For reasons described in Bug#38133 and Bug#41124 (Server hangs on Windows with --external-locking after INSERT...SELECT) and in the review thread at http://lists.mysql.com/commits/60721 it seems to be the better option than not to unlock here. If one day someone notices a way how to do file lock type changes on Windows without unlocking before taking the new lock, please change this code accordingly to fix the race condition. */ if (!UnlockFileEx(hFile, 0, liLength.LowPart, liLength.HighPart, &ov) && (GetLastError() != ERROR_NOT_LOCKED)) goto error; if (timeout_sec == WIN_LOCK_INFINITE) { if (LockFileEx(hFile, dwFlags, 0, liLength.LowPart, liLength.HighPart, &ov)) DBUG_RETURN(0); goto error; } dwFlags|= LOCKFILE_FAIL_IMMEDIATELY; timeout_millis= timeout_sec * 1000; /* Try lock in a loop, until the lock is acquired or timeout happens */ for(i= 0; ;i+= WIN_LOCK_SLEEP_MILLIS) { if (LockFileEx(hFile, dwFlags, 0, liLength.LowPart, liLength.HighPart, &ov)) DBUG_RETURN(0); if (GetLastError() != ERROR_LOCK_VIOLATION) goto error; if (i >= timeout_millis) break; Sleep(WIN_LOCK_SLEEP_MILLIS); } /* timeout */ errno= EAGAIN; DBUG_RETURN(-1); error: my_osmaperr(GetLastError()); DBUG_RETURN(-1); }