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