1/**************************************************************************** 2 * fs/vfs/fs_pread.c 3 * 4 * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved. 5 * Based on NuttX originally written by Gregory Nutt 6 * 7 * Copyright (C) 2014, 2016-2017 Gregory Nutt. All rights reserved. 8 * Author: Gregory Nutt <gnutt@nuttx.org> 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 3. Neither the name NuttX nor the names of its contributors may be 21 * used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 31 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 * 37 ****************************************************************************/ 38 39/**************************************************************************** 40 * Included Files 41 ****************************************************************************/ 42 43#include "vfs_config.h" 44 45#include "sys/types.h" 46#include "unistd.h" 47#include "errno.h" 48 49#include "fs/file.h" 50 51/**************************************************************************** 52 * Public Functions 53 ****************************************************************************/ 54 55/**************************************************************************** 56 * Name: file_pread64 57 * 58 * Description: 59 * Equivalent to the standard pread function except that is accepts a 60 * struct file instance instead of a file descriptor. Currently used 61 * only by aio_read(); 62 * 63 ****************************************************************************/ 64 65ssize_t file_pread64(struct file *filep, void *buf, size_t nbytes, 66 off64_t offset) 67{ 68 off64_t savepos; 69 off64_t pos; 70 ssize_t ret; 71 int errcode; 72 73 /* Perform the seek to the current position. This will not move the 74 * file pointer, but will return its current setting 75 */ 76 77 savepos = file_seek64(filep, 0, SEEK_CUR); 78 if (savepos == (off64_t)-1) 79 { 80 /* file_seek64 might fail if this if the media is not seekable */ 81 82 return VFS_ERROR; 83 } 84 85 /* Then seek to the correct position in the file */ 86 87 pos = file_seek64(filep, offset, SEEK_SET); 88 if (pos == (off64_t)-1) 89 { 90 /* This might fail is the offset is beyond the end of file */ 91 92 return VFS_ERROR; 93 } 94 95 /* Then perform the read operation */ 96 97 ret = file_read(filep, buf, nbytes); 98 errcode = get_errno(); 99 100 /* Restore the file position */ 101 102 pos = file_seek64(filep, savepos, SEEK_SET); 103 if (pos == (off64_t)-1 && ret >= 0) 104 { 105 /* This really should not fail */ 106 107 return VFS_ERROR; 108 } 109 110 if (errcode != 0) 111 { 112 set_errno(errcode); 113 } 114 return ret; 115} 116 117/**************************************************************************** 118 * Name: pread64 119 * 120 * Description: 121 * The pread() function performs the same action as read(), except that it 122 * reads from a given position in the file without changing the file 123 * pointer. The first three arguments to pread() are the same as read() 124 * with the addition of a fourth argument offset for the desired position 125 * inside the file. An attempt to perform a pread() on a file that is 126 * incapable of seeking results in an error. 127 * 128 * NOTE: This function could have been wholly implemented within libc but 129 * it is not. Why? Because if pread were implemented in libc, it would 130 * require four system calls. If it is implemented within the kernel, 131 * only three. 132 * 133 * Input Parameters: 134 * file File structure instance 135 * buf User-provided to save the data 136 * nbytes The maximum size of the user-provided buffer 137 * offset The file offset 138 * 139 * Returned Value: 140 * The positive non-zero number of bytes read on success, 0 on if an 141 * end-of-file condition, or -1 on failure with errno set appropriately. 142 * See read() return values 143 * 144 ****************************************************************************/ 145 146ssize_t pread64(int fd, void *buf, size_t nbytes, off64_t offset) 147{ 148 struct file *filep; 149 150 /* Get the file structure corresponding to the file descriptor. */ 151 152 int ret = fs_getfilep(fd, &filep); 153 if (ret < 0) 154 { 155 /* The errno value has already been set */ 156 return (ssize_t)VFS_ERROR; 157 } 158 159 if (filep->f_oflags & O_DIRECTORY) 160 { 161 set_errno(EBADF); 162 return VFS_ERROR; 163 } 164 165 /* Let file_pread do the real work */ 166 167 return file_pread64(filep, buf, nbytes, offset); 168} 169