xref: /third_party/NuttX/fs/vfs/fs_rmdir.c (revision beacf11b)
1/****************************************************************************
2 * fs/vfs/fs_rmdir.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 "unistd.h"
28#include "errno.h"
29#include "stdlib.h"
30#include "vnode.h"
31#include "sys/stat.h"
32#include "string.h"
33#include "limits.h"
34#include "fs/mount.h"
35
36/****************************************************************************
37 * Private Functions
38 ****************************************************************************/
39static int check_target(struct Vnode *vnode, char *name)
40{
41  if (vnode == NULL)
42    {
43      return -ENOENT;
44    }
45
46  if ((vnode->originMount) && (vnode->originMount->mountFlags & MS_RDONLY))
47    {
48      return -EROFS;
49    }
50
51  if (vnode->type != VNODE_TYPE_DIR)
52    {
53      return -ENOTDIR;
54    }
55
56  if (vnode->useCount > 0)
57    {
58      return -EBUSY;
59    }
60
61  if ((vnode->flag & VNODE_FLAG_MOUNT_ORIGIN)
62      || (vnode->flag & VNODE_FLAG_MOUNT_NEW))
63    {
64      return -EBUSY;
65    }
66
67  char cwd[PATH_MAX];
68  char *pret = getcwd(cwd, PATH_MAX);
69  if (pret != NULL)
70    {
71      struct Vnode *cwdnode = NULL;
72      int ret = VnodeLookup(cwd, &cwdnode, 0);
73      if (ret == OK && (cwdnode == vnode))
74        {
75          return -EBUSY;
76        }
77    }
78  return OK;
79}
80/****************************************************************************
81 * Public Functions
82 ****************************************************************************/
83
84/****************************************************************************
85 * Name: do_rmdir
86 *
87 * Description:  Remove a file managed a mountpoint
88 *
89 ****************************************************************************/
90
91int do_rmdir(int dirfd, const char *pathname)
92{
93  struct Vnode *vnode = NULL;
94  char             *fullpath     = NULL;
95  char             *relativepath = NULL;
96  char             *name         = NULL;
97  int               ret;
98
99  if (pathname == NULL)
100    {
101      ret = -EINVAL;
102      goto errout;
103    }
104
105  /* Get relative path by dirfd*/
106  ret = get_path_from_fd(dirfd, &relativepath);
107  if (ret < 0)
108    {
109      goto errout;
110    }
111
112  if (relativepath)
113    {
114      ret = vfs_normalize_path((const char *)relativepath, pathname, &fullpath);
115      free(relativepath);
116      if (ret < 0)
117        {
118          goto errout;
119        }
120
121      name = strrchr(fullpath, '/');
122      VnodeHold();
123      ret = VnodeLookup(fullpath, &vnode, 0);
124    }
125  else
126    {
127      name = strrchr(pathname, '/');
128      VnodeHold();
129      if (name == NULL)
130        {
131          name = (char *)pathname;
132        }
133      else
134        {
135          name++;
136        }
137      ret = VnodeLookup(pathname, &vnode, 0);
138    }
139
140  if (ret != OK)
141    {
142      goto errout_with_lock;
143    }
144
145  ret = check_target(vnode, name);
146  if (ret != OK) {
147      PRINT_ERR("rmdir failed err = %d\n", ret);
148      goto errout_with_lock;
149  }
150
151  if (VfsVnodePermissionCheck(vnode->parent, (WRITE_OP | EXEC_OP))) {
152      ret = -EACCES;
153      goto errout_with_lock;
154  }
155
156  if (vnode && vnode->vop && vnode->vop->Rmdir) {
157      ret = vnode->vop->Rmdir(vnode->parent, vnode, name);
158  } else {
159      ret = -ENOSYS;
160  }
161  if (ret < 0) {
162      goto errout_with_lock;
163  }
164  VnodeFree(vnode);
165  VnodeDrop();
166
167  /* Successfully unlinked */
168  if (fullpath)
169    {
170      free(fullpath);
171    }
172
173  return OK;
174
175errout_with_lock:
176  VnodeDrop();
177
178errout:
179  if (fullpath)
180    {
181      free(fullpath);
182    }
183
184  set_errno(-ret);
185  return VFS_ERROR;
186}
187
188/****************************************************************************
189 * Name: rmdir
190 *
191 * Description:  Remove a file managed a mountpoint
192 *
193 ****************************************************************************/
194
195int rmdir(const char *pathname)
196{
197  return do_rmdir(AT_FDCWD, pathname);
198}
199