Commit 12d8f2bf authored by thek@kpdesk.mysql.com's avatar thek@kpdesk.mysql.com
Browse files

Bug#22828 _my_b_read() ignores return values for my_seek() calls

- Because my_seek actually is capable of returning an error code we should
  exploit that in the best possible way.
- There might be kernel errors or other errors we can't predict and capturing
  the return value of all system calls gives us better understanding of
  possible errors.
parent 397f0df9
Loading
Loading
Loading
Loading
+90 −12
Original line number Diff line number Diff line
@@ -440,11 +440,24 @@ int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)

  /* pos_in_file always point on where info->buffer was read */
  pos_in_file=info->pos_in_file+(uint) (info->read_end - info->buffer);

  /* 
    Whenever a function which operates on IO_CACHE flushes/writes
    some part of the IO_CACHE to disk it will set the property
    "seek_not_done" to indicate this to other functions operating
    on the IO_CACHE.
  */
  if (info->seek_not_done)
  {					/* File touched, do seek */
    VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)));
  {
    if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) 
        == MY_FILEPOS_ERROR)
    {
        info->error= -1;
        DBUG_RETURN(1);
    }
    info->seek_not_done=0;
  }

  diff_length=(uint) (pos_in_file & (IO_SIZE-1));
  if (Count >= (uint) (IO_SIZE+(IO_SIZE-diff_length)))
  {					/* Fill first intern buffer */
@@ -633,8 +646,22 @@ int _my_b_read_r(register IO_CACHE *info, byte *Buffer, uint Count)
    if (lock_io_cache(info, pos_in_file))
    {
      info->share->active=info;
      if (info->seek_not_done)             /* File touched, do seek */
        VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)));
      /*
        Whenever a function which operates on IO_CACHE flushes/writes
        some part of the IO_CACHE to disk it will set the property
        "seek_not_done" to indicate this to other functions operating
        on the IO_CACHE.
      */
      if (info->seek_not_done)
      {
        if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0))
            == MY_FILEPOS_ERROR)
        {
          info->error= -1;
          unlock_io_cache(info);
          DBUG_RETURN(1);
        }
      }
      len=(int)my_read(info->file,info->buffer, length, info->myflags);
      info->read_end=info->buffer + (len == -1 ? 0 : len);
      info->error=(len == (int)length ? 0 : len);
@@ -668,11 +695,16 @@ int _my_b_read_r(register IO_CACHE *info, byte *Buffer, uint Count)


/*
  Do sequential read from the SEQ_READ_APPEND cache
  we do this in three stages:
  Do sequential read from the SEQ_READ_APPEND cache.
  
  We do this in three stages:
   - first read from info->buffer
   - then if there are still data to read, try the file descriptor
   - afterwards, if there are still data to read, try append buffer

  RETURNS
    0  Success
    1  Failed to read
*/

int _my_b_seq_read(register IO_CACHE *info, byte *Buffer, uint Count)
@@ -700,7 +732,13 @@ int _my_b_seq_read(register IO_CACHE *info, byte *Buffer, uint Count)
    With read-append cache we must always do a seek before we read,
    because the write could have moved the file pointer astray
  */
  VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)));
  if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0))
      == MY_FILEPOS_ERROR)
  {
   info->error= -1;
   unlock_append_buffer(info);
   return (1);
  }
  info->seek_not_done=0;

  diff_length=(uint) (pos_in_file & (IO_SIZE-1));
@@ -816,6 +854,21 @@ int _my_b_seq_read(register IO_CACHE *info, byte *Buffer, uint Count)

#ifdef HAVE_AIOWAIT

/*
  Read from the IO_CACHE into a buffer and feed asynchronously
  from disk when needed.

  SYNOPSIS
    _my_b_async_read()
      info                      IO_CACHE pointer
      Buffer                    Buffer to retrieve count bytes from file
      Count                     Number of bytes to read into Buffer

  RETURN VALUE
    -1          An error has occurred; my_errno is set.
     0          Success
     1          An error has occurred; IO_CACHE to error state.
*/
int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
{
  uint length,read_length,diff_length,left_length,use_length,org_Count;
@@ -906,7 +959,14 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
      info->error=(int) (read_length+left_length);
      return 1;
    }
    VOID(my_seek(info->file,next_pos_in_file,MY_SEEK_SET,MYF(0)));
    
    if (my_seek(info->file,next_pos_in_file,MY_SEEK_SET,MYF(0))
        == MY_FILEPOS_ERROR)
    {
      info->error= -1;
      return (1);
    }

    read_length=IO_SIZE*2- (uint) (next_pos_in_file & (IO_SIZE-1));
    if (Count < read_length)
    {					/* Small block, read to cache */
@@ -999,7 +1059,15 @@ int _my_b_get(IO_CACHE *info)
  return (int) (uchar) buff;
}

	/* Returns != 0 if error on write */
