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