1 /****************************************************************************
2 * fs/vfs/fs_read.c
3 *
4 * Copyright (C) 2007-2009, 2012-2014, 2016-2017 Gregory Nutt. All rights
5 * reserved.
6 * Author: Gregory Nutt <gnutt@nuttx.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 * 3. Neither the name NuttX nor the names of its contributors may be
19 * used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 ****************************************************************************/
36
37 /****************************************************************************
38 * Included Files
39 ****************************************************************************/
40
41 #include "vfs_config.h"
42 #include "sys/types.h"
43 #include "sys/socket.h"
44 #include "console.h"
45 #include "unistd.h"
46 #include "fcntl.h"
47 #include "sched.h"
48 #include "assert.h"
49 #include "errno.h"
50 #include "user_copy.h"
51 #include "vnode.h"
52
53 /****************************************************************************
54 * Public Functions
55 ****************************************************************************/
56
57 /****************************************************************************
58 * Name: file_read
59 *
60 * Description:
61 * file_read() is an interanl OS interface. It is functionally similar to
62 * the standard read() interface except:
63 *
64 * - It does not modify the errno variable,
65 * - It is not a cancellation point,
66 * - It does not handle socket descriptors, and
67 * - It accepts a file structure instance instead of file descriptor.
68 *
69 * Input Parameters:
70 * filep - File structure instance
71 * buf - User-provided to save the data
72 * nbytes - The maximum size of the user-provided buffer
73 *
74 * Returned Value:
75 * The positive non-zero number of bytes read on success, 0 on if an
76 * end-of-file condition, or a negated errno value on any failure.
77 *
78 ****************************************************************************/
79
file_read(struct file * filep,void * buf,size_t nbytes)80 ssize_t file_read(struct file *filep, void *buf, size_t nbytes)
81 {
82 int ret = -EBADF;
83
84 if (buf == NULL)
85 {
86 ret = -EFAULT;
87 }
88
89 /* Was this file opened for read access? */
90
91 else if (((unsigned int)(filep->f_oflags) & O_ACCMODE) == O_WRONLY)
92 {
93 /* No.. File is not read-able */
94
95 ret = -EACCES;
96 }
97
98 /* Is a driver or mountpoint registered? If so, does it support the read
99 * method?
100 */
101
102 else if (filep->ops && filep->ops->read)
103 {
104 /* Yes.. then let it perform the read. NOTE that for the case of the
105 * mountpoint, we depend on the read methods being identical in
106 * signature and position in the operations vtable.
107 */
108
109 ret = (int)filep->ops->read(filep, (char *)buf, (size_t)nbytes);
110 }
111
112 /* If an error occurred, set errno and return -1 (ERROR) */
113
114 if (ret < 0)
115 {
116 set_errno(-ret);
117 return VFS_ERROR;
118 }
119
120 /* Otherwise, return the number of bytes read */
121
122 return ret;
123 }
124
125 /****************************************************************************
126 * Name: read
127 *
128 * Description:
129 * The standard, POSIX read interface.
130 *
131 * Input Parameters:
132 * fd - File descriptor to read from
133 * buf - User-provided to save the data
134 * nbytes - The maximum size of the user-provided buffer
135 *
136 * Returned Value:
137 * The positive non-zero number of bytes read on success, 0 on if an
138 * end-of-file condition, or -1 on failure with errno set appropriately.
139 *
140 ****************************************************************************/
141
read(int fd,void * buf,size_t nbytes)142 ssize_t read(int fd, void *buf, size_t nbytes)
143 {
144 /* Did we get a valid file descriptor? */
145
146 #if CONFIG_NFILE_DESCRIPTORS > 0
147 struct file *filep = NULL;
148
149 if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS)
150 #endif
151 {
152 /* No.. If networking is enabled, read() is the same as recv() with
153 * the flags parameter set to zero.
154 */
155
156 #if defined(LOSCFG_NET_LWIP_SACK)
157 void *bufbak = buf;
158 ssize_t ret;
159 if (LOS_IsUserAddress((VADDR_T)(uintptr_t)buf))
160 {
161 if (buf != NULL && nbytes > 0)
162 {
163 buf = malloc(nbytes);
164 if (buf == NULL)
165 {
166 set_errno(ENOMEM);
167 return VFS_ERROR;
168 }
169 }
170 }
171 ret = recv(fd, buf, nbytes, 0);
172 if (ret > 0 && buf != bufbak)
173 {
174 if (LOS_ArchCopyToUser(bufbak, buf, ret) != 0)
175 {
176 /* data lost here */
177 set_errno(EFAULT);
178 ret = VFS_ERROR;
179 }
180 }
181 if (buf != bufbak)
182 {
183 free(buf);
184 }
185 return ret;
186 #else
187 /* No networking... it is a bad descriptor in any event */
188
189 set_errno(EBADF);
190 return VFS_ERROR;
191 #endif
192 }
193
194 #if CONFIG_NFILE_DESCRIPTORS > 0
195 else
196 {
197 if (fd <= STDERR_FILENO && fd >= STDIN_FILENO) /* fd : [0,2] */
198 {
199 fd = ConsoleUpdateFd();
200 if (fd < 0)
201 {
202 set_errno(EBADF);
203 return VFS_ERROR;
204 }
205 }
206
207 /* The descriptor is in a valid range to file descriptor... do the
208 * read. First, get the file structure.
209 */
210
211 int ret = fs_getfilep(fd, &filep);
212 if (ret < 0)
213 {
214 /* The errno value has already been set */
215 return VFS_ERROR;
216 }
217
218 if (filep->f_oflags & O_DIRECTORY)
219 {
220 set_errno(EBADF);
221 return VFS_ERROR;
222 }
223
224 /* Then let file_read do all of the work */
225
226 return file_read(filep, buf, nbytes);
227 }
228 #endif
229 }
230