#At file:///home/thek/bzr/mysql-trunk/ based on revid:dlenev@stripped
3197 Kristofer Pettersson 2010-09-27
Bug#29071 invalid Open_files or Slave_open_temp_tables value in show global status
If an error occurred during registration of
a file handle, the Open_files counter would
show very large numbers.
Only decrese my_file_opened or my_stream_opened if the file
descriptor was maked as anything but UNOPEN
@ mysys/my_fopen.c
* The variable "my_stream_opened" needs to be strongly associated
with the my_file_info::type attribute.
@ mysys/my_open.c
* The variable "my_file_opened" needs to be strongly associated
with the my_file_info::type attribute.
@ unittest/gunit/CMakeLists.txt
* Added two test cases my_open-t.cc, my_fopen-t.cc
added:
unittest/gunit/my_fopen-t.cc
unittest/gunit/my_open-t.cc
modified:
mysys/my_fopen.c
mysys/my_open.c
unittest/gunit/CMakeLists.txt
=== modified file 'mysys/my_fopen.c'
--- a/mysys/my_fopen.c 2010-07-08 21:20:08 +0000
+++ b/mysys/my_fopen.c 2010-09-27 13:11:49 +0000
@@ -20,18 +20,18 @@
static void make_ftype(char * to,int flag);
-/*
+/**
Open a file as stream
- SYNOPSIS
- my_fopen()
- FileName Path-name of file
- Flags Read | write | append | trunc (like for open())
- MyFlags Flags for handling errors
-
- RETURN
- 0 Error
- # File handler
+ @param FileName Path-name of file
+ @param Flags like for open()
+ @param MyFlags Flags for handling errors
+
+ @see my_win_fopen()
+
+ @return
+ @retval 0 Error
+ @retval # File handler
*/
FILE *my_fopen(const char *filename, int flags, myf MyFlags)
@@ -52,20 +52,27 @@ FILE *my_fopen(const char *filename, int
if (fd != 0)
{
/*
- The test works if MY_NFILE < 128. The problem is that fileno() is char
- on some OS (SUNOS). Actually the filename save isn't that important
- so we can ignore if this doesn't work.
+ @todo The problem is that fileno() is of type char on some OS (SUNOS).
*/
int filedesc= my_fileno(fd);
+ mysql_mutex_lock(&THR_LOCK_open);
if ((uint)filedesc >= my_file_limit)
{
- thread_safe_increment(my_stream_opened,&THR_LOCK_open);
- DBUG_RETURN(fd); /* safeguard */
+ /*
+ The number of concurrently opened files exceeds the limits or
+ the file descriptor can't be mapped to the my_file_info array.
+ */
+ my_errno= EMFILE;
+#ifndef _WIN32
+ fclose(fd);
+#else
+ my_win_fclose(fd);
+#endif
+ mysql_mutex_unlock(&THR_LOCK_open);
+ goto err;
}
- mysql_mutex_lock(&THR_LOCK_open);
- if ((my_file_info[filedesc].name= (char*)
- my_strdup(filename,MyFlags)))
+ if ((my_file_info[filedesc].name= (char*) my_strdup(filename,MyFlags)))
{
my_stream_opened++;
my_file_total_opened++;
@@ -80,6 +87,8 @@ FILE *my_fopen(const char *filename, int
}
else
my_errno=errno;
+
+err:
DBUG_PRINT("error",("Got error %d on open",my_errno));
if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
my_error((flags & O_RDONLY) || (flags == O_RDONLY ) ? EE_FILENOTFOUND :
@@ -98,13 +107,25 @@ int my_fclose(FILE *fd, myf MyFlags)
DBUG_ENTER("my_fclose");
DBUG_PRINT("my",("stream: 0x%lx MyFlags: %d", (long) fd, MyFlags));
- mysql_mutex_lock(&THR_LOCK_open);
+ if(fd == 0)
+ {
+ /* Function called with wrong parameters */
+ DBUG_RETURN(EBADF);
+ }
+
file= my_fileno(fd);
+ if ((uint) file >= my_file_limit)
+ {
+ /* Function called with wrong parameters */
+ DBUG_RETURN(EBADF);
+ }
+
#ifndef _WIN32
err= fclose(fd);
#else
err= my_win_fclose(fd);
#endif
+ mysql_mutex_lock(&THR_LOCK_open);
if(err < 0)
{
my_errno=errno;
@@ -112,12 +133,12 @@ int my_fclose(FILE *fd, myf MyFlags)
my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),
my_filename(file),errno);
}
- else
- my_stream_opened--;
- if ((uint) file < my_file_limit && my_file_info[file].type != UNOPEN)
+
+ if (my_file_info[file].type != UNOPEN)
{
my_file_info[file].type = UNOPEN;
my_free(my_file_info[file].name);
+ my_stream_opened--;
}
mysql_mutex_unlock(&THR_LOCK_open);
DBUG_RETURN(err);
=== modified file 'mysys/my_open.c'
--- a/mysys/my_open.c 2010-07-08 21:20:08 +0000
+++ b/mysys/my_open.c 2010-09-27 13:11:49 +0000
@@ -19,17 +19,20 @@
#include <errno.h>
-/*
+/**
Open a file
- SYNOPSIS
- my_open()
- FileName Fully qualified file name
- Flags Read | write
- MyFlags Special flags
-
- RETURN VALUE
- File descriptor
+ @param FileName Fully qualified file name
+ @param Flags Same as for unix system call open(2)
+ @param MyFlags Special flags
+
+ @note This function encapsluates my_win_open and open(3) calls.
+
+ @see my_win_open
+
+ @return
+ @retval -1 An error occurred; my_errno has the error code.
+ @retval # On success a file descriptor is returned.
*/
File my_open(const char *FileName, int Flags, myf MyFlags)
@@ -70,6 +73,11 @@ int my_close(File fd, myf MyFlags)
DBUG_ENTER("my_close");
DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
+ if (fd < 0 || fd >= my_file_limit)
+ {
+ /* Function called with wrong parameters */
+ DBUG_RETURN(EBADF);
+ }
mysql_mutex_lock(&THR_LOCK_open);
#ifndef _WIN32
do
@@ -86,15 +94,15 @@ int my_close(File fd, myf MyFlags)
if (MyFlags & (MY_FAE | MY_WME))
my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),my_filename(fd),errno);
}
- if ((uint) fd < my_file_limit && my_file_info[fd].type != UNOPEN)
+ if (my_file_info[fd].type != UNOPEN)
{
my_free(my_file_info[fd].name);
#if defined(THREAD) && !defined(HAVE_PREAD) && !defined(_WIN32)
mysql_mutex_destroy(&my_file_info[fd].mutex);
#endif
my_file_info[fd].type = UNOPEN;
+ my_file_opened--;
}
- my_file_opened--;
mysql_mutex_unlock(&THR_LOCK_open);
DBUG_RETURN(err);
} /* my_close */
@@ -103,17 +111,15 @@ int my_close(File fd, myf MyFlags)
/*
Register file in my_file_info[]
- SYNOPSIS
- my_register_filename()
- fd File number opened, -1 if error on open
- FileName File name
- type_file_type How file was created
- error_message_number Error message number if caller got error (fd == -1)
- MyFlags Flags for my_close()
-
- RETURN
- -1 error
- # Filenumber
+ @param fd File number opened, -1 if error on open
+ @param FileName File name
+ @param type_file_type How file was created
+ @param error_message_numbe Error message number if caller got error (fd == -1)
+ @param MyFlags Flags for my_close()
+
+ @return
+ @retval -1 An error occurred
+ @retval # On success the file descriptor is returned.
*/
@@ -121,41 +127,56 @@ File my_register_filename(File fd, const
type_of_file, uint error_message_number, myf MyFlags)
{
DBUG_ENTER("my_register_filename");
- if ((int) fd >= MY_FILE_MIN)
+ if (fd < 0)
{
- if ((uint) fd >= my_file_limit)
+ /*
+ The file descriptor indicates that the FileName couldn't be opened
+ properly; - Report the error.
+ */
+ my_errno= errno;
+ goto err;
+ }
+
+ mysql_mutex_lock(&THR_LOCK_open);
+ if (fd >= my_file_limit)
+ {
+ /*
+ The number of concurrently opened files exceeds the limits or
+ the file descriptor can't be mapped to the my_file_info array.
+ */
+ my_errno= EMFILE;
+#ifndef _WIN32
+ int ret;
+ do
{
-#if defined(THREAD) && !defined(HAVE_PREAD)
- my_errno= EMFILE;
+ ret= close(fd);
+ } while (ret == -1 && errno == EINTR);
#else
- thread_safe_increment(my_file_opened,&THR_LOCK_open);
- DBUG_RETURN(fd); /* safeguard */
-#endif
- }
- else
- {
- mysql_mutex_lock(&THR_LOCK_open);
- if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags)))
- {
- my_file_opened++;
- my_file_total_opened++;
- my_file_info[fd].type = type_of_file;
-#if defined(THREAD) && !defined(HAVE_PREAD) && !defined(_WIN32)
- mysql_mutex_init(key_my_file_info_mutex, &my_file_info[fd].mutex,
- MY_MUTEX_INIT_FAST);
+ my_win_close(fd);
#endif
- mysql_mutex_unlock(&THR_LOCK_open);
- DBUG_PRINT("exit",("fd: %d",fd));
- DBUG_RETURN(fd);
- }
- mysql_mutex_unlock(&THR_LOCK_open);
- my_errno= ENOMEM;
- }
- (void) my_close(fd, MyFlags);
+ mysql_mutex_unlock(&THR_LOCK_open);
+ goto err;
}
- else
- my_errno= errno;
+ if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags)))
+ {
+ my_file_opened++;
+ my_file_total_opened++;
+ my_file_info[fd].type = type_of_file;
+#if defined(THREAD) && !defined(_WIN32) && !defined(HAVE_PREAD)
+ mysql_mutex_init(key_my_file_info_mutex, &my_file_info[fd].mutex,
+ MY_MUTEX_INIT_FAST);
+#endif
+ mysql_mutex_unlock(&THR_LOCK_open);
+ DBUG_PRINT("exit",("fd: %d",fd));
+ DBUG_RETURN(fd);
+ }
+#if defined(THREAD)
+ mysql_mutex_unlock(&THR_LOCK_open);
+#endif
+ my_errno= ENOMEM;
+
+err:
DBUG_PRINT("error",("Got error %d on open", my_errno));
if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
{
=== modified file 'unittest/gunit/CMakeLists.txt'
--- a/unittest/gunit/CMakeLists.txt 2010-07-30 08:34:23 +0000
+++ b/unittest/gunit/CMakeLists.txt 2010-09-27 13:11:49 +0000
@@ -207,7 +207,7 @@ IF (CMAKE_CXX_COMPILER_ID STREQUAL "SunP
ENDIF()
# Add tests (link them with sql library)
-SET(TESTS sql_list mdl mdl_mytap my_regex thread_utils)
+SET(TESTS sql_list mdl mdl_mytap my_regex thread_utils my_open my_fopen)
FOREACH(test ${TESTS})
ADD_EXECUTABLE(${test}-t ${test}-t.cc)
TARGET_LINK_LIBRARIES(${test}-t gunit sqlgunitlib strings dbug regex)
=== added file 'unittest/gunit/my_fopen-t.cc'
--- a/unittest/gunit/my_fopen-t.cc 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/my_fopen-t.cc 2010-09-27 13:11:49 +0000
@@ -0,0 +1,191 @@
+/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+
+ 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,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#include "my_config.h"
+#include <gtest/gtest.h>
+#include "mysqld_error.h"
+#include "my_sys.h"
+
+#define MAX_NUMBER_OF_FILE_DESCRIPTORS (OS_FILE_LIMIT+MY_NFILE+1024)
+#define DUMMY_FILE_NAME "successful_open_rdonly.bin"
+
+struct st_my_file_info my_file_info_default[MY_NFILE];
+class My_open_test : public ::testing::Test
+{
+public:
+ My_open_test()
+ {
+ }
+
+ virtual void SetUp()
+ {
+ /* set all global variables for each TEST_F. */
+ my_thread_basic_global_reinit();
+ my_stream_opened= 0;
+ my_file_total_opened= 0;
+ my_set_max_open_files(MAX_NUMBER_OF_FILE_DESCRIPTORS);
+ my_errno= 0;
+ }
+
+ /**
+ Set up test case for all tests
+ */
+ static void SetUpTestCase()
+ {
+ my_thread_basic_global_init();
+ FILE *fp;
+ fp= my_fopen(DUMMY_FILE_NAME, O_WRONLY | O_CREAT | O_BINARY, MYF(0));
+ if (fp == 0)
+ {
+ ADD_FAILURE() << "Failed to SetUpTestCase().";
+ exit(EXIT_FAILURE);
+ }
+ my_fclose(fp, MYF(0));
+ }
+
+ static void TearDownTestCase()
+ {
+ /*
+ The std lib routine unlink(3) is considered trusted.
+ */
+ if (unlink(DUMMY_FILE_NAME) > 0)
+ {
+ ADD_FAILURE() << "Failed to TearDownTestCase().";
+ exit(EXIT_FAILURE);
+ }
+ }
+
+private:
+
+};
+
+TEST_F(My_open_test, EnvironmentCheck)
+{
+}
+
+TEST_F(My_open_test, FailToOpenUnknownFile)
+{
+ FILE *fp;
+ fp= my_fopen("/really/unknown/does-not-exist.bin", O_RDONLY | O_BINARY, MYF(0));
+ EXPECT_EQ((FILE *)0, fp);
+ EXPECT_EQ(0, my_stream_opened);
+ EXPECT_EQ(0, my_file_total_opened);
+}
+
+
+TEST_F(My_open_test, SuccessToOpenKnownBinaryFile)
+{
+ EXPECT_EQ(0, my_stream_opened);
+ FILE *fp;
+ fp= my_fopen(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0));
+ /*
+ The file should exist in the test dir and the call to my_open should not
+ fail under normal circumstances.
+ */
+ EXPECT_NE((FILE *)0, fp);
+
+ /*
+ The number of currently opened files should have increased
+ */
+ EXPECT_EQ(1, my_stream_opened);
+ /*
+ The number of total files should have increased
+ */
+ EXPECT_EQ(1, my_file_total_opened);
+
+
+ /*
+ When the file is closed the number of currently opened files should have
+ decreased to 0.
+ */
+ my_fclose(fp, MYF(0));
+ EXPECT_EQ(0, my_stream_opened);
+
+ /*
+ But the number of files which has been opened should of course stay the
+ same.
+ */
+ EXPECT_EQ(1, my_file_total_opened);
+
+ /*
+ Lets try it again to see if the number of files ever opened in the system
+ increases to 2
+ */
+ fp= my_fopen(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0));
+ EXPECT_NE((FILE *)0, fp);
+ EXPECT_EQ(1, my_stream_opened);
+ EXPECT_EQ(2, my_file_total_opened);
+ my_fclose(fp, MYF(0));
+ EXPECT_EQ(0, my_stream_opened);
+ EXPECT_EQ(2, my_file_total_opened);
+
+}
+
+TEST_F(My_open_test, TooManyOpenFiles)
+{
+ FILE *fp[MAX_NUMBER_OF_FILE_DESCRIPTORS+1];
+ /*
+ Attempt to open MAX_NUMBER_OF_FILE_DESCRIPTORS number of files.
+ NOTE: Couting begins at 0 hence we exclude i==MAX_NUMBER_OF_FILE_DESCRIPTORS
+ */
+ int opened_files= 0;
+ for(unsigned i= 0; i<MAX_NUMBER_OF_FILE_DESCRIPTORS; ++i)
+ {
+ fp[i]= my_fopen(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0));
+ if (fp[i] == 0)
+ break;
+ else
+ ++opened_files;
+ }
+ /*
+ We now have depleted the number of available file descriptors.
+ Next attempt to open a file will fail.
+ */
+ fp[opened_files]= my_fopen(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0));
+ EXPECT_EQ((FILE *)0, fp[opened_files]);
+
+ /*
+ Apply my_fclose) on all file descriptors to make sure all files are closed
+ */
+ for(int i= opened_files; i>=0; --i)
+ {
+ my_fclose(fp[i],MYF(0));
+ }
+ /*
+ No more files should be opened.
+ */
+ EXPECT_EQ(0, my_stream_opened);
+ EXPECT_EQ(opened_files, my_file_total_opened);
+}
+
+TEST_F(My_open_test, MultipleClose)
+{
+ FILE *fp;
+ fp= my_fopen(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0));
+ EXPECT_NE((FILE *)0, fp);
+ my_fclose(fp, MYF(0));
+ my_fclose(fp, MYF(0));
+ my_fclose(fp, MYF(0));
+ EXPECT_EQ(0, my_stream_opened);
+ EXPECT_EQ(1, my_file_total_opened);
+ fp= my_fopen("/really/dont/exist.bin", O_RDONLY | O_BINARY, MYF(0));
+ EXPECT_EQ((FILE *)0, fp);
+ my_fclose(fp, MYF(0));
+ my_fclose(fp, MYF(0));
+ my_fclose(fp, MYF(0));
+ EXPECT_EQ(0, my_stream_opened);
+ EXPECT_EQ(1, my_file_total_opened);
+}
+
=== added file 'unittest/gunit/my_open-t.cc'
--- a/unittest/gunit/my_open-t.cc 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/my_open-t.cc 2010-09-27 13:11:49 +0000
@@ -0,0 +1,182 @@
+/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+
+ 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,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
+
+#include "my_config.h"
+#include <gtest/gtest.h>
+#include "mysqld_error.h"
+#include "my_sys.h"
+
+#define MAX_NUMBER_OF_FILE_DESCRIPTORS (OS_FILE_LIMIT+MY_NFILE+1024)
+#define DUMMY_FILE_NAME "successful_open_rdonly.bin"
+
+struct st_my_file_info my_file_info_default[MY_NFILE];
+class My_open_test : public ::testing::Test
+{
+public:
+ My_open_test()
+ {
+ }
+
+ virtual void SetUp()
+ {
+ /* set all global variables for each TEST_F */
+ my_thread_basic_global_reinit();
+ my_file_opened= 0;
+ my_file_total_opened= 0;
+ my_set_max_open_files(MAX_NUMBER_OF_FILE_DESCRIPTORS);
+ my_errno= 0;
+ }
+
+ static void SetUpTestCase()
+ {
+ my_thread_basic_global_init();
+ File fd;
+ fd= my_open(DUMMY_FILE_NAME, O_WRONLY | O_CREAT | O_BINARY, MYF(0));
+ if (fd == -1)
+ {
+ ADD_FAILURE() << "Failed to SetUpTestCase().";
+ exit(EXIT_FAILURE);
+ }
+ my_close(fd, MYF(0));
+ }
+
+ static void TearDownTestCase()
+ {
+ /*
+ The std lib routine unlink(3) is considered trusted.
+ */
+ if (unlink(DUMMY_FILE_NAME) > 0)
+ {
+ ADD_FAILURE() << "Failed to TearDownTestCase().";
+ exit(EXIT_FAILURE);
+ }
+ }
+
+private:
+
+};
+
+TEST_F(My_open_test, FailToOpenUnknownFile)
+{
+ File fd;
+ fd= my_open("/really/unknown/does-not-exist.bin", O_RDONLY | O_BINARY, MYF(0));
+ EXPECT_EQ(-1, fd);
+ EXPECT_EQ(0, my_file_opened);
+ EXPECT_EQ(0, my_file_total_opened);
+}
+
+
+TEST_F(My_open_test, SuccessToOpenKnownBinaryFile)
+{
+ File fd;
+ fd= my_open(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0));
+ /*
+ The file should exist in the test dir and the call to my_open should not
+ fail under normal circumstances.
+ */
+ EXPECT_NE(-1, fd);
+
+ /*
+ The number of currently opened files should have increased
+ */
+ EXPECT_EQ(1, my_file_opened);
+ /*
+ The number of total files should have increased
+ */
+ EXPECT_EQ(1, my_file_total_opened);
+
+ my_close(fd, MYF(0));
+
+ /*
+ When the file is closed the number of currently opened files should have
+ decreased to 0.
+ */
+ EXPECT_EQ(0, my_file_opened);
+ /*
+ But the number of files which has been opened should of course stay the
+ same.
+ */
+ EXPECT_EQ(1, my_file_total_opened);
+
+ /*
+ Lets try it again to see if the number of files ever opened in the system
+ increases to 2
+ */
+ fd= my_open(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0));
+ EXPECT_NE(-1, fd);
+ EXPECT_EQ(1, my_file_opened);
+ EXPECT_EQ(2, my_file_total_opened);
+ my_close(fd, MYF(0));
+ EXPECT_EQ(0, my_file_opened);
+ EXPECT_EQ(2, my_file_total_opened);
+
+}
+
+TEST_F(My_open_test, TooManyOpenFiles)
+{
+ File fd[MAX_NUMBER_OF_FILE_DESCRIPTORS+1];
+ /*
+ Attempt to open MAX_NUMBER_OF_FILE_DESCRIPTORS number of files.
+ NOTE: Couting begins at 0 hence we exclude i==MAX_NUMBER_OF_FILE_DESCRIPTORS
+ */
+ int opened_files= 0;
+ for(unsigned i= 0; i<MAX_NUMBER_OF_FILE_DESCRIPTORS; ++i)
+ {
+ fd[i]= my_open(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0));
+ if (fd[i] == -1)
+ break;
+ else
+ ++opened_files;
+ }
+ /*
+ We now have depleted the number of available file descriptors.
+ Next attempt to open a file will fail.
+ */
+ fd[opened_files]= my_open(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0));
+ EXPECT_EQ(-1, fd[opened_files]);
+
+ /*
+ Apply my_close() on all file descriptors to make sure all files are closed
+ */
+ for(int i= opened_files; i>=0; --i)
+ {
+ my_close(fd[i],MYF(0));
+ }
+ /*
+ No more files should be opened.
+ */
+ EXPECT_EQ(0, my_file_opened);
+ EXPECT_EQ(opened_files, my_file_total_opened);
+}
+
+TEST_F(My_open_test, MultipleClose)
+{
+ File fd;
+ fd= my_open(DUMMY_FILE_NAME, O_RDONLY | O_BINARY, MYF(0));
+ EXPECT_NE(-1, fd);
+ my_close(fd, MYF(0));
+ my_close(fd, MYF(0));
+ my_close(fd, MYF(0));
+ EXPECT_EQ(0, my_file_opened);
+ EXPECT_EQ(1, my_file_total_opened);
+ fd= my_open("/really/dont/exist.bin", O_RDONLY | O_BINARY, MYF(0));
+ EXPECT_EQ(-1, fd);
+ my_close(fd, MYF(0));
+ my_close(fd, MYF(0));
+ my_close(fd, MYF(0));
+ EXPECT_EQ(0, my_file_opened);
+ EXPECT_EQ(1, my_file_total_opened);
+}
+
Attachment: [text/bzr-bundle] bzr/kristofer.pettersson@oracle.com-20100927131149-uezcc29lyxm735cp.bundle