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