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