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