1 /****************************************************************************
2 * fs/vfs/fs_open.c
3 *
4 * Copyright (C) 2007-2009, 2011-2012, 2016-2018 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
43 #include "errno.h"
44 #include "sys/types.h"
45 #include "fcntl.h"
46 #include "sched.h"
47 #include "assert.h"
48 #ifdef LOSCFG_FILE_MODE
49 #include "stdarg.h"
50 #endif
51 #include "stdlib.h"
52 #include "vnode.h"
53 #include "blockproxy.h"
54 #include "path_cache.h"
55 #include "unistd.h"
56
57 /****************************************************************************
58 * Public Functions
59 ****************************************************************************/
60
oflag_convert_mode(int oflags)61 static int oflag_convert_mode(int oflags)
62 {
63 /* regular file operations */
64
65 int acc_mode = 0;
66 if ((oflags & O_ACCMODE) == O_RDONLY)
67 acc_mode |= READ_OP;
68 if (oflags & O_WRONLY)
69 acc_mode |= WRITE_OP;
70 if (oflags & O_RDWR)
71 acc_mode |= READ_OP | WRITE_OP;
72
73 /* Opens the file, if it is existing. If not, a new file is created. */
74
75 if (oflags & O_CREAT)
76 acc_mode |= WRITE_OP;
77
78 /* Creates a new file. If the file is existing, it is truncated and overwritten. */
79
80 if (oflags & O_TRUNC)
81 acc_mode |= WRITE_OP;
82
83 /* Creates a new file. The function fails if the file is already existing. */
84
85 if (oflags & O_EXCL)
86 acc_mode |= WRITE_OP;
87 if (oflags & O_APPEND)
88 acc_mode |= WRITE_OP;
89
90 /* mark for executing operation */
91
92 if (oflags & O_EXECVE)
93 acc_mode |= EXEC_OP;
94 return acc_mode;
95 }
96
get_path_from_fd(int fd,char ** path)97 int get_path_from_fd(int fd, char **path)
98 {
99 struct file *file = NULL;
100 char *copypath = NULL;
101
102 if (fd == AT_FDCWD)
103 {
104 return OK;
105 }
106
107 int ret = fs_getfilep(fd, &file);
108 if (ret < 0)
109 {
110 return -ENOENT;
111 }
112
113 if ((file == NULL) || (file->f_vnode == NULL) || (file->f_path == NULL))
114 {
115 return -EBADF;
116 }
117
118 copypath = strdup((const char*)file->f_path);
119 if (copypath == NULL)
120 {
121 return VFS_ERROR;
122 }
123
124 *path = copypath;
125 return OK;
126 }
127
do_creat(struct Vnode * parentNode,char * fullpath,mode_t mode,struct Vnode ** node)128 static int do_creat(struct Vnode *parentNode, char *fullpath, mode_t mode, struct Vnode **node)
129 {
130 int ret;
131 char *name = strrchr(fullpath, '/') + 1;
132 parentNode->useCount++;
133
134 if (parentNode->vop != NULL && parentNode->vop->Create != NULL)
135 {
136 ret = parentNode->vop->Create(parentNode, name, mode, node);
137 }
138 else
139 {
140 ret = -ENOSYS;
141 }
142
143 parentNode->useCount--;
144 if (ret < 0)
145 {
146 return ret;
147 }
148
149 struct PathCache *dt = PathCacheAlloc(parentNode, *node, name, strlen(name));
150 if (dt == NULL)
151 {
152 // alloc name cache failed is not a critical problem, let it go.
153 PRINT_ERR("alloc path cache %s failed\n", name);
154 }
155 return OK;
156 }
157
fp_open(int dirfd,const char * path,int oflags,mode_t mode)158 int fp_open(int dirfd, const char *path, int oflags, mode_t mode)
159 {
160 int ret;
161 int accmode;
162 struct file *filep = NULL;
163 struct Vnode *vnode = NULL;
164 struct Vnode *parentVnode = NULL;
165 char *fullpath = NULL;
166
167 VnodeHold();
168 ret = follow_symlink(dirfd, path, &vnode, &fullpath);
169 if (ret == OK)
170 {
171 /* if file exist */
172 if (vnode->type == VNODE_TYPE_BCHR)
173 {
174 ret = -EINVAL;
175 VnodeDrop();
176 goto errout;
177 }
178 #ifdef LOSCFG_FS_VFS_BLOCK_DEVICE
179 if (vnode->type == VNODE_TYPE_BLK)
180 {
181 VnodeDrop();
182 int fd = block_proxy(fullpath, oflags);
183 if (fd < 0)
184 {
185 ret = fd;
186 goto errout;
187 }
188 return fd;
189 }
190 #endif
191 if ((vnode->originMount) && (vnode->originMount->mountFlags & MS_RDONLY) &&
192 (((oflags & O_ACCMODE) != O_RDONLY) || (oflags & O_TRUNC)))
193 {
194 ret = -EROFS;
195 VnodeDrop();
196 goto errout;
197 }
198 if ((oflags & O_CREAT) && (oflags & O_EXCL))
199 {
200 ret = -EEXIST;
201 VnodeDrop();
202 goto errout;
203 }
204 if (vnode->type == VNODE_TYPE_DIR)
205 {
206 ret = -EISDIR;
207 VnodeDrop();
208 goto errout;
209 }
210 accmode = oflag_convert_mode(oflags);
211 if (VfsVnodePermissionCheck(vnode, accmode))
212 {
213 ret = -EACCES;
214 VnodeDrop();
215 goto errout;
216 }
217 }
218
219 if ((ret != OK) && (oflags & O_CREAT) && vnode)
220 {
221 /* if file not exist, but parent dir of the file is exist */
222 if ((vnode->originMount) && (vnode->originMount->mountFlags & MS_RDONLY))
223 {
224 ret = -EROFS;
225 VnodeDrop();
226 goto errout;
227 }
228 if (VfsVnodePermissionCheck(vnode, (WRITE_OP | EXEC_OP)))
229 {
230 ret = -EACCES;
231 VnodeDrop();
232 goto errout;
233 }
234 parentVnode = vnode;
235 ret = do_creat(parentVnode, fullpath, mode, &vnode);
236 if (ret != OK)
237 {
238 VnodeDrop();
239 goto errout;
240 }
241 vnode->filePath = strdup(fullpath);
242 }
243
244 if (ret != OK)
245 {
246 /* found nothing */
247 VnodeDrop();
248 goto errout;
249 }
250 vnode->useCount++;
251 VnodeDrop();
252
253 if (oflags & O_TRUNC)
254 {
255 if (vnode->useCount > 1)
256 {
257 ret = -EBUSY;
258 goto errout_with_count;
259 }
260
261 if (vnode->vop->Truncate)
262 {
263 ret = vnode->vop->Truncate(vnode, 0);
264 if (ret != OK)
265 {
266 goto errout_with_count;
267 }
268 }
269 else
270 {
271 ret = -ENOSYS;
272 goto errout_with_count;
273 }
274 }
275
276 filep = files_allocate(vnode, oflags, 0, NULL, FILE_START_FD);
277 if (filep == NULL)
278 {
279 ret = -EMFILE;
280 goto errout_with_count;
281 }
282
283 if (filep->ops && filep->ops->open)
284 {
285 ret = filep->ops->open(filep);
286 }
287
288 if (ret < 0)
289 {
290 files_release(filep->fd);
291 goto errout_with_count;
292 }
293
294 if (fullpath)
295 {
296 free(fullpath);
297 }
298 return filep->fd;
299
300 errout_with_count:
301 VnodeHold();
302 vnode->useCount--;
303 VnodeDrop();
304 errout:
305 if (fullpath)
306 {
307 free(fullpath);
308 }
309 set_errno(-ret);
310 return VFS_ERROR;
311 }
312
do_open(int dirfd,const char * path,int oflags,mode_t mode)313 int do_open(int dirfd, const char *path, int oflags, mode_t mode)
314 {
315 int ret;
316 int fd;
317
318 if ((oflags & (O_WRONLY | O_CREAT)) != 0)
319 {
320 mode &= ~GetUmask();
321 mode &= (S_IRWXU | S_IRWXG | S_IRWXO);
322 }
323
324 fd = fp_open(dirfd, path, oflags, mode);
325 if (fd < 0)
326 {
327 ret = -get_errno();
328 goto errout;
329 }
330
331 return fd;
332
333 errout:
334 set_errno(-ret);
335 return VFS_ERROR;
336 }
337
338 /****************************************************************************
339 * Name: open
340 *
341 * Description: Standard 'open' interface
342 *
343 ****************************************************************************/
344
open(const char * path,int oflags,...)345 int open(const char *path, int oflags, ...)
346 {
347 mode_t mode = DEFAULT_FILE_MODE; /* File read-write properties. */
348 #ifdef LOSCFG_FILE_MODE
349 va_list ap;
350 va_start(ap, oflags);
351 mode = va_arg(ap, int);
352 va_end(ap);
353 #endif
354
355 return do_open(AT_FDCWD, path, oflags, mode);
356 }
357
open64(const char * __path,int __oflag,...)358 int open64 (const char *__path, int __oflag, ...)
359 {
360 mode_t mode = DEFAULT_FILE_MODE; /* File read-write properties. */
361 #ifdef LOSCFG_FILE_MODE
362 va_list ap;
363 va_start(ap, __oflag);
364 mode = va_arg(ap, int);
365 va_end(ap);
366 if ((__oflag & (O_WRONLY | O_CREAT)) != 0)
367 {
368 mode &= ~GetUmask();
369 mode &= (S_IRWXU|S_IRWXG|S_IRWXO);
370 }
371 #endif
372 return open (__path, ((unsigned int)__oflag) | O_LARGEFILE, mode);
373 }
374