• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * fs/dirent/fs_opendir.c
3  *
4  * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved.
5  * Based on NuttX originally written by Gregory Nutt
6  *
7  *   Copyright (C) 2007-2009, 2011, 2013-2014, 2017-2018 Gregory Nutt. All
8  *     rights reserved.
9  *   Author: Gregory Nutt <gnutt@nuttx.org>
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in
19  *    the documentation and/or other materials provided with the
20  *    distribution.
21  * 3. Neither the name NuttX nor the names of its contributors may be
22  *    used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
32  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
33  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  ****************************************************************************/
39 
40 /****************************************************************************
41  * Included Files
42  ****************************************************************************/
43 
44 #include "vfs_config.h"
45 #include "dirent.h"
46 #include "string.h"
47 #include "assert.h"
48 #include "errno.h"
49 #include "stdlib.h"
50 #include "fs/dirent_fs.h"
51 #include "vnode.h"
52 #include "path_cache.h"
53 
54 /****************************************************************************
55  * Public Functions
56  ****************************************************************************/
57 
58 /****************************************************************************
59  * Name: opendir
60  *
61  * Description:
62  *   The  opendir() function opens a directory stream corresponding to the
63  *   directory name, and returns a pointer to the directory stream. The
64  *   stream is positioned at the first entry in the directory.
65  *
66  * Input Parameters:
67  *   path -- the directory to open
68  *
69  * Returned Value:
70  *   The opendir() function returns a pointer to the directory stream.  On
71  *   error, NULL is returned, and errno is set appropriately.
72  *
73  *   EACCES  - Permission denied.
74  *   EMFILE  - Too many file descriptors in use by process.
75  *   ENFILE  - Too many files are currently open in the
76  *             system.
77  *   ENOENT  - Directory does not exist, or name is an empty
78  *             string.
79  *   ENOMEM  - Insufficient memory to complete the operation.
80  *   ENOTDIR - 'path' is not a directory.
81  *
82  ****************************************************************************/
83 
opendir(const char * path)84 DIR *opendir(const char *path)
85 {
86   struct Vnode *vp = NULL;
87   struct fs_dirent_s *dir = NULL;
88   int ret;
89 
90   /* Find the node matching the path. */
91   VnodeHold();
92   ret = VnodeLookup(path, &vp, 0);
93   if (vp == NULL || ret != OK)
94     {
95       VnodeDrop();
96       goto errout;
97     }
98   if (vp->type != VNODE_TYPE_DIR)
99     {
100       ret = -ENOTDIR;
101       PRINT_ERR("opendir (%s) failed, err=%d\n", path, ret);
102       VnodeDrop();
103       goto errout;
104     }
105 
106   vp->useCount++;
107   VnodeDrop();
108 
109   /* Allocate a type DIR -- which is little more than an vp container. */
110   dir = (struct fs_dirent_s *)calloc(1, sizeof(struct fs_dirent_s));
111   if (!dir)
112     {
113       /* Insufficient memory to complete the operation. */
114       ret = -ENOMEM;
115       goto errout_with_count;
116     }
117 
118   /* Populate the DIR structure and return it to the caller.  The way that
119    * we do this depends on whenever this is a "normal" pseudo-file-system
120    * vp or a file system mountpoint.
121    */
122 
123   dir->fd_position = 0;      /* This is the position in the read stream */
124 
125   if (vp->vop != NULL && vp->vop->Opendir != NULL)
126     {
127       ret = vp->vop->Opendir(vp, dir);
128     }
129   else
130     {
131       ret = -ENOSYS;
132     }
133   if (ret < 0)
134     {
135       free(dir);
136       goto errout_with_count;
137     }
138   dir->fd_status = DIRENT_MAGIC;
139   dir->fd_root = vp;
140 
141   return ((DIR *)dir);
142 
143   /* Nasty goto's make error handling simpler */
144 
145 errout_with_count:
146   VnodeHold();
147   vp->useCount--;
148   VnodeDrop();
149 errout:
150   set_errno(-ret);
151   return NULL;
152 }
153 
do_opendir(const char * path,int oflags)154 int do_opendir(const char *path, int oflags)
155 {
156   int ret;
157 
158   struct Vnode *vp = NULL;
159   struct file *filep = NULL;
160   struct fs_dirent_s *dir = NULL;
161   char *fullpath = NULL;
162   char *relativepath = NULL;
163 
164   if (path == NULL || *path == 0)
165     {
166        ret = -EINVAL;
167        goto errout;
168     }
169 
170   ret = get_path_from_fd(AT_FDCWD, &relativepath);
171   if (ret < 0)
172     {
173       goto errout;
174     }
175 
176   ret = vfs_normalize_path((const char *)relativepath, path, &fullpath);
177   if (relativepath)
178     {
179       free(relativepath);
180     }
181   if (ret < 0)
182     {
183       goto errout;
184     }
185 
186   VnodeHold();
187   /* Get an vnode for this file */
188   ret = VnodeLookup(path, &vp, 0);
189   if (ret < 0)
190     {
191       VnodeDrop();
192       goto errout;
193     }
194   if (vp->type != VNODE_TYPE_DIR)
195     {
196       ret = -ENOTDIR;
197       VnodeDrop();
198       goto errout;
199     }
200   vp->useCount++;
201   VnodeDrop();
202 
203   filep = files_allocate(vp, oflags, 0, NULL, FILE_START_FD);
204   if (filep == NULL)
205     {
206       ret = -EMFILE;
207       goto errout_with_vnode;
208     }
209 
210   /* Allocate a type DIR -- which is little more than an vnode  container. */
211   dir = (struct fs_dirent_s *)zalloc(sizeof(struct fs_dirent_s));
212   if (dir == NULL)
213     {
214       ret = -ENOMEM;
215       goto errout_with_file;
216     }
217   dir->fd_position = 0;      /* This is the position in the read stream */
218 
219   /* Open the directory at the relative path */
220   if (vp->vop != NULL && vp->vop->Opendir != NULL)
221     {
222       ret = vp->vop->Opendir(vp, dir);
223     }
224   else
225     {
226       ret = -ENOSYS;
227     }
228 
229   if (ret < 0)
230     {
231       free(dir);
232       goto errout_with_file;
233     }
234 
235   dir->fd_root = vp;
236   dir->fd_status = DIRENT_MAGIC;
237   filep->f_dir = dir;
238   if (fullpath)
239     {
240       free(fullpath);
241     }
242 
243   return filep->fd;
244 
245 errout_with_file:
246   files_release(filep->fd);
247 errout_with_vnode:
248   VnodeHold();
249   vp->useCount--;
250   VnodeDrop();
251 errout:
252   if (fullpath)
253     {
254       free(fullpath);
255     }
256   set_errno(-ret);
257   return VFS_ERROR;
258 }
259