Commit 716099e0 authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

This is the downport of

Bug#24509 - 2048 file descriptor limit on windows needs increasing, also 
WL#3049 - improved Windows I/O
                        
The patch replaces the use of the POSIX I/O interfaces in mysys on Windows with 
the Win32 API calls (CreateFile, WriteFile, etc). The Windows HANDLE for the open 
file is stored in the my_file_info struct, along with a flag for append mode 
because the Windows API does not support opening files in append mode in all cases)
The default max open files has been increased to 16384 and can be increased further
by setting --max-open-files=<value> during the server start.
                              
Another major change in this patch that almost all Windows specific file IO code
has been moved to a new file my_winfile.c, greatly reducing the amount of code 
in #ifdef blocks within mysys, thus improving readability.
                               
                                    
Minor enhancements:
- my_(f)stat() is changed to use __stati64 structure with  64 file size
and timestamps. It will return correct file size now (C runtime implementation
used to report outdated information)
- my_lock on Windows is prepared to handle additional timeout parameter
- after review : changed __WIN__ to _WIN32 in the new and changed code.

client/mysqlbinlog.cc:
  fileno -> my_fileno
client/readline.cc:
  fileno -> my_fileno
include/config-win.h:
  Increase OS_FILE_LIMIT for Windows.
  Remove O_SHARE - Windows does not support it. Its definition conflicts with
  O_SHORT_LIVED, that has different semantics.
include/my_dir.h:
  Use stat64 for stat() family of functions on Windows, because of 64 bit file size.
include/my_global.h:
  Increased default value for open file limit to 16K
include/my_sys.h:
  - my_file_info got new structure members - file handle and open flags
  - 2 new Windows-only mysys functions : my_get_osfhandle and my_osmaperr,
    modelled after Windows C runtime functions _get_osfhandle and _dosmaperr
libmysql/CMakeLists.txt:
  new files my_winfile.c and my_winerr.c
mysql-test/suite/large_tests/r/lock_tables_big.result:
  test for more then 2048 open file descriptors on Windows
mysql-test/suite/large_tests/t/lock_tables_big.test:
  test for more then 2048 open file descriptors on Windows
mysys/CMakeLists.txt:
  new files my_winfile.c and my_winerr.c
mysys/Makefile.am:
  new files my_winfile.c and my_winerr.c
mysys/default_modify.c:
  fileno -> my_fileno
mysys/my_chsize.c:
  implementation of chsize on Windows now moved to my_winfile.c
mysys/my_create.c:
  - my_sopen->my_win_open
  - close open file before removing (won't generally work on Windows otherwise)
mysys/my_file.c:
  On Windows, files returned by my_open will not start with 0, but 2048 
  (making it simple to detect incompatible mix of CRT and mysys  io functions)
mysys/my_fopen.c:
  fileno->my_win_fileno , fclose->my_win_fclose, fdopen->my_win_fdopen
  Check for legal filename is done by my_win_[f]open functions
mysys/my_fstream.c:
  fileno->my_fileno
mysys/my_lib.c:
  Windows stat() functions are moved to my_winfile.c
mysys/my_lock.c:
  Move Windows code under #ifdef to a separate function win_lock().
  Add a parameter for lock wait timeout
mysys/my_mmap.c:
   _get_osfhandle->my_get_osfhandle
mysys/my_open.c:
  my_sopen->my_win_open (simpler interface)
mysys/my_pread.c:
  moved most windows specific code to my_win_file.c
  Use my_win_pread
mysys/my_quick.c:
  Use my_win_read/my_win_write
mysys/my_read.c:
  Moved most of windows specific code to my_win_file.c
  Use my_win_read()
mysys/my_seek.c:
  On Windows, use my_win_lseek() in my_seek()/my_tell()
  Removed dead code (synchronization of lseeks)
  Improved DBUG tracing (file position is ulonglong, not ulong)
mysys/my_static.c:
  Removed array initialization. my_file_info_default is global variable
  thus it is initialized with all zeros anyway
mysys/my_sync.c:
  _commit->my_win_fsync
mysys/my_winerr.c:
  New file my_winerr.c
  Exports my_osmaperr modelled after undocumented C runtime
  function _dosmaperr(). The problem with _dosmaperr() used previously is that 
  1) it is nowhere documented and thus code relying on it is not guaranteed to work
     in subsequent releases on the C runtime
  2) it is present only in static C runtime (mysqld does not link if compiled with
    /MD)
mysys/my_winfile.c:
  New file my_winfile.c
  Implements ANSI/Posix file IO routines, when possible using native Windows IO, without
  C runtime (C runtime dropped because of the 2048 file descriptor limit).
mysys/my_write.c:
  write->my_win_write
mysys/mysys_priv.h:
  Declaration of Windows Posix functions (private to mysys, shall not be visible
  outside)
storage/innobase/handler/ha_innodb.cc:
  mysys native Windows IO : correct innodb tmp file handling
  mysql_tmpfile does not return valid CRT file descriptor, thus
  it is not possible to dup() it. Instead, the native file handle has 
  to be duplicated and then converted to CRT descriptor.
storage/myisam/mi_locking.c:
  _commit->my_sync
