1 /****************************************************************************
2 * fs/dirent/fs_readdir.c
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership. The
7 * ASF licenses this file to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance with the
9 * License. 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, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16 * License for the specific language governing permissions and limitations
17 * under the License.
18 *
19 ****************************************************************************/
20
21 /****************************************************************************
22 * Included Files
23 ****************************************************************************/
24
25 #include "vfs_config.h"
26 #include "string.h"
27 #include "dirent.h"
28 #include "errno.h"
29 #include "unistd.h"
30 #include "fs/dirent_fs.h"
31 #include "user_copy.h"
32 #include "fs/file.h"
33 #include "vnode.h"
34
35 /****************************************************************************
36 * Name: do_readdir
37 *
38 * Description:
39 * The do_readdir() function returns a pointer to a dirent structure
40 * representing the next directory entry in the directory stream pointed
41 * to by dir. It returns NULL on reaching the end-of-file or if an error
42 * occurred.
43 *
44 * Input Parameters:
45 * dirp -- An instance of type DIR created by a previous call to opendir();
46 *
47 * Returned Value:
48 * The do_readdir() function returns a pointer to a dirent structure, or NULL
49 * if an error occurs or end-of-file is reached. On error, errno is set
50 * appropriately.
51 *
52 * EBADF - Invalid directory stream descriptor dir
53 *
54 ****************************************************************************/
__readdir(DIR * dirp,int * lencnt)55 static struct dirent *__readdir(DIR *dirp, int *lencnt)
56 {
57 struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp;
58 struct Vnode *vnode_ptr = NULL;
59 int ret = 0;
60 int file_cnt = 0;
61
62 /* Verify that we were provided with a valid directory structure */
63
64 if (!idir)
65 {
66 ret = -EBADF;
67 goto errout;
68 }
69
70 vnode_ptr = idir->fd_root;
71 if (vnode_ptr == NULL)
72 {
73 /* End of file and error conditions are not distinguishable
74 * with readdir. We return NULL to signal either case.
75 */
76
77 ret = -ENOENT;
78 goto errout;
79 }
80
81 /* Perform the readdir() operation */
82 #ifdef LOSCFG_ENABLE_READ_BUFFER
83 idir->read_cnt = MAX_DIRENT_NUM;
84 #else
85 idir->read_cnt = 1;
86 #endif
87
88 if (vnode_ptr->vop != NULL && vnode_ptr->vop->Readdir != NULL)
89 {
90 file_cnt = vnode_ptr->vop->Readdir(vnode_ptr, idir);
91 }
92 else
93 {
94 ret = -ENOSYS;
95 goto errout;
96 }
97
98 if (file_cnt > 0)
99 {
100 *lencnt = file_cnt * sizeof(struct dirent);
101 return &(idir->fd_dir[0]);
102 }
103
104 errout:
105 if (ret < 0)
106 {
107 set_errno(ret);
108 }
109 else if (file_cnt <= 0)
110 {
111 set_errno(ENOENT);
112 }
113
114 return (struct dirent *)NULL;
115 }
116
117 /****************************************************************************
118 * Public Functions
119 ****************************************************************************/
120
121 /****************************************************************************
122 * Name: readdir
123 *
124 * Description:
125 * The readdir() function returns a pointer to a dirent structure
126 * representing the next directory entry in the directory stream pointed
127 * to by dir. It returns NULL on reaching the end-of-file or if an error
128 * occurred.
129 *
130 * Inputs:
131 * dirp -- An instance of type DIR created by a previous call to opendir();
132 *
133 * Return:
134 * The readdir() function returns a pointer to a dirent structure, or NULL
135 * if an error occurs or end-of-file is reached. On error, errno is set
136 * appropriately.
137 *
138 * EBADF - Invalid directory stream descriptor dir
139 *
140 ****************************************************************************/
readdir(DIR * dirp)141 struct dirent *readdir(DIR *dirp)
142 {
143 int ret;
144 int old_err = get_errno();
145 int dirent_len = 0;
146 struct dirent *de = NULL;
147 struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp;
148
149 if (idir->cur_pos != 0 && idir->cur_pos < MAX_DIRENT_NUM && idir->cur_pos < idir->end_pos)
150 {
151 de = &(idir->fd_dir[idir->cur_pos]);
152
153 if (idir->cur_pos == MAX_DIRENT_NUM)
154 {
155 idir->cur_pos = 0;
156 }
157 idir->cur_pos++;
158
159 return de;
160 }
161 else
162 {
163 de = __readdir(dirp, &dirent_len);
164 idir->end_pos = dirent_len / sizeof(struct dirent);
165 idir->cur_pos = 1;
166
167 if (de == NULL)
168 {
169 idir->cur_pos = 0;
170 ret = get_errno();
171 /* Special case: ret = -ENOENT is end of file */
172
173 if (ret == ENOENT)
174 {
175 set_errno(old_err);
176 }
177 }
178 }
179 return de;
180 }
181
182 /* readdir syscall routine */
183
do_readdir(int fd,struct dirent ** de,unsigned int count)184 int do_readdir(int fd, struct dirent **de, unsigned int count)
185 {
186 struct dirent *de_src = NULL;
187 int de_len = 0;
188 /* Did we get a valid file descriptor? */
189
190 #if CONFIG_NFILE_DESCRIPTORS > 0
191 struct file *filep = NULL;
192
193 if (de == NULL)
194 {
195 return -EINVAL;
196 }
197
198 if ((fd < 3) || (unsigned int)fd >= CONFIG_NFILE_DESCRIPTORS)
199 {
200 return -EBADF;
201 }
202 else
203 {
204 /* The descriptor is in a valid range to file descriptor... do the
205 * read. First, get the file structure.
206 */
207
208 int ret = fs_getfilep(fd, &filep);
209 if (ret < 0)
210 {
211 /* The errno value has already been set */
212 return -get_errno();
213 }
214
215 /* Then let do_readdir do all of the work */
216
217 de_src = __readdir(filep->f_dir, &de_len);
218 if (de_src == NULL)
219 {
220 /* Special case: ret = -ENOENT is end of file */
221 return -get_errno();
222 }
223 *de = de_src;
224
225 return de_len;
226 }
227 #endif
228 return OK;
229 }
230