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