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