• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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