xref: /third_party/NuttX/fs/vfs/fs_mkdir.c (revision beacf11b)
1/****************************************************************************
2 * fs/vfs/fs_mkdir.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#include "errno.h"
27#include "sys/types.h"
28#include "sys/stat.h"
29#include "stdlib.h"
30#include "vnode.h"
31#include "string.h"
32#include "capability_api.h"
33#include "path_cache.h"
34
35/****************************************************************************
36 * Private Functions
37 ****************************************************************************/
38int do_mkdir(int dirfd, const char *pathname, mode_t mode)
39{
40  struct Vnode *parentVnode = NULL;
41  struct Vnode *vnode = NULL;
42  struct Mount *mount = NULL;
43  int ret;
44  char *fullpath = NULL;
45  char *relativepath = NULL;
46  char *dirname = NULL;
47
48  mode &= ~GetUmask();
49  mode &= (S_IRWXU|S_IRWXG|S_IRWXO);
50
51  /* Get absolute path by dirfd*/
52  ret = get_path_from_fd(dirfd, &relativepath);
53  if (ret < 0)
54    {
55      goto errout;
56    }
57
58  ret = vfs_normalize_path((const char *)relativepath, pathname, &fullpath);
59  if (relativepath)
60    {
61      free(relativepath);
62    }
63
64  if (ret < 0)
65    {
66      goto errout;
67    }
68#ifdef LOSCFG_KERNEL_PLIMITS
69  if (!strncmp(fullpath, "/dev", 4) || !strcmp(fullpath, "/proc"))
70#else
71  if (!strncmp(fullpath, "/dev", 4) || !strncmp(fullpath, "/proc", 5))
72#endif
73    {
74      // virtual root create virtual dir
75      VnodeHold();
76      ret = VnodeLookup(fullpath, &vnode, V_DUMMY|V_CREATE);
77      if (ret != OK)
78        {
79          goto errout_with_lock;
80        }
81      vnode->mode = mode | S_IFDIR;
82      vnode->type = VNODE_TYPE_DIR;
83      VnodeDrop();
84      goto out;
85    }
86
87  dirname = strrchr(fullpath, '/') + 1;
88
89  VnodeHold();
90  ret = VnodeLookup(fullpath, &parentVnode, 0);
91  if (ret == OK)
92    {
93      ret = -EEXIST;
94      goto errout_with_lock;
95    }
96
97  if (parentVnode == NULL)
98    {
99      ret = -ENOENT;
100      goto errout_with_lock;
101    }
102  mount = parentVnode->originMount;
103  if ((mount != NULL) && (mount->mountFlags & MS_RDONLY))
104    {
105      ret = -EROFS;
106      goto errout_with_lock;
107    }
108
109  parentVnode->useCount++;
110
111  if (VfsVnodePermissionCheck(parentVnode, (WRITE_OP | EXEC_OP)))
112    {
113      ret = -EACCES;
114      goto errout_with_count;
115    }
116
117  if ((parentVnode->vop != NULL) && (parentVnode->vop->Mkdir != NULL))
118    {
119      ret = parentVnode->vop->Mkdir(parentVnode, dirname, mode, &vnode);
120    }
121  else
122    {
123      ret = -ENOSYS;
124    }
125
126  if (ret < 0)
127    {
128      goto errout_with_count;
129    }
130
131  struct PathCache *dt = PathCacheAlloc(parentVnode, vnode, dirname, strlen(dirname));
132  if (dt == NULL) {
133      // alloc name cache failed is not a critical problem, let it go.
134      PRINT_ERR("alloc path cache %s failed\n", dirname);
135  }
136  vnode->filePath = strdup(fullpath);
137  parentVnode->useCount--;
138  VnodeDrop();
139out:
140  /* Directory successfully created */
141  free(fullpath);
142
143  return OK;
144errout_with_count:
145  parentVnode->useCount--;
146errout_with_lock:
147  VnodeDrop();
148errout:
149  set_errno(-ret);
150  if (fullpath)
151    {
152      free(fullpath);
153    }
154  return VFS_ERROR;
155}
156
157/****************************************************************************
158 * Public Functions
159 ****************************************************************************/
160
161/****************************************************************************
162 * Name: mkdir
163 *
164 * Description:  Create a directory
165 *
166 ****************************************************************************/
167
168int mkdir(const char *pathname, mode_t mode)
169{
170  return do_mkdir(AT_FDCWD, pathname, mode);
171}
172
173/****************************************************************************
174 * Name: mkdirat
175 *
176 * Description:  Create a directory by dirfd
177 *
178 ****************************************************************************/
179
180int mkdirat(int dirfd, const char *pathname, mode_t mode)
181{
182  return do_mkdir(dirfd, pathname, mode);
183}
184