• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * fs/dirent/fs_readdir.c
3  *
4  *   Copyright (C) 2007-2009, 2011, 2017-2018 Gregory Nutt. All rights
5  *     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 "string.h"
43 #include "dirent.h"
44 #include "errno.h"
45 #include "unistd.h"
46 #include "fs/dirent_fs.h"
47 #include "user_copy.h"
48 #include "fs/file.h"
49 #include "vnode.h"
50 
51 /****************************************************************************
52  * Name: do_readdir
53  *
54  * Description:
55  *   The do_readdir() function returns a pointer to a dirent structure
56  *   representing the next directory entry in the directory stream pointed
57  *   to by dir.  It returns NULL on reaching the end-of-file or if an error
58  *   occurred.
59  *
60  * Input Parameters:
61  *   dirp -- An instance of type DIR created by a previous call to opendir();
62  *
63  * Returned Value:
64  *   The do_readdir() function returns a pointer to a dirent structure, or NULL
65  *   if an error occurs or end-of-file is reached.  On error, errno is set
66  *   appropriately.
67  *
68  *   EBADF   - Invalid directory stream descriptor dir
69  *
70  ****************************************************************************/
__readdir(DIR * dirp,int * lencnt)71 static struct dirent *__readdir(DIR *dirp, int *lencnt)
72 {
73   struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp;
74   struct Vnode *vnode_ptr = NULL;
75   int ret = 0;
76   int file_cnt = 0;
77 
78   /* Verify that we were provided with a valid directory structure */
79 
80   if (!idir)
81     {
82       ret = -EBADF;
83       goto errout;
84     }
85 
86   vnode_ptr = idir->fd_root;
87   if (vnode_ptr == NULL)
88     {
89       /* End of file and error conditions are not distinguishable
90        * with readdir.  We return NULL to signal either case.
91        */
92 
93       ret = -ENOENT;
94       goto errout;
95     }
96 
97   /* Perform the readdir() operation */
98 #ifdef LOSCFG_ENABLE_READ_BUFFER
99   idir->read_cnt = MAX_DIRENT_NUM;
100 #else
101   idir->read_cnt = 1;
102 #endif
103 
104   if (vnode_ptr->vop != NULL && vnode_ptr->vop->Readdir != NULL)
105     {
106       file_cnt = vnode_ptr->vop->Readdir(vnode_ptr, idir);
107     }
108   else
109     {
110       ret = -ENOSYS;
111       goto errout;
112     }
113 
114   if (file_cnt > 0)
115     {
116       *lencnt = file_cnt * sizeof(struct dirent);
117       return &(idir->fd_dir[0]);
118     }
119 
120 errout:
121   if (ret < 0)
122     {
123       set_errno(ret);
124     }
125   else if (file_cnt <= 0)
126     {
127       set_errno(ENOENT);
128     }
129 
130   return (struct dirent *)NULL;
131 }
132 
133 /****************************************************************************
134  * Public Functions
135  ****************************************************************************/
136 
137 /****************************************************************************
138  * Name: readdir
139  *
140  * Description:
141  *   The readdir() function returns a pointer to a dirent structure
142  *   representing the next directory entry in the directory stream pointed
143  *   to by dir.  It returns NULL on reaching the end-of-file or if an error
144  *   occurred.
145  *
146  * Inputs:
147  *   dirp -- An instance of type DIR created by a previous call to opendir();
148  *
149  * Return:
150  *   The readdir() function returns a pointer to a dirent structure, or NULL
151  *   if an error occurs or end-of-file is reached.  On error, errno is set
152  *   appropriately.
153  *
154  *   EBADF   - Invalid directory stream descriptor dir
155  *
156  ****************************************************************************/
readdir(DIR * dirp)157 struct dirent *readdir(DIR *dirp)
158 {
159   int ret;
160   int old_err = get_errno();
161   int dirent_len = 0;
162   struct dirent *de = NULL;
163   struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp;
164 
165   if (idir->cur_pos != 0 && idir->cur_pos < MAX_DIRENT_NUM && idir->cur_pos < idir->end_pos)
166     {
167       de = &(idir->fd_dir[idir->cur_pos]);
168 
169       if (idir->cur_pos == MAX_DIRENT_NUM)
170         {
171           idir->cur_pos = 0;
172         }
173       idir->cur_pos++;
174 
175       return de;
176     }
177   else
178     {
179       de = __readdir(dirp, &dirent_len);
180       idir->end_pos = dirent_len / sizeof(struct dirent);
181       idir->cur_pos = 1;
182 
183       if (de == NULL)
184         {
185           idir->cur_pos = 0;
186           ret = get_errno();
187           /* Special case: ret = -ENOENT is end of file */
188 
189           if (ret == ENOENT)
190             {
191               set_errno(old_err);
192             }
193         }
194     }
195   return de;
196 }
197 
198 /* readdir syscall routine */
199 
do_readdir(int fd,struct dirent ** de,unsigned int count)200 int do_readdir(int fd, struct dirent **de, unsigned int count)
201 {
202   struct dirent *de_src = NULL;
203   int de_len = 0;
204   /* Did we get a valid file descriptor? */
205 
206 #if CONFIG_NFILE_DESCRIPTORS > 0
207   struct file *filep = NULL;
208 
209   if (de == NULL)
210     {
211       return -EINVAL;
212     }
213 
214   if ((fd < 3) || (unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS)
215     {
216       return -EBADF;
217     }
218   else
219     {
220       /* The descriptor is in a valid range to file descriptor... do the
221        * read.  First, get the file structure.
222        */
223 
224       int ret = fs_getfilep(fd, &filep);
225       if (ret < 0)
226         {
227           /* The errno value has already been set */
228           return -get_errno();
229         }
230 
231       /* Then let do_readdir do all of the work */
232 
233       de_src = __readdir(filep->f_dir, &de_len);
234       if (de_src == NULL)
235         {
236           /* Special case: ret = -ENOENT is end of file */
237           return -get_errno();
238         }
239       *de = de_src;
240 
241       return de_len;
242     }
243 #endif
244   return OK;
245 }
246