parent 905d715f
......@@ -1909,7 +1909,7 @@ static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
return ERROR_STOP;
}
#endif
if (init_io_cache(file, fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
if (init_io_cache(file, my_fileno(stdin), 0, READ_CACHE, (my_off_t) 0,
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
{
error("Failed to init IO cache.");
......
......@@ -1199,7 +1199,7 @@ get_options(int *argc,char ***argv)
if (opt_csv_str[0] == '-')
{
csv_file= fileno(stdout);
csv_file= my_fileno(stdout);
}
else
{
......
......@@ -33,7 +33,7 @@ LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file)
if (!(line_buff=(LINE_BUFFER*)
my_malloc(sizeof(*line_buff),MYF(MY_WME | MY_ZEROFILL))))
return 0;
if (init_line_buffer(line_buff,fileno(file),IO_SIZE,max_size))
if (init_line_buffer(line_buff,my_fileno(file),IO_SIZE,max_size))
{
my_free(line_buff,MYF(0));
return 0;
......
......@@ -65,7 +65,6 @@
#endif
/* File and lock constants */
#define O_SHARE 0x1000 /* Open file in sharing mode */
#ifdef __BORLANDC__
#define F_RDLCK LK_NBLCK /* read lock */
#define F_WRLCK LK_NBRLCK /* write lock */
......@@ -336,7 +335,7 @@ inline ulonglong double2ulonglong(double d)
#define FN_DEVCHAR ':'
#define FN_NETWORK_DRIVES /* Uses \\ to indicate network drives */
#define FN_NO_CASE_SENCE /* Files are not case-sensitive */
#define OS_FILE_LIMIT 2048
#define OS_FILE_LIMIT UINT_MAX /* No limit*/
#define DO_NOT_REMOVE_THREAD_WRAPPERS
#define thread_safe_increment(V,L) InterlockedIncrement((long*) &(V))
......
......@@ -69,7 +69,11 @@ typedef struct my_stat
#else
#if(_MSC_VER)
#define MY_STAT struct _stati64 /* 64 bit file size */
#else
#define MY_STAT struct stat /* Orginal struct have what we need */
#endif
#endif /* USE_MY_STAT_STRUCT */
......
......@@ -736,7 +736,41 @@ typedef SOCKET_SIZE_TYPE size_socket;
#define FN_LIBCHAR '/'
#define FN_ROOTDIR "/"
#endif
#define MY_NFILE 64 /* This is only used to save filenames */
/*
MY_FILE_MIN is Windows speciality and is used to quickly detect
the mismatch of CRT and mysys file IO usage on Windows at runtime.
CRT file descriptors can be in the range 0-2047, whereas descriptors returned
by my_open() will start with 2048. If a file descriptor with value less then
MY_FILE_MIN is passed to mysys IO function, chances are it stemms from
open()/fileno() and not my_open()/my_fileno.
For Posix, mysys functions are light wrappers around libc, and MY_FILE_MIN
is logically 0.
*/
#ifdef _WIN32
#define MY_FILE_MIN 2048
#else
#define MY_FILE_MIN 0
#endif
/*
MY_NFILE is the default size of my_file_info array.
It is larger on Windows, because it all file handles are stored in my_file_info
Default size is 16384 and this should be enough for most cases.If it is not
enough, --max-open-files with larger value can be used.
For Posix , my_file_info array is only used to store filenames for
error reporting and its size is not a limitation for number of open files.
*/
#ifdef _WIN32
#define MY_NFILE (16384 + MY_FILE_MIN)
#else
#define MY_NFILE 64
#endif
#ifndef OS_FILE_LIMIT
#define OS_FILE_LIMIT 65535
#endif
......@@ -773,9 +807,8 @@ typedef SOCKET_SIZE_TYPE size_socket;
/* Some things that this system doesn't have */
#define NO_HASH /* Not needed anymore */
#ifdef __WIN__
#define NO_DIR_LIBRARY /* Not standar dir-library */
#define USE_MY_STAT_STRUCT /* For my_lib */
#ifdef _WIN32
#define NO_DIR_LIBRARY /* Not standard dir-library */
#endif
/* Some defines of functions for portability */
......
......@@ -310,9 +310,13 @@ enum file_type
struct st_my_file_info
{
char * name;
enum file_type type;
#if defined(THREAD) && !defined(HAVE_PREAD)
char *name;
#ifdef _WIN32
HANDLE fhandle; /* win32 file handle */
int oflag; /* open flags, e.g O_APPEND */
#endif
enum file_type type;
#if defined(THREAD) && !defined(HAVE_PREAD) && !defined(_WIN32)
pthread_mutex_t mutex;
#endif
};
......@@ -617,12 +621,12 @@ extern void *my_memmem(const void *haystack, size_t haystacklen,
const void *needle, size_t needlelen);
#ifdef __WIN__
extern int my_access(const char *path, int amode);
extern File my_sopen(const char *path, int oflag, int shflag, int pmode);
#ifdef _WIN32
extern int my_access(const char *path, int amode);
#else
#define my_access access
#endif
extern int check_if_legal_filename(const char *path);
extern int check_if_legal_tablename(const char *path);
......@@ -633,6 +637,13 @@ extern int nt_share_delete(const char *name,myf MyFlags);
#define my_delete_allow_opened(fname,flags) my_delete((fname),(flags))
#endif
#ifdef _WIN32
/* Windows-only functions (CRT equivalents)*/
extern File my_sopen(const char *path, int oflag, int shflag, int pmode);
extern HANDLE my_get_osfhandle(File fd);
extern void my_osmaperr(unsigned long last_error);
#endif
#ifndef TERMINATE
extern void TERMINATE(FILE *file, uint flag);
#endif
......@@ -641,6 +652,7 @@ extern void wait_for_free_space(const char *filename, int errors);
extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags);
extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags);
extern int my_fclose(FILE *fd,myf MyFlags);
extern File my_fileno(FILE *fd);
extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags);
extern int my_sync(File fd, myf my_flags);
extern int my_sync_dir(const char *dir_name, myf my_flags);
......
......@@ -98,7 +98,7 @@ SET(CLIENT_SOURCES ../mysys/array.c ../strings/bchange.c ../strings/bmove.c
../strings/strtoll.c ../strings/strtoull.c ../strings/strxmov.c ../strings/strxnmov.c
../mysys/thr_mutex.c ../mysys/typelib.c ../vio/vio.c ../vio/viosocket.c
../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c ../mysys/mf_qsort.c
../mysys/my_getsystime.c ../mysys/my_sync.c ${LIB_SOURCES})
../mysys/my_getsystime.c ../mysys/my_sync.c ../mysys/my_winerr.c ../mysys/my_winfile.c ${LIB_SOURCES})
# Need to set USE_TLS for building the DLL, since __declspec(thread)
# approach to thread local storage does not work properly in DLLs.
......
#
# Bug#24509 cannot use more than 2048 file descriptors on windows
#
--disable_query_log
create database many_tables;
use many_tables;
let $max_tables=3000;
let $i=$max_tables;
--disable_warnings
create table t (i int);
let $table_list=t READ;
while ($i)
{
eval create table t$i (i int);
let $table_list= $table_list ,t$i READ;
dec $i;
}
#lock all tables we just created (resembles mysqldump startup is doing with --all-databases operation)
#There will be 3 descriptors for each table (table.FRM, table.MYI and table.MYD files) means 9000 files
#descriptors altogether. For Microsoft C runtime, this is way too many.
eval LOCK TABLES $table_list;
unlock tables;
drop database many_tables;
--disable_query_log
--echo all done
......@@ -39,7 +39,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c default_
my_mkdir.c my_mmap.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c
my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_sleep.c
my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c my_wincond.c
my_windac.c my_winthread.c my_write.c ptr_cmp.c queues.c stacktrace.c
my_winerr.c my_winfile.c my_windac.c my_winthread.c my_write.c ptr_cmp.c queues.c stacktrace.c
rijndael.c safemalloc.c sha1.c string.c thr_alarm.c thr_lock.c thr_mutex.c
thr_rwlock.c tree.c typelib.c my_vle.c base64.c my_memmem.c my_getpagesize.c)
......
......@@ -56,7 +56,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \
EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \
thr_mutex.c thr_rwlock.c \
CMakeLists.txt mf_soundex.c \
my_conio.c my_wincond.c my_winthread.c
my_conio.c my_wincond.c my_winthread.c my_winerr.c my_winfile.c
libmysys_a_LIBADD = @THREAD_LOBJECTS@
# test_dir_DEPENDENCIES= $(LIBRARIES)
# testhash_DEPENDENCIES= $(LIBRARIES)
......
......@@ -21,7 +21,7 @@
#define BUFF_SIZE 1024
#define RESERVE 1024 /* Extend buffer with this extent */
#ifdef __WIN__
#ifdef _WIN32
#define NEWLINE "\r\n"
#define NEWLINE_LEN 2
#else
......@@ -78,7 +78,7 @@ int modify_defaults_file(const char *file_location, const char *option,
DBUG_RETURN(2);
/* my_fstat doesn't use the flag parameter */
if (my_fstat(fileno(cnf_file), &file_stat, MYF(0)))
if (my_fstat(my_fileno(cnf_file), &file_stat, MYF(0)))
goto malloc_err;
if (option && option_value)
......@@ -213,7 +213,7 @@ int modify_defaults_file(const char *file_location, const char *option,
if (opt_applied)
{
/* Don't write the file if there are no changes to be made */
if (my_chsize(fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer), 0,
if (my_chsize(my_fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer), 0,
MYF(MY_WME)) ||
my_fseek(cnf_file, 0, MY_SEEK_SET, MYF(0)) ||
my_fwrite(cnf_file, (uchar*) file_buffer, (size_t) (dst_ptr - file_buffer),
......
......@@ -52,20 +52,13 @@ int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
if (oldsize > newlength)
{
#if defined(HAVE_SETFILEPOINTER)
/* This is for the moment only true on windows */
long is_success;
HANDLE win_file= (HANDLE) _get_osfhandle(fd);
long length_low, length_high;
length_low= (long) (ulong) newlength;
length_high= (long) ((ulonglong) newlength >> 32);
is_success= SetFilePointer(win_file, length_low, &length_high, FILE_BEGIN);
if (is_success == -1 && (my_errno= GetLastError()) != NO_ERROR)
#ifdef _WIN32
if (my_win_chsize(fd, newlength))
{
my_errno= errno;
goto err;
if (SetEndOfFile(win_file))
DBUG_RETURN(0);
my_errno= GetLastError();
goto err;
}
DBUG_RETURN(0);
#elif defined(HAVE_FTRUNCATE)
if (ftruncate(fd, (off_t) newlength))
{
......
......@@ -18,7 +18,7 @@
#include "mysys_err.h"
#include <errno.h>
#include <my_sys.h>
#if defined(__WIN__)
#if defined(_WIN32)
#include <share.h>
#endif
......@@ -41,16 +41,12 @@ File my_create(const char *FileName, int CreateFlags, int access_flags,
FileName, CreateFlags, access_flags, MyFlags));
#if !defined(NO_OPEN_3)
fd = open((char *) FileName, access_flags | O_CREAT,
fd= open((char *) FileName, access_flags | O_CREAT,
CreateFlags ? CreateFlags : my_umask);
#elif defined(VMS)
fd = open((char *) FileName, access_flags | O_CREAT, 0,
"ctx=stm","ctx=bin");
#elif defined(__WIN__)
fd= my_sopen((char *) FileName, access_flags | O_CREAT | O_BINARY,
SH_DENYNO, MY_S_IREAD | MY_S_IWRITE);
#elif defined(_WIN32)
fd= my_win_open(FileName, access_flags | O_CREAT);
#else
fd = open(FileName, access_flags);
fd= open(FileName, access_flags);
#endif
if ((MyFlags & MY_SYNC_DIR) && (fd >=0) &&
......@@ -71,6 +67,7 @@ File my_create(const char *FileName, int CreateFlags, int access_flags,
if (unlikely(fd >= 0 && rc < 0))
{
int tmp= my_errno;
my_close(fd, MyFlags);
my_delete(FileName, MyFlags);
my_errno= tmp;
}
......
......@@ -29,7 +29,11 @@ File my_dup(File file, myf MyFlags)
const char *filename;
DBUG_ENTER("my_dup");
DBUG_PRINT("my",("file: %d MyFlags: %d", file, MyFlags));
fd = dup(file);
#ifdef _WIN32
fd= my_win_dup(file);
#else
fd= dup(file);
#endif
filename= (((uint) file < my_file_limit) ?
my_file_info[(int) file].name : "Unknown");
DBUG_RETURN(my_register_filename(fd, filename, FILE_BY_DUP,
......
......@@ -97,6 +97,7 @@ uint my_set_max_open_files(uint files)
DBUG_ENTER("my_set_max_open_files");
DBUG_PRINT("enter",("files: %u my_file_limit: %u", files, my_file_limit));
files+= MY_FILE_MIN;
files= set_max_open_files(min(files, OS_FILE_LIMIT));
if (files <= MY_NFILE)
DBUG_RETURN(files);
......
......@@ -41,24 +41,14 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags)
DBUG_ENTER("my_fopen");
DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %d",
filename, flags, MyFlags));
/*
if we are not creating, then we need to use my_access to make sure
the file exists since Windows doesn't handle files like "com1.sym"
very well
*/
#ifdef __WIN__
if (check_if_legal_filename(filename))
{
errno= EACCES;
fd= 0;
}
else
make_ftype(type,flags);
#ifdef _WIN32
fd= my_win_fopen(filename, type);
#else
fd= fopen(filename, type);
#endif
{
make_ftype(type,flags);
fd = fopen(filename, type);
}
if (fd != 0)
{
/*
......@@ -66,18 +56,20 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags)
on some OS (SUNOS). Actually the filename save isn't that important
so we can ignore if this doesn't work.
*/
if ((uint) fileno(fd) >= my_file_limit)
int filedesc= my_fileno(fd);
if ((uint)filedesc >= my_file_limit)
{
thread_safe_increment(my_stream_opened,&THR_LOCK_open);
DBUG_RETURN(fd); /* safeguard */
}
pthread_mutex_lock(&THR_LOCK_open);
if ((my_file_info[fileno(fd)].name = (char*)
if ((my_file_info[filedesc].name= (char*)
my_strdup(filename,MyFlags)))
{
my_stream_opened++;
my_file_total_opened++;
my_file_info[fileno(fd)].type = STREAM_BY_FOPEN;
my_file_info[filedesc].type= STREAM_BY_FOPEN;
pthread_mutex_unlock(&THR_LOCK_open);
DBUG_PRINT("exit",("stream: 0x%lx", (long) fd));
DBUG_RETURN(fd);
......@@ -99,6 +91,7 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags)
/* Close a stream */
/* Close a stream */
int my_fclose(FILE *fd, myf MyFlags)
{
int err,file;
......@@ -106,8 +99,13 @@ int my_fclose(FILE *fd, myf MyFlags)
DBUG_PRINT("my",("stream: 0x%lx MyFlags: %d", (long) fd, MyFlags));
pthread_mutex_lock(&THR_LOCK_open);
file=fileno(fd);
if ((err = fclose(fd)) < 0)
file= my_fileno(fd);
#ifndef _WIN32
err= fclose(fd);
#else
err= my_win_fclose(fd);
#endif
if(err < 0)
{
my_errno=errno;
if (MyFlags & (MY_FAE | MY_WME))
......@@ -138,7 +136,12 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags)
Filedes, Flags, MyFlags));
make_ftype(type,Flags);
if ((fd = fdopen(Filedes, type)) == 0)
#ifdef _WIN32
fd= my_win_fdopen(Filedes, type);
#else
fd= fdopen(Filedes, type);
#endif
if (!fd)
{
my_errno=errno;
if (MyFlags & (MY_FAE | MY_WME))
......
......@@ -56,11 +56,11 @@ size_t my_fread(FILE *stream, uchar *Buffer, size_t Count, myf MyFlags)
{
if (ferror(stream))
my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
my_filename(fileno(stream)),errno);
my_filename(my_fileno(stream)),errno);
else
if (MyFlags & (MY_NABP | MY_FNABP))
my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
my_filename(fileno(stream)),errno);
my_filename(my_fileno(stream)),errno);
}
my_errno=errno ? errno : -1;
if (ferror(stream) || MyFlags & (MY_NABP | MY_FNABP))
......@@ -142,7 +142,7 @@ size_t my_fwrite(FILE *stream, const uchar *Buffer, size_t Count, myf MyFlags)
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
{
my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
my_filename(fileno(stream)),errno);
my_filename(my_fileno(stream)),errno);
}
writtenbytes= (size_t) -1; /* Return that we got error */
break;
......@@ -182,3 +182,14 @@ my_off_t my_ftell(FILE *stream, myf MyFlags __attribute__((unused)))
DBUG_PRINT("exit",("ftell: %lu",(ulong) pos));
DBUG_RETURN((my_off_t) pos);
} /* my_ftell */
/* Get a File corresponding to the stream*/
int my_fileno(FILE *f)
{
#ifdef _WIN32
return my_win_fileno(f);
#else
return fileno(f);
#endif
}
......@@ -35,8 +35,7 @@
# if defined(HAVE_NDIR_H)
# include <ndir.h>
# endif
# if defined(__WIN__)
# include <dos.h>
# if defined(_WIN32)
# ifdef __BORLANDC__
# include <dir.h>
# endif
......@@ -92,7 +91,7 @@ static int comp_names(struct fileinfo *a, struct fileinfo *b)
} /* comp_names */
#if !defined(__WIN__)
#if !defined(_WIN32)
MY_DIR *my_dir(const char *path, myf MyFlags)
{
......@@ -507,19 +506,24 @@ error:
DBUG_RETURN((MY_DIR *) NULL);
} /* my_dir */
#endif /* __WIN__ */
#endif /* _WIN32 */
/****************************************************************************
** File status
** Note that MY_STAT is assumed to be same as struct stat
****************************************************************************/
int my_fstat(int Filedes, MY_STAT *stat_area,
int my_fstat(File Filedes, MY_STAT *stat_area,
myf MyFlags __attribute__((unused)))
{
DBUG_ENTER("my_fstat");
DBUG_PRINT("my",("fd: %d MyFlags: %d", Filedes, MyFlags));
#ifdef _WIN32
DBUG_RETURN(my_win_fstat(Filedes, stat_area));
#else
DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
#endif
}
......@@ -531,11 +535,15 @@ MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
(long) stat_area, my_flags));
if ((m_used= (stat_area == NULL)))
if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
if (!(stat_area= (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
goto error;
if (! stat((char *) path, (struct stat *) stat_area) )
DBUG_RETURN(stat_area);
#ifndef _WIN32
if (! stat((char *) path, (struct stat *) stat_area) )
DBUG_RETURN(stat_area);
#else
if (! my_win_stat(path, stat_area) )
DBUG_RETURN(stat_area);
#endif
DBUG_PRINT("error",("Got errno: %d from stat", errno));
my_errno= errno;
if (m_used) /* Free if new area */
......
......@@ -22,13 +22,113 @@
#undef NO_ALARM_LOOP
#endif
#include <my_alarm.h>
#ifdef __WIN__
#include <sys/locking.h>
#endif
#ifdef __NETWARE__
#include <nks/fsio.h>
#endif
#ifdef _WIN32
#define WIN_LOCK_INFINITE -1
#define WIN_LOCK_SLEEP_MILLIS 100
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);
}
#endif
/*
Lock a part of a file
......@@ -48,8 +148,9 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
#ifdef __NETWARE__
int nxErrno;
#endif
DBUG_ENTER("my_lock");
DBUG_PRINT("my",("Fd: %d Op: %d start: %ld Length: %ld MyFlags: %d",
DBUG_PRINT("my",("fd: %d Op: %d start: %ld Length: %ld MyFlags: %d",
fd,locktype,(long) start,(long) length,MyFlags));
#ifdef VMS
DBUG_RETURN(0);
......@@ -97,29 +198,16 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
DBUG_RETURN(0);
}
}
#elif defined(HAVE_LOCKING)
/* Windows */
#elif defined(_WIN32)
{
my_bool error= FALSE;
pthread_mutex_lock(&my_file_info[fd].mutex);
if (MyFlags & MY_SEEK_NOT_DONE)
{
if( my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE))
== MY_FILEPOS_ERROR )
{
/*
If my_seek fails my_errno will already contain an error code;
just unlock and return error code.
*/
DBUG_PRINT("error",("my_errno: %d (%d)",my_errno,errno));
pthread_mutex_unlock(&my_file_info[fd].mutex);
DBUG_RETURN(-1);
}
}
error= locking(fd,locktype,(ulong) length) && errno != EINVAL;
pthread_mutex_unlock(&my_file_info[fd].mutex);
if (!error)
DBUG_RETURN(0);
int timeout_sec;
if (MyFlags & MY_DONT_WAIT)
timeout_sec= 0;
else
timeout_sec= WIN_LOCK_INFINITE;
if(win_lock(fd, locktype, start, length, timeout_sec) == 0)
DBUG_RETURN(0);
}
#else
#if defined(HAVE_FCNTL)
......
......@@ -27,17 +27,17 @@ int my_msync(int fd, void *addr, size_t len, int flags)
return my_sync(fd, MYF(0));
}
#elif defined(__WIN__)
#elif defined(_WIN32)
static SECURITY_ATTRIBUTES mmap_security_attributes=
{sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
void *my_mmap(void *addr, size_t len, int prot,
int flags, int fd, my_off_t offset)
int flags, File fd, my_off_t offset)
{
HANDLE hFileMap;
LPVOID ptr;
HANDLE hFile= (HANDLE)_get_osfhandle(fd);
HANDLE hFile= (HANDLE)my_get_osfhandle(fd);
if (hFile == INVALID_HANDLE_VALUE)
return MAP_FAILED;
......
......@@ -17,9 +17,7 @@
#include "mysys_err.h"
#include <my_dir.h>
#include <errno.h>
#if defined(__WIN__)
#include <share.h>
#endif
/*
Open a file
......@@ -43,29 +41,8 @@ File my_open(const char *FileName, int Flags, myf MyFlags)
DBUG_ENTER("my_open");
DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d",
FileName, Flags, MyFlags));
#if defined(__WIN__)
/*
Check that we don't try to open or create a file name that may
cause problems for us in the future (like PRN)
*/
if (check_if_legal_filename(FileName))
{
errno= EACCES;
DBUG_RETURN(my_register_filename(-1, FileName, FILE_BY_OPEN,
EE_FILENOTFOUND, MyFlags));
}
#ifndef __WIN__
if (Flags & O_SHARE)
fd = sopen((char *) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO,
MY_S_IREAD | MY_S_IWRITE);
else
fd = open((char *) FileName, Flags | O_BINARY,
MY_S_IREAD | MY_S_IWRITE);
#else
fd= my_sopen((char *) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO,
MY_S_IREAD | MY_S_IWRITE);
#endif
#if defined(_WIN32)
fd= my_win_open(FileName, Flags);
#elif !defined(NO_OPEN_3)
fd = open(FileName, Flags, my_umask); /* Normal unix */
#else
......@@ -94,11 +71,14 @@ int my_close(File fd, myf MyFlags)
DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
pthread_mutex_lock(&THR_LOCK_open);
#ifndef _WIN32
do
{
err= close(fd);
} while (err == -1 && errno == EINTR);
#else
err= my_win_close(fd);
#endif
if (err)
{
DBUG_PRINT("error",("Got error %d on close",err));
......@@ -109,7 +89,7 @@ int my_close(File fd, myf MyFlags)
if ((uint) fd < my_file_limit && my_file_info[fd].type != UNOPEN)
{
my_free(my_file_info[fd].name, MYF(0));
#if defined(THREAD) && !defined(HAVE_PREAD)
#if defined(THREAD) && !defined(HAVE_PREAD) && !defined(_WIN32)
pthread_mutex_destroy(&my_file_info[fd].mutex);
#endif
my_file_info[fd].type = UNOPEN;
......@@ -141,11 +121,11 @@ File my_register_filename(File fd, const char *FileName, enum file_type
type_of_file, uint error_message_number, myf MyFlags)
{
DBUG_ENTER("my_register_filename");
if ((int) fd >= 0)
if ((int) fd >= MY_FILE_MIN)
{
if ((uint) fd >= my_file_limit)
{
#if defined(THREAD) && !defined(HAVE_PREAD)
#if defined(THREAD) && !defined(HAVE_PREAD)
my_errno= EMFILE;
#else
thread_safe_increment(my_file_opened,&THR_LOCK_open);
......@@ -160,7 +140,7 @@ File my_register_filename(File fd, const char *FileName, enum file_type
my_file_opened++;
my_file_total_opened++;
my_file_info[fd].type = type_of_file;
#if defined(THREAD) && !defined(HAVE_PREAD)
#if defined(THREAD) && !defined(HAVE_PREAD) && !defined(_WIN32)
pthread_mutex_init(&my_file_info[fd].mutex,MY_MUTEX_INIT_FAST);
#endif
pthread_mutex_unlock(&THR_LOCK_open);
......@@ -187,188 +167,7 @@ File my_register_filename(File fd, const char *FileName, enum file_type
DBUG_RETURN(-1);
}
#ifdef __WIN__
extern void __cdecl _dosmaperr(unsigned long);
/*
Open a file with sharing. Similar to _sopen() from libc, but allows managing
share delete on win32
SYNOPSIS
my_sopen()
path fully qualified file name
oflag operation flags
shflag share flag
pmode permission flags
RETURN VALUE
File descriptor of opened file if success
-1 and sets errno if fails.
*/
File my_sopen(const char *path, int oflag, int shflag, int pmode)
{
int fh; /* handle of opened file */
int mask;
HANDLE osfh; /* OS handle of opened file */
DWORD fileaccess; /* OS file access (requested) */
DWORD fileshare; /* OS file sharing mode */
DWORD filecreate; /* OS method of opening/creating */
DWORD fileattrib; /* OS file attribute flags */
SECURITY_ATTRIBUTES SecurityAttributes;
SecurityAttributes.nLength= sizeof(SecurityAttributes);
SecurityAttributes.lpSecurityDescriptor= NULL;
SecurityAttributes.bInheritHandle= !(oflag & _O_NOINHERIT);
/*
* decode the access flags
*/
switch (oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
case _O_RDONLY: /* read access */
fileaccess= GENERIC_READ;
break;
case _O_WRONLY: /* write access */
fileaccess= GENERIC_WRITE;
break;
case _O_RDWR: /* read and write access */
fileaccess= GENERIC_READ | GENERIC_WRITE;
break;
default: /* error, bad oflag */
errno= EINVAL;
_doserrno= 0L; /* not an OS error */
return -1;
}
/*
* decode sharing flags
*/
switch (shflag) {
case _SH_DENYRW: /* exclusive access except delete */
fileshare= FILE_SHARE_DELETE;
break;
case _SH_DENYWR: /* share read and delete access */
fileshare= FILE_SHARE_READ | FILE_SHARE_DELETE;
break;
case _SH_DENYRD: /* share write and delete access */
fileshare= FILE_SHARE_WRITE | FILE_SHARE_DELETE;
break;
case _SH_DENYNO: /* share read, write and delete access */
fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
break;
case _SH_DENYRWD: /* exclusive access */
fileshare= 0L;
break;
case _SH_DENYWRD: /* share read access */
fileshare= FILE_SHARE_READ;
break;
case _SH_DENYRDD: /* share write access */
fileshare= FILE_SHARE_WRITE;
break;
case _SH_DENYDEL: /* share read and write access */
fileshare= FILE_SHARE_READ | FILE_SHARE_WRITE;
break;
default: /* error, bad shflag */
errno= EINVAL;
_doserrno= 0L; /* not an OS error */
return -1;
}
/*
* decode open/create method flags
*/
switch (oflag & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
case 0:
case _O_EXCL: /* ignore EXCL w/o CREAT */
filecreate= OPEN_EXISTING;
break;
case _O_CREAT:
filecreate= OPEN_ALWAYS;
break;
case _O_CREAT | _O_EXCL:
case _O_CREAT | _O_TRUNC | _O_EXCL:
filecreate= CREATE_NEW;
break;
case _O_TRUNC:
case _O_TRUNC | _O_EXCL: /* ignore EXCL w/o CREAT */
filecreate= TRUNCATE_EXISTING;
break;
case _O_CREAT | _O_TRUNC:
filecreate= CREATE_ALWAYS;
break;
default:
/* this can't happen ... all cases are covered */
errno= EINVAL;
_doserrno= 0L;
return -1;
}
/*
* decode file attribute flags if _O_CREAT was specified
*/
fileattrib= FILE_ATTRIBUTE_NORMAL; /* default */
if (oflag & _O_CREAT)
{
_umask((mask= _umask(0)));
if (!((pmode & ~mask) & _S_IWRITE))
fileattrib= FILE_ATTRIBUTE_READONLY;
}
/*
* Set temporary file (delete-on-close) attribute if requested.
*/
if (oflag & _O_TEMPORARY)
{
fileattrib|= FILE_FLAG_DELETE_ON_CLOSE;
fileaccess|= DELETE;
}
/*
* Set temporary file (delay-flush-to-disk) attribute if requested.
*/
if (oflag & _O_SHORT_LIVED)
fileattrib|= FILE_ATTRIBUTE_TEMPORARY;
/*
* Set sequential or random access attribute if requested.
*/
if (oflag & _O_SEQUENTIAL)
fileattrib|= FILE_FLAG_SEQUENTIAL_SCAN;
else if (oflag & _O_RANDOM)
fileattrib|= FILE_FLAG_RANDOM_ACCESS;
/*
* try to open/create the file
*/
if ((osfh= CreateFile(path, fileaccess, fileshare, &SecurityAttributes,
filecreate, fileattrib, NULL)) == INVALID_HANDLE_VALUE)
{
/*
* OS call to open/create file failed! map the error, release
* the lock, and return -1. note that it's not necessary to
* call _free_osfhnd (it hasn't been used yet).
*/
_dosmaperr(GetLastError()); /* map error */
return -1; /* return error to caller */
}
if ((fh= _open_osfhandle((intptr_t)osfh,
oflag & (_O_APPEND | _O_RDONLY | _O_TEXT))) == -1)
{
_dosmaperr(GetLastError()); /* map error */
CloseHandle(osfh);
}
return fh; /* return handle */
}
#endif /* __WIN__ */
#ifdef EXTRA_DEBUG
......
......@@ -15,11 +15,15 @@
#include "mysys_priv.h"
#include "mysys_err.h"
#include "my_base.h"
#include <m_string.h>
#include <errno.h>
#ifdef HAVE_PREAD
#if defined (HAVE_PREAD) && !defined(_WIN32)
#include <unistd.h>
#endif
/*
Read a chunk of bytes from a file from a given position
......@@ -46,27 +50,39 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
{
size_t readbytes;
int error= 0;
#if !defined (HAVE_PREAD) && !defined (_WIN32)
int save_errno;
#endif
DBUG_ENTER("my_pread");
DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: 0x%lx Count: %u MyFlags: %d",
Filedes, (ulong) offset, (long) Buffer, (uint) Count,
MyFlags));
DBUG_PRINT("my",("fd: %d Seek: %llu Buffer: %p Count: %lu MyFlags: %d",
Filedes, (ulonglong)offset, Buffer, (ulong)Count, MyFlags));
for (;;)
{
#ifndef __WIN__
errno=0; /* Linux doesn't reset this */
#endif
#ifndef HAVE_PREAD
errno= 0; /* Linux, Windows don't reset this on EOF/success */
#if !defined (HAVE_PREAD) && !defined (_WIN32)
pthread_mutex_lock(&my_file_info[Filedes].mutex);
readbytes= (uint) -1;
error= (lseek(Filedes, offset, MY_SEEK_SET) == (my_off_t) -1 ||
(readbytes= read(Filedes, Buffer, (uint) Count)) != Count);
(readbytes= read(Filedes, Buffer, Count)) != Count);
save_errno= errno;
pthread_mutex_unlock(&my_file_info[Filedes].mutex);
if (error)
errno= save_errno;
#else
if ((error= ((readbytes= pread(Filedes, Buffer, Count, offset)) != Count)))
my_errno= errno ? errno : -1;
#if defined(_WIN32)
readbytes= my_win_pread(Filedes, Buffer, Count, offset);
#else
readbytes= pread(Filedes, Buffer, Count, offset);
#endif
error= (readbytes != Count);
#endif
if (error || readbytes != Count)
if(error)
{
my_errno= errno ? errno : -1;
if (errno == 0 || (readbytes != (size_t) -1 &&
(MyFlags & (MY_NABP | MY_FNABP))))
my_errno= HA_ERR_FILE_TOO_SHORT;
DBUG_PRINT("warning",("Read only %d bytes off %u from %d, errno: %d",
(int) readbytes, (uint) Count,Filedes,my_errno));
#ifdef THREAD
......@@ -79,19 +95,19 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
#endif
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
{
if (readbytes == (size_t) -1)
my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
my_filename(Filedes),my_errno);
else if (MyFlags & (MY_NABP | MY_FNABP))
my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
my_filename(Filedes),my_errno);
if (readbytes == (size_t) -1)
my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
my_filename(Filedes),my_errno);
else if (MyFlags & (MY_NABP | MY_FNABP))
my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
my_filename(Filedes),my_errno);
}
if (readbytes == (size_t) -1 || (MyFlags & (MY_FNABP | MY_NABP)))
DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
}
if (MyFlags & (MY_NABP | MY_FNABP))
DBUG_RETURN(0); /* Read went ok; Return 0 */
DBUG_RETURN(readbytes); /* purecov: inspected */
DBUG_RETURN(0); /* Read went ok; Return 0 */
DBUG_RETURN(readbytes); /* purecov: inspected */
}
} /* my_pread */
......@@ -117,42 +133,45 @@ size_t my_pread(File Filedes, uchar *Buffer, size_t Count, my_off_t offset,
# Number of bytes read
*/
size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
size_t my_pwrite(File Filedes, const uchar *Buffer, size_t Count,
my_off_t offset, myf MyFlags)
{
size_t writenbytes, written;
size_t writtenbytes, written;
uint errors;
DBUG_ENTER("my_pwrite");
DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: 0x%lx Count: %u MyFlags: %d",
Filedes, (ulong) offset, (long) Buffer, (uint) Count,
MyFlags));
DBUG_PRINT("my",("fd: %d Seek: %llu Buffer: %p Count: %lu MyFlags: %d",
Filedes, offset, Buffer, (ulong)Count, MyFlags));
errors= 0;
written= 0;
for (;;)
{
#ifndef HAVE_PREAD
#if !defined (HAVE_PREAD) && !defined (_WIN32)
int error;
writenbytes= (size_t) -1;
writtenbytes= (size_t) -1;
pthread_mutex_lock(&my_file_info[Filedes].mutex);
error= (lseek(Filedes, offset, MY_SEEK_SET) != (my_off_t) -1 &&
(writenbytes = write(Filedes, Buffer, (uint) Count)) == Count);
(writtenbytes= write(Filedes, Buffer, Count)) == Count);
pthread_mutex_unlock(&my_file_info[Filedes].mutex);
if (error)
break;
#elif defined (_WIN32)
writtenbytes= my_win_pwrite(Filedes, Buffer, Count, offset);
#else
if ((writenbytes= pwrite(Filedes, Buffer, Count,offset)) == Count)
writtenbytes= pwrite(Filedes, Buffer, Count, offset);
#endif
if(writtenbytes == Count)
break;
my_errno= errno;
#endif
if (writenbytes != (size_t) -1)
{ /* Safegueard */
written+=writenbytes;
Buffer+=writenbytes;
Count-=writenbytes;
offset+=writenbytes;
if (writtenbytes != (size_t) -1)
{
written+= writtenbytes;
Buffer+= writtenbytes;
Count-= writtenbytes;
offset+= writtenbytes;
}
DBUG_PRINT("error",("Write only %u bytes", (uint) writenbytes));
DBUG_PRINT("error",("Write only %u bytes", (uint) writtenbytes));
#ifndef NO_BACKGROUND
#ifdef THREAD
if (my_thread_var->abort)
......@@ -165,15 +184,15 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
errors++;
continue;
}
if ((writenbytes && writenbytes != (size_t) -1) || my_errno == EINTR)
if ((writtenbytes && writtenbytes != (size_t) -1) || my_errno == EINTR)
continue; /* Retry */
#endif
if (MyFlags & (MY_NABP | MY_FNABP))
{
if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
{
my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG),
my_filename(Filedes),my_errno);
my_error(EE_WRITE, MYF(ME_BELL | ME_WAITTANG),
my_filename(Filedes),my_errno);
}
DBUG_RETURN(MY_FILE_ERROR); /* Error on read */
}
......@@ -183,5 +202,5 @@ size_t my_pwrite(int Filedes, const uchar *Buffer, size_t Count,
DBUG_EXECUTE_IF("check", my_seek(Filedes, -1, SEEK_SET, MYF(0)););
if (MyFlags & (MY_NABP | MY_FNABP))
DBUG_RETURN(0); /* Want only errors */
DBUG_RETURN(writenbytes+written); /* purecov: inspected */
DBUG_RETURN(writtenbytes+written); /* purecov: inspected */
} /* my_pwrite */
......@@ -19,11 +19,19 @@
#include "my_nosys.h"
#ifdef _WIN32
extern size_t my_win_read(File Filedes,uchar *Buffer,size_t Count);
#endif
size_t my_quick_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags)
{
size_t readbytes;
if ((readbytes = read(Filedes, Buffer, (uint) Count)) != Count)
#ifdef _WIN32
readbytes= my_win_read(Filedes, Buffer, Count);
#else
readbytes= read(Filedes, Buffer, Count);
#endif
if(readbytes != Count)
{
#ifndef DBUG_OFF
if ((readbytes == 0 || readbytes == (size_t) -1) && errno == EINTR)
......@@ -40,8 +48,13 @@ size_t my_quick_read(File Filedes,uchar *Buffer,size_t Count,myf MyFlags)
}
size_t my_quick_write(File Filedes,const uchar *Buffer,size_t Count)
size_t my_quick_write(File Filedes, const uchar *Buffer, size_t Count)
{
#ifdef _WIN32
return my_win_write(Filedes, Buffer, Count);
#else
#ifndef DBUG_OFF
size_t writtenbytes;
#endif
......@@ -50,7 +63,7 @@ size_t my_quick_write(File Filedes,const uchar *Buffer,size_t Count)
#ifndef DBUG_OFF
writtenbytes =
#endif
(size_t) write(Filedes,Buffer, (uint) Count)) != Count)
(size_t) write(Filedes,Buffer,Count)) != Count)
{
#ifndef DBUG_OFF
if ((writtenbytes == 0 || writtenbytes == (size_t) -1) && errno == EINTR)
......@@ -64,4 +77,5 @@ size_t my_quick_write(File Filedes,const uchar *Buffer,size_t Count)
return (size_t) -1;
}
return 0;
#endif
}
......@@ -15,9 +15,9 @@
#include "mysys_priv.h"
#include "mysys_err.h"
#include <my_base.h>
#include <errno.h>
/*
Read a chunk of bytes from a file with retry's if needed
......@@ -37,16 +37,25 @@ size_t my_read(File Filedes, uchar *Buffer, size_t Count, myf MyFlags)
{
size_t readbytes, save_count;
DBUG_ENTER("my_read");
DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d",
Filedes, (long) Buffer, (ulong) Count, MyFlags));
DBUG_PRINT("my",("fd: %d Buffer: %p Count: %lu MyFlags: %d",
Filedes, Buffer, (ulong) Count, MyFlags));
save_count= Count;
for (;;)
{
errno= 0; /* Linux doesn't reset this */
if ((readbytes= read(Filedes, Buffer, (uint) Count)) != Count)
errno= 0; /* Linux, Windows don't reset this on EOF/success */
#ifdef _WIN32
readbytes= my_win_read(Filedes, Buffer, Count);
#else
readbytes= read(Filedes, Buffer, Count);
#endif
if (readbytes != Count)
{
my_errno= errno ? errno : -1;
my_errno= errno;
if (errno == 0 || (readbytes != (size_t) -1 &&
(MyFlags & (MY_NABP | MY_FNABP))))
my_errno= HA_ERR_FILE_TOO_SHORT;
DBUG_PRINT("warning",("Read only %d bytes off %lu from %d, errno: %d",
(int) readbytes, (ulong) Count, Filedes,
my_errno));
......
......@@ -45,36 +45,30 @@
my_off_t my_seek(File fd, my_off_t pos, int whence,
myf MyFlags __attribute__((unused)))
{
reg1 os_off_t newpos= -1;
os_off_t newpos= -1;
DBUG_ENTER("my_seek");
DBUG_PRINT("my",("Fd: %d Hpos: %lu Pos: %lu Whence: %d MyFlags: %d",
fd, (ulong) (((ulonglong) pos) >> 32), (ulong) pos,
whence, MyFlags));
DBUG_PRINT("my",("fd: %d Pos: %llu Whence: %d MyFlags: %d",
fd, (ulonglong) pos, whence, MyFlags));
DBUG_ASSERT(pos != MY_FILEPOS_ERROR); /* safety check */
/*
Make sure we are using a valid file descriptor!
*/
DBUG_ASSERT(fd != -1);
#if defined(THREAD) && !defined(HAVE_PREAD)
if (MyFlags & MY_THREADSAFE)
{
pthread_mutex_lock(&my_file_info[fd].mutex);
newpos= lseek(fd, pos, whence);
pthread_mutex_unlock(&my_file_info[fd].mutex);
}
else
#if defined (_WIN32)
newpos= my_win_lseek(fd, pos, whence);
#else
newpos= lseek(fd, pos, whence);
#endif
newpos= lseek(fd, pos, whence);
if (newpos == (os_off_t) -1)
{
my_errno=errno;
DBUG_PRINT("error",("lseek: %lu errno: %d", (ulong) newpos,errno));
my_errno= errno;
DBUG_PRINT("error",("lseek: %llu errno: %d", (ulonglong) newpos,errno));
DBUG_RETURN(MY_FILEPOS_ERROR);
}
if ((my_off_t) newpos != pos)
{
DBUG_PRINT("exit",("pos: %lu", (ulong) newpos));
DBUG_PRINT("exit",("pos: %llu", (ulonglong) newpos));
}
DBUG_RETURN((my_off_t) newpos);
} /* my_seek */
......@@ -87,15 +81,15 @@ my_off_t my_tell(File fd, myf MyFlags __attribute__((unused)))
{
os_off_t pos;
DBUG_ENTER("my_tell");
DBUG_PRINT("my",("Fd: %d MyFlags: %d",fd, MyFlags));
DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
DBUG_ASSERT(fd >= 0);
#ifdef HAVE_TELL
pos=tell(fd);
#if defined (HAVE_TELL) && !defined (_WIN32)
pos= tell(fd);
#else
pos=lseek(fd, 0L, MY_SEEK_CUR);
pos= my_seek(fd, 0L, MY_SEEK_CUR,0);
#endif
if (pos == (os_off_t) -1)
my_errno=errno;
DBUG_PRINT("exit",("pos: %lu", (ulong) pos));
my_errno= errno;
DBUG_PRINT("exit",("pos: %llu", (ulonglong) pos));
DBUG_RETURN((my_off_t) pos);
} /* my_tell */
......@@ -35,7 +35,7 @@ int NEAR my_umask=0664, NEAR my_umask_dir=0777;
#ifndef THREAD
int NEAR my_errno=0;
#endif
struct st_my_file_info my_file_info_default[MY_NFILE]= {{0,UNOPEN}};
struct st_my_file_info my_file_info_default[MY_NFILE];
uint my_file_limit= MY_NFILE;
struct st_my_file_info *my_file_info= my_file_info_default;
......
......@@ -62,8 +62,8 @@ int my_sync(File fd, myf my_flags)
res= fdatasync(fd);
#elif defined(HAVE_FSYNC)
res= fsync(fd);
#elif defined(__WIN__)
res= _commit(fd);
#elif defined(_WIN32)
res= my_win_fsync(fd);
#else
#error Cannot find a way to sync a file, durability in danger
res= 0; /* No sync (strange OS) */
......
/* Copyright (C) 2008 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*
Convert Windows API error (GetLastError() to Posix equivalent (errno)
The exported function my_osmaperr() is modelled after and borrows
heavily from undocumented _dosmaperr()(found of the static Microsoft C runtime).
*/
#include <my_global.h>
#include <my_sys.h>
struct errentry
{
unsigned long oscode; /* OS return value */
int sysv_errno; /* System V error code */
};
static struct errentry errtable[]= {
{ ERROR_INVALID_FUNCTION, EINVAL }, /* 1 */
{ ERROR_FILE_NOT_FOUND, ENOENT }, /* 2 */
{ ERROR_PATH_NOT_FOUND, ENOENT }, /* 3 */
{ ERROR_TOO_MANY_OPEN_FILES, EMFILE }, /* 4 */
{ ERROR_ACCESS_DENIED, EACCES }, /* 5 */
{ ERROR_INVALID_HANDLE, EBADF }, /* 6 */
{ ERROR_ARENA_TRASHED, ENOMEM }, /* 7 */
{ ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, /* 8 */
{ ERROR_INVALID_BLOCK, ENOMEM }, /* 9 */
{ ERROR_BAD_ENVIRONMENT, E2BIG }, /* 10 */
{ ERROR_BAD_FORMAT, ENOEXEC }, /* 11 */
{ ERROR_INVALID_ACCESS, EINVAL }, /* 12 */
{ ERROR_INVALID_DATA, EINVAL }, /* 13 */
{ ERROR_INVALID_DRIVE, ENOENT }, /* 15 */
{ ERROR_CURRENT_DIRECTORY, EACCES }, /* 16 */
{ ERROR_NOT_SAME_DEVICE, EXDEV }, /* 17 */
{ ERROR_NO_MORE_FILES, ENOENT }, /* 18 */
{ ERROR_LOCK_VIOLATION, EACCES }, /* 33 */
{ ERROR_BAD_NETPATH, ENOENT }, /* 53 */
{ ERROR_NETWORK_ACCESS_DENIED, EACCES }, /* 65 */
{ ERROR_BAD_NET_NAME, ENOENT }, /* 67 */
{ ERROR_FILE_EXISTS, EEXIST }, /* 80 */
{ ERROR_CANNOT_MAKE, EACCES }, /* 82 */
{ ERROR_FAIL_I24, EACCES }, /* 83 */
{ ERROR_INVALID_PARAMETER, EINVAL }, /* 87 */
{ ERROR_NO_PROC_SLOTS, EAGAIN }, /* 89 */
{ ERROR_DRIVE_LOCKED, EACCES }, /* 108 */
{ ERROR_BROKEN_PIPE, EPIPE }, /* 109 */
{ ERROR_DISK_FULL, ENOSPC }, /* 112 */
{ ERROR_INVALID_TARGET_HANDLE, EBADF }, /* 114 */
{ ERROR_INVALID_HANDLE, EINVAL }, /* 124 */
{ ERROR_WAIT_NO_CHILDREN, ECHILD }, /* 128 */
{ ERROR_CHILD_NOT_COMPLETE, ECHILD }, /* 129 */
{ ERROR_DIRECT_ACCESS_HANDLE, EBADF }, /* 130 */
{ ERROR_NEGATIVE_SEEK, EINVAL }, /* 131 */
{ ERROR_SEEK_ON_DEVICE, EACCES }, /* 132 */
{ ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, /* 145 */
{ ERROR_NOT_LOCKED, EACCES }, /* 158 */
{ ERROR_BAD_PATHNAME, ENOENT }, /* 161 */
{ ERROR_MAX_THRDS_REACHED, EAGAIN }, /* 164 */
{ ERROR_LOCK_FAILED, EACCES }, /* 167 */
{ ERROR_ALREADY_EXISTS, EEXIST }, /* 183 */
{ ERROR_FILENAME_EXCED_RANGE, ENOENT }, /* 206 */
{ ERROR_NESTING_NOT_ALLOWED, EAGAIN }, /* 215 */
{ ERROR_NOT_ENOUGH_QUOTA, ENOMEM } /* 1816 */
};
/* size of the table */
#define ERRTABLESIZE (sizeof(errtable)/sizeof(errtable[0]))
/* The following two constants must be the minimum and maximum
values in the (contiguous) range of Exec Failure errors. */
#define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
#define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN
/* These are the low and high value in the range of errors that are
access violations */
#define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
#define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED
static int get_errno_from_oserr(unsigned long oserrno)
{
int i;
/* check the table for the OS error code */
for (i= 0; i < ERRTABLESIZE; ++i)
{
if (oserrno == errtable[i].oscode)
{
return errtable[i].sysv_errno;
}
}
/* The error code wasn't in the table. We check for a range of */
/* EACCES errors or exec failure errors (ENOEXEC). Otherwise */
/* EINVAL is returned. */
if (oserrno >= MIN_EACCES_RANGE && oserrno <= MAX_EACCES_RANGE)
return EACCES;
else if (oserrno >= MIN_EXEC_ERROR && oserrno <= MAX_EXEC_ERROR)
return ENOEXEC;
else
return EINVAL;
}
/* Set errno corresponsing to GetLastError() value */
void my_osmaperr ( unsigned long oserrno)
{
errno= get_errno_from_oserr(oserrno);
}
This diff is collapsed.
......@@ -20,14 +20,14 @@
/* Write a chunk of bytes to a file */
size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
size_t my_write(File Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
{
size_t writenbytes, written;
size_t writtenbytes, written;
uint errors;
DBUG_ENTER("my_write");
DBUG_PRINT("my",("Fd: %d Buffer: 0x%lx Count: %lu MyFlags: %d",
Filedes, (long) Buffer, (ulong) Count, MyFlags));
errors=0; written=0;
DBUG_PRINT("my",("fd: %d Buffer: %p Count: %lu MyFlags: %d",
Filedes, Buffer, (ulong) Count, MyFlags));
errors= 0; written= 0;
/* The behavior of write(fd, buf, 0) is not portable */
if (unlikely(!Count))
......@@ -35,17 +35,22 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
for (;;)
{
if ((writenbytes= write(Filedes, Buffer, Count)) == Count)
#ifdef _WIN32
writtenbytes= my_win_write(Filedes, Buffer, Count);
#else
writtenbytes= write(Filedes, Buffer, Count);
#endif
if (writtenbytes == Count)
break;
if (writenbytes != (size_t) -1)
if (writtenbytes != (size_t) -1)
{ /* Safeguard */
written+=writenbytes;
Buffer+=writenbytes;
Count-=writenbytes;
written+= writtenbytes;
Buffer+= writtenbytes;
Count-= writtenbytes;
}
my_errno=errno;
my_errno= errno;
DBUG_PRINT("error",("Write only %ld bytes, error: %d",
(long) writenbytes, my_errno));
(long) writtenbytes, my_errno));
#ifndef NO_BACKGROUND
#ifdef THREAD
if (my_thread_var->abort)
......@@ -59,19 +64,19 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
continue;
}
if ((writenbytes == 0 || writenbytes == (size_t) -1))
if ((writtenbytes == 0 || writtenbytes == (size_t) -1))
{
if (my_errno == EINTR)
{
DBUG_PRINT("debug", ("my_write() was interrupted and returned %ld",
(long) writenbytes));
(long) writtenbytes));
continue; /* Interrupted */
}
if (!writenbytes && !errors++) /* Retry once */
if (!writtenbytes && !errors++) /* Retry once */
{
/* We may come here if the file quota is exeeded */
errno=EFBIG; /* Assume this is the error */
errno= EFBIG; /* Assume this is the error */
continue;
}
}
......@@ -92,5 +97,5 @@ size_t my_write(int Filedes, const uchar *Buffer, size_t Count, myf MyFlags)
}
if (MyFlags & (MY_NABP | MY_FNABP))
DBUG_RETURN(0); /* Want only errors */
DBUG_RETURN(writenbytes+written);
DBUG_RETURN(writtenbytes+written);
} /* my_write */
......@@ -42,3 +42,27 @@ extern pthread_mutex_t THR_LOCK_charset, THR_LOCK_time;
#endif
void my_error_unregister_all(void);
#ifdef _WIN32
/* my_winfile.c exports, should not be used outside mysys */
extern File my_win_open(const char *path, int oflag);
extern int my_win_close(File fd);
extern size_t my_win_read(File fd, uchar *buffer, size_t count);
extern size_t my_win_write(File fd, const uchar *buffer, size_t count);
extern size_t my_win_pread(File fd, uchar *buffer, size_t count,
my_off_t offset);
extern size_t my_win_pwrite(File fd, const uchar *buffer, size_t count,
my_off_t offset);
extern my_off_t my_win_lseek(File fd, my_off_t pos, int whence);
extern int my_win_chsize(File fd, my_off_t newlength);
extern FILE* my_win_fopen(const char *filename, const char *type);
extern File my_win_fclose(FILE *file);
extern File my_win_fileno(FILE *file);
extern FILE* my_win_fdopen(File Filedes, const char *type);
extern int my_win_stat(const char *path, struct _stat64 *buf);
extern int my_win_fstat(File fd, struct _stat64 *buf);
extern int my_win_fsync(File fd);
extern File my_win_dup(File fd);
extern File my_win_sopen(const char *path, int oflag, int shflag, int perm);
extern File my_open_osfhandle(HANDLE handle, int oflag);
#endif
......@@ -1135,7 +1135,29 @@ innobase_mysql_tmpfile(void)
will be passed to fdopen(), it will be closed by invoking
fclose(), which in turn will invoke close() instead of
my_close(). */
#ifdef _WIN32
/* Note that on Windows, the integer returned by mysql_tmpfile
has no relation to C runtime file descriptor. Here, we need
to call my_get_osfhandle to get the HANDLE and then convert it
to C runtime filedescriptor. */
{
HANDLE hFile = my_get_osfhandle(fd);
HANDLE hDup;
BOOL bOK =
DuplicateHandle(GetCurrentProcess(), hFile, GetCurrentProcess(),
&hDup, 0, FALSE, DUPLICATE_SAME_ACCESS);
if(bOK) {
fd2 = _open_osfhandle((intptr_t)hDup,0);
}
else {
my_osmaperr(GetLastError());
fd2 = -1;
}
}
#else
fd2 = dup(fd);
#endif
if (fd2 < 0) {
DBUG_PRINT("error",("Got error %d on dup",fd2));
my_errno=errno;
......
......@@ -236,7 +236,7 @@ int mi_lock_database(MI_INFO *info, int lock_type)
break; /* Impossible */
}
}
#ifdef __WIN__
#ifdef _WIN32
else
{
/*
......@@ -455,11 +455,11 @@ int _mi_writeinfo(register MI_INFO *info, uint operation)
share->state.update_count= info->last_loop= ++info->this_loop;
if ((error=mi_state_info_write(share->kfile, &share->state, 1)))
olderror=my_errno;
#ifdef __WIN__
#ifdef _WIN32
if (myisam_flush)
{
_commit(share->kfile);
_commit(info->dfile);
my_sync(share->kfile,0);
my_sync(info->dfile,0);
}
#endif
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment