• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * fs/vfs/fs_write.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 "unistd.h"
44 #include "fcntl.h"
45 #include "sched.h"
46 #include "assert.h"
47 #include "errno.h"
48 #include "sys/socket.h"
49 #include "console.h"
50 #include "user_copy.h"
51 #include "vnode.h"
52 
53 /****************************************************************************
54  * Public Functions
55  ****************************************************************************/
56 
57 /****************************************************************************
58  * Name: file_write
59  *
60  * Description:
61  *   Equivalent to the standard write() function except that is accepts a
62  *   struct file instance instead of a file descriptor.  It is functionally
63  *   equivalent to write() except that in addition to the differences in
64  *   input paramters:
65  *
66  *  - It does not modify the errno variable,
67  *  - It is not a cancellation point, and
68  *  - It does not handle socket descriptors.
69  *
70  * Input Parameters:
71  *   filep  - Instance of struct file to use with the write
72  *   buf    - Data to write
73  *   nbytes - Length of data to write
74  *
75  * Returned Value:
76  *  On success, the number of bytes written are returned (zero indicates
77  *  nothing was written).  On any failure, a negated errno value is returned
78  *  (see comments withwrite() for a description of the appropriate errno
79  *  values).
80  *
81  ****************************************************************************/
file_write(struct file * filep,const void * buf,size_t nbytes)82 ssize_t file_write(struct file *filep, const void *buf, size_t nbytes)
83 {
84   int ret;
85   int err;
86 
87   if (buf == NULL)
88     {
89       err = EFAULT;
90       goto errout;
91     }
92 
93   /* Was this file opened for write access? */
94 
95   if ((((unsigned int)(filep->f_oflags)) & O_ACCMODE) == O_RDONLY)
96     {
97       err = EACCES;
98       goto errout;
99     }
100 
101   /* Is a driver registered? Does it support the write method? */
102 
103   if (!filep->ops || !filep->ops->write)
104     {
105       err = EBADF;
106       goto errout;
107     }
108 
109   /* Yes, then let the driver perform the write */
110 
111   ret = filep->ops->write(filep, (const char *)buf, nbytes);
112   if (ret < 0)
113     {
114       err = -ret;
115       goto errout;
116     }
117 
118   return ret;
119 
120 errout:
121   set_errno(err);
122   return VFS_ERROR;
123 }
124 
125 /****************************************************************************
126  * Name: write
127  *
128  * Description:
129  *  write() writes up to nytes bytes to the file referenced by the file
130  *  descriptor fd from the buffer starting at buf.
131  *
132  * Input Parameters:
133  *   fd     - file descriptor (or socket descriptor) to write to
134  *   buf    - Data to write
135  *   nbytes - Length of data to write
136  *
137  * Returned Value:
138  *  On success, the number of bytes written are returned (zero indicates
139  *  nothing was written). On error, -1 is returned, and errno is set appro-
140  *  priately:
141  *
142  *  EAGAIN
143  *    Non-blocking I/O has been selected using O_NONBLOCK and the write
144  *    would block.
145  *  EBADF
146  *    fd is not a valid file descriptor or is not open for writing.
147  *  EFAULT
148  *    buf is outside your accessible address space.
149  *  EFBIG
150  *    An attempt was made to write a file that exceeds the implementation
151  *    defined maximum file size or the process' file size limit, or
152  *    to write at a position past the maximum allowed offset.
153  *  EINTR
154  *    The call was interrupted by a signal before any data was written.
155  *  EINVAL
156  *    fd is attached to an object which is unsuitable for writing; or
157  *    the file was opened with the O_DIRECT flag, and either the address
158  *    specified in buf, the value specified in count, or the current
159  *     file offset is not suitably aligned.
160  *  EIO
161  *    A low-level I/O error occurred while modifying the vnode.
162  *  ENOSPC
163  *    The device containing the file referred to by fd has no room for
164  *    the data.
165  *  EPIPE
166  *    fd is connected to a pipe or socket whose reading end is closed.
167  *    When this happens the writing process will also receive a SIGPIPE
168  *    signal. (Thus, the write return value is seen only if the program
169  *    catches, blocks or ignores this signal.)
170  *
171  ****************************************************************************/
172 
write(int fd,const void * buf,size_t nbytes)173 ssize_t write(int fd, const void *buf, size_t nbytes)
174 {
175 #if CONFIG_NFILE_DESCRIPTORS > 0
176   struct file *filep;
177 #endif
178 
179   /* Did we get a valid file descriptor? */
180 
181 #if CONFIG_NFILE_DESCRIPTORS > 0
182   if ((unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS)
183 #endif
184     {
185       /* Write to a socket descriptor is equivalent to send with flags == 0 */
186 
187 #if defined(LOSCFG_NET_LWIP_SACK)
188       const void *bufbak = buf;
189       ssize_t ret;
190       if (LOS_IsUserAddress((VADDR_T)(uintptr_t)buf))
191         {
192           if (buf != NULL && nbytes > 0)
193             {
194               buf = malloc(nbytes);
195               if (buf == NULL)
196                 {
197                   set_errno(ENOMEM);
198                   return VFS_ERROR;
199                 }
200               if (LOS_ArchCopyFromUser((void*)buf, bufbak, nbytes) != 0)
201                 {
202                   free((void*)buf);
203                   set_errno(EFAULT);
204                   return VFS_ERROR;
205                 }
206             }
207         }
208       ret = send(fd, buf, nbytes, 0);
209       if (buf != bufbak)
210         {
211           free((void*)buf);
212         }
213       return ret;
214 #else
215       set_errno(EBADF);
216       return VFS_ERROR;
217 #endif
218     }
219 
220 #if CONFIG_NFILE_DESCRIPTORS > 0
221   /* The descriptor is in the right range to be a file descriptor... write
222    * to the file.
223    */
224 
225   if (fd <= STDERR_FILENO && fd >= STDIN_FILENO) /* fd : [0,2] */
226     {
227       fd = ConsoleUpdateFd();
228       if (fd < 0)
229         {
230           set_errno(EBADF);
231           return VFS_ERROR;
232         }
233     }
234 
235   int ret = fs_getfilep(fd, &filep);
236   if (ret < 0)
237     {
238       /* The errno value has already been set */
239       return VFS_ERROR;
240     }
241 
242   if (filep->f_oflags & O_DIRECTORY)
243     {
244       set_errno(EBADF);
245       return VFS_ERROR;
246     }
247 
248   if (filep->f_oflags & O_APPEND)
249     {
250       if (file_seek64(filep, 0, SEEK_END) == -1)
251         {
252           return VFS_ERROR;
253         }
254     }
255 
256   /* Perform the write operation using the file descriptor as an index */
257 
258   return file_write(filep, buf, nbytes);
259 #endif
260 }
261