Back to index

glibc  2.9
readv.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991, 1992, 1996, 1997, 2002 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <stdlib.h>
00020 #include <unistd.h>
00021 #include <string.h>
00022 #include <limits.h>
00023 #include <stdbool.h>
00024 #include <sys/param.h>
00025 #include <sys/uio.h>
00026 #include <errno.h>
00027 
00028 /* Read data from file descriptor FD, and put the result in the
00029    buffers described by VECTOR, which is a vector of COUNT `struct iovec's.
00030    The buffers are filled in the order specified.
00031    Operates just like `read' (see <unistd.h>) except that data are
00032    put in VECTOR instead of a contiguous buffer.  */
00033 ssize_t
00034 __libc_readv (int fd, const struct iovec *vector, int count)
00035 {
00036   char *buffer;
00037   char *buffer_start;
00038   size_t bytes;
00039   ssize_t bytes_read;
00040   int i;
00041   bool use_malloc = false;
00042 
00043   /* Find the total number of bytes to be read.  */
00044   bytes = 0;
00045   for (i = 0; i < count; ++i)
00046     {
00047       /* Check for ssize_t overflow.  */
00048       if (SSIZE_MAX - bytes < vector[i].iov_len)
00049        {
00050          __set_errno (EINVAL);
00051          return -1;
00052        }
00053       bytes += vector[i].iov_len;
00054     }
00055 
00056   /* Allocate a temporary buffer to hold the data.  We should normally
00057      use alloca since it's faster and does not require synchronization
00058      with other threads.  But we cannot if the amount of memory
00059      required is too large.  */
00060   if (__libc_use_alloca (bytes))
00061     buffer = (char *) __alloca (bytes);
00062   else
00063     {
00064       buffer = (char *) malloc (bytes);
00065       if (buffer == NULL)
00066        /* XXX I don't know whether it is acceptable to try reading
00067           the data in chunks.  Probably not so we just fail here.  */
00068        return -1;
00069 
00070       use_malloc = true;
00071     }
00072 
00073   /* Read the data.  */
00074   bytes_read = __read (fd, buffer, bytes);
00075   if (bytes_read <= 0)
00076     return -1;
00077 
00078   /* Copy the data from BUFFER into the memory specified by VECTOR.  */
00079   bytes = bytes_read;
00080   buffer_start = buffer;
00081   for (i = 0; i < count; ++i)
00082     {
00083       size_t copy = MIN (vector[i].iov_len, bytes);
00084 
00085       (void) memcpy ((void *) vector[i].iov_base, (void *) buffer, copy);
00086 
00087       buffer += copy;
00088       bytes -= copy;
00089       if (bytes == 0)
00090        break;
00091     }
00092 
00093   if (use_malloc)
00094     free (buffer_start);
00095 
00096   return bytes_read;
00097 }
00098 #ifndef __libc_readv
00099 strong_alias (__libc_readv, __readv)
00100 weak_alias (__libc_readv, readv)
00101 #endif