/* 
   Write a byte buffer to IO_CACHE and flush to disk
   if IO_CACHE is full.

   RETURN VALUE
    1 On error on write
    0 On success
   -1 On error; my_errno contains error code.
*/

int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
{
@@ -1022,8 +1090,18 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
  {					/* Fill first intern buffer */
    length=Count & (uint) ~(IO_SIZE-1);
    if (info->seek_not_done)
    {					/* File touched, do seek */
      VOID(my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0)));
    {
      /*
        Whenever a function which operates on IO_CACHE flushes/writes
        some part of the IO_CACHE to disk it will set the property
        "seek_not_done" to indicate this to other functions operating
        on the IO_CACHE.
      */
      if (my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0)))
      {
        info->error= -1;
        return (1);
      }
      info->seek_not_done=0;
    }
    if (my_write(info->file,Buffer,(uint) length,info->myflags | MY_NABP))
+5 −1
Original line number Diff line number Diff line
@@ -88,7 +88,11 @@ int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
      Fill space between requested length and true length with 'filler'
      We should never come here on any modern machine
    */
    VOID(my_seek(fd, newlength, MY_SEEK_SET, MYF(MY_WME+MY_FAE)));
    if (my_seek(fd, newlength, MY_SEEK_SET, MYF(MY_WME+MY_FAE))
        == MY_FILEPOS_ERROR)
    {
      goto err;
    }
    swap_variables(my_off_t, newlength, oldsize);
  }
#endif
+34 −5
Original line number Diff line number Diff line
@@ -35,7 +35,14 @@
#include <nks/fsio.h>
#endif

	/* Lock a part of a file */
/* 
  Lock a part of a file 

  RETURN VALUE
    0   Success
    -1  An error has occured and 'my_errno' is set
        to indicate the actual error code.
*/

int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
	    myf MyFlags)
@@ -104,10 +111,22 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
#elif defined(HAVE_LOCKING)
  /* Windows */
  {
    my_bool error;
    my_bool error= false;
    pthread_mutex_lock(&my_file_info[fd].mutex);
    if (MyFlags & MY_SEEK_NOT_DONE) 
      VOID(my_seek(fd,start,MY_SEEK_SET,MYF(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)
@@ -145,7 +164,17 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
  }
#else
  if (MyFlags & MY_SEEK_NOT_DONE)
    VOID(my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE)));
  {
    if (my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE))
        == MY_FILEPOS_ERROR)
    {
      /*
        If an error has occured in my_seek then we will already
        have an error code in my_errno; Just return error code.
      */
      DBUG_RETURN(-1);
    }
  }
  if (lockf(fd,locktype,length) != -1)
    DBUG_RETURN(0);
#endif /* HAVE_FCNTL */
+24 −2
Original line number Diff line number Diff line
@@ -16,8 +16,30 @@

#include "mysys_priv.h"

	/* Seek to position in file */
	/*ARGSUSED*/
/* 
  Seek to a position in a file.

  ARGUMENTS
  File fd          The file descriptor
  my_off_t pos     The expected position (absolute or relative)
  int whence       A direction parameter and one of 
                   {SEEK_SET, SEEK_CUR, SEEK_END}
  myf MyFlags      Not used.

  DESCRIPTION
    The my_seek  function  is a wrapper around the system call lseek and
    repositions  the  offset of the file descriptor fd to the argument 
    offset according to the directive whence as follows:
      SEEK_SET    The offset is set to offset bytes.
      SEEK_CUR    The offset is set to its current location plus offset bytes
      SEEK_END    The offset is set to the size of the file plus offset bytes

  RETURN VALUE
    my_off_t newpos    The new position in the file.
    MY_FILEPOS_ERROR   An error was encountered while performing 
                       the seek. my_errno is set to indicate the
                       actual error.
*/

my_off_t my_seek(File fd, my_off_t pos, int whence,
		 myf MyFlags __attribute__((unused)))