• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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