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