diff --git a/fs/vfs/fs_read.c b/fs/vfs/fs_read.c index 1d93af0e04bf1..e92379a781b1a 100644 --- a/fs/vfs/fs_read.c +++ b/fs/vfs/fs_read.c @@ -50,19 +50,14 @@ * ****************************************************************************/ -static ssize_t file_readv_compat(FAR struct file *filep, FAR struct uio *uio) +static ssize_t file_readv_compat(FAR struct file *filep, + FAR const struct iovec *iov, int iovcnt) { - FAR const struct iovec *iov = uio->uio_iov; - int iovcnt = uio->uio_iovcnt; FAR struct inode *inode = filep->f_inode; ssize_t ntotal; ssize_t nread; - size_t remaining; - FAR uint8_t *buffer; int i; - DEBUGASSERT(inode->u.i_ops->read != NULL); - /* Process each entry in the struct iovec array */ for (i = 0, ntotal = 0; i < iovcnt; i++) @@ -74,36 +69,41 @@ static ssize_t file_readv_compat(FAR struct file *filep, FAR struct uio *uio) continue; } - buffer = iov[i].iov_base; - remaining = iov[i].iov_len; + /* Sanity check to avoid total length overflow */ + + if (SSIZE_MAX - ntotal < iov[i].iov_len) + { + if (ntotal > 0) + { + break; + } + + return -EINVAL; + } - nread = inode->u.i_ops->read(filep, (void *)buffer, remaining); + nread = inode->u.i_ops->read(filep, iov[i].iov_base, + iov[i].iov_len); /* Check for a read error */ if (nread < 0) { - return ntotal ? ntotal : nread; + if (ntotal > 0) + { + break; + } + + return nread; } ntotal += nread; /* Check for a parital success condition, including an end-of-file */ - if (nread < remaining) + if (nread < iov[i].iov_len) { - return ntotal; + break; } - - /* Update the pointer */ - - buffer += nread; - remaining -= nread; - } - - if (ntotal >= 0) - { - uio_advance(uio, ntotal); } return ntotal; @@ -126,7 +126,8 @@ static ssize_t file_readv_compat(FAR struct file *filep, FAR struct uio *uio) * * Input Parameters: * filep - File structure instance - * uio - User buffer information + * iov - User-provided iovec to save the data + * iovcnt - The number of iovec * * Returned Value: * The positive non-zero number of bytes read on success, 0 on if an @@ -134,7 +135,8 @@ static ssize_t file_readv_compat(FAR struct file *filep, FAR struct uio *uio) * ****************************************************************************/ -ssize_t file_readv(FAR struct file *filep, FAR struct uio *uio) +ssize_t file_readv(FAR struct file *filep, + FAR const struct iovec *iov, int iovcnt) { FAR struct inode *inode; ssize_t ret = -EBADF; @@ -162,11 +164,17 @@ ssize_t file_readv(FAR struct file *filep, FAR struct uio *uio) { if (inode->u.i_ops->readv) { - ret = inode->u.i_ops->readv(filep, uio); + struct uio uio; + + ret = uio_init(&uio, iov, iovcnt); + if (ret == 0) + { + ret = inode->u.i_ops->readv(filep, &uio); + } } else if (inode->u.i_ops->read) { - ret = file_readv_compat(filep, uio); + ret = file_readv_compat(filep, iov, iovcnt); } } @@ -207,18 +215,11 @@ ssize_t file_readv(FAR struct file *filep, FAR struct uio *uio) ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes) { struct iovec iov; - struct uio uio; - ssize_t ret; iov.iov_base = buf; iov.iov_len = nbytes; - ret = uio_init(&uio, &iov, 1); - if (ret != 0) - { - return ret; - } - return file_readv(filep, &uio); + return file_readv(filep, &iov, 1); } /**************************************************************************** @@ -244,7 +245,6 @@ ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes) ssize_t nx_readv(int fd, FAR const struct iovec *iov, int iovcnt) { - struct uio uio; FAR struct file *filep; ssize_t ret; @@ -253,20 +253,15 @@ ssize_t nx_readv(int fd, FAR const struct iovec *iov, int iovcnt) */ ret = (ssize_t)fs_getfilep(fd, &filep); - if (ret < 0) + if (ret >= 0) { - return ret; - } + /* Then let file_readv do all of the work. */ - /* Then let file_readv do all of the work. */ + ret = file_readv(filep, iov, iovcnt); - ret = uio_init(&uio, iov, iovcnt); - if (ret == 0) - { - ret = file_readv(filep, &uio); + fs_putfilep(filep); } - fs_putfilep(filep); return ret; } diff --git a/fs/vfs/fs_uio.c b/fs/vfs/fs_uio.c index 0ee178bfbfec8..c18bf1867f152 100644 --- a/fs/vfs/fs_uio.c +++ b/fs/vfs/fs_uio.c @@ -131,7 +131,7 @@ int uio_init(FAR struct uio *uio, FAR const struct iovec *iov, int iovcnt) resid = uio_calc_resid(uio); if (resid < 0) { - return -EINVAL; + return resid; } uio->uio_resid = resid; diff --git a/fs/vfs/fs_write.c b/fs/vfs/fs_write.c index 16be9ea957f38..025bbc424110b 100644 --- a/fs/vfs/fs_write.c +++ b/fs/vfs/fs_write.c @@ -51,19 +51,13 @@ ****************************************************************************/ static ssize_t file_writev_compat(FAR struct file *filep, - FAR struct uio *uio) + FAR const struct iovec *iov, int iovcnt) { - FAR const struct iovec *iov = uio->uio_iov; - int iovcnt = uio->uio_iovcnt; FAR struct inode *inode = filep->f_inode; - ssize_t ntotal; ssize_t nwritten; - size_t remaining; - FAR uint8_t *buffer; + ssize_t ntotal; int i; - DEBUGASSERT(inode->u.i_ops->write != NULL); - /* Process each entry in the struct iovec array */ for (i = 0, ntotal = 0; i < iovcnt; i++) @@ -75,36 +69,41 @@ static ssize_t file_writev_compat(FAR struct file *filep, continue; } - buffer = iov[i].iov_base; - remaining = iov[i].iov_len; + /* Sanity check to avoid total length overflow */ - nwritten = inode->u.i_ops->write(filep, (void *)buffer, remaining); + if (SSIZE_MAX - ntotal < iov[i].iov_len) + { + if (ntotal > 0) + { + break; + } + + return -EINVAL; + } + + nwritten = inode->u.i_ops->write(filep, iov[i].iov_base, + iov[i].iov_len); /* Check for a write error */ if (nwritten < 0) { - return ntotal ? ntotal : nwritten; + if (ntotal > 0) + { + break; + } + + return nwritten; } ntotal += nwritten; /* Check for a parital success condition */ - if (nwritten < remaining) + if (nwritten < iov[i].iov_len) { - return ntotal; + break; } - - /* Update the pointer */ - - buffer += nwritten; - remaining -= nwritten; - } - - if (ntotal >= 0) - { - uio_advance(uio, ntotal); } return ntotal; @@ -128,7 +127,8 @@ static ssize_t file_writev_compat(FAR struct file *filep, * * Input Parameters: * filep - Instance of struct file to use with the write - * uio - User buffer information + * iov - Data to write + * iovcnt - The number of vectors * * Returned Value: * On success, the number of bytes written are returned (zero indicates @@ -138,7 +138,8 @@ static ssize_t file_writev_compat(FAR struct file *filep, * ****************************************************************************/ -ssize_t file_writev(FAR struct file *filep, FAR struct uio *uio) +ssize_t file_writev(FAR struct file *filep, + FAR const struct iovec *iov, int iovcnt) { FAR struct inode *inode; ssize_t ret = -EBADF; @@ -159,11 +160,17 @@ ssize_t file_writev(FAR struct file *filep, FAR struct uio *uio) { if (inode->u.i_ops->writev) { - ret = inode->u.i_ops->writev(filep, uio); + struct uio uio; + + ret = uio_init(&uio, iov, iovcnt); + if (ret == 0) + { + ret = inode->u.i_ops->writev(filep, &uio); + } } else if (inode->u.i_ops->write) { - ret = file_writev_compat(filep, uio); + ret = file_writev_compat(filep, iov, iovcnt); } } @@ -206,18 +213,11 @@ ssize_t file_write(FAR struct file *filep, FAR const void *buf, size_t nbytes) { struct iovec iov; - struct uio uio; - ssize_t ret; iov.iov_base = (FAR void *)buf; iov.iov_len = nbytes; - ret = uio_init(&uio, &iov, 1); - if (ret != 0) - { - return ret; - } - return file_writev(filep, &uio); + return file_writev(filep, &iov, 1); } /**************************************************************************** @@ -247,7 +247,6 @@ ssize_t file_write(FAR struct file *filep, FAR const void *buf, ssize_t nx_writev(int fd, FAR const struct iovec *iov, int iovcnt) { - struct uio uio; FAR struct file *filep; ssize_t ret; @@ -262,11 +261,7 @@ ssize_t nx_writev(int fd, FAR const struct iovec *iov, int iovcnt) * index. Note that file_writev() will return the errno on failure. */ - ret = uio_init(&uio, iov, iovcnt); - if (ret == 0) - { - ret = file_writev(filep, &uio); - } + ret = file_writev(filep, iov, iovcnt); fs_putfilep(filep); } diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index 72edf64d65543..156d67279a146 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -1419,7 +1419,8 @@ int close_mtddriver(FAR struct inode *pinode); ****************************************************************************/ ssize_t file_read(FAR struct file *filep, FAR void *buf, size_t nbytes); -ssize_t file_readv(FAR struct file *filep, FAR struct uio *uio); +ssize_t file_readv(FAR struct file *filep, + FAR const struct iovec *iov, int iovcnt); /**************************************************************************** * Name: nx_read @@ -1473,7 +1474,8 @@ ssize_t nx_readv(int fd, FAR const struct iovec *iov, int iovcnt); ssize_t file_write(FAR struct file *filep, FAR const void *buf, size_t nbytes); -ssize_t file_writev(FAR struct file *filep, FAR struct uio *uio); +ssize_t file_writev(FAR struct file *filep, + FAR const struct iovec *iov, int iovcnt); /**************************************************************************** * Name: nx_write