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
file_pread64(struct file * filep,void * buf,size_t nbytes,off64_t offset)65 ssize_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
pread64(int fd,void * buf,size_t nbytes,off64_t offset)146 ssize_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